import os
from datetime import datetime, timedelta
from enum import Enum

from pony.orm import *

"""
ENUM
"""

class Etat(Enum):
    TODO = 1
    CORBEILLE = 2
    INCUBATEUR = 3
    CLASSER = 4
    TERMINE = 5
    DELEGUER = 6

"""
BASE DE DONNEE
"""

database = Database()

class Idee(database.Entity):
    texte = Required(str)
    etat = Required(int)
    dateCreation = Required(datetime)
    commentaire = Optional(str)
    delegue = Optional("PersonneDelegue")
    etapes = Set("Etape")

class PersonneDelegue(database.Entity):
    nom = Required(str)
    idee = Set(Idee)

class Etape(database.Entity):
    order = Required(int)
    texte = Required(str)
    dateExecution = Optional(datetime)
    idee = Required(Idee)
    fait = Required(bool)

"""
    Méthode d'administration de la base
"""

def __get_database_file(chemmin_option: str):
    """
    Retourne la base de donnée
    :param chemmin_option: le chemin ou se trouve la base de donnée
    :return: le chemin complet de la BDD
    """
    return chemmin_option + ("\\" if os.name == 'nt' else "/") + "gtd.sqlite"

def open_db(chemin_option: str):
    """
    ouvre la base de donnée
    :param chemin_option: le chemin ou se trouve la base
    :return:
    """
    chemin = __get_database_file(chemin_option)
    database.bind("sqlite", chemin, create_db=True)
    database.generate_mapping(create_tables=True)
    sql_debug(False)

"""
    Méthodes de gestion des données
"""

@db_session
def ajouter_idee(idee: str):
    """
    Ajoute une nouvelle idée en base de donnée
    :param idee: le texte de l'idée à ajouter
    :return:
    """
    Idee(
        texte=idee,
        etat=Etat.TODO.value,
        dateCreation=datetime.today(),
    )

@db_session
def get_idee_by_id(id_idee: int):
    """
    Récupère une idée avec le nom de son delegue éventule
    :param id_idee: l'id de l'idée recherchée
    :return: l'idée
    """
    idee = Idee[id_idee]
    if idee.delegue:
        idee.delegue.nom
    return idee

@db_session
def delete_idee_perime(nb_jours_en_moins: int, etat: Etat):
    """
    Efface les idées périmées depuis plus de
    :param nb_jours_en_moins: le nombre de jour à partir d'aujourd'hui ou la donnée est périmée
    :param etat: l'état dans lequel l'idée doit être pour être supprimée
    :return:
    """
    day = datetime.today() - timedelta(days=nb_jours_en_moins)
    delete(i for i in Idee if i.dateCreation <= day and i.etat == etat.value)

@db_session
def get_all_idee_by_etat(etat: Etat):
    """
     Récpère toute les idées à partir de leurs état
    :param etat: l'état dont on recherche les idées
    :return: une liste d'idée
    """
    result = select(i for i in Idee if i.etat is etat.value)
    retour = []
    for r in result:
        retour.append(r)
    return retour

@db_session
def count_all_idee_by_etat(etat_cherche: Etat):
    """
    Compte les idées par état
    :param etat_cherche: l'état dont on cherche les idées
    :return: le nombre de résultats
    """
    return count(i for i in Idee if i.etat is etat_cherche.value)

@db_session
def count_idee_todo_todefine():
    """
    Compte le nombre d'idées en cours mais dont les étapes sont à définir
    :return: le résultat
    """
    return count(i for i in Idee if i.etat == Etat.TODO.value and len(i.etapes) == 0)

@db_session
def count_idee_todo_en_cours():
    """
    Compte le nombre d'idées en cours mais dont les étapes sont définis
    :return: le résultat
    """
    return count(i for i in Idee if i.etat == Etat.TODO.value and len(i.etapes) > 0)

@db_session
def check_idee_a_definir(id_idee: int):
    """
    Vérifie si une idée possède des étapes ou non
    :param id_idee: l'id de l'idée en question
    :return:
    """
    idee = Idee[id_idee]
    return idee.etapes.count() > 0 and idee.etat != Etat.DELEGUER.value

@db_session
def changer_etat_idee(id_idee: int, etat: Etat):
    """
    change l'état d'une idée
    :param id_idee: l'id de l'idée à changer
    :param etat: le nouvel état
    :return:
    """
    idee = Idee[id_idee]
    if idee.etat == Etat.DELEGUER.value and etat.value != Etat.DELEGUER.value:
        idee.delegue = None
    idee.etat = etat.value

@db_session
def modifier_idee_db(id_idee: int, idee: str, delegue: str, commentaire: str, etat: Etat):
    """
    Modifie une idée en base
    :param id_idee: l'id de l'idée
    :param idee: le texte de l'idée
    :param delegue: le nom de la personne à qui l'idée peut être délégué
    :param commentaire: le commetnaire
    :param etat: le nouvel état
    :return:
    """
    idee_obj = Idee[id_idee]
    idee_obj.texte = idee
    idee_obj.commentaire = commentaire
    idee_obj.etat = etat.value

    if delegue:
        delegue_idee(id_idee, delegue)
    else:
        idee_obj.delegue = None

@db_session
def __get_or_create_personne_delegue(nom: str):
    """
    Delegue une idée à quelqu'un (recherche en base si le nom existe déjà avant)
    :param nom: le nom de la personne à délégué
    :return: la personne trouvée ou crée
    """
    if PersonneDelegue.exists(lambda p: p.nom == nom):
        return PersonneDelegue.get(nom=nom)
    else:
        PersonneDelegue(
            nom=nom
        )
        return PersonneDelegue.get(nom=nom)

@db_session
def delegue_idee(id_idee: int, nom_delegue: str):
    """
    Délègue une idée
    :param id_idee: l'id de l'idée à déléguer
    :param nom_delegue: le nom de personne à qui on délègue
    :return:
    """
    personne = __get_or_create_personne_delegue(nom_delegue)
    Idee[id_idee].delegue = personne.id
    Idee[id_idee].etat = Etat.DELEGUER.value

@db_session
def recherche_delegue(nom: str):
    """
    recherche le nom d'une personne
    :param nom: le nom
    :return: la liste des noms trouvés
    """
    data = select(p.nom for p in PersonneDelegue if nom.upper() in p.nom.upper())
    retour = []
    for r in data:
        retour.append(r)
    return retour

@db_session
def get_etapes_idee(id_dee: int):
    """
    Retourne les étapes d'une idée
    :param id_dee: l'id de l'idée
    :return: la liste des étapes
    """
    data = Idee[id_dee].etapes

    retour = []
    for e in data:
        retour.append(e)
    retour.sort(key=lambda x: x.order)
    return retour

@db_session
def ajouter_modifier_etape(idee: Idee, ordre: int, texte: str, fait: bool, date: datetime = None, id_etape: int = None):
    """
    ajoute ou modifie une étape à une idée
    :param idee: l'idée concernée
    :param ordre: l'odre de l'étape
    :param texte: le texte de l'étape
    :param fait: l'état de l'étape
    :param date: la date d'éxécution éventuelle
    :param id_etape: l'id de l'étape si modification
    :return:
    """
    if id_etape:
        etape = Etape[id_etape]
        etape.dateExecution = date
        etape.texte = texte
        etape.order = ordre
        etape.fait = fait
    else:
        Etape(
            texte=texte,
            fait=fait,
            dateExecution=date,
            order=ordre,
            idee=Idee[idee.id],
        )
    __check_ordre_etape_idee(idee.id)

@db_session
def inverser_etat_etape(etape_id: int):
    """
    Change l'état d'une étape
    :param etape_id: l'id de l'étape
    :return:
    """
    etape = Etape[etape_id]
    etape.fait = not etape.fait

@db_session
def __check_ordre_etape_idee(id_idee: int):
    """
    vérifié l'ordre des étapes d'une idée
    :param id_idee: l'id de l'idée
    :return:
    """
    etapes = Idee[id_idee].etapes
    tmp = []
    for e in etapes:
        tmp.append(e)
    tmp.sort(key=lambda x: x.order)
    numero_attendu = 1
    for etape in tmp:
        if etape.order != numero_attendu:
            etape.order = numero_attendu
        numero_attendu = numero_attendu + 1

@db_session
def get_idee_delegue():
    """
    retourne les idées délégués
    :return:
    """
    retour = []
    data = select(i for i in Idee if i.etat == Etat.DELEGUER.value)
    for e in data:
        if e.delegue:
            e.delegue.nom
        retour.append(e)
    return retour

@db_session
def get_etapes_todo():
    """
    retourne les prochaines étapes de chaque idée à faire (si elles n'ont pas de date d'éxécution)
    :return: la liste des étapes
    """
    retour = []
    liste = select(i for i in Idee if i.etat == Etat.TODO.value and len(i.etapes) > 0) \
        .order_by(lambda x: x.dateCreation)
    for idee in liste:
        etape = select(e for e in Etape if e.dateExecution is None and not e.fait and e.idee.id == idee.id
                       and e.order == min(ee.order for ee in Etape if ee.idee.id == idee.id
                                          and not ee.fait)).first()
        if etape:
            retour.append(etape)
    return retour

@db_session
def get_etapes_planifie():
    """
    retourne les prochaines étapes de chaque idée à faire (si elles ont de date d'éxécution)
    :return: la liste des étapes
    """
    retour = []
    liste = select(i for i in Idee if i.etat == Etat.TODO.value and len(i.etapes) > 0) \
        .order_by(lambda x: x.dateCreation)
    for idee in liste:
        etape = select(e for e in Etape if e.dateExecution is not None and not e.fait and e.idee.id == idee.id
                       and e.order == min(ee.order for ee in Etape if ee.idee.id == idee.id
                                          and not ee.fait)).first()
        if etape:
            retour.append(etape)
    return retour

@db_session
def verif_fin_etapes_marque_idee_termine(etape: Etape):
    """
    verifie si toute les étapes d'une idées sont éeffectuées. Si c'est le cas l'idée est marquée comme terminée
    :param etape: l'étape à vérifier
    :return:
    """
    nb_etape_non_fait = count(e for e in Etape if not e.fait and e.idee.id == etape.idee.id)
    if nb_etape_non_fait == 0:
        changer_etat_idee(etape.idee.id, Etat.TERMINE)

@db_session
def supprimer_etape_db(etape: Etape):
    """
    Efface une étape de la base de donnée
    :param etape: l'étape à effacer
    :return:
    """
    id_idee = Etape[etape.id].idee.id
    Etape[etape.id].delete()
    __check_ordre_etape_idee(id_idee)

@db_session
def inverser_ordre_etape_db(etape_a: Etape, etape_b: Etape):
    """
       Inverse l'ordre de deux étapes
       :param etape_a: une étape
       :param etape_b: l'autre étape
       :return:
       """
    Etape[etape_a.id].order = etape_b.order
    Etape[etape_b.id].order = etape_a.order


"""Plot the dynamic functional connctivity for a single subject."""
import os
from copy import copy

import matplotlib.pyplot as plt

import numpy as np
import pandas as pd

from brainpipe.system import Study
from brainpipe.connectivity import (remove_site_contact, dfc_summarize,
                                    anat_based_reorder)
from mne.stats import fdr_correction, bonferroni_correction

from bct.algorithms.clustering import clustering_coef_wd

st = Study('DMN-CORR')

###############################################################################
suj = 'th'
th = 1.5
session = 2
condition = ('gamma50-150', 'lp1-10_', 'cmi')
rm_succ_site = 'hard'  # 'soft' | None
plt_as = 'mpl'  # {'mpl', 'visbrain'}
savefig = False
###############################################################################

# Path :
print('-> Get path')
dfc_file = st.search(suj, *condition, folder='dfc')
xyz_file = st.search(suj, 'bipo', folder='xyz')
chan_file = st.search(suj, 'bipo', folder='channels')
anat_file = st.search(suj, folder='anatomy')
fig_path = st.path_to_folder('figure/corr_gamma')
assert len(dfc_file) == len(xyz_file) == len(chan_file) == len(anat_file) == 1

# Load the file :
print('-> Load files')
xyz = st.load(xyz_file[0], folder='xyz')
channels = st.load(chan_file[0], folder='channels')
arch = st.load(dfc_file[0], folder='dfc')
df = st.load(anat_file[0], folder='anatomy')
dfc = arch['dfc'].mean(-1)  #[..., session]
# pval = arch['pval'][..., session]

