import sys
import json
import logging
import argparse
import select
import time
import logs.server_log_config
from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR
from common.variables import ACTION, PRESENCE, TIME, USER, ACCOUNT_NAME, RESPONSE, \
    MESSAGE, MESSAGE_TEXT, ERROR, DEFAULT_PORT, MAX_CONNECTIONS, SENDER
from common.utils import get_message, send_message
from decorators import log

# Инициализация логирования сервера:
SERVER_LOGGER = logging.getLogger('server')

@log
def process_client_message(message, messages_list, client):
    """
    Обработчик сообщений от клиентов.
    Функция принимает словарь-сообщение от клиента, проверяет корректность, возвращает словарь-ответ для клиента.
    :param message:
    :param messages_list:
    :param client:
    :return:
    """
    SERVER_LOGGER.debug(f'Разбор сообщения от клиента: {message}.')
    # Если это сообщение присутствует, принимаем и отвечаем.
    if ACTION in message and message[ACTION] == PRESENCE and TIME in message \
            and USER in message and message[USER][ACCOUNT_NAME] == 'Guest':
        send_message(client, {RESPONSE: 200})
        return
    # Если это сообщение, то добавляем его в очередь сообщений. Ответ не требуется.
    elif ACTION in message and message[ACTION] == MESSAGE and TIME in message \
            and MESSAGE_TEXT in message:
        messages_list.append((message[ACCOUNT_NAME], message[MESSAGE_TEXT]))
        return
    else:
        send_message(client, {
            RESPONSE: 400,
            ERROR: 'Bad request',
        })
        return

@log
def arg_parser():
    """Парсер аргументов командной строки."""
    parser = argparse.ArgumentParser()
    parser.add_argument('-p', default=DEFAULT_PORT, type=int, nargs='?')
    parser.add_argument('-a', default='', nargs='?')
    namespace = parser.parse_args(sys.argv[1:])
    listen_address = namespace.a
    listen_port = namespace.p

    # Проверка получения корректного номера порта для работы сервера.
    if not 1023 < listen_port < 65535:
        SERVER_LOGGER.critical(
            f'Попытка запуска сервера с неподходящим номером порта: {listen_port}.'
            f' Допустимые адреса с 1024 до 65535. Клиент завершается.'
        )
        sys.exit(1)

    return listen_address, listen_port

def main():
    """
    Загрузка параметров командной строки.
    Если нет параметров, то задаем значения по умолчанию.
    :return:
    """
    listen_address, listen_port = arg_parser()

    SERVER_LOGGER.info(f'Запущен сервер. Порт для подключений: {listen_port}, '
                       f'адрес, с которого принимаются подключения: {listen_address}. '
                       f'Если адрес не указан, то принимаются соединения с любых адресов.')

    # Готовим сокет.
    transport = socket(AF_INET, SOCK_STREAM)
    transport.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    transport.bind((listen_address, listen_port))
    transport.settimeout(1)

    # Список клиентов, очередь сообщений.
    clients = []
    messages = []

    # Слушаем порт.
    transport.listen(MAX_CONNECTIONS)

    while True:
        try:
            client, client_address = transport.accept()
        except OSError as err:
            print(err.errno)
            pass
        else:
            SERVER_LOGGER.info(f'Установлено соединение с ПК {client_address}.')
            clients.append(client)

        recv_data_list = []
        send_data_list = []
        err_list = []

        # Проверяем на наличие ждущих клиентов.
        try:
            if clients:
                recv_data_list, send_data_list, err_list = select.select(clients, clients, [], 0)
        except OSError:
            pass

        # Принимаем сообщения и еcли они есть, то кладем в словарь. В случае ошибки исключаем клиента.
        if recv_data_list:
            for client_with_message in recv_data_list:
                try:
                    process_client_message(get_message(client_with_message), messages, client_with_message)
                except:
                    SERVER_LOGGER.info(f'Клиент {client_with_message.getpeername()} отключился от сервера.')
                    clients.remove(client_with_message)
        # Если есть сообщения для отправки и ожидающие клиенты, то отправляем им сообщение.
        if messages and send_data_list:
            message = {
                ACTION: MESSAGE,
                SENDER: messages[0][0],
                TIME: time.time(),
                MESSAGE_TEXT: messages[0][1]
            }
            del messages[0]
            for waiting_client in send_data_list:
                try:
                    send_message(waiting_client, message)
                except:
                    SERVER_LOGGER.info(f'Клиент {waiting_client.getpeername()} отключился от сервера.')
                    waiting_client.close()
                    clients.remove(waiting_client)

if __name__ == '__main__':
    main()


"""
Main Neural Network Pipeline.
"""
#-------------------------- set gpu using tf ---------------------------#
import tensorflow as tf
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
session = tf.Session(config=config)

#-------------------  start importing keras module ---------------------#

from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, Conv1D, GlobalAveragePooling2D
from keras.callbacks import ModelCheckpoint
from datagenerator import DataGenerator
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
import numpy as np
import itertools
import os

# Parameters

if os.path.abspath('~') == '/Users/ghunk/~':
	data_root = "/Users/ghunk/Desktop/GRADUATE/CSC_464/Final_Project/Dataset/stft_binaural_0.5s/"
else:
	data_root = "/scratch/ghunkins/stft_binaural_0.5s/"

elevations = [-45, -30, -15, 0, 15, 30, 45]
azimuths = [15*x for x in range(24)]
el_az = list(itertools.product(elevations, azimuths))
classes = [str(x) + '_' + str(y) for x, y in el_az]
encoder = LabelEncoder()
encoder.fit(classes)

params = {'batch_size': 32,
		  'Y_encoder': encoder,
          'shuffle': True}

LIMIT = 2000000
RANDOM_STATE = 3

# Datasets
IDs = os.listdir(data_root)[:LIMIT]

Train_IDs, Test_IDs, _, _, = train_test_split(IDs, np.arange(len(IDs)), test_size=0.2, random_state=RANDOM_STATE)

# Generators
training_generator = DataGenerator(**params).generate(Train_IDs)
validation_generator = DataGenerator(**params).generate(Test_IDs)

# Design model
model = Sequential()
model.add(Conv2D(256, kernel_size=(804, 1), activation='relu', input_shape=(804, 47, 1)))
model.add(Conv2D(256, kernel_size=(1, 3), strides=(1, 2), activation='relu'))
model.add(Conv2D(256, kernel_size=(1, 3), strides=(1, 2), activation='relu'))
model.add(Conv2D(256, kernel_size=(1, 3), strides=(1, 2), activation='relu'))
model.add(GlobalAveragePooling2D(data_format='channels_last'))

model.add(Dense(168, activation='relu'))
model.add(Dense(168, activation='softmax'))