dfc_std = dfc_summarize(dfc, axis=2, method='std')
dfc_mean = dfc.mean(-1)
dfc_std = anat_based_reorder(dfc_std, df, 'name_7')[0]
dfc_mean, labels, r_index = anat_based_reorder(dfc_mean, df, 'name_7')
channels = channels[r_index]

mask = remove_site_contact(dfc_std, channels, mode='hard')
mask[np.tril_indices(dfc_std.shape[0])] = True
mask[dfc_mean < th] = True

cluster = clustering_coef_wd(dfc_std)

dfc_std = np.ma.masked_array(dfc_std, mask=mask)
dfc_mean = np.ma.masked_array(dfc_mean, mask=mask)

if plt_as == 'mpl':
    # Colormap build :
    cmap_std = copy(plt.cm.viridis)
    cmap_mean = copy(plt.cm.bwr)
    cmap_std.set_bad('black')
    cmap_mean.set_bad('black')

    plt.subplot(1, 2, 1)
    im = plt.imshow(dfc_std, cmap=cmap_std)
    # im.set_clim(0., 1.)
    plt.colorbar(im)

    plt.subplot(1, 2, 2)
    m = np.abs(dfc_mean).max()
    im = plt.imshow(dfc_mean, cmap=cmap_mean)
    # im.set_clim(-m, m)
    plt.colorbar(im)

    plt.show()
elif plt_as == 'visbrain':
    from visbrain.gui import Brain
    from visbrain.objects import SourceObj, ConnectObj, BrainObj

    b_obj = BrainObj('B3')
    s_obj = SourceObj('s', xyz[r_index, :], data=cluster, radius_min=1,
                      radius_max=30, text=channels, text_size=1., edge_width=0.)
    s_obj.color_sources(data=cluster, cmap='bwr')
    c_obj = ConnectObj('c', xyz[r_index, :], dfc_mean, antialias=True)
    Brain(source_obj=s_obj, connect_obj=c_obj, brain_obj=b_obj).show()


# -*- coding: UTF-8 -*-
import logging
from openpyxl import Workbook

_LOGGER = logging.getLogger('armory')

class ArmoryExcel(object):
    '''
    armory excel lib, use this lib to read and write excle
    '''
    @staticmethod
    def wirte_excel(file_path, title, sheet_value):
        '''
        write excel
        parameter: two dimension array
        result: a excel file with the data in two
        '''
        workbook = Workbook()
        sheet = workbook.active
        sheet.title = title
        for row_num, row_value in enumerate(sheet_value):
            for column_num, column_value in enumerate(row_value):
                sheet.cell(row=row_num + 1, column=column_num + 1).value = column_value
        workbook.save(file_path)

if __name__ == '__main__':
    content = [[1, 2, 3], [4, 5, 6]]
    ArmoryExcel.write_excel('./a.xlsx', 'test', content)


from django.forms import formset_factory
from django.utils import timezone

from .forms import CreatePowerForm, make_enhancement_form, make_drawback_form, make_parameter_form, \
    EditPowerAdditionalForm
from .models import Enhancement_Instance, Drawback_Instance, Power, DICE_SYSTEM, Enhancement, Drawback, \
    Power_Param, \
    Parameter_Value, Base_Power_System, Power_Full, CREATION_REASON

def get_create_power_context_from_base(base_power):
    system = Base_Power_System.objects.filter(dice_system=DICE_SYSTEM[1][0]).get(base_power=base_power)
    primary_form = CreatePowerForm(base_power, initial={'system': system.system_text})
    enhancement_forms = []
    for enhancement in Enhancement.objects.filter(pk__in=base_power.enhancements.all()):
        enhancement_forms.append(formset_factory(make_enhancement_form(enhancement), extra = 1)())
    drawback_forms = []
    for drawback in Drawback.objects.filter(pk__in=base_power.drawbacks.all()):
        drawback_forms.append(formset_factory(make_drawback_form(drawback), extra = 1)())
    parameter_forms = []
    for parameter in Power_Param.objects.filter(relevant_base_power=base_power).all():
        parameter_forms.append(formset_factory(make_parameter_form(parameter))())
    system = Base_Power_System.objects.filter(dice_system=DICE_SYSTEM[1][0]).get(base_power=base_power.slug)
    context = {
        'base_power': base_power,
        'power_system': system,
        'form': primary_form,
        'parameters': parameter_forms,
        'enhancements': enhancement_forms,
        'drawbacks': drawback_forms,
    }
    return context

def get_create_power_context_from_power(power):
    primary_form = CreatePowerForm(power.base,
                                   initial={'system': power.system,
                                            'description': power.description,
                                            'flavor': power.flavor_text,
                                            'activation_style': power.activation_style,
                                            'power_name': power.name})
    enhancement_forms = get_enhancement_formsets_from_power(power)
    drawback_forms = get_drawback_formsets_from_power(power)
    parameter_forms = []
    for parameter_value in Parameter_Value.objects.filter(relevant_power=power).all():
        init= [{'level_picker': parameter_value.value}]
        parameter_forms.append(formset_factory(make_parameter_form(parameter_value.relevant_power_param), extra = 0)(initial = init))
    system = Base_Power_System.objects.filter(dice_system=DICE_SYSTEM[1][0]).get(base_power=power.base.slug)
    context = {
        'base_power': power.base,
        'power_system': system,
        'form': primary_form,
        'parameters': parameter_forms,
        'enhancements': enhancement_forms,
        'drawbacks': drawback_forms,
    }
    return context

def get_edit_power_context_from_power(og_power, power_full):
    context = get_create_power_context_from_power(og_power)
    context["og_power"] = og_power
    context["edit_form"] = EditPowerAdditionalForm()
    return context

def get_enhancement_formsets_from_power(power):
    enhancement_forms = []
    enhancement_instances = Enhancement_Instance.objects.filter(relevant_power=power).all()
    for base_enhancement in Enhancement.objects.filter(pk__in=power.base.enhancements.all()):
        instances_of_this_enhancement = set(
            x for x in enhancement_instances if (x.relevant_enhancement == base_enhancement))
        init = []
        num_extra = 0
        for enhancement_instance in instances_of_this_enhancement:
            init.append({
                'is_selected': True,
                'detail_text': enhancement_instance.detail,
            })
        if base_enhancement.multiplicity_allowed or not instances_of_this_enhancement:
            num_extra = 1
        new_form = formset_factory(make_enhancement_form(base_enhancement), extra=num_extra, max_num=4)(initial=init)
        enhancement_forms.append(new_form)
    return enhancement_forms

def get_drawback_formsets_from_power(power):
    drawback_forms = []
    drawback_instances = Drawback_Instance.objects.filter(relevant_power=power).all()
    for base_drawback in Drawback.objects.filter(pk__in=power.base.drawbacks.all()):
        instances_of_this_drawback = set(
            x for x in drawback_instances if (x.relevant_drawback == base_drawback))
        init = []
        num_extra = 0
        for drawback_instance in instances_of_this_drawback:
            init.append({
                'is_selected': True,
                'detail_text': drawback_instance.detail,
            })
        if base_drawback.multiplicity_allowed or not instances_of_this_drawback:
            num_extra = 1
        new_form = formset_factory(make_drawback_form(base_drawback), extra=num_extra, max_num=4)(initial=init)
        drawback_forms.append(new_form)
    return drawback_forms

def get_enhancement_instances(post_data, enhancements, new_power):
    instances = []
    for enhancement in enhancements:
        if enhancement.slug + "-e-is_selected" in post_data:
            detail_texts = []
            if enhancement.slug + "-e-detail_text" in post_data:
                detail_texts = post_data.getlist(enhancement.slug + "-e-detail_text")
            for on in post_data.getlist(enhancement.slug + "-e-is_selected"):
                if detail_texts:
                    new_detail_text = detail_texts.pop(0)
                else:
                    new_detail_text = ""
                instances.append(Enhancement_Instance(relevant_enhancement=enhancement,
                                     relevant_power=new_power,
                                     detail=new_detail_text))
    return instances

def get_drawback_instances(post_data, drawbacks, new_power):
    instances = []
    for drawback in drawbacks:
        if drawback.slug + "-d-is_selected" in post_data:
            detail_texts = []
            if drawback.slug + "-d-detail_text" in post_data:
                detail_texts = post_data.getlist(drawback.slug + "-d-detail_text")
            for on in post_data.getlist(drawback.slug + "-d-is_selected"):
                if detail_texts:
                    new_detail_text = detail_texts.pop(0)
                else:
                    new_detail_text = ""
                instances.append(Drawback_Instance(relevant_drawback=drawback,
                                     relevant_power=new_power,
                                     detail=new_detail_text))
    return instances

def create_new_full_power(power_form, base):
    return Power_Full(name=power_form.cleaned_data['power_name'],
                  dice_system=DICE_SYSTEM[1][0],
                  base=base,
                  pub_date=timezone.now())

def get_power_from_form(power_form, base):
    return Power(name=power_form.cleaned_data['power_name'],
                  flavor_text=power_form.cleaned_data['flavor'],
                  description=power_form.cleaned_data['description'],
                  system=power_form.cleaned_data['system'],
                  activation_style=power_form.cleaned_data['activation_style'],
                  base=base,
                  dice_system=DICE_SYSTEM[1][0],
                  pub_date=timezone.now())

def create_power_for_new_edit(base_power, request, power_full):
    power_form = CreatePowerForm(base_power, request.POST)
    additional_form = EditPowerAdditionalForm(request.POST)
    if power_form.is_valid() and additional_form.is_valid():
        return create_power_from_post_and_base(base_power, request, power_full)

def create_new_power_and_parent(base_power, request):
    form = CreatePowerForm(base_power, request.POST)
    if form.is_valid():
        power_full = create_new_full_power(power_form=form, base=base_power)
        if request.user.id:
            power_full.owner = request.user
        power_full.save()
        return create_power_from_post_and_base(base_power, request, power_full)
    else:
        print(form.errors)
        return None

def create_power_from_post_and_base(base_power, request, power_full):
    form = CreatePowerForm(base_power, request.POST)
    if form.is_valid():
        power = get_power_from_form(power_form=form, base=base_power)
        additional_form = EditPowerAdditionalForm(request.POST)
        if additional_form.is_valid():
            power.creation_reason = additional_form.cleaned_data['edit_reason']
            power.creation_reason_expanded_text = additional_form.cleaned_data['edit_explanation']
        else:
            power.creation_reason  = CREATION_REASON[0][0]
        if request.user.id:
            power.created_by = request.user
        power.parent_power = power_full
        power.save()
        enhancement_instances = get_enhancement_instances(post_data=request.POST,
                                                          enhancements=Enhancement.objects.filter(
                                                              pk__in=base_power.enhancements.all()),
                                                          new_power=power)
        for enhancement_instance in enhancement_instances:
            enhancement_instance.save()
        drawback_instances = get_drawback_instances(post_data=request.POST,
                                                    drawbacks=Drawback.objects.filter(
                                                        pk__in=base_power.drawbacks.all()),
                                                    new_power=power)
        for drawback_instance in drawback_instances:
            drawback_instance.save()
        power.save()
        for power_param in Power_Param.objects.filter(relevant_base_power=base_power):
            param_val = Parameter_Value(relevant_power=power,
                                        relevant_power_param=power_param,
                                        value=request.POST[power_param.relevant_parameter.slug])
            param_val.save()
        return power
    else:
        print(form.errors)
        return None


import sqlite3

with sqlite3.connect("cars.db") as connection:
	c = connection.cursor()

	#Insert 5 records, 3 Ford, 2 Honda. Structure is make, model, quantity in collection inventory

	cars = [
			('Ford', 'Tarus', 1),
			('Ford', 'Explorer', 3),
			('Ford', 'Tarus', 2),
			('Honda', 'Civic', 1),
			('Honda', 'CRV', 2)
			]

	c.executemany('INSERT INTO inventory VALUES(?, ?, ?)', cars)


# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from api_v2.action.views import ActionViewSet
from api_v2.config.views import ConfigLogViewSet
from api_v2.hostprovider.views import HostProviderViewSet
from api_v2.upgrade.views import UpgradeViewSet
from rest_framework.routers import SimpleRouter
from rest_framework_nested.routers import NestedSimpleRouter

router = SimpleRouter()
router.register("", HostProviderViewSet)

hostprovider_action_router = NestedSimpleRouter(parent_router=router, parent_prefix="", lookup="hostprovider")
hostprovider_action_router.register(prefix="actions", viewset=ActionViewSet, basename="provider-action")

hostprovider_config_router = NestedSimpleRouter(parent_router=router, parent_prefix="", lookup="hostprovider")
hostprovider_config_router.register(prefix="configs", viewset=ConfigLogViewSet, basename="provider-config")

hostprovider_upgrade_router = NestedSimpleRouter(parent_router=router, parent_prefix="", lookup="hostprovider")
hostprovider_upgrade_router.register(prefix="upgrades", viewset=UpgradeViewSet)

urlpatterns = [
    *router.urls,
    *hostprovider_action_router.urls,
    *hostprovider_config_router.urls,
    *hostprovider_upgrade_router.urls,
]


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

def populate_subject_body(apps, schema_editor):
    """
    """

    Message = apps.get_model('mailer', 'Message')

    q = models.Q(subject__isnull=True) | models.Q(body__isnull=True)
    msgs = Message.objects.filter(q)

    # Resetting the pickled EmailObject resets subject and body
    for msg in msgs:
        msg.email = msg.email
        msg.save()

class Migration(migrations.Migration):

    dependencies = [
        ('mailer', '0002_auto_20141118_0316'),
    ]

    operations = [
        migrations.RunPython(populate_subject_body)
    ]


# Premier Projet d'Informatique

import pygame, math, random

# CONSTANTES

BLANC = (255, 255, 255)
NOIR = (0, 0, 0)
GRIS = (96, 96, 96)
ROUGE = (255, 0, 0)
VERT = (0, 255, 0)
VERT_FONCE = (0, 155, 0)
BLEU = (0, 0, 255)
JAUNE = (255, 255, 0)
BLEU_CIEL = (119, 181, 254)
HERBE = (34, 120, 15)
MAUVE = (153, 0, 153)

DROITE = pygame.K_RIGHT
GAUCHE = pygame.K_LEFT
HAUT = pygame.K_UP
BAS = pygame.K_DOWN
D = pygame.K_d
Q = pygame.K_q
Z = pygame.K_z
S = pygame.K_s
MENU_DROITE = pygame.K_RIGHT
MENU_GAUCHE = pygame.K_LEFT
MENU_HAUT = pygame.K_UP
MENU_BAS = pygame.K_DOWN
ENTREE = pygame.K_RETURN
P = pygame.K_p
ESPACE = pygame.K_SPACE

PI = math.pi

# PARAMETRES

# Fenetre
FENETRE_LARGEUR = 1280
FENETRE_HAUTEUR = 720
IMAGES_PAR_SECONDE = 60

# Jeu
VIE_MAX = 10
TAILLE = 15
MANIABILITE = 25
VITESSE_MAX = 8
VITESSE_MIN = VITESSE_MAX//2
PUISSANCE = 20
RESISTANCE = 20
DELAI_TIR = 15
BALLE_VITESSE = 15
BALLE_LONGUEUR = 20
BALLE_EPAISSEUR = 3
MANCHE_MIN = 3
COLLISION = False
POWER = True
GRAVITE = 6

# FONCTIONS

def gerer_entree():
    for evenement in pygame.event.get():
        if evenement.type == pygame.QUIT:
            global Fini, Jeu
            Fini = True

        if(Jeu == False and evenement.type == pygame.KEYDOWN and evenement.key == ENTREE):
            Jeu = True

        else:
            if evenement.type == pygame.KEYDOWN:
                if evenement.key == P or evenement.key == ESPACE:
                    global Pause, Pause_delai
                    Pause_delai = 100
                    if Pause:
                        Pause = False
                    else:
                        Pause = True
            if Pause:
                if evenement.type == pygame.KEYDOWN:
                    global select
                    if evenement.key == HAUT or evenement.key == Z:
                        select[0] -= 1
                    elif evenement.key == BAS or evenement.key == S:
                        select[0] += 1
                    elif evenement.key == ENTREE:
                        if select[0] == 0:
                            Pause = False
                        if select[0] == 1:
                            Pause = False
                            reinitialiser(True)
                            for avion in avions:
                                avion['score'] = 0
                                avion['ajoute_vitesse'] = 0
                                avion['ajoute_inclinaison'] = 0
                        if select[0] == 2:
                            Pause = False
                            reinitialiser(True)
                            Jeu = False

            else:
                if evenement.type == pygame.KEYDOWN:

                    if evenement.key == DROITE:
                        avions[0]['ajoute_inclinaison'] += PI * (MANIABILITE/1000)
                    if evenement.key == GAUCHE:
                        avions[0]['ajoute_inclinaison'] -= PI * (MANIABILITE/1000)
                    if evenement.key == HAUT:
                        avions[0]['ajoute_vitesse'] += PUISSANCE/1000
                    if evenement.key == BAS:
                        avions[0]['ajoute_vitesse'] -= PUISSANCE/1000

                    if evenement.key == D:
                        avions[1]['ajoute_inclinaison'] += PI * (MANIABILITE/1000)
                    if evenement.key == Q:
                        avions[1]['ajoute_inclinaison'] -= PI * (MANIABILITE/1000)
                    if evenement.key == Z:
                        avions[1]['ajoute_vitesse'] += PUISSANCE/1000
                    if evenement.key == S:
                        avions[1]['ajoute_vitesse'] -= PUISSANCE/1000

                if evenement.type == pygame.KEYUP:

                    if evenement.key == DROITE:
                        avions[0]['ajoute_inclinaison'] -= PI * (MANIABILITE/1000)
                    if evenement.key == GAUCHE:
                        avions[0]['ajoute_inclinaison'] += PI * (MANIABILITE/1000)
                    if evenement.key == HAUT:
                        avions[0]['ajoute_vitesse'] -= PUISSANCE/1000
                    if evenement.key == BAS:
                        avions[0]['ajoute_vitesse'] += PUISSANCE/1000

                    if evenement.key == D:
                        avions[1]['ajoute_inclinaison'] -= PI * (MANIABILITE/1000)
                    if evenement.key == Q:
                        avions[1]['ajoute_inclinaison'] += PI * (MANIABILITE/1000)
                    if evenement.key == Z:
                        avions[1]['ajoute_vitesse'] -= PUISSANCE/1000
                    if evenement.key == S:
                        avions[1]['ajoute_vitesse'] += PUISSANCE/1000

def gerer_entree_menu():
    for evenement in pygame.event.get():
        global select, Fini, Jeu, Option
        if evenement.type == pygame.QUIT:
            Fini = True
        elif evenement.type == pygame.KEYDOWN:
            if evenement.key == pygame.K_BACKSPACE:
                if (select[1]+select[0]*12) < len(options) and options[select[1]] < 100 :
                    if select[1]+select[0]*12 == 10:
                        options[10] = False
                    elif select[1]+select[0]*12 == 11:
                        options[11] = False
                    else:
                        options[select[1]+select[0]*12] -= 1
            elif evenement.key == ENTREE:
                if(Option):
                    if select[1] == 12:
                        Option = False
                        mettre_a_jour_options()
                        reinitialiser(True)
                    elif (select[1]+select[0]*12) < len(options) and options[select[1]] < 100:
                        if select[1]+select[0]*12 == 10:
                            options[10] = True
                        elif select[1]+select[0]*12 == 11:
                            options[11] = True
                        else:
                            options[select[1]+select[0]*12] += 1

                elif select[1] == 0:
                    global manche
                    Jeu = True
                    for avion in avions:
                        avion['score'] = 0
                        avion['ajoute_vitesse'] = 0
                        avion['ajoute_inclinaison'] = 0
                        manche = 0
                elif select[1] == 1:
                    Option = True
                    select = [0, 0]
                elif select[1] == 2:
                    Fini = True

            if evenement.key == MENU_BAS:
                select[1] += 1
            elif evenement.key == MENU_HAUT:
                select[1] -= 1
            elif evenement.key == MENU_GAUCHE:
                select[0] -= 1
            elif evenement.key == MENU_DROITE:
                select[0] += 1

def menu_pause():
    global Pause, Pause_delai
    if Pause:
        select[0] %= 3
        largeur = 400
        hauteur = 600
        pygame.draw.rect(fenetre, BLANC, (5, 5, 10, 25))
        pygame.draw.rect(fenetre, BLANC, (20, 5, 10, 25))
        pygame.draw.rect(fenetre, GRIS, (dimensions_fenetre[0]/2 - largeur/2, dimensions_fenetre[1]/2 - hauteur/2, largeur, hauteur))
        police  = pygame.font.Font("police/crochet.otf", 100)
        affiche_message("PAUSE", police, (dimensions_fenetre[0]/2, dimensions_fenetre[1]/2 - 4*hauteur/4 + 380), BLANC)
        police  = pygame.font.Font("police/crochet.otf", 60)

        couleurs = [BLANC, BLANC, BLANC]
        i = 0
        for i in range(3):
            if select[0] == i:
                couleurs[i] = JAUNE
            else:
                couleurs[i] = BLANC

        affiche_message("Continuer", police, (dimensions_fenetre[0]/2, dimensions_fenetre[1]/2 - 3*hauteur/4 + 380), couleurs[0])
        affiche_message("Recommencer", police, (dimensions_fenetre[0]/2, dimensions_fenetre[1]/2 - 2*hauteur/4 + 380), couleurs[1])
        affiche_message("Quitter", police, (dimensions_fenetre[0]/2, dimensions_fenetre[1]/2 - 1*hauteur/4 + 380), couleurs[2])
    elif Pause_delai > 0:
        Pause_delai -= 1
        pygame.draw.polygon (fenetre, BLANC, [(5, 5), (5,30), (30, 17.5)])