model.compile(loss='categorical_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])

model.summary()

# set callback: https://machinelearningmastery.com/check-point-deep-learning-models-keras/

filepath="weights-improvement-{epoch:02d}-{val_acc:.2f}.hdf5"
checkpoint = ModelCheckpoint(filepath, monitor='val_acc', verbose=1, save_best_only=True, mode='max')
callbacks_list = [checkpoint]

# Train model on dataset

model.fit_generator(generator = training_generator,
					          steps_per_epoch = len(Train_IDs)//params['batch_size'],
                    nb_epoch = 50,
                    validation_data = validation_generator,
                    validation_steps = len(Test_IDs)//params['batch_size'],
                    verbose=2,
                    callbacks=callbacks_list)

model.save("./model_200000_job_epoch12.h5py")


import json

# # Data to be written
# dictionary = {
#     "hello":"lol"
# }

# # Serializing json
# json_object = json.dumps(dictionary, indent=4)

# Writing to sample.json
# with open("sample.json", "a") as outfile:
#     outfile.write(json_object)
filename="sample.json"
entry={'hello','lol1'}
with open(filename, "r") as file:
    data = json.load(file)
# 2. Update json object
data.append(entry)
# 3. Write json file
with open(filename, "w") as file:
    json.dump(data, file)


import pandas as pd
import geopandas as gpd
from sqlalchemy import create_engine
from shapely.geometry import box

from SGIS.api import SGISRequest
from credentials.database import AP

CSV = '/Users/dongookson/Code/data-project/SGIS/key_locations/ad8.csv'
QUERY = 'select * from key_locations'
GET = False

# connect to database AP
engine = create_engine(AP)

if GET:
    # read dummy data
    df = pd.read_csv(CSV)[0:10]

    # Make API GET request
    patient_locs = [SGISRequest().geocode_addr(patient) for patient in df['Address']]
    df['x_5179'] = [p.get('x') for p in patient_locs]
    df['y_5179'] = [p.get('y') for p in patient_locs]

    # create geodataframe
    gdf = gpd.GeoDataFrame(
            df,
            crs='epsg:5179',
            geometry=gpd.points_from_xy(x=df.x_5179, y=df.y_5179)
        )

    # create well-known-text(wkt) column for WGS84
    gdf['wkt_4326'] = gdf.to_crs(4326)['geometry']

    # write as table
    gdf.to_postgis(
        'key_locations',
        engine
    )
else:
    gdf = gpd.read_postgis(QUERY, engine, geom_col='geometry')
    print(gdf.head(10))
    # print(gdf.crs)
    # print(gdf['geometry'].sindex.query(box(988969.330849867, 988969.33084999, 1818020.086700, 1818020.0860560)))
    # print(type(gdf['geometry']))


from sys import argv
from panda3d.core import Vec3
from pandac.PandaModules import loadPrcFileData
loadPrcFileData('configurate', 'window-title Loading')
from direct.directbase import DirectStart
from direct.task import Task
from direct.actor.Actor import Actor
from direct.gui.DirectGui import *
from pandac.PandaModules import *
from direct.interval.IntervalGlobal import *
from direct.showbase.InputStateGlobal import inputState
from direct.controls.GravityWalker import GravityWalker
from direct.showbase import DirectObject
from direct.interval.IntervalGlobal import *
import urllib, os, __main__, random
from pandac.PandaModules import *
from random import choice

base.disableMouse()
title = OnscreenImage(image='phase_3/maps/Game_Toontown_Logo_1.jpg', pos=(0, 0, 0.0), parent=render2d)
base.graphicsEngine.renderFrame()
base.graphicsEngine.renderFrame()
base.graphicsEngine.renderFrame()
base.graphicsEngine.renderFrame()
title.destroy()
props = WindowProperties()
props.setTitle('League Of Toons')
base.win.requestProperties(props)
from panda3d.core import *

class guitools():

    def createFrame(self, filepath, resX = None, resY = None):
        yresolution = 600
        tex = loader.loadTexture(filepath)
        tex.setBorderColor(Vec4(0, 0, 0, 0))
        tex.setWrapU(Texture.WMRepeat)
        tex.setWrapV(Texture.WMRepeat)
        cm = CardMaker(filepath + ' card')
        if resX == None:
            resX = tex.getOrigFileXSize()
        if resY == None:
            resY = tex.getOrigFileySize()
        cm.setFrame(-resX, resX, -resY, resY)
        card = NodePath(cm.generate())
        card.setTexture(tex)
        card.flattenLight()
        card.setScale(card.getScale() / yresolution)
        return card

    def createButton(self, cmd, position, hpr, model, buttonImgs, scale, colour = (1, 1, 1, 1), text = ''):
        ButtonImage = loader.loadModel(model)
        ButtonImageUp = ButtonImage.find('**/' + buttonImgs[0])
        ButtonImageDown = ButtonImage.find('**/' + buttonImgs[1])
        ButtonImageRollover = ButtonImage.find('**/' + buttonImgs[-1])
        return DirectButton(frameSize=None, image=(ButtonImageUp, ButtonImageDown, ButtonImageRollover), relief=None, command=cmd, geom=None, pad=(0.01, 0.01), text=text, suppressKeys=0, pos=position, hpr=hpr, text_fg=(1, 1, 1, 1), color=colour, text_scale=0.059, borderWidth=(0.13, 0.01), scale=scale)

class ClassicBook():
    Book = loader.loadModel('phase_3.5/models/gui/stickerbook_gui.bam')

    def __beingOpened__(self):
        self.BookClose.hide()
        try:
            base.localAvatar.b_setAnimState('OpenBook')
        except:
            pass

        return True

    def __openBook__(self):
        seq = Sequence()
        seq.append(Func(self.__beingOpened__))
        seq.append(Wait(0.3))
        seq.append(Func(self.__addNavs__))
        seq.start()
        return True

    def __delNavs__(self):
        self.bg[0].hide()
        self.bg[1].hide()
        self.BookOpen.removeNode()
        self.__addOnButton__()
        try:
            base.localAvatar.b_setAnimState('CloseBook')
            base.localAvatar.physControls.enableAvatarControls()
        except:
            pass

        return True

    def __addNavs__(self):
        self.BookClose.removeNode()
        self.bg = []
        for b in range(2):
            self.bg.append(Guitools.createFrame('phase_3.5/maps/Book.jpg', base.win.getXSize() + 160, base.win.getYSize() + 125))
            self.bg.append(Guitools.createFrame('phase_3.5/maps/big_book.jpg',600,450))
            self.bg[b].reparentTo(aspect2d)

        self.bg[0].setPos(0, 0, 0)
        self.bg[1].setPos(0, 0, 0.1)
        self.BookOpen = DirectButton(frameSize=None, image=(self.Book.find('**/BookIcon_OPEN'), self.Book.find('**/BookIcon_CLSD'), self.Book.find('**/BookIcon_RLVR2')), relief=None, command=self.__delNavs__, text='', text_pos=(0, -0.015), geom=None, scale=0.305, pad=(0.01, 0.01), suppressKeys=0, pos=(1.16, 0, -0.83), hpr=(0, 0, 0), text_scale=0.06, borderWidth=(0.015, 0.01))
        try:
            base.localAvatar.b_setAnimState('ReadBook')
        except:
            pass

        return True

    def __addOnButton__(self):
        self.BookClose = DirectButton(frameSize=None, image=(self.Book.find('**/BookIcon_CLSD'), self.Book.find('**/BookIcon_OPEN'), self.Book.find('**/BookIcon_RLVR')), relief=None, command=self.__openBook__, text='', text_pos=(0, -0.015), geom=None, scale=0.305, pad=(0.01, 0.01), suppressKeys=0, pos=(1.16, 0, -0.83), hpr=(0, 0, 0), text_scale=0.06, borderWidth=(0.015, 0.01))
        return True

    def __init__(self):
        self.__addOnButton__()

Guitools = guitools()
BookGui = ClassicBook()
base.disableMouse()
legsAnimDict = {'right-hand-start': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_right-hand-start.bam',
 'firehose': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_firehose.bam',
 'rotateL-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_rotateL-putt.bam',
 'slip-forward': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_slip-forward.bam',
 'catch-eatnrun': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_eatnrun.bam',
 'tickle': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_tickle.bam',
 'water-gun': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_water-gun.bam',
 'leverNeutral': 'phase_10/models/char/tt_a_chr_dgs_shorts_legs_leverNeutral.bam',
 'swim': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_swim.bam',
 'catch-run': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_gamerun.bam',
 'sad-neutral': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_sad-neutral.bam',
 'pet-loop': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_petloop.bam',
 'jump-squat': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_jump-zstart.bam',
 'wave': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_wave.bam',
 'reel-neutral': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_reelneutral.bam',
 'pole-neutral': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_poleneutral.bam',
 'bank': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_jellybeanJar.bam',
 'scientistGame': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_scientistGame.bam',
 'right-hand': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_right-hand.bam',
 'lookloop-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_lookloop-putt.bam',
 'victory': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_victory-dance.bam',
 'lose': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_lose.bam',
 'cringe': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_cringe.bam',
 'right': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_right.bam',
 'headdown-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_headdown-putt.bam',
 'conked': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_conked.bam',
 'jump': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_jump.bam',
 'into-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_into-putt.bam',
 'fish-end': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_fishEND.bam',
 'running-jump-land': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_leap_zend.bam',
 'shrug': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_shrug.bam',
 'sprinkle-dust': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_sprinkle-dust.bam',
 'hold-bottle': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_hold-bottle.bam',
 'takePhone': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_takePhone.bam',
 'melt': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_melt.bam',
 'pet-start': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_petin.bam',
 'look-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_look-putt.bam',
 'loop-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_loop-putt.bam',
 'good-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_good-putt.bam',
 'juggle': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_juggle.bam',
 'run': 'phase_3/models/char/tt_a_chr_dgs_shorts_legs_run.bam',
 'pushbutton': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_press-button.bam',
 'sidestep-right': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_jump-back-right.bam',
 'water': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_water.bam',
 'right-point-start': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_right-point-start.bam',
 'bad-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_bad-putt.bam',
 'struggle': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_struggle.bam',
 'running-jump': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_running-jump.bam',
 'callPet': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_callPet.bam',
 'throw': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_pie-throw.bam',
 'catch-eatneutral': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_eat_neutral.bam',
 'tug-o-war': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_tug-o-war.bam',
 'bow': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_bow.bam',
 'swing': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_swing.bam',
 'climb': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_climb.bam',
 'scientistWork': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_scientistWork.bam',
 'think': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_think.bam',
 'catch-intro-throw': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_gameThrow.bam',
 'walk': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_walk.bam',
 'down': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_down.bam',
 'pole': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_pole.bam',
 'periscope': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_periscope.bam',
 'duck': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_duck.bam',
 'curtsy': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_curtsy.bam',
 'jump-land': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_jump-zend.bam',
 'loop-dig': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_loop_dig.bam',
 'angry': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_angry.bam',
 'bored': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_bored.bam',
 'swing-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_swing-putt.bam',
 'pet-end': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_petend.bam',
 'spit': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_spit.bam',
 'right-point': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_right-point.bam',
 'start-dig': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_into_dig.bam',
 'castlong': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_castlong.bam',
 'confused': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_confused.bam',
 'neutral': 'phase_3/models/char/tt_a_chr_dgs_shorts_legs_neutral.bam',
 'jump-idle': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_jump-zhang.bam',
 'reel': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_reel.bam',
 'slip-backward': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_slip-backward.bam',
 'sound': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_shout.bam',
 'sidestep-left': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_sidestep-left.bam',
 'up': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_up.bam',
 'fish-again': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_fishAGAIN.bam',
 'cast': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_cast.bam',
 'phoneBack': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_phoneBack.bam',
 'phoneNeutral': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_phoneNeutral.bam',
 'scientistJealous': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_scientistJealous.bam',
 'battlecast': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_fish.bam',
 'sit-start': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_intoSit.bam',
 'toss': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_toss.bam',
 'happy-dance': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_happy-dance.bam',
 'running-jump-squat': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_leap_zstart.bam',
 'teleport': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_teleport.bam',
 'sit': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_sit.bam',
 'sad-walk': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_losewalk.bam',
 'give-props-start': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_give-props-start.bam',
 'book': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_book.bam',
 'running-jump-idle': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_leap_zhang.bam',
 'scientistEmcee': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_scientistEmcee.bam',
 'leverPull': 'phase_10/models/char/tt_a_chr_dgs_shorts_legs_leverPull.bam',
 'tutorial-neutral': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_tutorial-neutral.bam',
 'badloop-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_badloop-putt.bam',
 'give-props': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_give-props.bam',
 'hold-magnet': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_hold-magnet.bam',
 'hypnotize': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_hypnotize.bam',
 'left-point': 'phase_3.5/models/char/tt_a_chr_dgs_shorts_legs_left-point.bam',
 'leverReach': 'phase_10/models/char/tt_a_chr_dgs_shorts_legs_leverReach.bam',
 'feedPet': 'phase_5.5/models/char/tt_a_chr_dgs_shorts_legs_feedPet.bam',
 'reel-H': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_reelH.bam',
 'applause': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_applause.bam',
 'smooch': 'phase_5/models/char/tt_a_chr_dgs_shorts_legs_smooch.bam',
 'rotateR-putt': 'phase_6/models/char/tt_a_chr_dgs_shorts_legs_rotateR-putt.bam',
 'fish-neutral': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_fishneutral.bam',
 'push': 'phase_9/models/char/tt_a_chr_dgs_shorts_legs_push.bam',
 'catch-neutral': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_gameneutral.bam',
 'left': 'phase_4/models/char/tt_a_chr_dgs_shorts_legs_left.bam'}
torsoAnimDict = {'right-hand-start': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_right-hand-start.bam',
 'firehose': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_firehose.bam',
 'rotateL-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_rotateL-putt.bam',
 'slip-forward': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_slip-forward.bam',
 'catch-eatnrun': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_eatnrun.bam',
 'tickle': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_tickle.bam',
 'water-gun': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_water-gun.bam',
 'leverNeutral': 'phase_10/models/char/tt_a_chr_dgl_shorts_torso_leverNeutral.bam',
 'swim': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_swim.bam',
 'catch-run': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_gamerun.bam',
 'sad-neutral': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_sad-neutral.bam',
 'pet-loop': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_petloop.bam',
 'jump-squat': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_jump-zstart.bam',
 'wave': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_wave.bam',
 'reel-neutral': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_reelneutral.bam',
 'pole-neutral': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_poleneutral.bam',
 'bank': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_jellybeanJar.bam',
 'scientistGame': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_scientistGame.bam',
 'right-hand': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_right-hand.bam',
 'lookloop-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_lookloop-putt.bam',
 'victory': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_victory-dance.bam',
 'lose': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_lose.bam',
 'cringe': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_cringe.bam',
 'right': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_right.bam',
 'headdown-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_headdown-putt.bam',
 'conked': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_conked.bam',
 'jump': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_jump.bam',
 'into-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_into-putt.bam',
 'fish-end': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_fishEND.bam',
 'running-jump-land': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_leap_zend.bam',
 'shrug': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_shrug.bam',
 'sprinkle-dust': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_sprinkle-dust.bam',
 'hold-bottle': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_hold-bottle.bam',
 'takePhone': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_takePhone.bam',
 'melt': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_melt.bam',
 'pet-start': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_petin.bam',
 'look-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_look-putt.bam',
 'loop-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_loop-putt.bam',
 'good-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_good-putt.bam',
 'juggle': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_juggle.bam',
 'run': 'phase_3/models/char/tt_a_chr_dgl_shorts_torso_run.bam',
 'pushbutton': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_press-button.bam',
 'sidestep-right': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_jump-back-right.bam',
 'water': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_water.bam',
 'right-point-start': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_right-point-start.bam',
 'bad-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_bad-putt.bam',
 'struggle': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_struggle.bam',
 'running-jump': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_running-jump.bam',
 'callPet': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_callPet.bam',
 'throw': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_pie-throw.bam',
 'catch-eatneutral': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_eat_neutral.bam',
 'tug-o-war': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_tug-o-war.bam',
 'bow': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_bow.bam',
 'swing': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_swing.bam',
 'climb': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_climb.bam',
 'scientistWork': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_scientistWork.bam',
 'think': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_think.bam',
 'catch-intro-throw': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_gameThrow.bam',
 'walk': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_walk.bam',
 'down': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_down.bam',
 'pole': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_pole.bam',
 'periscope': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_periscope.bam',
 'duck': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_duck.bam',
 'curtsy': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_curtsy.bam',
 'jump-land': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_jump-zend.bam',
 'loop-dig': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_loop_dig.bam',
 'angry': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_angry.bam',
 'bored': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_bored.bam',
 'swing-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_swing-putt.bam',
 'pet-end': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_petend.bam',
 'spit': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_spit.bam',
 'right-point': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_right-point.bam',
 'start-dig': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_into_dig.bam',
 'castlong': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_castlong.bam',
 'confused': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_confused.bam',
 'neutral': 'phase_3/models/char/tt_a_chr_dgl_shorts_torso_neutral.bam',
 'jump-idle': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_jump-zhang.bam',
 'reel': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_reel.bam',
 'slip-backward': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_slip-backward.bam',
 'sound': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_shout.bam',
 'sidestep-left': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_sidestep-left.bam',
 'up': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_up.bam',
 'fish-again': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_fishAGAIN.bam',
 'cast': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_cast.bam',
 'phoneBack': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_phoneBack.bam',
 'phoneNeutral': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_phoneNeutral.bam',
 'scientistJealous': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_scientistJealous.bam',
 'battlecast': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_fish.bam',
 'sit-start': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_intoSit.bam',
 'toss': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_toss.bam',
 'happy-dance': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_happy-dance.bam',
 'running-jump-squat': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_leap_zstart.bam',
 'teleport': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_teleport.bam',
 'sit': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_sit.bam',
 'sad-walk': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_losewalk.bam',
 'give-props-start': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_give-props-start.bam',
 'book': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_book.bam',
 'running-jump-idle': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_leap_zhang.bam',
 'scientistEmcee': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_scientistEmcee.bam',
 'leverPull': 'phase_10/models/char/tt_a_chr_dgl_shorts_torso_leverPull.bam',
 'tutorial-neutral': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_tutorial-neutral.bam',
 'badloop-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_badloop-putt.bam',
 'give-props': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_give-props.bam',
 'hold-magnet': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_hold-magnet.bam',
 'hypnotize': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_hypnotize.bam',
 'left-point': 'phase_3.5/models/char/tt_a_chr_dgl_shorts_torso_left-point.bam',
 'leverReach': 'phase_10/models/char/tt_a_chr_dgl_shorts_torso_leverReach.bam',
 'feedPet': 'phase_5.5/models/char/tt_a_chr_dgl_shorts_torso_feedPet.bam',
 'reel-H': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_reelH.bam',
 'applause': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_applause.bam',
 'smooch': 'phase_5/models/char/tt_a_chr_dgl_shorts_torso_smooch.bam',
 'rotateR-putt': 'phase_6/models/char/tt_a_chr_dgl_shorts_torso_rotateR-putt.bam',
 'fish-neutral': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_fishneutral.bam',
 'push': 'phase_9/models/char/tt_a_chr_dgl_shorts_torso_push.bam',
 'catch-neutral': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_gameneutral.bam',
 'left': 'phase_4/models/char/tt_a_chr_dgl_shorts_torso_left.bam'}
DuckHead = loader.loadModel('phase_3/models/char/duck-heads-1000.bam')
otherParts = DuckHead.findAllMatches('**/*long*')
for partNum in range(0, otherParts.getNumPaths()):
    otherParts.getPath(partNum).removeNode()

ntrlMuzzle = DuckHead.find('**/*muzzle*neutral')
otherParts = DuckHead.findAllMatches('**/*muzzle*')
for partNum in range(0, otherParts.getNumPaths()):
    part = otherParts.getPath(partNum)
    if part != ntrlMuzzle:
        otherParts.getPath(partNum).removeNode()

DuckTorso = loader.loadModel('phase_3/models/char/tt_a_chr_dgl_shorts_torso_1000.bam')
DuckLegs = loader.loadModel('phase_3/models/char/tt_a_chr_dgs_shorts_legs_1000.bam')
otherParts = DuckLegs.findAllMatches('**/boots*') + DuckLegs.findAllMatches('**/shoes')
for partNum in range(0, otherParts.getNumPaths()):
    otherParts.getPath(partNum).removeNode()

DuckBody = Actor({'head': DuckHead,
 'torso': DuckTorso,
 'legs': DuckLegs}, {'torso': torsoAnimDict,
 'legs': legsAnimDict})
DuckBody.attach('head', 'torso', 'def_head')
DuckBody.attach('torso', 'legs', 'joint_hips')
gloves = DuckBody.findAllMatches('**/hands')
ears = DuckBody.findAllMatches('**/*ears*')
head = DuckBody.findAllMatches('**/head-*')
sleeves = DuckBody.findAllMatches('**/sleeves')
shirt = DuckBody.findAllMatches('**/torso-top')
shorts = DuckBody.findAllMatches('**/torso-bot')
neck = DuckBody.findAllMatches('**/neck')
arms = DuckBody.findAllMatches('**/arms')
legs = DuckBody.findAllMatches('**/legs')
feet = DuckBody.findAllMatches('**/feet')
bodyNodes = []
bodyNodes += [gloves]
bodyNodes += [head, ears]
bodyNodes += [sleeves, shirt, shorts]
bodyNodes += [neck,
 arms,
 legs,
 feet]
bodyNodes[0].setColor(1, 1, 1, 1)
bodyNodes[1].setColor(1, 0.5, 0, 1)
bodyNodes[2].setColor(1, 0.5, 0, 1)
bodyNodes[3].setColor(0.264, 0.308, 0.676, 1)
bodyNodes[4].setColor(0.264, 0.308, 0.676, 1)
bodyNodes[5].setColor(1, 1, 1, 1)
bodyNodes[6].setColor(1, 0.5, 0, 1)
bodyNodes[7].setColor(1, 0.5, 0, 1)
bodyNodes[8].setColor(0.276, 0.872, 0.36, 1)
bodyNodes[9].setColor(0.276, 0.872, 0.36, 1)
topTex = loader.loadTexture('phase_3/maps/desat_shirt_5.jpg')
botTex = loader.loadTexture('phase_4/maps/CowboyShorts1.jpg')
sleeveTex = loader.loadTexture('phase_3/maps/desat_sleeve_5.jpg')
bodyNodes[3].setTexture(sleeveTex, 1)
bodyNodes[4].setTexture(topTex, 1)
bodyNodes[5].setTexture(botTex, 1)
DuckBody.reparentTo(render)
geom = DuckBody.getGeomNode()
geom.getChild(0).setSx(0.730000019073)
geom.getChild(0).setSz(0.730000019073)
offset = 3.2375
base.camera.reparentTo(DuckBody)
base.camera.setPos(0, -9.0 - offset, offset)
wallBitmask = BitMask32(1)
floorBitmask = BitMask32(2)
base.cTrav = CollisionTraverser()
base.camera.hide()

def getAirborneHeight():
    return offset + 0.025

walkControls = GravityWalker(legacyLifter=True)
walkControls.setWallBitMask(wallBitmask)
walkControls.setFloorBitMask(floorBitmask)
walkControls.setWalkSpeed(16.0, 24.0, 8.0, 80.0)
walkControls.initializeCollisions(base.cTrav, DuckBody, floorOffset=0.025, reach=4.0)
walkControls.setAirborneHeightFunc(getAirborneHeight)
walkControls.enableAvatarControls()
DuckBody.physControls = walkControls

def setWatchKey(key, input, keyMapName):

    def watchKey(active = True):
        if active == True:
            inputState.set(input, True)
            keyMap[keyMapName] = 1
        else:
            inputState.set(input, False)
            keyMap[keyMapName] = 0

    base.accept(key, watchKey, [True])
    base.accept(key + '-up', watchKey, [False])

keyMap = {'left': 0,
 'right': 0,
 'forward': 0,
 'backward': 0,
 'control': 0}
setWatchKey('arrow_up', 'forward', 'forward')
setWatchKey('control-arrow_up', 'forward', 'forward')
setWatchKey('alt-arrow_up', 'forward', 'forward')
setWatchKey('shift-arrow_up', 'forward', 'forward')
setWatchKey('arrow_down', 'reverse', 'backward')
setWatchKey('control-arrow_down', 'reverse', 'backward')
setWatchKey('alt-arrow_down', 'reverse', 'backward')
setWatchKey('shift-arrow_down', 'reverse', 'backward')
setWatchKey('arrow_left', 'turnLeft', 'left')
setWatchKey('control-arrow_left', 'turnLeft', 'left')
setWatchKey('alt-arrow_left', 'turnLeft', 'left')
setWatchKey('shift-arrow_left', 'turnLeft', 'left')
setWatchKey('arrow_right', 'turnRight', 'right')
setWatchKey('control-arrow_right', 'turnRight', 'right')
setWatchKey('alt-arrow_right', 'turnRight', 'right')
setWatchKey('shift-arrow_right', 'turnRight', 'right')
setWatchKey('control', 'jump', 'control')
movingNeutral, movingForward = (False, False)
movingRotation, movingBackward = (False, False)
movingJumping = False

def setMovementAnimation(loopName, playRate = 1.0):
    global movingRotation
    global movingBackward
    global movingForward
    global movingNeutral
    global movingJumping
    if 'jump' in loopName:
        movingJumping = True
        movingForward = False
        movingNeutral = False
        movingRotation = False
        movingBackward = False
    elif loopName == 'run':
        movingJumping = False
        movingForward = True
        movingNeutral = False
        movingRotation = False
        movingBackward = False
    elif loopName == 'walk':
        movingJumping = False
        movingForward = False
        movingNeutral = False
        if playRate == -1.0:
            movingBackward = True
            movingRotation = False
        else:
            movingBackward = False
            movingRotation = True
    elif loopName == 'neutral':
        movingJumping = False
        movingForward = False
        movingNeutral = True
        movingRotation = False
        movingBackward = False
    else:
        movingJumping = False
        movingForward = False
        movingNeutral = False
        movingRotation = False
        movingBackward = False
    ActorInterval(DuckBody, loopName, playRate=playRate).loop()

def handleMovement(task):
    if keyMap['control'] == 1:
        if keyMap['forward'] or keyMap['backward'] or keyMap['left'] or keyMap['right']:
            if movingJumping == False:
                if DuckBody.physControls.isAirborne:
                    setMovementAnimation('running-jump-idle')
                elif keyMap['forward']:
                    if movingForward == False:
                        setMovementAnimation('run')
                elif keyMap['backward']:
                    if movingBackward == False:
                        setMovementAnimation('walk', playRate=-1.0)
                elif keyMap['left'] or keyMap['right']:
                    if movingRotation == False:
                        setMovementAnimation('walk')
            elif not DuckBody.physControls.isAirborne:
                if keyMap['forward']:
                    if movingForward == False:
                        setMovementAnimation('run')
                elif keyMap['backward']:
                    if movingBackward == False:
                        setMovementAnimation('walk', playRate=-1.0)
                elif keyMap['left'] or keyMap['right']:
                    if movingRotation == False:
                        setMovementAnimation('walk')
        elif movingJumping == False:
            if DuckBody.physControls.isAirborne:
                setMovementAnimation('jump-idle')
            elif movingNeutral == False:
                setMovementAnimation('neutral')
        elif not DuckBody.physControls.isAirborne:
            if movingNeutral == False:
                setMovementAnimation('neutral')
                fsrun.stop()
    elif keyMap['forward'] == 1:
        if movingForward == False:
            if not DuckBody.physControls.isAirborne:
                setMovementAnimation('run')
    elif keyMap['backward'] == 1:
        if movingBackward == False:
            if not DuckBody.physControls.isAirborne:
                setMovementAnimation('walk', playRate=-1.0)
    elif keyMap['left'] or keyMap['right']:
        if movingRotation == False:
            if not DuckBody.physControls.isAirborne:
                setMovementAnimation('walk')
                fswalk = loader.loadSfx('phase_3.5/audio/sfx/AV_footstep_walkloop.wav')
    elif not DuckBody.physControls.isAirborne:
        if movingNeutral == False:
            setMovementAnimation('neutral')
    return Task.cont

base.taskMgr.add(handleMovement, 'controlManager')

def collisionsOn():
    DuckBody.physControls.setCollisionsActive(True)
    DuckBody.physControls.isAirborne = True

def collisionsOff():
    DuckBody.physControls.setCollisionsActive(False)
    DuckBody.physControls.isAirborne = True

def toggleCollisions():
    if DuckBody.physControls.getCollisionsActive():
        DuckBody.physControls.setCollisionsActive(False)
        DuckBody.physControls.isAirborne = True
    else:
        DuckBody.physControls.setCollisionsActive(True)
        DuckBody.physControls.isAirborne = True

base.accept('f1', toggleCollisions)
DuckBody.collisionsOn = collisionsOn
DuckBody.collisionsOff = collisionsOff
DuckBody.toggleCollisions = toggleCollisions
fsrun = loader.loadSfx('phase_3/audio/bgm/tt_theme.mid')
fsrun.setLoop(True)
fsrun.play()
localAvatar = DuckBody
base.localAvatar = localAvatar
localAvatar.physControls.placeOnFloor()
onScreenDebug.enabled = False

def updateOnScreenDebug(task):
    onScreenDebug.add('Avatar Position', localAvatar.getPos())
    onScreenDebug.add('Avatar Angle', localAvatar.getHpr())
    return Task.cont

MickeyFont = loader.loadFont('phase_3/models/fonts/MickeyFont.bam')

class EnvironmentTTC():

    def __init__(self):
        self.modeldict = {}
        self.LoadTTC()

    def LoadTTC(self):
        self.modelloader('Sky', 'phase_3.5/models/props/TT_sky.bam', render, 0, 0, 0, 0, 0, 0, 5, 5, 5)
        Clouds1 = self.modeldict['Sky'].find('**/cloud1')
        Clouds2 = self.modeldict['Sky'].find('**/cloud2')
        Clouds1.setScale(0.6, 0.6, 0.6)
        Clouds2.setScale(0.9, 0.9, 0.9)
        Clouds1Spin = Clouds1.hprInterval(360, Vec3(60, 0, 0))
        Clouds1Spin.loop()
        Clouds2Spin = Clouds2.hprInterval(360, Vec3(-60, 0, 0))
        Clouds2Spin.loop()
        self.modelloader('TTC', 'phase_4/models/neighborhoods/toontown_central.bam', render, 0, 0, 0, -90, 0, 0, 1, 1, 1)
        self.modeldict['TTC'].setTransparency(TransparencyAttrib.MBinary, 1)
        self.modelloader('ToonHQ', 'phase_3.5/models/modules/hqTT.bam', render, 24.6425, 24.8587, 4.00001, 135, 0, 0, 1, 1, 1)
        self.modeldict['ToonHQ'].find('**/doorFrameHoleRight_0').hide()
        self.modeldict['ToonHQ'].find('**/doorFrameHoleLeft_0').hide()
        self.modeldict['ToonHQ'].find('**/doorFrameHoleRight_1').hide()
        self.modeldict['ToonHQ'].find('**/doorFrameHoleLeft_1').hide()
        self.modelloader('Partygate', 'phase_4/models/modules/partyGate_TT.bam', render, 77.935, -159.939, 2.70141, 195, 0, 0, 1, 1, 1)
        self.modelloader('Petshop', 'phase_4/models/modules/PetShopExterior_TT.bam', render, -124.375, 74.3749, 0.5, 49, 0, 0, 1, 1, 1)
        self.modelloaderanimate('PetshopFish', 'phase_4/models/props/exteriorfish-zero.bam', 'phase_4/models/props/exteriorfish-swim.bam', self.modeldict['Petshop'], 0, 0, 0, 0, 0, 0, 1, 1, 1, 'swim')
        Petsign1 = self.modeldict['Petshop'].find('**/sign_origin')
        self.textloader('Pettext2', 'Pettextnode2', 'Pettextname2', 'Pet Shop', MickeyFont, Petsign1, -5, -0.2, 0.2, 0, 0, 0, 2, 2, 2, 0.9, 0.88, 0.1)
        Petdoor = self.modeldict['Petshop'].find('**/door_origin')
        self.modelloadercopyto('Door1', 'phase_3.5/models/modules/doors_practical.bam', 'door_double_round_ur', Petdoor, 0, -0.1, 0, 0, 0, 0, 1, 1, 1)
        self.modeldict['Door1'].setColor(1, 0.87, 0.38)
        self.modelloader('Clothingshop', 'phase_4/models/modules/clothshopTT.bam', render, 106.265, 160.831, 3, -30, 0, 0, 1, 1, 1)
        Clothingsign1 = self.modeldict['Clothingshop'].find('**/sign_origin')
        self.textloader('Clothingtext2', 'Clothingtextnode2', 'Clothingtextname2', 'Clothing Shop', MickeyFont, Clothingsign1, -6.7, -0.2, 0.1, 0, 0, 0, 1.5, 1.5, 1.5, 0.88, 0.45, 0.38)
        Clothingdoor = self.modeldict['Clothingshop'].find('**/door_origin')
        self.modelloadercopyto('Door2', 'phase_3.5/models/modules/doors_practical.bam', 'door_double_clothshop', Clothingdoor, 0, -0.1, 0, 0, 0, 0, 1, 1, 1)
        self.modeldict['Door2'].setColor(0.88, 0.45, 0.38)
        self.modelloader('Toonhall', 'phase_4/models/modules/toonhall.bam', render, 116.66, 24.29, 4, -90, 0, 0, 1, 1, 1)
        Hallsign = self.modeldict['Toonhall'].find('**/sign_origin')
        self.textloader('Halltext1', 'Halltextnode1', 'Halltextname1', 'Mickey', MickeyFont, Hallsign, -5, -0.2, -0.5, 0, 0, 0, 2.5, 2.5, 2.5, 0.9, 0.88, 0.1)
        self.textloader('Halltext2', 'Halltextnode2', 'Halltextname2', 'Toon Hall', MickeyFont, Hallsign, -7, -0.2, -3, 0, 0, 0, 2.5, 2.5, 2.5, 0.9, 0.88, 0.1)
        Halldoor = self.modeldict['Toonhall'].find('**/toonhall_door_origin')
        self.modelloadercopyto('Door3', 'phase_3.5/models/modules/doors_practical.bam', 'door_double_round_ur', Halldoor, 0, -0.1, 0, 0, 0, 0, 1, 1, 1)
        self.modeldict['Door3'].setColor(0.88, 0.45, 0.38)
        self.modelloader('Schoolhouse', 'phase_4/models/modules/school_house.bam', render, 129.919, -138.445, 2.4997, -140, 0, 0, 1, 1, 1)
        Schoolsign = self.modeldict['Schoolhouse'].find('**/sign_origin')
        self.modelloadercopyto('Schoolsign', 'phase_4/models/props/signs_TTC.bam', 'TTC_sign3', Schoolsign, 1, -0.05, 3.7, 0, 0, 0, 1, 1, 1)
        self.textloader('Schooltext1', 'Schooltextnode1', 'Schooltextname1', 'Toontown', MickeyFont, Schoolsign, -2.5, -0.07, 4.8, 0, 0, 0, 1, 1, 1, 0.9, 0.88, 0.4)
        self.textloader('Schooltext2', 'Schooltextnode2', 'Schooltextname2', 'School House', MickeyFont, Schoolsign, -4.8, -0.07, 3, 0, 0, 0, 1.4, 1.4, 1.4, 0.9, 0.5, 0.1)
        Schooldoor = self.modeldict['Schoolhouse'].find('**/school_door_origin')
        self.modelloadercopyto('Door4', 'phase_3.5/models/modules/doors_practical.bam', 'door_double_square_ul', Schooldoor, 0, -0.1, 0, 0, 0, 0, 1, 1, 1)
        self.modeldict['Door4'].setColor(1, 0.63, 0.38)
        self.modelloader('Bank', 'phase_4/models/modules/bank.bam', render, 57.1796, 38.6656, 4, 0, 0, 0, 1, 1, 1)
        Banksign = self.modeldict['Bank'].find('**/sign_origin')
        self.textloader('Banktext1', 'Banktextnode1', 'Banktextname1', 'Bank', MickeyFont, Banksign, -3.1, -0.2, -1, 0, 0, 0, 2.5, 2.5, 2.5, 0.9, 0.6, 0.1)
        Bankdoor = self.modeldict['Bank'].find('**/bank_door_origin')
        self.modelloadercopyto('Door5', 'phase_3.5/models/modules/doors_practical.bam', 'door_double_round_ur', Bankdoor, 0, -0.1, 0, 0, 0, 0, 1, 1, 1)
        self.modeldict['Door5'].setColor(0.88, 0.45, 0.38)
        self.modelloader('Library', 'phase_4/models/modules/library.bam', render, 91.4475, -44.9255, 4, 180, 0, 0, 1, 1, 1)
        Librarysign = self.modeldict['Library'].find('**/sign_origin')
        self.modelloadercopyto('Librarysign', 'phase_4/models/props/signs_TTC.bam', 'TTC_sign3', Librarysign, 1.7, -0.05, 3.7, 0, 0, 0, 1, 1, 1)
        self.textloader('Librarytext1', 'Librarytextnode1', 'Librarytextname1', 'Toontown', MickeyFont, Librarysign, -1.5, -0.07, 4.8, 0, 0, 0, 1, 1, 1, 0.9, 0.88, 0.4)
        self.textloader('Librarytext2', 'Librarytextnode2', 'Librarytextname2', 'Library', MickeyFont, Librarysign, -2.8, -0.07, 3, 0, 0, 0, 1.9, 1.9, 1.9, 0.9, 0.5, 0.1)
        Librarydoor = self.modeldict['Library'].find('**/library_door_origin')
        self.modelloadercopyto('Door6', 'phase_3.5/models/modules/doors_practical.bam', 'door_double_round_ur', Librarydoor, 0, 0, 0, 0, 0, 0, 1, 1, 1)
        self.modeldict['Door6'].setColor(0.88, 0.45, 0.38)
        self.modelloader('Gagshop', 'phase_4/models/modules/gagShop_TT.bam', render, -86.6848, -90.5693, 0.500015, 0, 0, 0, 1, 1, 1)
        Gagdoor = self.modeldict['Gagshop'].find('**/building_front')
        self.modelloadercopyto('Door7', 'phase_3.5/models/modules/doors_practical.bam', 'door_double_square_ur', Gagdoor, 3, 0.1, 0, 180, 0, 0, 1, 1, 1)
        self.modeldict['Door7'].setColor(1, 0.63, 0.38)
        self.modelloader('GoofyTunnel', 'phase_4/models/modules/Speedway_Tunnel.bam', render, 20.9205, 172.683, 3.24925, -150, -0.083787, 0.0101321, 1, 1, 1)
        Goofysign = self.modeldict['GoofyTunnel'].find('**/sign_origin')
        self.textloader('Goofytext1', 'Goofytextnode1', 'Goofytextname1', 'Goofy', MickeyFont, Goofysign, -2, -0.07, 0.7, 0, 0, 0, 2.2, 2.2, 2.2, 0.1, 0.1, 0.7)
        self.textloader('Goofytext2', 'Goofytextnode2', 'Goofytextname2', 'Speed Way', MickeyFont, Goofysign, -6.1, -0.07, -2.8, 0, 0, 0, 2.6, 2.6, 2.6, 0.9, 0.5, 0.1)
        self.modelloader('FirstTunnel', 'phase_4/models/modules/safe_zone_tunnel_TT.bam', render, -239.67, 64.08, -6.18, -90, 0, 0, 1, 1, 1)
        SignOrigin1 = self.modeldict['FirstTunnel'].find('**/sign_origin')
        self.modelloader('Orangesign1', 'phase_3.5/models/props/tunnel_sign_orange.bam', SignOrigin1, 0, -0.05, 0, 0, 0, 0, 1.5, 1.5, 1.5)
        self.textloader('Tunnel1text1', 'Tunnel1textnode1', 'Tunnel1textname1', 'Loopy Lane', MickeyFont, SignOrigin1, -5.5, -0.07, -1.8, 0, 0, 0, 1.6, 1.6, 1.6, 0.0, 0.6, 0.1)
        self.textloader('Tunnel1text2', 'Tunnel1textnode2', 'Tunnel1textname2', 'Toontown Central', MickeyFont, SignOrigin1, -5.7, -0.7, -2.9, 0, 0, 0, 1, 1, 1, 0.0, 0.6, 0.0)
        self.modelloader('MickeyLogo1', 'phase_3.5/models/props/mickeySZ.bam', SignOrigin1, 0, -0.07, 2, 0, 0, 0, 4.5, 4.5, 4.5)
        self.modelloader('SecondTunnel', 'phase_4/models/modules/safe_zone_tunnel_TT.bam', render, -68.38, -202.64, -3.58, -31, 0, 0, 1, 1, 1)
        SignOrigin2 = self.modeldict['SecondTunnel'].find('**/sign_origin')
        self.textloader('Tunnel2text1', 'Tunnel2textnode1', 'Tunnel2textname1', 'Silly Street', MickeyFont, SignOrigin2, -5.9, -0.07, -1.8, 0, 0, 0, 1.6, 1.6, 1.6, 0.0, 0.6, 0.1)
        self.textloader('Tunnel2text2', 'Tunnel2textnode2', 'Tunnel2textname2', 'Toontown Central', MickeyFont, SignOrigin2, -5.7, -0.7, -2.9, 0, 0, 0, 1, 1, 1, 0.0, 0.6, 0.0)
        self.modelloader('Orangesign2', 'phase_3.5/models/props/tunnel_sign_orange.bam', SignOrigin2, 0, -0.05, 0, 0, 0, 0, 1.5, 1.5, 1.5)
        self.modelloader('MickeyLogo2', 'phase_3.5/models/props/mickeySZ.bam', SignOrigin2, 0, -0.07, 2, 0, 0, 0, 4.5, 4.5, 4.5)
        self.modelloader('ThirdTunnel', 'phase_4/models/modules/safe_zone_tunnel_TT.bam', render, 27.6402, 176.475, -6.18, 171, 0, 0, 1, 1, 1)
        SignOrigin3 = self.modeldict['ThirdTunnel'].find('**/sign_origin')
        self.textloader('Tunnel3text1', 'Tunnel3textnode1', 'Tunnel3textname1', 'Punchline Place', MickeyFont, SignOrigin3, -7.7, -0.07, -1.8, 0, 0, 0, 1.6, 1.6, 1.6, 0.0, 0.6, 0.1)
        self.textloader('Tunnel3text2', 'Tunnel3textnode2', 'Tunnel3textname2', 'Toontown Central', MickeyFont, SignOrigin3, -5.7, -0.7, -2.9, 0, 0, 0, 1, 1, 1, 0.0, 0.6, 0.0)
        self.modelloader('Orangesign3', 'phase_3.5/models/props/tunnel_sign_orange.bam', SignOrigin3, 0, -0.05, 0, 0, 0, 0, 1.5, 1.5, 1.5)
        self.modelloader('MickeyLogo3', 'phase_3.5/models/props/mickeySZ.bam', SignOrigin3, 0, -0.07, 2, 0, 0, 0, 4.5, 4.5, 4.5)
        self.modelloader('Fishingdock1', 'phase_4/models/props/piers_tt.bam', render, -63.5335, 41.648, -3.36708, 120, 0, 0, 1, 1, 1)
        self.modelloader('Fishingdock2', 'phase_4/models/props/piers_tt.bam', render, -90.2253, 42.5202, -3.3105, -135, 0, 0, 1, 1, 1)
        self.modelloader('Fishingdock3', 'phase_4/models/props/piers_tt.bam', render, -94.9218, 31.4153, -3.20083, -105, 0, 0, 1, 1, 1)
        self.modelloader('Fishingdock4', 'phase_4/models/props/piers_tt.bam', render, -77.5199, 46.9817, -3.28456, -180, 0, 0, 1, 1, 1)
        self.modelloader('DDSign1', 'phase_4/models/props/neighborhood_sign_DD.bam', render, -59.1768, 92.9836, 0.499824, -9, 0, 0, 1, 1, 1)
        self.modelloader('DDSign2', 'phase_4/models/props/neighborhood_sign_DD.bam', render, -33.749, 88.9499, 0.499825, 170, 0, 0, 1, 1, 1)
        self.modelloader('MMSign1', 'phase_4/models/props/neighborhood_sign_MM.bam', render, -143.503, -8.9528, 0.499987, 90, 0, 0, 1, 1, 1)
        self.modelloader('MMSign2', 'phase_4/models/props/neighborhood_sign_MM.bam', render, -143.242, 16.9541, 0.499977, -90, 0, 0, 1, 1, 1)
        self.modelloader('DGSign1', 'phase_4/models/props/neighborhood_sign_DG.bam', render, 21.3941, -144.665, 2.99998, -30, 0, 0, 1, 1, 1)
        self.modelloader('DGSign2', 'phase_4/models/props/neighborhood_sign_DG.bam', render, 44.1038, -157.906, 2.99998, 148, 0, 0, 1, 1, 1)
        self.modelloader('Gazebo', 'phase_4/models/modules/gazebo.bam', render, -60.44, -11.4, -2, -178, 0, 0, 1, 1, 1)
        self.modelloader('Fountain', 'phase_4/models/props/toontown_central_fountain.bam', render, 93.2057, -106.482, 2.50002, 0, 0, 0, 1, 1, 1)
        self.modelloader('Mickeyhorse', 'phase_4/models/props/mickey_on_horse.bam', render, 73.6829, 121.026, 2.49996, 0, 0, 0, 1, 1, 1)
        self.modelloader('FlowerPlant1', 'phase_3.5/models/props/big_planter.bam', render, 18.9496, -48.977, 4.95856, 135, 0, 0, 1, 1, 1)
        self.modelloader('FlowerPlant2', 'phase_3.5/models/props/big_planter.bam', render, 19.2327, 52.5553, 4.95837, -135, 0, 0, 1, 1, 1)
        self.modelloader('Fence1', 'phase_3.5/models/modules/wood_fence.bam', render, -148, -23, 0.5, 90, 0, 0, 1, 1, 1)
        self.modelloader('Fence2', 'phase_3.5/models/modules/wood_fence.bam', render, -147, -32.8, 0.5, 96, 0, 0, 1, 1, 1)
        self.modelloader('Fence3', 'phase_3.5/models/modules/wood_fence.bam', render, -144.1, -41.9, 0.5, 107, 0, 0, 1, 1, 1)
        self.modelloader('Fence4', 'phase_3.5/models/modules/wood_fence.bam', render, -95, -95.5, 0.5, 160, 0, 0, 1, 1, 1)
        self.modelloader('Fence5', 'phase_3.5/models/modules/wood_fence.bam', render, -104, -92.2, 0.5, 150, 0, 0, 1, 1, 1)
        self.modelloader('Fence6', 'phase_3.5/models/modules/wood_fence.bam', render, -112.5, -87.3, 0.5, 148, 0, 0, 1, 1, 1)
        self.modelloader('Fence7', 'phase_3.5/models/modules/wood_fence.bam', render, -140.73, -53, 0.5, 107, 0, 0, 1.16, 1, 1.0)
        self.modelloaderstreetlight('Streetlight1', 'phase_3.5/models/props/streetlight_TT.bam', render, -125, 60, 0.5, 1500, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight2', 'phase_3.5/models/props/streetlight_TT.bam', render, 58.8, 93.6, 3, -90, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight3', 'phase_3.5/models/props/streetlight_TT.bam', render, 95, 93.6, 3, -90, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight4', 'phase_3.5/models/props/streetlight_TT.bam', render, 134, -126, 3, -130, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight5', 'phase_3.5/models/props/streetlight_TT.bam', render, 108, -28, 4, -90, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight6', 'phase_3.5/models/props/streetlight_TT.bam', render, 108, 32, 4, -90, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight7', 'phase_3.5/models/props/streetlight_TT.bam', render, 32, 61, 4, -90, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight8', 'phase_3.5/models/props/streetlight_TT.bam', render, 28, -57, 4, -90, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight9', 'phase_3.5/models/props/streetlight_TT.bam', render, -101, -70, 0.5, 80, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight10', 'phase_3.5/models/props/streetlight_TT.bam', render, -129, -42.5, 0.5, 90, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight11', 'phase_3.5/models/props/streetlight_TT.bam', render, 3.8, 118, 3, -110, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight12', 'phase_3.5/models/props/streetlight_TT.bam', render, 116, 146, 3, 145, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight13', 'phase_3.5/models/props/streetlight_TT.bam', render, 86, 164, 3, -95, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight14', 'phase_3.5/models/props/streetlight_TT.bam', render, 45.5, -88, 3, -2, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight15', 'phase_3.5/models/props/streetlight_TT.bam', render, 78.3, -88, 3, -2, 0, 0, 1, 1, 1)
        self.modelloaderstreetlight('Streetlight16', 'phase_3.5/models/props/streetlight_TT.bam', render, 100, -157, 3, 30, 0, 0, 1, 1, 1)
        self.modelloadercopyto('Tree1', 'phase_3.5/models/props/trees.bam', 'prop_tree_large_no_box_ul', render, -80.9143, 79.7948, 0.2, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree2', 'phase_3.5/models/props/trees.bam', 'prop_tree_large_no_box_ul', render, -26.1169, 73.7975, 0.2, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree3', 'phase_3.5/models/props/trees.bam', 'prop_tree_fat_no_box_ul', render, 7.14367, 100.346, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree4', 'phase_3.5/models/props/trees.bam', 'prop_tree_fat_no_box_ul', render, 55.8308, 153.977, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree5', 'phase_3.5/models/props/trees.bam', 'prop_tree_fat_no_box_ul', render, 102.359, 81.1646, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree6', 'phase_3.5/models/props/trees.bam', 'prop_tree_fat_no_box_ul', render, 114.09, 57.3141, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree7', 'phase_3.5/models/props/trees.bam', 'prop_tree_fat_no_box_ul', render, 143.598, 110.178, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree8', 'phase_3.5/models/props/trees.bam', 'prop_tree_large_no_box_ul', render, -128.41, 32.9562, 0.2, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree9', 'phase_3.5/models/props/trees.bam', 'prop_tree_large_no_box_ul', render, -128.708, -23.9096, 0.2, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree10', 'phase_3.5/models/props/trees.bam', 'prop_tree_large_no_box_ul', render, -52.4323, -73.2793, 0.2, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree11', 'phase_3.5/models/props/trees.bam', 'prop_tree_fat_no_box_ul', render, 7.00708, -99.2181, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree12', 'phase_3.5/models/props/trees.bam', 'prop_tree_small_no_box_ul', render, 96.5467, -145.522, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree13', 'phase_3.5/models/props/trees.bam', 'prop_tree_small_no_box_ul', render, 119.57, -127.05, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree14', 'phase_3.5/models/props/trees.bam', 'prop_tree_small_no_box_ul', render, 128.064, -60.4145, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree15', 'phase_3.5/models/props/trees.bam', 'prop_tree_small_no_box_ul', render, 121.146, -45.0892, 2.725, 1, 1, 1, 1, 1, 1)
        self.modelloadercopyto('Tree16', 'phase_3.5/models/props/trees.bam', 'prop_tree_small_no_box_ul', render, 113.503, -57.8055, 2.725, 1, 1, 1, 1, 1, 1)

    def modelloader(self, nodename, modelpath, renderparent, x, y, z, h, p, r, scale1, scale2, scale3):
        self.modeldict[nodename] = loader.loadModel(modelpath)
        self.modeldict[nodename].reparentTo(renderparent)
        self.modeldict[nodename].setPos(x, y, z)
        self.modeldict[nodename].setHpr(h, p, r)
        self.modeldict[nodename].setScale(scale1, scale2, scale3)

    def modelloadercopyto(self, nodename, modelpath, findmodel, renderparent, x, y, z, h, p, r, scale1, scale2, scale3):
        self.modeldict[nodename] = loader.loadModel(modelpath)
        self.modeldict[nodename] = self.modeldict[nodename].find('**/' + findmodel).copyTo(renderparent)
        self.modeldict[nodename].setPos(x, y, z)
        self.modeldict[nodename].setHpr(h, p, r)
        self.modeldict[nodename].setScale(scale1, scale2, scale3)

    def modelloaderanimate(self, nodename, modelpath, animatepath, renderparent, x, y, z, h, p, r, scale1, scale2, scale3, animation):
        self.modeldict[nodename] = Actor(modelpath, {animation: animatepath})
        self.modeldict[nodename].reparentTo(renderparent)
        self.modeldict[nodename].setPos(x, y, z)
        self.modeldict[nodename].setHpr(h, p, r)
        self.modeldict[nodename].setScale(scale1, scale2, scale3)
        self.modeldict[nodename].loop(animation)

    def textloader(self, nodename, Textnodename, Textname, Textdata, Fonttype, renderparent, x, y, z, h, p, r, scale1, scale2, scale3, color1, color2, color3):
        Textname = TextNode(Textnodename)
        Textname.setText(Textdata)
        Textname.setFont(Fonttype)
        self.modeldict[nodename] = renderparent.attachNewNode(Textname)
        self.modeldict[nodename].setPos(x, y, z)
        self.modeldict[nodename].setHpr(h, p, r)
        self.modeldict[nodename].setScale(scale1, scale2, scale3)
        self.modeldict[nodename].setColor(color1, color2, color3)

    def modelloaderstreetlight(self, nodename, modelpath, renderparent, x, y, z, h, p, r, scale1, scale2, scale3):
        self.modeldict[nodename] = loader.loadModel(modelpath)
        self.modeldict[nodename].reparentTo(renderparent)
        self.modeldict[nodename].setPos(x, y, z)
        self.modeldict[nodename].setHpr(h, p, r)
        self.modeldict[nodename].setScale(scale1, scale2, scale3)
        self.modeldict[nodename].find('**/prop_post_light_base').hide()
        self.modeldict[nodename].find('**/p1').hide()
        self.modeldict[nodename].find('**/prop_post_one_light').hide()
        self.modeldict[nodename].find('**/p13').hide()

BTFont = loader.loadFont('phase_3/models/fonts/MickeyFont.bam')
bk_text = ' '
textObject = OnscreenText(text=bk_text, pos=(0.95, -0.95), scale=0.07, fg=(1,
 0.5,
 0.5,
 1), align=TextNode.ACenter, mayChange=1)
textObject.setFont(BTFont)

def setText(textEntered):
    textObject.setText(textEntered)
    if b:
        b.hide()
        ImgBtn2.show()

def clearText():
    if b:
        b.enterText('')

def openChatGui():
    if b:
        b.show()
        ImgBtn2.hide()

chatGui = loader.loadModel('phase_3.5/models/gui/chat_input_gui.bam')
b = DirectEntry(text='', scale=0.05, command=setText, initialText='Type Something', numLines=3, focus=1, focusInCommand=clearText)
b.hide()
chatGui = loader.loadModel('phase_3.5/models/gui/chat_input_gui.bam')
chatGui = loader.loadModel('phase_3.5/models/gui/chat_input_gui.bam')
ImgBtn2 = DirectButton(frameSize=None, text=' ', image=(chatGui.find('**/ChtBx_ChtBtn_UP'), chatGui.find('**/ChtBx_ChtBtn_DN'), chatGui.find('**/ChtBx_ChtBtn_RLVR')), relief=None, command=openChatGui, text_pos=(2, -0.325), geom=None, pad=(0.01, 0.01), suppressKeys=0, pos=(-1.21, -1, 0.9), text_scale=1, borderWidth=(0.015, 0.01))
b.setPos(-1.21, -2, 5)
chatGui = loader.loadModel('phase_3.5/models/gui/chat_input_gui.bam')
ImgBtn2 = DirectButton(frameSize=None, text=' ', image=(chatGui.find('**/ChtBx_ChtBtn_UP'), chatGui.find('**/ChtBx_ChtBtn_DN'), chatGui.find('**/ChtBx_ChtBtn_RLVR')), relief=None, command=openChatGui, text_pos=(2, -0.325), geom=None, pad=(0.01, 0.01), suppressKeys=0, pos=(-1.1, -1, 0.9), text_scale=0.06, color=(0, 1, 0), borderWidth=(0.015, 0.01))
b.setPos(-1.21, -2, 0.75)
Font = loader.loadFont('phase_3/models/fonts/Courier.bam')
tag = OnscreenText(scale=0.5, text='Smirky Superchomp', bg=(0.9,
 0.9,
 0.9,
 0.3), fg=(0.35,
 0.35,
 0.95,
 1), decal=True)
tag.wrtReparentTo(DuckBody)
tag.setBillboardAxis()
tag.setPos(0, 0)
tag.setDepthTest(True)
tag.setDepthWrite(True)
tag.reparentTo(DuckBody)
tag.setZ(tag, DuckBody.find('**/__Actor_head').getZ(DuckBody) + -1)
tag.reparentTo(DuckBody.find('**/def_head'))
tag.setFont(BTFont)
fist = loader.loadModel('phase_3.5/models/gui/tt_m_gui_gm_toonResistance_fist.bam')
fist.reparentTo(DuckBody.find('**/def_head'))
fist.setPos(0, 0, 0)
fist.setScale(2.3)
fist.find('**/gmPartyHat').remove()
ttHatSpin = fist.find('**/fistIcon').hprInterval(3, Vec3(360, 0, 0))
ttHatSpin.loop()
fedora = loader.loadModel('phase_4/models/accessories/tt_m_chr_avt_acc_hat_fedora.bam')
fedora.reparentTo(DuckBody.find('**/def_head'))
fedora.setScale(0.35)
fedora.setZ(0.75)
fedora.setH(180)
nerdglasses = loader.loadModel('phase_4/models/accessories/tt_m_chr_avt_acc_msk_squareRims.bam')
nerdglasses.reparentTo(DuckBody.find('**/def_head'))
nerdglasses.setH(180)
nerdglasses.setScale(0.45)
nerdglasses.setZ(0.2)
nerdglasses.setY(0.05)
CS1 = loader.loadModel('phase_5/models/modules/TT_A2.bam')
CS1.reparentTo(render)
CS1.setH(138.37)
CS1.setX(-109.07)
CS1.setY(-92.27)
CS2 = loader.loadModel('phase_5/models/modules/TT_A3.bam')
CS2.reparentTo(render)
CS2.setH(104.93)
CS2.setX(-132.65)
CS2.setY(-74.96)

def TP1():
    DuckBody.setZ(500.89)
    DuckBody.setY(59.6964)
    DuckBody.setX(-1.00264)

ButtonImage = loader.loadModel('phase_3/models/gui/quit_button.bam')
ImgBtn11 = DirectButton(frameSize=None, text='SpeedWay', image=(ButtonImage.find('**/QuitBtn_UP'), ButtonImage.find('**/QuitBtn_DN'), ButtonImage.find('**/QuitBtn_RLVR')), relief=None, command=TP1, text_pos=(0, -0.015), geom=None, pad=(0.01, 0.01), suppressKeys=0, pos=(-0.05, 0, 0.95), text_scale=0.059, borderWidth=(0.13, 0.01), scale=0.7, color=(0, 1, 0))
environ = loader.loadModel('phase_6/models/karting/GasolineAlley_TT.bam')
environ.reparentTo(render)
environ.setZ(500)
tunnel = loader.loadModel('phase_4/models/modules/safe_zone_tunnel_TT.bam')
tunnel.reparentTo(render)
tunnel.setPos(60, 175, 493)
tunnel.setHpr(180, 0, 0)
tunnel.setScale(1)
tunnelsign = loader.loadModel('phase_3.5/models/props/tunnel_sign_orange.bam')
tunnelsign.reparentTo(tunnel)
tunnelsign.setPos(60, 95.01, 523.7)
tunnelsign.setHpr(180, 0, 0)
tunnelsign.setScale(1.6)
SZsign = loader.loadModel('phase_4/models/props/goofySZ.bam')
SZsign.reparentTo(tunnel)
SZsign.setPos(60, 95.025, 523.7)
SZsign.setHpr(180, 0, 0)
SZsign.setScale(4)
kartshop = loader.loadModel('phase_6/models/karting/kartShop.bam')
kartshop.reparentTo(render)
kartshop.setPos(0, 10, 500)
scoreboard = loader.loadModel('phase_6/models/karting/tt_m_ara_gfs_leaderBoardCrashed.bam')
scoreboard.reparentTo(render)
scoreboard.setPos(1, -111, 500)
scoreboard.setHpr(180, 0, 0)
wrench = loader.loadModel('phase_6/models/karting/KartArea_WrenchJack.bam')
wrench.reparentTo(render)
wrench.setPos(-33, 5, 500)
wrench.setHpr(180, 0, 0)
tires = loader.loadModel('phase_6/models/karting/KartArea_Tires.bam')
tires.reparentTo(render)
tires.setPos(33, 5, 500)
trees1 = loader.loadModel('phase_6/models/karting/GoofyStadium_TreeBase.bam')
trees1.reparentTo(render)
trees1.setPos(-13, 58, 499.7)
trees1.setScale(12)
trees2 = loader.loadModel('phase_6/models/karting/GoofyStadium_TreeBase.bam')
trees2.reparentTo(render)
trees2.setPos(13, 58, 499.7)
trees2.setScale(12)
trees3 = loader.loadModel('phase_6/models/karting/GoofyStadium_TreeBase.bam')
trees3.reparentTo(render)
trees3.setPos(-13, -35, 499.7)
trees3.setScale(12)
trees4 = loader.loadModel('phase_6/models/karting/GoofyStadium_TreeBase.bam')
trees4.reparentTo(render)
trees4.setPos(13, -35, 499.7)
trees4.setScale(12)
trees5 = loader.loadModel('phase_6/models/karting/GoofyStadium_TreeBase.bam')
trees5.reparentTo(render)
trees5.setPos(-10, -76, 499.7)
trees5.setScale(12)
trees6 = loader.loadModel('phase_6/models/karting/GoofyStadium_TreeBase.bam')
trees6.reparentTo(render)
trees6.setPos(10, -76, 499.7)
trees6.setScale(12)
light1 = loader.loadModel('phase_6/models/karting/GoofyStadium_Lamppost_Base1.bam')
light1.reparentTo(render)
light1.setPos(-10, -52, 499.3)
light1.setScale(14)
light2 = loader.loadModel('phase_6/models/karting/GoofyStadium_Lamppost_Base1.bam')
light2.reparentTo(render)
light2.setPos(10, -52, 499.3)
light2.setScale(14)
box = loader.loadModel('phase_6/models/karting/GoofyStadium_Mailbox.bam')
box.reparentTo(render)
box.setPos(16, -50, 500)
box.setHpr(210, 0, 0)
box.setScale(10)
flag1 = loader.loadModel('phase_6/models/karting/flag.bam')
flag1.reparentTo(render)
flag1.setPos(-18, 6, 499.8)
flag2 = loader.loadModel('phase_6/models/karting/flag.bam')
flag2.reparentTo(render)
flag2.setPos(18, 6, 499.8)
sign = loader.loadModel('phase_6/models/karting/KartShowBlockSign.bam')
sign.reparentTo(render)
sign.setPos(-16, -50, 500)
sign.setHpr(-120, 0, 0)
sign.setScale(26)
announcer1 = loader.loadModel('phase_6/models/karting/announcer.bam')
announcer1.reparentTo(render)
announcer1.setPos(25, -150, 499.3)
announcer1.setHpr(-140, 0, 0)
announcer2 = loader.loadModel('phase_6/models/karting/announcer.bam')
announcer2.reparentTo(render)
announcer2.setPos(-26, -149, 499.3)
announcer2.setHpr(-212, 0, 0)
announcer3 = loader.loadModel('phase_6/models/karting/announcer.bam')
announcer3.reparentTo(render)
announcer3.setPos(-38, -135, 499.3)
announcer3.setHpr(-212, 0, 0)
announcer4 = loader.loadModel('phase_6/models/karting/announcer.bam')
announcer4.reparentTo(render)
announcer4.setPos(37, -137.5, 499.3)
announcer4.setHpr(-140, 0, 0)
cone1 = loader.loadModel('phase_6/models/karting/cone.bam')
cone1.reparentTo(render)
cone1.setPos(13, -4, 499.7)
cone2 = loader.loadModel('phase_6/models/karting/cone.bam')
cone2.reparentTo(render)
cone2.setPos(13, 20, 499.7)
cone3 = loader.loadModel('phase_6/models/karting/cone.bam')
cone3.reparentTo(render)
cone3.setPos(-14, 18, 499.7)
cone4 = loader.loadModel('phase_6/models/karting/cone.bam')
cone4.reparentTo(render)
cone4.setPos(-14, -3, 499.7)
cone5 = loader.loadModel('phase_6/models/karting/cone.bam')
cone5.reparentTo(render)
cone5.setPos(-23, 9, 499.7)
cone6 = loader.loadModel('phase_6/models/karting/cone.bam')
cone6.reparentTo(render)
cone6.setPos(45, -138, 499.4)
cone7 = loader.loadModel('phase_6/models/karting/cone.bam')
cone7.reparentTo(render)
cone7.setPos(25, -109, 500)
cone8 = loader.loadModel('phase_6/models/karting/cone.bam')
cone8.reparentTo(render)
cone8.setPos(24, -111, 500)
cone8.setHpr(45, 0, 0)
cone9 = loader.loadModel('phase_6/models/karting/cone.bam')
cone9.reparentTo(render)
cone9.setPos(75, -106, 500)
cone9.setHpr(0, 0, -120)
cone10 = loader.loadModel('phase_6/models/karting/cone.bam')
cone10.reparentTo(render)
cone10.setPos(76.5, -107.5, 500)
cone10.setHpr(0, 120, 0)
cone11 = loader.loadModel('phase_6/models/karting/cone.bam')
cone11.reparentTo(render)
cone11.setPos(26, -154, 499.3)
cone11.setHpr(42, 0, 0)
cone12 = loader.loadModel('phase_6/models/karting/cone.bam')
cone12.reparentTo(render)
cone12.setPos(1, -187, 501.22)
cone12.setHpr(42, 0, 0)
krate1 = loader.loadModel('phase_6/models/karting/krate.bam')
krate1.reparentTo(render)
krate1.setPos(1, -187, 499.3)
krate1.setScale(1.2)
krate2 = loader.loadModel('phase_6/models/karting/krate.bam')
krate2.reparentTo(render)
krate2.setPos(-48, -115, 499.3)
krate2.setScale(1.2)
krate3 = loader.loadModel('phase_6/models/karting/krate.bam')
krate3.reparentTo(render)
krate3.setPos(-50, -113, 499.3)
krate3.setHpr(45, 0, 0)
krate3.setScale(1.2)
krate4 = loader.loadModel('phase_6/models/karting/krate.bam')
krate4.reparentTo(render)
krate4.setPos(-49, -114, 501.22)
krate4.setHpr(60, 0, 0)
krate4.setScale(1.2)

def TP2():
    DuckBody.setZ(0)
    DuckBody.setX(0)
    DuckBody.setY(0)

ButtonImage = loader.loadModel('phase_3/models/gui/quit_button.bam')
ImgBtn11 = DirectButton(frameSize=None, text='TTC', image=(ButtonImage.find('**/QuitBtn_UP'), ButtonImage.find('**/QuitBtn_DN'), ButtonImage.find('**/QuitBtn_RLVR')), relief=None, command=TP2, text_pos=(0, -0.015), geom=None, pad=(0.01, 0.01), suppressKeys=0, pos=(1, 0, 0.95), text_scale=0.059, borderWidth=(0.13, 0.01), scale=0.7, color=(0, 1, 0))
lord = Actor('phase_3/models/char/mickey-1200.bam', {'walk': 'phase_3/models/char/mickey-walk.bam'})
lord.reparentTo(render)
lord.loop('walk')
lord.setX(106.58)
lord.setY(-1.37)
lord.setZ(4.46)
lord.setH(104.62)
cs = CollisionSphere(0, 0, 1, 3)
cnodePath = lord.attachNewNode(CollisionNode('cnode'))
cnodePath.node().addSolid(cs)
pandaPosInterval1 = lord.posInterval(3, Point3(96.3312, 0.553801, 4.025), startPos=Point3(96.3312, 0.553801, 4.025))
pandaHprInterval1 = lord.hprInterval(3, Point3(96.3312, 0.553801, 4.025), startHpr=Point3(96.3312, 0.553801, 4.025))
pandaPosInterval2 = lord.posInterval(3, Point3(54.1032, 10.1371, 4.025), startPos=Point3(96.3312, 0.553801, 4.025))
pandaHprInterval2 = lord.hprInterval(3, Point3(172.798, 0, 0), startHpr=Point3(96.3312, 0.553801, 4.025))
pandaPosInterval3 = lord.posInterval(3, Point3(62.9905, -21.4791, 6.05112), startPos=Point3(54.1032, 10.1371, 4.025))
pandaHprInterval3 = lord.hprInterval(3, Point3(438.492, 0, 0), startHpr=Point3(172.798, 0, 0))
lord.pandaPace = Sequence(pandaPosInterval1, pandaHprInterval1, pandaPosInterval2, pandaHprInterval2, pandaPosInterval3, pandaHprInterval3)
lord.pandaPace.loop()
environ = EnvironmentTTC()
base.taskMgr.add(updateOnScreenDebug, 'UpdateOSD')
tag2 = OnscreenText(scale=2, text='Mickey', bg=(0.9,
 0.9,
 0.9,
 0.3), fg=(0.35,
 0.35,
 0.95,
 1), decal=True)
tag2.wrtReparentTo(lord)
tag2.setBillboardAxis()
tag2.setPos(0, 0)
tag2.setDepthTest(True)
tag2.setDepthWrite(True)
tag2.reparentTo(lord)
tag2.setZ(tag, lord.find('**/joint_pupilL').getZ(lord) + 1)
tag2.reparentTo(lord.find('**/joint_pupilL'))
tag2.setFont(BTFont)
tag2.setColor(1, 0.1, 0.1, 1.0)
title.destroy()

base.oobe()
run()


from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.graphics import Color, Line, Rectangle
from image_to_text import get_text, train_model
import cv2
from string import ascii_uppercase as UC

class DrawWidget(RelativeLayout):

    def __init__(self, **kwargs):

        super(DrawWidget, self).__init__(**kwargs)

        with self.canvas:
           Color(*(1,1,1),mode="rgb")

           self.rect = Rectangle(size = self.size, pos = self.pos)
        self.bind(size=self.update_rect)

    def on_touch_down(self, touch):
        color = (0,0,0)
        with self.canvas:
            Color(*color,mode="rgb")
            width = 2.5
            x,y = self.to_local(x=touch.x, y=touch.y)
            touch.ud["line"] = Line(points=(x, y),width=width)
    def on_touch_move(self,touch):
        x,y = self.to_local(x=touch.x, y=touch.y)
        touch.ud['line'].points += [x, y]

    def update_rect(self, instance, value):
        self.rect.size = self.size
        self.rect.pos = self.pos

class DrawApp(App):

    def build(self):
        self.title = 'Convert To Text'

        parent = RelativeLayout()

        self.draw = DrawWidget(size_hint=(0.5,0.8),pos_hint={'x':0,'y':0.2})

        clear_btn = Button(size_hint=(0.5,0.1),text="Clear",pos_hint={'x':0,'y':0.1})
        clear_btn.bind(on_release=self.clear_canvas)

        convert_btn = Button(size_hint=(0.5,0.1),text="Convert to text",pos_hint={'x':0.5,'y':0.1})
        convert_btn.bind(on_release=self.convert)

        self.label = Label(size_hint=(0.5,0.9),pos_hint={'x':0.5,'y':0.2})

        label1 = Label(size_hint=(0.3,0.1),pos_hint={"x":0,"y":0},text="Wrong conversion? Type in correct capital letters comma separated and train")
        label1.bind(width=lambda *x: label1.setter('text_size')(label1, (label1.width, None)), texture_size=lambda *x: label1.setter('height')(label1, label1.texture_size[1]))

        self.inp_txt = TextInput(size_hint=(0.4,0.1),pos_hint={"x":0.3,"y":0})
        self.train_btn = Button(size_hint=(0.3,0.1),pos_hint={"x":0.7,"y":0},text="Train", disabled=True)
        self.train_btn.bind(on_release = self.train)

        parent.add_widget(self.draw)
        parent.add_widget(self.label)
        parent.add_widget(clear_btn)
        parent.add_widget(convert_btn)
        parent.add_widget(label1)
        parent.add_widget(self.inp_txt)
        parent.add_widget(self.train_btn)

        return parent

    def clear_canvas(self, obj):
        self.draw.canvas.clear()
        with self.draw.canvas:
           Color(*(1,1,1),mode="rgb")
           self.draw.rect = Rectangle(size = self.draw.size, pos = (0,0))
        self.draw.bind(size=self.draw.update_rect)
        self.train_btn.disabled = True

    def convert(self, obj):
        self.train_btn.disabled = False
        self.draw.export_to_png("draw.png")
        img = cv2.imread("draw.png")
        self.lets, self.imgs = get_text(img)
        txt = " ".join(self.lets)
        self.label.text = txt

    def train(self, obj):
        let = self.inp_txt.text
        let = let.replace(" ","").split(",")
        lbls = []
        chars = list(UC)
        for l in let:
            lbls.append(chars.index(l))
        if len(lbls) == len(self.imgs):
            train_model(self.imgs, lbls)

if __name__ == "__main__":
    DrawApp().run()


from os import stat
from flask import Flask, Response

from flask_restx import Resource, Api, reqparse
import random
import json
import os

from werkzeug.exceptions import BadHost, BadRequest

app = Flask(__name__)
api = Api(app)

#Cette route va permettre de retourner la valeur +1
@api.route('/plus_one/<int:number>')
@api.doc(params={"x": "Must be an integer."})
class Add(Resource):
    def get(self, number):
        return {'value': number+1}

#Cette route permet de retourner la valeur au carré et, pour mon cas j'ai testé de transmettre deux paramètres

@api.route('/square')
@api.doc(params={"int": "Must be an integer", "email": "Must be a string"}, location="query")
class Square(Resource):
    def get(self):
        parser = reqparse.RequestParser()
        parser.add_argument('int', type=int)
        parser.add_argument('email', type=str)
        args = parser.parse_args()
        return {'value': args['int'] ** 2, 'email': args['email']}

#Cette route prend en paramètre le choix de l'utilisateur sous forme de int et renvoie le message final

@api.route('/game/<int:choice>')
@api.doc(params={"choice": "1: Pierre \n 2: Papier \n 3: Ciseaux \n 4: Lézard \n 5: Spock"})
class Game(Resource):
    def get(self, choice):
        liste_choices = ["Pierre", "Papier", "Ciseaux", "Lézard", "Spock"]

        def choice_computer(index):
            possibilities = ["Pierre", "Papier", "Ciseaux", "Lézard", "Spock"]
            possibilities.remove(possibilities[index])
            computer = possibilities[random.randint(0, len(possibilities)-1)]
            return computer

        if choice not in [1,2,3,4,5]:
            return Response(
        "Send a number between 1 and 5 !",
        status=400,
    )
        else:
            user_choice= liste_choices[choice-1]
            computer_choice= choice_computer(choice-1)
            index_computer = liste_choices.index(computer_choice)

            result = {0: {1: True, 2: False, 3: True, 4: False },
            1: {0: True, 2: False, 3: False, 4: True},
            2: {0: False, 1: True, 3: True, 4: False},
            3: {0: False, 1: True, 2: False, 4: True},
            4: {0: True, 1: False, 2: True, 3: False} }

            if result[choice-1][index_computer] == False:
                with open('stats.json') as json_file:
                    data = json.load(json_file)
                    data[user_choice] = int(data[user_choice]) + 1

                    with open('stats.json', 'w') as json_file:
                        json.dump(data, json_file)
                return {"ordinateur" : computer_choice, "user": user_choice, "message": "Vous avez perdu."}
            else:
                with open('stats.json') as json_file:
                    data = json.load(json_file)
                    data[user_choice] = int(data[user_choice]) + 1

                    with open('stats.json', 'w') as json_file:
                        json.dump(data, json_file)

                return {"ordinateur" : computer_choice, "user": user_choice, "message": "Vous avez gagné !"}

@api.route('/stats')
class Stats(Resource):
    def get(self):
        SITE_ROOT = os.path.realpath(os.path.dirname(__file__))
        json_url = os.path.join(SITE_ROOT,"stats.json")
        data = json.load(open(json_url))
        return data

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


import bpy
import bmesh
import os

#function for changing the topology of the object by triangulating it
def triangulate_object(obj):
    me = obj.data
    # Get a BMesh representation
    bm = bmesh.new()
    bm.from_mesh(me)

    bmesh.ops.triangulate(bm, faces=bm.faces[:], quad_method=0, ngon_method=0)

    # Finish up, write the bmesh back to the mesh
    bm.to_mesh(me)
    bm.free()

#retrieves the radi for the Envelope based elip
def min_max_axis(object):
     Xs = []
     Ys = []
     Zs = []
     boundaries = []

     coords = [(object.matrix_world * v.co) for v in object.data.vertices]

     for vert in coords:
         Xs.append(vert[0])
         Ys.append(vert[1])
         Zs.append(vert[2])

     Xs.sort()
     Ys.sort()
     Zs.sort()

     boundaries.append(Xs[len(Xs) - 1])
     boundaries.append(Xs[0])
     boundaries.append(Ys[len(Ys) - 1])
     boundaries.append(Ys[0])
     boundaries.append(Zs[len(Zs) - 1])
     boundaries.append(Zs[0])

     E_radi.append((abs(boundaries[0] - boundaries[1]))/2)
     E_radi.append((abs(boundaries[2] - boundaries[3]))/2)
     E_radi.append((abs(boundaries[4] - boundaries[5]))/2)

#create folder and move blend file into it
file = bpy.path.basename(bpy.context.blend_data.filepath)

filename = file.strip('.blend')

mom_folder = '/Users/rileysterman/Desktop/blender objects/pre-pre-animation/'

object_folder = mom_folder + filename

os.makedirs(object_folder)

os.rename(bpy.context.blend_data.filepath, object_folder + '/' + file)

#identify object of interest,create lists of elip radi, and reset its location to the origin, and set the center to be based on mass volume
ob = bpy.data.objects[0]
E_radi = []

ob.location = (0,0,0)
#ob.origin_set(type='ORIGIN_CENTER_OF_VOLUME')

#triangulate the object
triangulate_object(ob)

#export stl file of triangulated object into the object folder
stl_path = object_folder + '/' + filename + '.stl'
bpy.ops.export_mesh.stl(filepath=stl_path)

#export fbx file
fbx_path = object_folder + '/' + filename + '.fbx'
bpy.ops.export_scene.fbx(filepath =fbx_path)

# E_radi
min_max_axis(ob)

#noramlize E_radi
radi_sum = E_radi[0] + E_radi[1] + E_radi[2]
E_radi[0] = E_radi[0] /radi_sum
E_radi[1] = E_radi[1] /radi_sum
E_radi[2] = E_radi[2] /radi_sum

E = open(object_folder +'/'+ 'E' + filename, 'w+')
E.write(str(E_radi[0]) + '~' + str(E_radi[1]) + '~' + str(E_radi[2]))
E.close()


from calendar import c
from pyexpat import model
from re import L
import numpy as np
import pandas as pd

compas_scores_raw= pd.read_csv("compas_score_raw.csv",  lineterminator='\n')
compas_scores_two_year= pd.read_csv("compas_scores_two_years.csv",  lineterminator='\n')
print('-----------------Compas Scores Raw-----------------')
print('type',type(compas_scores_raw))
print('-----------------Compas Scores Two Year-----------------')
print('type',type(compas_scores_two_year))

#number of rows and columns
print('-----------------Compas Scores Raw-----------------')
print('shape',compas_scores_raw.shape)
print('-----------------Compas Scores Two Year-----------------')
print('shape',compas_scores_two_year.shape)

# fitlering the data with the following conditions
# 1. if charge data was not within 30 days of arrest
# 2. c_charge_degree is not missing
# 3. score_text is not missing
# 4. is_recid is not missing -1 means missing

print('-----------------Compas Scores two year-----------------')
df= compas_scores_two_year[[ 'age', 'c_charge_degree','race', 'age_cat', 'score_text', 'sex', 'priors_count', 'days_b_screening_arrest', 'decile_score', 'is_recid',  'c_jail_in', 'c_jail_out',  'v_decile_score','two_year_recid\r']]
print(np.shape(df))

df = df.loc[(df['days_b_screening_arrest'] <= 30) & (df['days_b_screening_arrest'] >= -30) & (df['is_recid'] != -1) & (df['c_charge_degree'] != 'O') & (df['score_text'] != 'N/A')]
print('shape of filtered data',df.shape)

#length of stay in jail
df['length_of_stay'] = pd.to_datetime(df['c_jail_out']) - pd.to_datetime(df['c_jail_in'])
df['length_of_stay'] = df['length_of_stay'].astype('timedelta64[D]')
df['length_of_stay'] = df['length_of_stay'].astype(int)
print(df['length_of_stay'])
print('shape of filtered data',df.shape)
print('length of stay',df['length_of_stay'].describe())
#correlation between length of stay and decile score
print('correlation between length of stay and decile score',df['length_of_stay'].corr(df['decile_score']))

print('-----------------describe age-----------------')
print(df['age'].describe())
print('-----------------describe race----------------')
print(df['race'].describe())

print('-----------------race split-----------------')
race  = ['African-American', 'Caucasian', 'Hispanic', 'Asian', 'Native American', 'Other']
for i in race :
    print( i,len(df[df['race']== i])/len(df['race']))

print ('-----------------describe score text----------------')
print('low ', len(df[df['score_text'] == 'Low']))
print('medium ', len(df[df['score_text'] == 'Medium']))
print('high ', len(df[df['score_text'] == 'High']))

#race and sex split
female = []
male = []

for i in race :

    temp  = len(df[(df['race']== i) & (df['sex'] == 'Male')]  )
    print(temp)
    male.append(temp)
    temp  = len(df[(df['race']== i) & (df['sex'] == 'Female')])
    female.append(temp)

print(race)
print ('female', female)
print('male', male)

f = pd.crosstab(df['sex'], df['race'])
print('f',f)

# find decide score for african american
print('-----------------decile score for african american-----------------')
print(df[(df['race']) == 'African-American']['decile_score'].describe())

decile = [1,2,3,4,5,6,7,8,9,10]
# plot decide score for african american
import matplotlib.pyplot as plt

# bar plot for decide score for african american and caucasian

df_race_decile_score = df[['race', 'decile_score']]
df_african = df_race_decile_score[ df_race_decile_score['race'] == 'African-American']
df_caucasian = df_race_decile_score[ df_race_decile_score['race'] == 'Caucasian']
counts_decile_AA = []
counts_decile_C = []
temp = []
for i in decile:
    temp = len(df_african[df_african['decile_score'] == i])
    counts_decile_AA.append(temp)
    temp = len(df_caucasian[df_caucasian['decile_score'] == i])
    counts_decile_C.append(temp)

fig = plt.figure()
ax = fig.subplots(1,2)
ax[0].bar(decile, counts_decile_AA)
ax[0].set_title('African American')
ax[1].bar(decile, counts_decile_C)
ax[1].set_title('Caucasian')

ax[0].set_ylabel('Count')
ax[0].set_xlabel('Decile score')
ax[0].set_ylim(0, 650)
ax[1].set_ylabel('Count')
ax[1].set_xlabel('Decile score')
ax[1].set_ylim(0, 650)

plt.show()

# # plot volinent decide score for african american and caucasian

df_race_V_decile_score = df[['race', 'v_decile_score']]
df_african = df_race_V_decile_score[ df_race_V_decile_score['race'] == 'African-American']
df_caucasian = df_race_V_decile_score[ df_race_V_decile_score['race'] == 'Caucasian']
counts_decile_AA = []
counts_decile_C = []
temp = []
for i in decile:
    temp = len(df_african[df_african['v_decile_score'] == i])
    counts_decile_AA.append(temp)
    temp = len(df_caucasian[df_caucasian['v_decile_score'] == i])
    counts_decile_C.append(temp)

fig = plt.figure()
ax = fig.subplots(1,2)
ax[0].bar(decile, counts_decile_AA)
ax[0].set_title('African American')
ax[1].bar(decile, counts_decile_C)
ax[1].set_title('Caucasian')

ax[0].set_ylabel('Count')
ax[0].set_xlabel('Violent Decile score')
ax[0].set_ylim(0, 850)
ax[1].set_ylabel('Count')
ax[1].set_xlabel('Violent Decile score')
ax[1].set_ylim(0, 850)

plt.show()

# create some factors for logistic regression
df_c_charge_degree = df[['c_charge_degree']]
df_age_cat = df[['age_cat']]
df_race = df[['race']]
df_sex = df[['sex']]
df_age_race = df[['race']]
df_score = df[['score_text']]

# df_c_charge_degree = pd.get_dummies(df_c_charge_degree)

# print('head', df_c_charge_degree.head())
#labels, uniques = pd.factorize(df_c_charge_degree)

#factorize df_c_charge_degree
crime_factor, u_charge_degree = pd.factorize(df_c_charge_degree['c_charge_degree'])
f_age_cat, u_age_cat= pd.factorize(df_age_cat['age_cat'])
#relevel age cat with reference = 1
f_age_cat = f_age_cat - 1
#factorize race
f_race_AA, u_race_AA= pd.factorize(df_age_race['race'] == 'African-American')
f_race_C, u_race = pd.factorize(df_age_race['race'] == 'Caucasian')
#relevel race with reference = 3
print('----------------race----------------')
print("Numeric Representation : \n", f_race_AA)
print("Unique Values : \n", u_race_AA)

#factorize gender with male and female labels
f_gender, uniques_gender  = pd.factorize(df_sex['sex'])
print("Numeric Representation : \n", f_gender)
print("Unique Values : \n", uniques_gender)
#factorise score text
f_score_text, u_score_text = pd.factorize(df_score['score_text'] != 'Low')
print("Numeric Representation : \n", f_score_text)
print("size of f_score_text", len(f_score_text))
print("Unique Values : \n", u_score_text)

# create a new maxtrix with the factors
priors_count  = df[['priors_count']]
two_year_recid = df[['two_year_recid\r']]

X = np.column_stack(( f_age_cat, crime_factor, f_race_AA, f_race_C, f_gender, priors_count, two_year_recid  ))

# build a binmal logistic regression model to explain the score text given the factors
from sklearn.linear_model import LogisticRegression
model  = LogisticRegression(penalty='l2', C=1)
model.fit(X, f_score_text)
ypred = model.predict(X)
#print summary
print('intercept', model.intercept_)
#print coefficients with corresponding factors
print('coefficients', model.coef_)
print('score', model.score(X, f_score_text))
#model accuracy
from sklearn.metrics import accuracy_score
print('accuracy', accuracy_score(f_score_text, ypred))

import statsmodels.api as sm
model = sm.GLM(f_score_text, X,  family=sm.families.Binomial())
results = model.fit()
print(results.summary())


import torch
import torch.nn as nn
from torch.utils.cpp_extension import load
import os
import time
import random
import math

cur_path = os.path.dirname(os.path.realpath(__file__))
cpu_unsorted_segsum = load('cpu_unsorted_segsum',
    [f'{cur_path}/cpu_extension.cc'],
    extra_cflags=['-fopenmp', '-O3', '-march=native'],
    extra_ldflags=['-lgomp', '-O3', '-march=native'],
    verbose=False)

import cpu_unsorted_segsum

if torch.cuda.is_available():
    cuda_unsorted_segsum = load('cuda_unsorted_segsum',
        [f'{cur_path}/cuda_extension.cu'],
        extra_cflags=['-fopenmp', '-O3', '-march=native'],
        extra_ldflags=['-lgomp', '-O3', '-march=native'],
        verbose=False)

    import cuda_unsorted_segsum

else:
    cuda_unsorted_segsum = None
    print('CUDA not available, cuda_unsorted_segsum will not be available')

def unsorted_segment_sum_ref(
    data : torch.Tensor,
    indices : torch.Tensor,
    num_segments : int
) -> torch.Tensor:
    return torch.cat([
        data[indices == i].sum(dim=0, keepdim=True)
        for i in range(num_segments)
    ], dim=0)

class UnsortedSegmentSum(torch.autograd.Function):
    @staticmethod
    def forward(ctx, data : torch.Tensor, indices  : torch.Tensor, num_segments : int) -> torch.Tensor:
        ctx.save_for_backward(indices)

        M = cuda_unsorted_segsum if data.device.type == 'cuda' else cpu_unsorted_segsum

        assert M is not None, f'No backend for {data.device}'

        if len(data.shape) == 2:
            return M.unsorted_segment_sum_fwd(data, indices, num_segments)
        else:
            raise NotImplementedError()

    @staticmethod
    def backward(ctx, grad):
        indices, = ctx.saved_tensors

        M = cuda_unsorted_segsum if grad.device.type == 'cuda' else cpu_unsorted_segsum

        assert M is not None, f'No backend for {grad.device}'

        if len(grad.shape) == 2:
            return M.unsorted_segment_sum_bwd(grad.contiguous(), indices), None, None
        else:
            raise NotImplementedError()

def unsorted_segment_sum(
    data : torch.Tensor,
    indices  : torch.Tensor,
    num_segments : int
) -> torch.Tensor:
    return UnsortedSegmentSum.apply(data, indices, num_segments)

def unit_test_cpu():
    print('==== Correctness Test CPU ====')
    data = torch.randn(1000, 3, requires_grad=False)
    indices = torch.randint(0, 100, (1000,), requires_grad=False)
    num_segments = 100

    d1 = data.clone().requires_grad_()
    d2 = data.clone().requires_grad_()

    ref = unsorted_segment_sum_ref(d1, indices, num_segments)
    out = UnsortedSegmentSum.apply(d2, indices, num_segments)

    print('(FWD) L2 = ', (ref - out).pow(2).sum().sqrt())

    ref.pow(2).sum().backward()
    out.pow(2).sum().backward()

    print('(BWD) L2 = ', (d1.grad - d2.grad).pow(2).sum().sqrt())

def unit_test_gpu():
    print('==== Correctness Test GPU ====')
    data = torch.randn(1000, 3, requires_grad=False)
    indices = torch.randint(0, 100, (1000,), requires_grad=False)
    num_segments = 100

    d1 = data.clone().requires_grad_()
    d2 = data.clone().cuda().requires_grad_()

    ref = unsorted_segment_sum_ref(d1, indices, num_segments)
    out = UnsortedSegmentSum.apply(d2, indices.clone().cuda(), num_segments)

    print('(FWD) L2 = ', (ref - out.cpu()).pow(2).sum().sqrt())

    ref.pow(2).sum().backward()
    out.pow(2).sum().backward()

    print('(BWD) L2 = ', (d1.grad - d2.grad.cpu()).pow(2).sum().sqrt())

if __name__ == '__main__':
    unit_test_cpu()
    unit_test_gpu()

    exit(0)

    # Benchmark

    t0 = time.perf_counter()
    for _ in range(1000):
        _ = unsorted_segment_sum_ref(data, indices, num_segments)
    t1 = time.perf_counter()
    print(f'Reference (Fwd): {(t1 - t0) * 1000:.2f} ms')

    t0 = time.perf_counter()
    for _ in range(1000):
        _ = UnsortedSegmentSum.apply(data, indices, num_segments)
    t1 = time.perf_counter()
    print(f'Extension (Fwd): {(t1 - t0) * 1000:.2f} ms')

    t0 = time.perf_counter()
    for _ in range(1000):
        out = unsorted_segment_sum_ref(d1, indices, num_segments)
        out.pow(2).sum().backward()
    t1 = time.perf_counter()
    print(f'Reference (Fwd + Bwd): {(t1 - t0) * 1000:.2f} ms')

    t0 = time.perf_counter()
    for _ in range(1000):
        out = UnsortedSegmentSum.apply(d2, indices, num_segments)
        out.pow(2).sum().backward()
    t1 = time.perf_counter()
    print(f'Extension (Fwd + Bwd): {(t1 - t0) * 1000:.2f} ms')