def affiche_menu():
    global select, Option
    fenetre.fill(BLEU_CIEL)
    temps = pygame.time.get_ticks()
    if Option:
        select[1] %= 13
        select[0] %= len(options)//12 + 1

        if select[1] == 12:
            dessiner_fleche((FENETRE_LARGEUR//2 - 160, 19*FENETRE_HAUTEUR//20) ,NOIR, 80, 16, 16, 2)
            dessiner_fleche((FENETRE_LARGEUR//2 - 160, 19*FENETRE_HAUTEUR//20) ,VERT, 80, 16, 16)

        else:
            dessiner_fleche((430 + select[0]*FENETRE_LARGEUR//3,  6*FENETRE_HAUTEUR//20 + select[1]*(1*FENETRE_HAUTEUR//20)),NOIR, 80, 16, 16, 2)
            dessiner_fleche((430 + select[0]*FENETRE_LARGEUR//3,   6*FENETRE_HAUTEUR//20 + select[1]*(1*FENETRE_HAUTEUR//20)),VERT, 80, 16, 16)

        police  = pygame.font.Font("police/crochet.otf", 100)
        affiche_message_centre("Options", police, (FENETRE_LARGEUR//2, FENETRE_HAUTEUR//8), 26, 10, NOIR, BLEU)
        police  = pygame.font.Font("police/crochet.otf", 24)

        for i in range(0, len(options)):
            if i > 11:
                j = i%11
                affiche_message(options_noms[i].format(options[i]), police, (FENETRE_LARGEUR//2 + (i//12)*FENETRE_LARGEUR//3, (j+5)*FENETRE_HAUTEUR//20), NOIR)
            else:
                affiche_message(options_noms[i].format(options[i]), police, (FENETRE_LARGEUR//2, (i+6)*FENETRE_HAUTEUR//20), NOIR)

        police  = pygame.font.Font("police/crochet.otf", 36)
        affiche_message_centre("Quitter", police, (FENETRE_LARGEUR//2, 19*FENETRE_HAUTEUR//20), 16, 4, NOIR, ROUGE)

    else:
        delai = 1000
        select[1] %= 3
        police  = pygame.font.Font("police/crochet.otf", 200)
        if( temps%delai <  delai/2 ):
            affiche_message_centre(" AIRPLANES ", police, (FENETRE_LARGEUR//2, FENETRE_HAUTEUR//5), 26, 10, ROUGE, MAUVE)
        else:
            affiche_message_centre(" AIRPLANES ", police, (FENETRE_LARGEUR//2, FENETRE_HAUTEUR//5), 26, 10, VERT, MAUVE)

        dessiner_fleche((50 + 6*FENETRE_LARGEUR//20, 11*FENETRE_HAUTEUR//20 + select[1]*(3*FENETRE_HAUTEUR//20)),NOIR, 80, 16, 16, 2)
        dessiner_fleche((50 + 6*FENETRE_LARGEUR//20, 11*FENETRE_HAUTEUR//20 + select[1]*(3*FENETRE_HAUTEUR//20)),VERT, 80, 16, 16)

        police  = pygame.font.Font("police/crochet.otf", 64)
        affiche_message_centre(" Jouer ", police, (FENETRE_LARGEUR//2, 11*FENETRE_HAUTEUR//20), 16, 4, NOIR, VERT_FONCE)
        affiche_message_centre(" Options ", police, (FENETRE_LARGEUR//2, 14*FENETRE_HAUTEUR//20), 16, 4, NOIR, BLEU)
        affiche_message_centre(" Quitter ", police, (FENETRE_LARGEUR//2, 17*FENETRE_HAUTEUR//20), 16, 4, NOIR, ROUGE)

    pygame.display.flip()
    horloge.tick(10)

def mettre_a_jour_options():
    global VIE_MAX, VITESSE_MAX, PUISSANCE, MANIABILITE, RESISTANCE, TAILLE, BALLE_VITESSE, BALLE_LONGUEUR, BALLE_EPAISSEUR, DELAI_TIR, VITESSE_MIN, MANCHE_MIN, COLLISION, POWER
    VIE_MAX = options[0]
    VITESSE_MAX = options[1]
    VITESSE_MIN = VITESSE_MAX/2
    PUISSANCE = options[2]
    MANIABILITE = options[3]
    RESISTANCE = options[4]
    BALLE_VITESSE = options[5]
    BALLE_LONGUEUR = options[6]
    BALLE_EPAISSEUR = options[7]
    DELAI_TIR = options[8]
    MANCHE_MIN = options[9]
    COLLISION = options[10]
    POWER = options[11]

def affiche_message_centre(texte, police, position, marge, epaisseur, couleur1 = NOIR, couleur2 = BLANC, gras = True, contour = True):
    message = police.render(texte, gras, couleur1)
    message_largeur, message_hauteur = police.size(texte)
    if contour:
        pygame.draw.rect(fenetre, couleur1, (position[0] - message_largeur//2 - marge//2, position[1] - message_hauteur//2 - marge//2, message_largeur + marge, message_hauteur + marge))
        marge -= epaisseur
    pygame.draw.rect(fenetre, couleur2, (position[0] - message_largeur//2 - marge//2, position[1] - message_hauteur//2 - marge//2, message_largeur + marge, message_hauteur + marge))
    fenetre.blit(message, (position[0] - message_largeur//2, position[1] - message_hauteur//2))

def affiche_message(texte, police, position, couleur1, gras=True):
    message = police.render(texte, gras, couleur1)
    message_largeur, message_hauteur = police.size(texte)
    fenetre.blit(message, (position[0] - message_largeur/2, position[1]- message_hauteur/2))

def dessiner_fleche(position, couleur, L, l, c, contour=0):
    dessine_triangle((position[0]+L//2, position[1]), couleur, c, contour)
    pygame.draw.rect(fenetre, couleur, (position[0] - L//2 - contour, position[1] - l//2 - contour, L+2*contour, l+2*contour))

def dessine_triangle(position, couleur, c, contour):
    pt1 = (position[0] - contour, position[1] + c + 2*contour)
    pt2 = (position[0] + 2*c + 2*contour, position[1])
    pt3 = (position[0] - contour, position[1] - c - 2*contour)
    pygame.draw.polygon(fenetre, couleur ,(pt1,pt2,pt3))

def maj_positions():
    global temps
    i = 0
    k = 0
    for avion in avions:
        if avion['vie'] <= 0:
            global t, ori, first
            if first[i]:
                crash.play()
                ori[i] = avion['orientation']
                first[i] = False
            t[i] += 1
            avion['tir_delai'] = 1000

            avion['position'][1] += avion['vitesse']*math.sin(ori[i])+GRAVITE*t[i]*t[i]/1000
            avion['position'][0] += avion['vitesse']*math.cos(ori[i])
            if(math.sin(avion['orientation']) < 0.95):

                if (math.cos(ori[i]) >= 0):
                    avion['orientation'] += PI/120
                else:
                    avion['orientation'] -= PI/120

        else:
            avion['vitesse'] += avion['ajoute_vitesse'] / ((VIE_MAX + RESISTANCE) / (avion['vie'] + RESISTANCE))
            avion['orientation'] += avion['ajoute_inclinaison'] / ((VIE_MAX +RESISTANCE) / (avion['vie'] + RESISTANCE))
            if(avion['vitesse'] > VITESSE_MAX):
                avion['vitesse'] = VITESSE_MAX
            elif(avion['vitesse'] < VITESSE_MIN):
                avion['vitesse'] = VITESSE_MIN
            if(avion['vitesse'] < (VITESSE_MIN + VITESSE_MAX)/2):
                avion['position'][1] += ((VITESSE_MIN + VITESSE_MAX)/2 - avion['vitesse'])*GRAVITE
            avion['position'][0] += avion['vitesse']*math.cos(avion['orientation'])
            avion['position'][1] += avion['vitesse']*math.sin(avion['orientation'])

            if sorti_haut(avion['position'], dimensions_avion[1]):
                avion['vitesse'] -= 0.1
            if sorti_gauche(avion['position'], dimensions_avion[0]):
                avion['position'][0] = FENETRE_LARGEUR + dimensions_avion[0]
            if sorti_droite(avion['position'], dimensions_avion[0]):
                avion['position'][0] = -dimensions_avion[0]
        i += 1

        if(avion['position'][1] > (dimensions_fenetre[1] - hauteur_sol(avion['position'][0], temps_maintenant))):
            avion['vie'] = 0
            avions[(k+1)%2]['score'] += 1
            crash.stop()
            boom.play()
            ajoute_explosion(avion['position'], 1)
            affiche_explosion()
            pygame.display.flip()
            pygame.time.wait(1000)
            reinitialiser()
        k += 1

def maj_balles():
    i = 0
    for avion in avions:
        if(avion['tir_delai'] > 0):
            avion['tir_delai'] -= 1
        if(avion['tir_delai'] == 0):
            avion['balles'] += [((avion['position'][0], avion['position'][1]), avion['orientation'])]
            avion['tir_delai'] = DELAI_TIR
            tir.play()
        j = 0
        for balle in avion['balles']:
            avions[i]['balles'][j] = ((balle[0][0] + BALLE_VITESSE*math.cos(balle[1]), (balle[0][1] + BALLE_VITESSE*math.sin(balle[1]))), balle[1])
            if sorti_fenetre(balle[0], dimensions_avion[0]//2):
                del(avions[i]['balles'][j])
            j += 1
        i += 1

def affiche_avions():
    for avion in avions:
        avion['rectangle'], image = rotation_centre(avion['image'], avion['rectangle'], avion['orientation'] + PI/20)
        position = (avion['position'][0] - avion['rectangle'][0]/2, avion['position'][1] - avion['rectangle'][1]/2)
        fenetre.blit(image, (int(position[0]), int(position[1])))

def affiche_balles():
    for avion in avions:
        for balle in avion['balles']:
            l = 1
            while(l < BALLE_LONGUEUR):
                pygame.draw.circle(fenetre, GRIS, (int(balle[0][0] - l*math.cos(balle[1])), int(balle[0][1] - l*math.sin(balle[1]))), BALLE_EPAISSEUR)
                l += 1
            pygame.draw.circle(fenetre, JAUNE, (int(balle[0][0]), int(balle[0][1])), BALLE_EPAISSEUR)
            pygame.draw.circle(fenetre, JAUNE, (int(balle[0][0]), int(balle[0][1])), BALLE_EPAISSEUR)

def affiche_nuage():
    i = 0
    for nuage in nuages:
        nuages[i] = (nuage[0]-1, nuage[1])
        fenetre.blit(IMAGE_NUAGE, (int(nuage[0]), int(nuage[1])))
        if sorti_horizontal(nuage, dimensions_nuage[0]):
            nuages[i] = (dimensions_fenetre[0] + dimensions_nuage[0], nuage[1])
        i += 1

def affiche_vies():
    for avion in avions:
        if(avion['vie'] < 0):
            avion['vie'] = 0
        if(avion['vie_delai'] >= 0):
            pygame.draw.rect(fenetre, NOIR, (avion['position'][0] - 26, avion['position'][1] - 1 - dimensions_avion[0]//1.5, 52, 10))
            pygame.draw.rect(fenetre, ROUGE, (avion['position'][0] - 25, avion['position'][1] - dimensions_avion[0]//1.5, 50, 8))
            pygame.draw.rect(fenetre, VERT, (avion['position'][0] - 25, avion['position'][1] - dimensions_avion[0]//1.5, 50*avion['vie']//VIE_MAX, 8))
            avion['vie_delai'] -= 1

def dessiner_sol1(temps):
    for x in range(dimensions_fenetre[0]):

        y = hauteur_sol(x, temps)
        pygame.draw.line(fenetre, VERT_FONCE, (x, dimensions_fenetre[1] - y), (x, dimensions_fenetre[1]))

def dessiner_sol2(temps):
    for x in range(dimensions_fenetre[0]):
        y = hauteur_sol(x, temps, 120, 100, 30)
        pygame.draw.line(fenetre, HERBE, (x, dimensions_fenetre[1] - y), (x, dimensions_fenetre[1]))

def score():
    global manche, MANCHE_MIN
    police = pygame.font.Font("police/crochet.otf", 42)
    if (manche+1) >= MANCHE_MIN:
        affiche_message("Manche finale", police, (FENETRE_LARGEUR//2, 22), NOIR)
    else:
        affiche_message("Manche {:d}".format(manche+1), police, (FENETRE_LARGEUR//2, 22), NOIR)
    affiche_message(":".format(avions[0]['score'], ), police, (FENETRE_LARGEUR//2, 58), NOIR)
    affiche_message("{:d}".format(avions[0]['score'], ), police, (FENETRE_LARGEUR//2 + 30, 60), ROUGE)
    affiche_message("{:d}".format(avions[1]['score'], ), police, (FENETRE_LARGEUR//2 - 30, 60), VERT)

def collision():
    global COLLISION
    for avion1 in avions:
        j = 0
        for power in power_up_list:
            d3 = distance2(power, avion1['position'])
            if(avion1['vie'] > 0 and d3 < ((dimensions_avion[1]/1.5)**2)):
                global DELAI_POWER_UP
                DELAI_POWER_UP = random.randint(200, 1000)
                del power_up_list[j]
                avion1['vie'] += VIE_MAX//4
                if avion1['vie'] > VIE_MAX:
                    avion1['vie'] = VIE_MAX
                avion1['vie_delai'] = 90
            j += 1
        for avion2 in avions:
            if COLLISION:
                d2 = distance2(avion1['position'], avion2['position'])
                if(avion1['image'] != avion2['image'] and avion1['vie'] > 0 and d2 < ((dimensions_avion[1]/1.5)**2)):
                    boom.play()
                    avion1['vie'] = 0
                    avion2['vie'] = 0
                    avion1['vie_delai'] = 90
                    avion2['vie_delai'] = 90
                    inter = ((avion1['position'][0]+avion2['position'][0])//2, (avion1['position'][1]+avion2['position'][1])//2)
                    ajoute_explosion(inter, 30)
            i = 0
            for balle in avion1['balles']:
                d = distance2(balle[0], (avion2['position'][0], avion2['position'][1]))
                if(avion1['image'] != avion2['image'] and d < ((dimensions_avion[1]/1.5)**2)):
                    del(avion1['balles'][i])
                    degat_avion(avion2)
                i += 1

def ajoute_explosion(position, duree):
    global explosions
    explosions += [((position[0] - dimensions_explo[0]//2, position[1] - dimensions_explo[1]//2), duree)]

def affiche_explosion():
    global explosions
    i = 0
    for explosion in explosions:
        if explosion[1] > 0:
            fenetre.blit(IMAGE_EXPLO, (explosion[0][0], explosion[0][1]))
            explosions[i] = (explosion[0], explosion[1] - 1)
        else:
            del(explosions[i])
        i += 1

def degat_avion(avion):
    avion['vie_delai'] = 90
    avion['vie'] -= 1
    avion['tir_delai'] = 60

def nouvel_avion(image):
    return {
    'image' : image,
    'position' : [],
    'vitesse' : VITESSE_MAX,
    'orientation' : 0,
    'rectangle' : image.get_size(),
    'ajoute_vitesse' : 0,
    'ajoute_inclinaison' : 0,
    'balles' : [],
    'tir_delai' : DELAI_TIR,
    'vie' : VIE_MAX,
    'vie_delai' : 0,
    'score' : 0
    }

def sorti_fenetre(point, marge=0):
    if sorti_vertical(point, marge) or sorti_horizontal(point, marge):
        return True
    else:
        return False

def sorti_vertical(point, marge=0):
    if(sorti_bas(point, marge) or sorti_haut(point, marge)):
        return True
    else:
        return False

def sorti_horizontal(point, marge=0):
    if(sorti_gauche(point, marge) or sorti_droite(point, marge)):
        return True
    else:
        return False

def sorti_droite(point, marge=0):
    if(point[0] > FENETRE_LARGEUR + marge):
        return True
    else:
        return False

def sorti_gauche(point, marge=0):
    if(point[0] < -marge):
        return True
    else:
        return False

def sorti_haut(point, marge=0):
    if(point[1] < -marge):
        return True
    else:
        return False

def sorti_bas(point, marge=0):
    if(point[1] > FENETRE_HAUTEUR + marge):
        return True
    else:
        return False

def rotation_centre(image, rectangle, angle):
    image2 = pygame.transform.rotate(image, -angle*180/PI)
    rectangle2 = image2.get_size()
    return rectangle2, image2

def distance2(pt1, pt2):
    dh = pt1[0] - pt2[0]
    dv = pt1[1] - pt2[1]
    d2 = dh*dh + dv*dv
    return d2

def hauteur_sol(x, temps=0, hauteur = 40, etireX = 50, etireY = 20):
    alpha = (-x - temps)/ etireX
    y = etireY * math.exp(math.cos(alpha)) / math.e + hauteur
    return y

def fait_nuage():
    global nuages
    i = 0
    while (i < 14):
        x = random.randint(-dimensions_nuage[0], dimensions_fenetre[0] + dimensions_nuage[0])
        y = random.randint(0, dimensions_fenetre[1]//2)
        nuages += [(x, y)]
        i += 1

def reinitialiser(new=False):
    global init, manche, Fini, t, first, ori, Jeu, power_up_list
    t = [0, 0]
    ori = [0, 0]
    first = [True, True]
    power_up_list = []

    avions[0]['position'] = [3*FENETRE_LARGEUR/4, FENETRE_HAUTEUR/2]
    avions[0]['orientation'] = PI
    avions[1]['position'] = [FENETRE_LARGEUR/4, FENETRE_HAUTEUR/2]
    avions[1]['orientation'] = 0
    for avion in avions:
        avion['vitesse'] = VITESSE_MAX
        avion['vie'] = VIE_MAX
        avion['vie_delai'] = 0
        avion['balles'] = []
        avion['tir_delai'] = 120
        if new:
            avion['score'] = 0

    if new:
        manche = 0
    else:
        manche += 1
        if(manche >= MANCHE_MIN and abs(avions[0]['score'] - avions[1]['score']) > 0):
            Jeu = False
            manche = 0
            police  = pygame.font.Font("police/crochet.otf", 150)
            if avions[0]['score'] > avions[1]['score']:
                affiche_message("Le joueur 1 a gagné !", police, (dimensions_fenetre[0]/2, dimensions_fenetre[1]/3), ROUGE)
            elif avions[1]['score'] > avions[0]['score']:
                affiche_message("Le joueur 2 a gagné !", police, (dimensions_fenetre[0]/2, dimensions_fenetre[1]/3), VERT_FONCE)
            else:
                affiche_message("Egalité !", police, (dimensions_fenetre[0]/2, dimensions_fenetre[1]/3), NOIR)
            pygame.display.flip()
            pygame.time.wait(2000)
    init = True

def power_up():
    global DELAI_POWER_UP, power_up_list
    if DELAI_POWER_UP > 0:
        DELAI_POWER_UP -= 1
    else:
        DELAI_POWER_UP = 1200
        ajoute_power_up()
    i = 0
    for power in power_up_list:
        power_up_list[i] = (power[0], power[1]+1)
    i += 1

def ajoute_power_up():
    global power_up_list
    pos = (random.randint(50, dimensions_fenetre[0]-50), -50)
    power_up_list += [pos]

def affiche_power_up():
    for power in power_up_list:
        fenetre.blit(IMAGE_CLE, (power[0]-dimensions_cle[0]//2, power[1]-dimensions_cle[1]//2))

# INITIALISATION

pygame.mixer.pre_init(44100, -16, 1, 512)
pygame.mixer.init()
pygame.font.init()
pygame.init()

dimensions_fenetre = (FENETRE_LARGEUR, FENETRE_HAUTEUR)
fenetre = pygame.display.set_mode(dimensions_fenetre)
pygame.display.set_caption("Airplanes")

crash = pygame.mixer.Sound("sons/crash.wav")
boom = pygame.mixer.Sound("sons/explosion.wav")
tir = pygame.mixer.Sound("sons/tir.wav")
tir.set_volume(0.1)
pygame.mixer.music.load("sons/RGT.wav")
pygame.mixer.music.set_volume(0.8)
pygame.mixer.music.play(-1)

IMAGE_AVION_VERT_ORIGINE = pygame.image.load('images/aircraft_green.png').convert_alpha(fenetre)
IMAGE_AVION_ROUGE_ORIGINE = pygame.image.load('images/aircraft_red.png').convert_alpha(fenetre)
dimensions_avion = IMAGE_AVION_VERT_ORIGINE.get_size()
rapport = 100/TAILLE
dimensions_avion = (dimensions_avion[0]/rapport, dimensions_avion[1]/rapport)
IMAGE_AVION_VERT = pygame.transform.scale(IMAGE_AVION_VERT_ORIGINE, (int(dimensions_avion[0]), int(dimensions_avion[1])))
IMAGE_AVION_ROUGE = pygame.transform.scale(IMAGE_AVION_ROUGE_ORIGINE, (int(dimensions_avion[0]), int(dimensions_avion[1])))

IMAGE_NUAGE = pygame.image.load('images/cloud.png').convert_alpha(fenetre)
dimensions_nuage = IMAGE_NUAGE.get_size()
dimensions_nuage = (dimensions_nuage[0]*2, dimensions_nuage[1]*2)
IMAGE_NUAGE = pygame.transform.scale(IMAGE_NUAGE, (dimensions_nuage[0], dimensions_nuage[1]))

IMAGE_EXPLO = pygame.image.load('images/explo.png').convert_alpha(fenetre)
dimensions_explo = IMAGE_EXPLO.get_size()
dimensions_explo = (dimensions_explo[0]/(3*rapport), dimensions_explo[1]/(3*rapport))
IMAGE_EXPLO = pygame.transform.scale(IMAGE_EXPLO, (int(dimensions_explo[0]), int(dimensions_explo[1])))

IMAGE_CLE = pygame.image.load('images/cle.png')
dimensions_cle = IMAGE_CLE.get_size()
dimensions_cle = (dimensions_cle[0]/15, dimensions_cle[1]/15)
IMAGE_CLE = pygame.transform.scale(IMAGE_CLE, (int(dimensions_cle[0]), int(dimensions_cle[1])))

explosions = []
nuages = []
avions = []
avions += [nouvel_avion(IMAGE_AVION_ROUGE)]
avions += [nouvel_avion(IMAGE_AVION_VERT)]

options = [VIE_MAX, VITESSE_MAX, PUISSANCE, MANIABILITE, RESISTANCE, BALLE_VITESSE, BALLE_LONGUEUR, BALLE_EPAISSEUR, DELAI_TIR, MANCHE_MIN, COLLISION, POWER]
options_noms = ["Vie              : {:d}", "Vitesse max      : {:d}", "Puissance        : {:d}", "Maniabilite      : {:d}", "Resistance       : {:d}", "Vitesse balles   : {:d}", "Longueur balles  : {:d}", "Epaisseur balles : {:d}", "Delai entre tirs : {:d}", "Manche           : {:d}","Collision        : {}", "Power up        : {}"]

DELAI_POWER_UP = 500
power_up_list = []
Fini = False
Jeu = False
Option = False
Pause = False
Pause_delai = 0

select = [0, 0]

horloge = pygame.time.Clock()

reinitialiser(True)
fait_nuage()

while not Fini:
    if not Jeu:
        affiche_menu()
        gerer_entree_menu()
    else:
        temps_maintenant = pygame.time.get_ticks()
        gerer_entree()
        if not Pause:
            maj_positions()
            maj_balles()
            if POWER:
                power_up()
        fenetre.fill(BLEU_CIEL)
        dessiner_sol2(temps_maintenant/20)
        affiche_nuage()
        affiche_vies()
        affiche_balles()
        affiche_avions()
        affiche_power_up()
        dessiner_sol1(temps_maintenant/10)
        collision()
        affiche_explosion()
        menu_pause()
        score()
        horloge.tick(IMAGES_PAR_SECONDE)
        pygame.display.flip()
        if init and Jeu:
            init = False
            pygame.time.wait(1000)

pygame.display.quit()
pygame.quit()
exit()


# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================

"""A binary to train CIFAR-10 using multiple GPUs with synchronous updates.

Accuracy:
cifar10_multi_gpu_train.py achieves ~86% accuracy after 100K steps (256
epochs of data) as judged by cifar10_eval.py.

Speed: With batch_size 128.

System        | Step Time (sec/batch)  |     Accuracy
--------------------------------------------------------------------
1 Tesla K20m  | 0.35-0.60              | ~86% at 60K steps  (5 hours)
1 Tesla K40m  | 0.25-0.35              | ~86% at 100K steps (4 hours)
2 Tesla K20m  | 0.13-0.20              | ~84% at 30K steps  (2.5 hours)
3 Tesla K20m  | 0.13-0.18              | ~84% at 30K steps
4 Tesla K20m  | ~0.10                  | ~84% at 30K steps

Usage:
Please see the tutorial and website for how to download the CIFAR-10
data set, compile the program and train the model.

http://tensorflow.org/tutorials/deep_cnn/
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

from datetime import datetime
import os.path
import re
import time

from PIL import Image

import math

from distutils.dir_util import copy_tree

from tensorflow.python import debug as tf_debug

import numpy as np
from six.moves import xrange  # pylint: disable=redefined-builtin
import tensorflow as tf
import cifar10

FLAGS = tf.app.flags.FLAGS

tf.app.flags.DEFINE_string('train_dir', './32_by_32_faces_train',
                           """Directory where to write event logs """
                           """and checkpoint.""")

tf.app.flags.DEFINE_string('input_filename', 'SFA_pixel_regions_training_set.tfrecords',
                           """TFRecords training set filename""")

tf.app.flags.DEFINE_string('eval_filename', 'SFA_pixel_regions_test_set.tfrecords',
                           """TFRecords eval set filename""")

# tf.app.flags.DEFINE_string('input_filename', 'cifar10_train.tfrecords',
#                            """TFRecords training set filename""")

tf.app.flags.DEFINE_integer('num_examples', cifar10.NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN,
                            """Number of examples to run.""")

tf.app.flags.DEFINE_integer('eval_num_examples', cifar10.NUM_EXAMPLES_PER_EPOCH_FOR_EVAL,
                            """Number of eval examples to run.""")

tf.app.flags.DEFINE_integer('max_steps', 1000000,
                            """Number of batches to run.""")
tf.app.flags.DEFINE_integer('num_gpus', 2,
                            """How many GPUs to use.""")
tf.app.flags.DEFINE_boolean('log_device_placement', False,
                            """Whether to log device placement.""")

tf.app.flags.DEFINE_string('best_dir', './best_dir',
                            """Best eval dir.""")

calculate_rates = True

# INITIAL_IMAGE_SIZE = 150
INITIAL_IMAGE_SIZE = cifar10.IMAGE_SIZE
IMAGE_SIZE = cifar10.IMAGE_SIZE

def _parse_function_no_distortion(example_proto):
    features = {"image": tf.FixedLenFeature((), tf.string, default_value=""),
                "label": tf.FixedLenFeature((), tf.int64, default_value=0)}
    parsed_features = tf.parse_single_example(example_proto, features)
    image_decoded = tf.reshape(tf.decode_raw(parsed_features["image"], tf.uint8), [
                                INITIAL_IMAGE_SIZE, INITIAL_IMAGE_SIZE, 3])

    image_decoded = tf.cast(image_decoded, tf.float32)

    final_image = tf.image.per_image_standardization(image_decoded)
    return final_image, tf.cast(parsed_features["label"], tf.int32)

def _parse_function(example_proto):
    features = {"image": tf.FixedLenFeature((), tf.string, default_value=""),
                "label": tf.FixedLenFeature((), tf.int64, default_value=0)}
    parsed_features = tf.parse_single_example(example_proto, features)
    image_decoded = tf.reshape(tf.decode_raw(parsed_features["image"], tf.uint8), [
                                INITIAL_IMAGE_SIZE , INITIAL_IMAGE_SIZE , 3])

    image_decoded = tf.cast(image_decoded, tf.float32)

    brightness_percentage = tf.random_uniform(
        [], minval=0, maxval=1, dtype=tf.float32)
    contrast_percentage = tf.random_uniform(
        [], minval=0, maxval=1, dtype=tf.float32)
    hue_percentage = tf.random_uniform(
        [], minval=0, maxval=1, dtype=tf.float32)
    saturation_percentage = tf.random_uniform(
        [], minval=0, maxval=1, dtype=tf.float32)
    rotation_percentage = tf.random_uniform(
        [], minval=0, maxval=1, dtype=tf.float32)
    zoom_percentage = tf.random_uniform(
        [], minval=0, maxval=1, dtype=tf.float32)
    skew_x_percentage = tf.random_uniform(
        [], minval=0, maxval=1, dtype=tf.float32)
    skew_y_percentage = tf.random_uniform(
        [], minval=0, maxval=1, dtype=tf.float32)
    translate_percentage = tf.random_uniform(
        [], minval=0, maxval=1, dtype=tf.float32)

    image_decoded = tf.image.random_flip_left_right(image_decoded)

    # angle = tf.random_uniform(
    #     [1], minval=(-1 * (math.pi / 4)), maxval=math.pi / 4, dtype=tf.float32)
    # image_rotated = tf.contrib.image.rotate(
    #     image_decoded, angle, interpolation='BILINEAR')
    # image_decoded = tf.cond(rotation_percentage < 0.4,
    #                         lambda: image_rotated, lambda: image_decoded)

    image_brightness = tf.image.random_brightness(image_decoded, max_delta=0.8)
    image_decoded = tf.cond(brightness_percentage < 0.3,
                            lambda: image_brightness, lambda: image_decoded)

    image_contrast = tf.image.random_contrast(
        image_decoded, lower=0.7, upper=1.5)
    image_decoded = tf.cond(contrast_percentage < 0.3,
                            lambda: image_contrast, lambda: image_decoded)

    image_hue = tf.image.random_hue(image_decoded, max_delta=0.2)
    image_decoded = tf.cond(hue_percentage < 0.5,
                            lambda: image_hue, lambda: image_decoded)

    image_saturation = tf.image.random_saturation(
        image_decoded, lower=0.5, upper=1.5)
    image_decoded = tf.cond(saturation_percentage < 0.3,
                            lambda: image_saturation, lambda: image_decoded)

    zoom_scale = tf.random_uniform(
        [], minval=1.0, maxval=1.1, dtype=tf.float32)
    new_size = tf.constant(
        [INITIAL_IMAGE_SIZE, INITIAL_IMAGE_SIZE], dtype=tf.float32) * zoom_scale
    new_size = tf.cast(new_size, tf.int32)
    image_zoom = tf.image.resize_images(image_decoded, new_size)
    image_zoom = tf.image.resize_image_with_crop_or_pad(
        image_zoom, INITIAL_IMAGE_SIZE, INITIAL_IMAGE_SIZE)
    image_decoded = tf.cond(zoom_percentage < 0.1,
                            lambda: image_zoom, lambda: image_decoded)

    # skew_x_angle = tf.random_uniform(
    #     [1], minval=(-1 * (math.pi / 12)), maxval=math.pi / 12, dtype=tf.float32)
    # skew_x_tan = tf.tan(skew_x_angle)
    # skew_x_vector_1 = tf.constant([1], dtype=tf.float32)
    # skew_x_vector_2 = tf.constant([0, 0, 1, 0, 0, 0], dtype=tf.float32)
    # skew_x_vector = tf.concat([skew_x_vector_1,skew_x_tan, skew_x_vector_2],0)
    # skewed_x_image = tf.contrib.image.transform(image_decoded, skew_x_vector, interpolation='BILINEAR')
    # image_decoded = tf.cond(skew_x_percentage < 0.1,
    #                         lambda: skewed_x_image, lambda: image_decoded)

    # skew_y_angle = tf.random_uniform(
    #     [1], minval=(-1 * (math.pi / 12)), maxval=math.pi / 6, dtype=tf.float32)
    # skew_y_tan = tf.tan(skew_y_angle)
    # skew_y_vector_1 = tf.constant([1, 0, 0], dtype=tf.float32)
    # skew_y_vector_2 = tf.constant([1, 0, 0, 0], dtype=tf.float32)
    # skew_y_vector = tf.concat([skew_y_vector_1,skew_y_tan, skew_y_vector_2],0)
    # skewed_y_image = tf.contrib.image.transform(image_decoded, skew_y_vector, interpolation='BILINEAR')
    # image_decoded = tf.cond(skew_y_percentage < 0.1,
    #                         lambda: skewed_y_image, lambda: image_decoded)

    # translate_y = tf.random_uniform(
    #     [1], minval=(-1 * (INITIAL_IMAGE_SIZE / 5)), maxval=INITIAL_IMAGE_SIZE / 6, dtype=tf.float32)
    # translate_x = tf.random_uniform(
    #     [1], minval=(-1 * (INITIAL_IMAGE_SIZE / 5)), maxval=INITIAL_IMAGE_SIZE / 6, dtype=tf.float32)
    # translate_vector_1 = tf.constant([1, 0], dtype=tf.float32)
    # translate_vector_2 = tf.constant([0, 1], dtype=tf.float32)
    # translate_vector_3 = tf.constant([0, 0], dtype=tf.float32)
    # translate_vector = tf.concat(
    #     [translate_vector_1, translate_x, translate_vector_2, translate_y, translate_vector_3], 0)
    # translated_image = tf.contrib.image.transform(image_decoded, translate_vector, interpolation='BILINEAR')
    # image_decoded = tf.cond(translate_percentage < 0.1,
    #                         lambda: translated_image, lambda: image_decoded)

    final_image = tf.image.per_image_standardization(image_decoded)
    return final_image, tf.cast(parsed_features["label"], tf.int32)

def tower_loss(scope, images, labels):
    """Calculate the total loss on a single tower running the CIFAR model.

    Args:
      scope: unique prefix string identifying the CIFAR tower, e.g. 'tower_0'
      images: Images. 4D tensor of shape [batch_size, height, width, 3].
      labels: Labels. 1D tensor of shape [batch_size].

    Returns:
       Tensor of shape [] containing the total loss for a batch of data
    """

    # Build inference Graph.
    logits = cifar10.inference(images, is_train=True)

    # Build the portion of the Graph calculating the losses. Note that we will
    # assemble the total_loss using a custom function below.
    _ = cifar10.loss(logits, labels)

    # Assemble all of the losses for the current tower only.
    losses = tf.get_collection('losses', scope)

    # Calculate the total loss for the current tower.
    total_loss = tf.add_n(losses, name='total_loss')

    # Attach a scalar summary to all individual losses and the total loss; do the
    # same for the averaged version of the losses.
    for l in losses + [total_loss]:
        # Remove 'tower_[0-9]/' from the name in case this is a multi-GPU training
        # session. This helps the clarity of presentation on tensorboard.
        loss_name = re.sub('%s_[0-9]*/' % cifar10.TOWER_NAME, '', l.op.name)
        tf.summary.scalar(loss_name, l)

    return total_loss

def average_gradients(tower_grads):
    """Calculate the average gradient for each shared variable across all towers.

    Note that this function provides a synchronization point across all towers.

    Args:
      tower_grads: List of lists of (gradient, variable) tuples. The outer list
        is over individual gradients. The inner list is over the gradient
        calculation for each tower.
    Returns:
       List of pairs of (gradient, variable) where the gradient has been averaged
       across all towers.
    """
    average_grads = []
    for grad_and_vars in zip(*tower_grads):
        # Note that each grad_and_vars looks like the following:
        #   ((grad0_gpu0, var0_gpu0), ... , (grad0_gpuN, var0_gpuN))
        grads = []
        for g, _ in grad_and_vars:
            # Add 0 dimension to the gradients to represent the tower.
            expanded_g = tf.expand_dims(g, 0)

            # Append on a 'tower' dimension which we will average over below.
            grads.append(expanded_g)

        # Average over the 'tower' dimension.
        grad = tf.concat(axis=0, values=grads)
        grad = tf.reduce_mean(grad, 0)

        # Keep in mind that the Variables are redundant because they are shared
        # across towers. So .. we will just return the first tower's pointer to
        # the Variable.
        v = grad_and_vars[0][1]
        grad_and_var = (grad, v)
        average_grads.append(grad_and_var)
    return average_grads

def eval_once(sess, summary_writer, top_k_op, summary_op, acc_iterator, global_step, eval, num_examples, current_lr, lr):
    """Run Eval once.

    Args:
        saver: Saver.
        summary_writer: Summary writer.
        top_k_op: Top K op.
        summary_op: Summary op.
    """

    # Start the queue runners.
    coord = tf.train.Coordinator()
    try:
        threads = []
        for qr in tf.get_collection(tf.GraphKeys.QUEUE_RUNNERS):
            threads.extend(qr.create_threads(sess, coord=coord, daemon=True,
                                             start=True))

        num_iter = int(math.ceil(num_examples / (2*FLAGS.batch_size) ))
        true_count = 0  # Counts the number of correct predictions.
        total_sample_count = num_iter * FLAGS.batch_size * 2
        step = 0
        while step < num_iter and not coord.should_stop():
            # predictions = sess.run([top_k_op], {lr: current_lr})
            predictions = sess.run([top_k_op])
            true_count += np.sum(predictions)
            step += 1

        # Compute precision @ 1.
        precision = true_count / total_sample_count

        summary = tf.Summary()
        # summary.ParseFromString(
        #     sess.run(summary_op, {lr: current_lr}) )
        summary.ParseFromString(
            sess.run(summary_op) )
        if eval:
            summary.value.add(tag='Eval Set Precision @ 1',
                              simple_value=precision)
        else:
            summary.value.add(tag='Training Precision @ 1',
                              simple_value=precision)
        summary_writer.add_summary(summary, global_step)
    except Exception as e:  # pylint: disable=broad-except
        coord.request_stop(e)

    coord.request_stop()
    coord.join(threads, stop_grace_period_secs=10)

    return precision

def train():
    """Train CIFAR-10 for a number of steps."""
    with tf.Graph().as_default(), tf.device('/cpu:0'):
        # Create a variable to count the number of train() calls. This equals the
        # number of batches processed * FLAGS.num_gpus.
        global_step = tf.get_variable(
            'global_step', [],
            initializer=tf.constant_initializer(0), trainable=False)

        num_steps_per_epoch = (
            cifar10.NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN) / (FLAGS.batch_size * FLAGS.num_gpus)
        decay_steps = int(num_steps_per_epoch * cifar10.NUM_EPOCHS_PER_DECAY)

        # Decay the learning rate exponentially based on the number of steps.
        # lr = tf.placeholder( dtype = tf.float32)
        lr = tf.train.exponential_decay(cifar10.INITIAL_LEARNING_RATE,
                                        global_step,
                                        decay_steps,
                                        cifar10.LEARNING_RATE_DECAY_FACTOR,
                                        staircase=True)

        # Create an optimizer that performs gradient descent.
        opt = tf.train.MomentumOptimizer(lr, 0.9, use_nesterov=True)

        # Get images and labels for CIFAR-10.

        dataset = tf.data.TFRecordDataset(FLAGS.input_filename)
        # Parse the record into tensors.
        dataset = dataset.map(_parse_function)
        dataset = dataset.shuffle(buffer_size=cifar10.NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN)
        dataset = dataset.repeat()  # Repeat the input indefinitely.
        dataset = dataset.prefetch(FLAGS.batch_size * 7)
        dataset = dataset.batch(FLAGS.batch_size)
        iterator = dataset.make_initializable_iterator()

        # GET TRAINING ACCURACY
        acc_dataset = tf.data.TFRecordDataset(FLAGS.input_filename)
        # Parse the record into tensors.
        acc_dataset = acc_dataset.map(_parse_function_no_distortion)
        acc_dataset = acc_dataset.repeat()  # Repeat the input indefinitely.
        acc_dataset = acc_dataset.batch(FLAGS.batch_size)
        acc_iterator = acc_dataset.make_initializable_iterator()

        eval_acc_dataset = tf.data.TFRecordDataset(FLAGS.eval_filename)
        # Parse the record into tensors.
        eval_acc_dataset = eval_acc_dataset.map(_parse_function_no_distortion)
        # Repeat the input indefinitely.
        eval_acc_dataset = eval_acc_dataset.repeat()
        eval_acc_dataset = eval_acc_dataset.batch(FLAGS.batch_size)
        eval_acc_iterator = eval_acc_dataset.make_initializable_iterator()

        # Calculate the gradients for each model tower.
        tower_grads = []
        acc_top_k_op_list = []
        eval_acc_top_k_op_list = []
        with tf.variable_scope(tf.get_variable_scope()):
            for i in xrange(FLAGS.num_gpus):
                with tf.device('/gpu:%d' % i):
                    with tf.name_scope('%s_%d' % (cifar10.TOWER_NAME, i)) as scope:
                        # Dequeues one batch for the GPU

                        image_batch, label_batch = iterator.get_next()

                        # Calculate the loss for one tower of the CIFAR model. This function
                        # constructs the entire CIFAR model but shares the variables across
                        # all towers.
                        loss = tower_loss(scope, image_batch, label_batch)

                        # Reuse variables for the next tower.
                        tf.get_variable_scope().reuse_variables()

                        acc_images, acc_labels = acc_iterator.get_next()
                        acc_logits = cifar10.inference(
                            acc_images, should_summarize=False)
                        acc_top_k_op_list.append(tf.nn.in_top_k(
                            acc_logits, acc_labels, 1))
                        tf.get_variable_scope().reuse_variables()

                        eval_acc_images, eval_acc_labels = eval_acc_iterator.get_next()
                        eval_acc_logits = cifar10.inference(
                            eval_acc_images, should_summarize=False)
                        eval_acc_top_k_op_list.append(tf.nn.in_top_k(
                            eval_acc_logits, eval_acc_labels, 1))
                        tf.get_variable_scope().reuse_variables()

                        # Retain the summaries from the final tower.
                        summaries = tf.get_collection(
                            tf.GraphKeys.SUMMARIES, scope)

                        # Calculate the gradients for the batch of data on this CIFAR tower.
                        grads = opt.compute_gradients(loss)

                        # Keep track of the gradients across all towers.
                        tower_grads.append(grads)

        acc_top_k_op = acc_top_k_op_list[0]
        eval_acc_top_k_op = eval_acc_top_k_op_list[0]
        for i in xrange(1,FLAGS.num_gpus):
            acc_top_k_op = tf.concat([acc_top_k_op,acc_top_k_op_list[i]],0)
            eval_acc_top_k_op = tf.concat([eval_acc_top_k_op,eval_acc_top_k_op_list[i]],0)

        # We must calculate the mean of each gradient. Note that this is the
        # synchronization point across all towers.
        grads = average_gradients(tower_grads)

        # Add a summary to track the learning rate.
        summaries.append(tf.summary.scalar('learning_rate', lr))

        # Add histograms for gradients.
        for grad, var in grads:
            if grad is not None:
                summaries.append(tf.summary.histogram(
                    var.op.name + '/gradients', grad))

        # Apply the gradients to adjust the shared variables.
        update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
        with tf.control_dependencies(update_ops):
            apply_gradient_op = opt.apply_gradients(
                grads, global_step=global_step)

        # Add histograms for trainable variables.
        for var in tf.trainable_variables():
            summaries.append(tf.summary.histogram(var.op.name, var))

        # Track the moving averages of all trainable variables.
        variable_averages = tf.train.ExponentialMovingAverage(
            cifar10.MOVING_AVERAGE_DECAY, global_step)
        variables_averages_op = variable_averages.apply(
            tf.trainable_variables())

        # Group all updates to into a single train op.
        train_op = tf.group(apply_gradient_op, variables_averages_op)

        # Create a saver.
        saver = tf.train.Saver(tf.global_variables())

        # Build the summary operation from the last tower summaries.
        summary_op = tf.summary.merge(summaries)

        # Build an initialization operation to run below.
        init = tf.group(tf.global_variables_initializer(),
                        tf.local_variables_initializer())

        # Start running operations on the Graph. allow_soft_placement must be set to
        # True to build towers on GPU, as some of the ops do not have GPU
        # implementations.
        sess = tf.Session(config=tf.ConfigProto(
            allow_soft_placement=True,
            log_device_placement=FLAGS.log_device_placement))

        # sess = tf_debug.LocalCLIDebugWrapperSession(sess, dump_root='./tmp_dump')
        # sess.add_tensor_filter("has_inf_or_nan", tf_debug.has_inf_or_nan)
        sess.run(init)

        coord = tf.train.Coordinator()

        # Start the queue runners.
        tf.train.start_queue_runners(sess=sess, coord=coord)

        sess.run(acc_iterator.initializer)
        sess.run(eval_acc_iterator.initializer)
        sess.run(iterator.initializer)

        summary_writer = tf.summary.FileWriter(FLAGS.train_dir, sess.graph)

        acc_last_precision = 0.0
        eval_acc_last_precision = 0.0

        # draw(sess, image_batch, label_batch)
        # exit()

        best_precision = 0.0

        for step in xrange(FLAGS.max_steps):
            start_time = time.time()
            current_epoch = float((step * FLAGS.batch_size * FLAGS.num_gpus) //
                                  (cifar10.NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN))

            if current_epoch == 0:
                current_lr = cifar10.INITIAL_LEARNING_RATE
            else:
                current_lr = (cifar10.INITIAL_LEARNING_RATE) / \
                    math.sqrt(current_epoch)
                if current_lr < 1e-6:
                    current_lr = 1e-6

            # _, loss_value = sess.run(
            #     [train_op, loss], {lr: current_lr})

            _, loss_value = sess.run(
                [train_op, loss])
            duration = time.time() - start_time

            assert not np.isnan(loss_value), 'Model diverged with loss = NaN'

            if step % 10 == 0:
                num_examples_per_step = FLAGS.batch_size * FLAGS.num_gpus
                examples_per_sec = num_examples_per_step / duration
                sec_per_batch = duration / FLAGS.num_gpus

                epoch = int(current_epoch)

                format_str = ('%s: step: %d; epoch: %d; loss = %.6f, last_precision = %.2f, last_eval_precision =  %.2f, best_eval_precision =  %.2f  (%.1f examples/sec; %.3f '
                              'sec/batch)')
                print (format_str % (datetime.now(), step, epoch, loss_value, acc_last_precision, eval_acc_last_precision, best_precision,
                                     examples_per_sec, sec_per_batch))

            if step % 100 == 0:
                # summary_str = sess.run(summary_op, {lr: current_lr})
                summary_str = sess.run(summary_op)
                summary_writer.add_summary(summary_str, step)

            # Save the model checkpoint periodically.
            if step % 1000 == 0 or (step + 1) == FLAGS.max_steps:
                checkpoint_path = os.path.join(FLAGS.train_dir, 'model.ckpt')
                saver.save(sess, checkpoint_path, global_step=step)

            if step % 15000 == 0 and calculate_rates and step > 0:

                acc_last_precision = eval_once(
                    sess, summary_writer, acc_top_k_op, summary_op, acc_iterator, step, False, FLAGS.num_examples, current_lr, lr)

                eval_acc_last_precision = eval_once(
                    sess, summary_writer, eval_acc_top_k_op, summary_op, eval_acc_iterator, step, True, FLAGS.eval_num_examples, current_lr, lr)

                if eval_acc_last_precision > best_precision:
                    best_precision = eval_acc_last_precision
                    if tf.gfile.Exists(FLAGS.best_dir):
                        tf.gfile.DeleteRecursively(FLAGS.best_dir)
                        tf.gfile.MakeDirs(FLAGS.best_dir)
                        copy_tree(FLAGS.train_dir,FLAGS.best_dir)

def draw(sess, image_batch, label_batch):

    im, label = sess.run([image_batch, label_batch])
    shape = im.shape
    for i in xrange(shape[0]):

        if label[i] == 0:
            continue

        imagem = im[i, :, :, :]

        im_min = np.amin(imagem)
        im_max = np.amax(imagem)

        imagem_f = (((imagem - im_min) / (im_max - im_min))
                    * 255).astype(np.uint8)

        imagem_f_rgb = np.zeros(imagem_f.shape,dtype = np.uint8)

        imagem_f_rgb[:,:,0] = imagem_f[:,:,2]
        imagem_f_rgb[:,:,1] = imagem_f[:,:,1]
        imagem_f_rgb[:,:,2] = imagem_f[:,:,0]

        pImg = Image.fromarray(imagem_f_rgb, "RGB")
        pImg = pImg.resize((INITIAL_IMAGE_SIZE, INITIAL_IMAGE_SIZE), Image.LANCZOS)
        pImg.show()

        raw_input()

def main(argv=None):  # pylint: disable=unused-argument
    # cifar10.maybe_download_and_extract()
    if tf.gfile.Exists(FLAGS.train_dir):
      tf.gfile.DeleteRecursively(FLAGS.train_dir)
    tf.gfile.MakeDirs(FLAGS.train_dir)

    if tf.gfile.Exists(FLAGS.best_dir):
      tf.gfile.DeleteRecursively(FLAGS.best_dir)
    tf.gfile.MakeDirs(FLAGS.best_dir)

    train()

if __name__ == '__main__':
    tf.app.run()


import torch
import numpy as np
from torch.utils.data import DataLoader
from torch.utils.data.sampler import SubsetRandomSampler, SequentialSampler
import math

class Dataloader():
    def __init__(self, dataset, batch_size, small=False, shuffle_indices=False):
        self.batch_size = batch_size
        self.dataset = dataset
        # take small amount of data for fast training
        if small == True:
            self.dataset_size = math.floor(len(dataset)/32)
        else:
            self.dataset_size = len(dataset)
        self.indices = list(range(self.dataset_size))
        if shuffle_indices:
            np.random.shuffle(self.indices)
        self.split = int(np.floor(0.1 * self.dataset_size))
        self.train_indices = self.indices[self.split:]
        self.test_indices = self.indices[:self.split]
        self.train_sampler = SequentialSampler(self.train_indices)
        self.test_sampler = SequentialSampler(self.test_indices)
        self.train_loader = DataLoader(self.dataset, batch_size=self.batch_size, sampler=self.train_sampler)
        self.test_loader = DataLoader(self.dataset, batch_size=self.batch_size, sampler=self.test_sampler)
        self.print_info()

    def print_info(self):
        print("Number of training/test patches:", (len(self.train_indices),len(self.test_indices)))


from threading import Lock

from panda3d.ode import OdeWorld, OdeJointGroup, OdeSimpleSpace

class Monde(OdeWorld):
    def __init__(self, app):
        OdeWorld.__init__(self)

        self.app = app

        self.lock = Lock()

        # Creation d'un espace
        self.espace = OdeSimpleSpace()
        # Activation de la collision automatique
        self.espace.setAutoCollideWorld(self)
        # Creation d'une jointure entre les collisions
        self.contactgroup = OdeJointGroup()
        self.espace.setAutoCollideJointGroup(self.contactgroup)

        # Creation d'une liste rassemblant les elements dynamique
        self.elements = []

    def ajouter_element(self, element):
        self.lock.acquire()
        # Ajout d'un element
        if element not in self.elements:
            self.elements.append(element)
        self.lock.release()

    def retirer_element(self, element):
        self.lock.acquire()
        # Suppression d'un element
        if element in self.elements:
            self.elements.remove(element)
        self.lock.release()

    def lancer(self):
        self.app.taskMgr.doMethodLater(1.0 / self.app.FPS, self.simulation, "SimulationPhysique")

    def arreter(self):
        self.app.taskMgr.remove("SimulationPhysique")

    def simulation(self, task):
        self.espace.autoCollide()  # Setup the contact joints
        # Step the simulation and set the new positions
        self.quickStep(1.0 / self.app.FPS)

        self.lock.acquire()

        # Met a jour chaque element dynamique lier a la physique du jeu
        for element in self.elements:
            element.maj_physique()

        self.lock.release()

        self.contactgroup.empty()  # Clear the contact joints
        return task.cont


import itertools
import time
import numpy as np
import pandas as pd
import seaborn as sns
import statsmodels.api as sm
import matplotlib.pyplot as plt
from sklearn import linear_model
from sklearn.metrics import mean_squared_error
from sklearn.linear_model import LogisticRegression
from tqdm import tnrange, tqdm_notebook

def fit_log_reg(X,Y, multi):
    #Fit linear regression model and return AIC, BIC, loglikelihood, and R squared values
    X = sm.add_constant(X)
    model_k = sm.Logit(Y, X.astype(float)).fit()
    if(multi == True):
        model_k=sm.MNLogit(Y, X.astype(float)).fit()
    AIC = model_k.aic
    BIC = model_k.bic
    LLH = model_k.llf
    R2 = model_k.prsquared
    return AIC, BIC, LLH,R2

#funcion of tring all combination to find the best model
def try_all(dat,  Yname, multi):
    #Initialization variables
    Y = dat[Yname]#dat["Airport"]
    if(Yname =="Airport"):
        Y = Y.replace(regex={1:0, 2:1})
    X = dat.drop(columns = Yname, axis = 1)
    #k = 11
    AIC_list, BIC_list,Log_list,RSquare_list, feature_list = [],[], [],[],[]
    numb_features = []

    #Looping over k = 1 to k snip= 11 features in X
    for k in tnrange(1,len(X.columns) + 1, desc = 'Loop...'):
        #Looping over all possible combinations: from 11 choose k
        for combo in itertools.combinations(X.columns,k):
            tmp_result = fit_log_reg(X.loc[:,list(combo)],Y,multi)   #Store temp result
            AIC_list.append(tmp_result[0])                  #Append lists
            BIC_list.append(tmp_result[1])
            Log_list.append(tmp_result[2])
            RSquare_list.append(tmp_result[3])
            feature_list.append(combo)
            numb_features.append(len(combo))

    #Store in DataFrame
    df = pd.DataFrame({'numb_features': numb_features,'AIC': AIC_list, 'BIC':BIC_list,'Loglikelihood':Log_list,'McFaddens R2':RSquare_list,'features':feature_list})
    return(df)


#!./env/bin/python3
"""
This script uses a timestamp file to keep track of and make egauge api requests for egauge sensor data.

Example command: python3 egauge_api.py 725 m ./output.log ./timestamp.log
"""

from io import StringIO

import arrow
import os
import pandas as pd
import requests
import sys
import traceback

script_name = os.path.basename(__file__)
error_log = 'error.log'
#a dictionary that maps unit_of_time arguments to the number of seconds in that unit
times = {
'm':60,
'h':3600
}

def pull_egauge_data(sensor_id='31871', unit_of_time='m', output_file='./output.log', timestamp_log='./timestamp.log'):
    """
    This function pulls egauge sensor data.

    Data pulled will start at and include the time read from the timestamp log up to (but not including) the current time. The data (not including the headers) pulled from the sensors by this program will be appended to a csv file ('output.log' by default).
    Any exceptions thrown during execution will be logged to a file.

    Keyword arguments:
        sensor_id: a string representing the id of the egauge sensor
        unit_of_time: the unit of time we want the data returned as
        output_file: the name of the file that egauge sensor data will be appended to
        timestamp_log: the name of the file that a timestamp will be read from and written to
    """
    try:
        current_timestamp = int(arrow.now().timestamp)
        # round down to the nearest unit of time (minute)
        current_timestamp = current_timestamp - (current_timestamp % times[unit_of_time])

        latest_timestamp_read_from_file = ''
        with open(timestamp_log, 'a+') as timestamp_file:
            timestamp_file.seek(0)
            for line in timestamp_file:
                line = line.rstrip()
                if line is not '':
                    latest_timestamp_read_from_file = int(line)

        if not latest_timestamp_read_from_file:
            with open(timestamp_log, 'a+') as timestamp_file:
                timestamp_file.write(str(current_timestamp) + '\n')
                print('File ' + timestamp_log + ' was empty. Appended current timestamp to file.')
        else:
            api_start_timestamp = latest_timestamp_read_from_file
            #The range returned is exclusive of the api end timestamp; eg. all data collected by the egauge sensor from the start time up to but not including the end time will be returned
            api_end_timestamp = current_timestamp
            if api_start_timestamp > api_end_timestamp:
                raise ValueError('Error: api_start_timestamp ' + str(arrow.get(api_start_timestamp)) + ' was later than api_end_timestamp '  + str(arrow.get(api_end_timestamp)))
            output_csv='c'
            delta_compression='C'
            host = 'http://egauge{}.egaug.es/cgi-bin/egauge-show?'
            host = host.format(sensor_id) + '&' + unit_of_time + '&' + output_csv + '&' + delta_compression
            time_window = {'t': api_start_timestamp, 'f': api_end_timestamp}

            request_timer_start = arrow.now()

            r = requests.get(host,params=time_window)
            if(r.status_code == requests.codes.ok):
                print('[' + str(arrow.get(current_timestamp)) + '] ' + 'Request was successful' + str(r))
                df = pd.read_csv(StringIO(r.text))
                df = df.sort_values(by='Date & Time')
                #Set header=False if we don't want to append header and set index=False to remove index column.
                df.to_csv(path_or_buf=output_file, index=False, header=False, mode='a+')
                rows_returned = df.shape[0]
                #check if any values were returned
                if rows_returned > 0:
                    #Will implement database insertion here
                    #Write current_timestamp to timestamp log
                    with open(timestamp_log, 'a+') as timestamp_file:
                        timestamp_file.write(str(current_timestamp) + '\n')
                request_timer_end = arrow.now()
                request_time_elapsed = request_timer_end - request_timer_start
                print(str(rows_returned) + ' row(s) returned by egauge api in ' + str(request_time_elapsed))
            else:
                r.raise_for_status()
    except Exception as e:
        error_msg = str(traceback.format_exc())
        print(error_msg)
        with open(error_log, 'a+') as error_file:
            current_time = arrow.now().format('ddd MMM DD YYYY HH:mm:ss ZZ')
            error_file.write('[' + str(current_time) + '] ')
            error_file.write(error_msg + '\n')

if __name__ == "__main__":
    #slice off script name argument since it is unused
    pull_egauge_data(*sys.argv[1:])


# -*- coding: utf-8 -*-

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

def make_boxplots_PM_var():

    dataDir="C:\\Users\\Justin\Dropbox\\Y90_heterogeneity_writeup\\"
    #GEt PM doses
    filename = dataDir+"PM_variation_doses.txt"
    df = pd.read_csv(filename, skiprows=1, delim_whitespace=True)
    T0,T1,T2,T3 = [df.PM_T0.values, df.PM_T1.values, df.PM_T2.values, df.PM_T3.values]
    NT0,NT1,NT2,NT3 = [df.PM_NT0.values, df.PM_NT1.values, df.PM_NT2.values, df.PM_NT3.values]

    #rows of single or multi tumors
    singleT=['1','7','14','15','17','19','25']
    singleIndex = df['patient'].isin(singleT)
    multiIndex = singleIndex.ne(True)

    sdf = df[singleIndex]
    sT0,sT1,sT2,sT3 = [sdf.PM_T0.values, sdf.PM_T1.values, sdf.PM_T2.values, sdf.PM_T3.values]
    sNT0,sNT1,sNT2,sNT3 = [sdf.PM_NT0.values, sdf.PM_NT1.values, sdf.PM_NT2.values, sdf.PM_NT3.values]

    mdf = df[multiIndex]
    mT0,mT1,mT2,mT3 = [mdf.PM_T0.values, mdf.PM_T1.values, mdf.PM_T2.values,mdf.PM_T3.values]
    mNT0,mNT1,mNT2,mNT3 = [mdf.PM_NT0.values, mdf.PM_NT1.values, mdf.PM_NT2.values, mdf.PM_NT3.values]

    #now make the boxplot
    fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(16,8))
    #left axes is T
    data = [sT0,mT0,T0,
            sT1,mT1,T1,
            sT2,mT2,T2,
            sT3,mT3,T3]
    commonprops={"linewidth":2}
    flierprops = {"markersize":16, "markeredgewidth":3}
    ax[0].boxplot(data, boxprops=commonprops, capprops=commonprops,flierprops=flierprops, whiskerprops=commonprops, medianprops=commonprops)
    ax[0].tick_params(axis='both', which='major', labelsize=16)
    ax[0].set_xticks(np.arange(12)+1, minor=False)
    ax[0].set_xticklabels(['sNT','mNT','NT',
                           'sS0','mS0','S0',
                           'sS1','mS1','S1',
                           'sS2','mS2','S2'], minor=False)
    ax[0].set_ylabel("PM T Absorbed Dose (Gy)", fontsize=24)
    #ax[0].set_xlim(0,12.5)
    y0min, y0max = ax[0].get_ylim()
    ax[0].vlines([3.5,6.5,9.5],y0min,y0max, linestyle="dotted", linewidth=2, alpha=0.5)

    #right axes is NT
    data = [sNT0,mNT0,NT0,
            sNT1,mNT1,NT1,
            sNT2,mNT2,NT2,
            sNT3,mNT3,NT3]
    ax[1].boxplot(data,boxprops=commonprops, capprops=commonprops,flierprops=flierprops, whiskerprops=commonprops, medianprops=commonprops)
    ax[1].tick_params(axis='both', which='major', labelsize=16)
    ax[1].set_xticks(np.arange(12)+1, minor=False)
    ax[1].set_xticklabels(['sNT','mNT','NT',
                           'sS0','mS0','S0',
                           'sS1','mS1','S1',
                           'sS2','mS2','S2'], minor=False)
    ax[1].set_ylabel("PM NT Absorbed Dose (Gy)", fontsize=24)
    #ax[1].set_xlim(0,12.5)
    y0min, y0max = ax[1].get_ylim()
    ax[1].vlines([3.5,6.5,9.5],y0min,y0max, linestyle="dotted", linewidth=2, alpha=0.5)

    #now place jitter plot of values
    markerSize=160
    linewidth=2

#    #helper function for plotting scatter next or over boxplots
#    def jitScat(jitsd, jitmean, valArr, axes,
#                marker="o", facecolors="red", markerSize=10, label=None,
#                edgecolor="black", alpha=0, linewidth=1):
#        xjit = jitsd*np.random.randn(np.size(valArr)) + jitmean
#        axes.scatter(xjit, valArr, marker=marker,s=markerSize, facecolors=facecolors, label=label, edgecolor=edgecolor, alpha=alpha, linewidth=linewidth)
#
#    y0min, y0max = ax[0].get_ylim()
#    jitScat(0.05, 0.5, T0, ax[0],
#            facecolors='none',marker='o', markerSize=markerSize,
#            label="NT", edgecolor="purple", alpha=0.8, linewidth=linewidth)
#    jitScat(0.05, 1.5, T1, ax[0],
#            facecolors='none',marker='^', markerSize=markerSize,
#            label="S0", edgecolor="purple", alpha=0.8, linewidth=linewidth)
#    jitScat(0.05, 2.5, T2, ax[0],
#            facecolors='none',marker='s', markerSize=markerSize,
#            label="S1", edgecolor="purple", alpha=0.8, linewidth=linewidth)
#    jitScat(0.05, 3.5, T3, ax[0],
#            facecolors='none',marker='D', markerSize=markerSize,
#            label="S2", edgecolor="purple", alpha=0.8, linewidth=linewidth)
#    ax[0].set_ylim([y0min,y0max])
#
#    y0min, y0max = ax[1].get_ylim()
#    jitScat(0.05, 0.5, NT0, ax[1],
#            facecolors='none',marker='o', markerSize=markerSize,
#            label="NT", edgecolor="purple", alpha=0.8, linewidth=linewidth)
#    jitScat(0.05, 1.5, NT1, ax[1],
#            facecolors='none',marker='^', markerSize=markerSize,
#            label="S0", edgecolor="purple", alpha=0.8, linewidth=linewidth)
#    jitScat(0.05, 2.5, NT2, ax[1],
#            facecolors='none',marker='s', markerSize=markerSize,
#            label="S1", edgecolor="purple", alpha=0.8, linewidth=linewidth)
#    jitScat(0.05, 3.5, NT3, ax[1],
#            facecolors='none',marker='D', markerSize=markerSize,
#            label="S2", edgecolor="purple", alpha=0.8, linewidth=linewidth)
#    ax[1].set_ylim([y0min,y0max])

    #ax[0].text(0.5,200,"N=21",fontsize=20)
    #ax[0].text(1.5,750,"N=21",fontsize=20)
    #ax[0].text(2.5,420,"N=42",fontsize=20)
    #ax[1].text(0.5,160,"N=21",fontsize=20)
    #ax[1].text(1.5,160,"N=21",fontsize=20)
    #ax[1].text(2.5,100,"N=21",fontsize=20)

    plt.tight_layout()
    plt.savefig("boxPlots_2.jpg")
    plt.close()