# programme permettant de créer, écouter et jouer à des histoires intéractives

# fait par Didier Mathias

import tkinter as tk
from tkinter import messagebox
from modules import module_lecture_fichier as read
"""
ajouter un menu d'aide et d'option
"""

def choix(dossier, root = None):
    """
    fonction qui affiche la liste des choix possibles dans un dossier
    parametres:
        dossier, une chaine de caracteres avec le nom du dossier
        root, optionnel, à mentionner si on ne souhaite pas changer de fenetre
    renvoie une fenetre tkinter avec la liste des choix possibles
    """
    liste = read.lister_fichier(dossier)

    if root == None:
        root = tk.Tk()
    else:
        # on nettoie la fenetre
        for c in root.winfo_children():
            c.destroy()

    root.title("Listes des Histoires")
    root.config(bg = "#87CEEB")

    zoneMenu = tk.Frame(root, borderwidth=3, bg='darkblue')
    zoneMenu.grid(row = 0, column = 0, columnspan = len(liste), sticky="NSEW")

    voix = tk.BooleanVar()
    ChoixVoix = tk.Checkbutton(zoneMenu, text='Voix', width='10', borderwidth=2, bg='gray', activebackground='darkorange', relief = "raised",variable = voix, onvalue = True, offvalue = False)
    ChoixVoix.grid(row=0, column=0, sticky="NSEW")

    Ajout = tk.Button(zoneMenu, text = 'Ajout', width='10', borderwidth=2, bg='gray', relief = "raised", command = lambda x=[root, dossier] : ajout(x[0], x[1]))
    Ajout.grid(row=0, column=1, sticky="NSEW")

    """
    ajouter un menu pour changer le font des textes : voir font dans histoire
    changer grid(zoneMenu)
    """

    for i_titre in range(len(liste)):
        # on ouvre un pack.png avec une image a afficher en row 1 column i_titre
        tk.Button(root, height = 5, width = 20, text = liste[i_titre], command = lambda x=[liste[i_titre], voix] : histoire(root, dossier + "/" + x[0], x[1].get())).grid(row = 2, column = i_titre, sticky="NSEW")

    grid(root, 3, len(liste))
    grid(zoneMenu, 1, 2)

    root.mainloop()

def histoire(root, dossier, voix = False):
    """
    fonction qui permet de raconter une histoire au format tkinter
    parametres:
        root, le fenetre tkinter dans laquelle se déroule l'histoire
        dossier, une chaine de caracteres avec le nom du dossier
        voix, optionnel, permet de d'activer la voix synthétique, par défaut False
    """
    root.title(dossier)

    # on nettoie la fenetre
    for c in root.winfo_children():
        c.destroy()

    narration = read.lire_fichier(dossier + "/narration.md")

    def detail_etapes(narration):
        etapes = {}
        i_ligne = 0
        while i_ligne < len(narration):

            if narration[i_ligne][0] == "#":
                numero = narration[i_ligne].split("\r")[0]

                etapes[numero] = []
                i_ligne += 1
                if ":" in narration[i_ligne]:
                    image = narration[i_ligne].split(" : ")[1]
                else:
                    image = ""
                etapes[numero] += [image]
                i_ligne += 1

                texte = ""
                while narration[i_ligne][0] not in ["/", "!"]:
                    texte += narration[i_ligne]
                    i_ligne += 1

                etapes[numero] += [texte]

                choix = []
                while narration[i_ligne][0] != "!":
                    separation = narration[i_ligne][1:].split("/")
                    texte = separation[0]

                    nbr = separation[1].split("\r")[0]
                    choix += [[texte, nbr]]
                    i_ligne += 1

                etapes[numero] += [choix]

            i_ligne += 1
        return etapes

    etapes = detail_etapes(narration)

    i = tk.StringVar()
    i.set("#0")
    forme = [("Comic Sans MS", 15, "bold"), ("Comic Sans MS", 10, "bold")]

    while True:
        nbr = i.get()
        for c in root.winfo_children():
            c.destroy()

        etape = etapes[nbr]
        nbr_column = len(etape[2])

        """
        image en 0-nbr_column 0
        """
        titre = tk.Label(root, text = etape[1], font = forme[0], bg = "#87CEEB")

        if voix:
            parole = ""
            for j in etape[1].split("\r"):
                parole += j + " "
            parler(parole)

            parole_fin = {}
            for j in etape[2]:
                parole_fin[j[1]] = j[0]

        if nbr_column > 0:
            titre.grid(row = 1, column = 0, columnspan = nbr_column, sticky="NSEW")
        else:
            titre.grid(row = 1, column = 0, sticky="NSEW")

        if nbr_column == 0:
            break

        else:
            taille =  "%dp" % (titre.winfo_reqwidth() // nbr_column)
            for i_choix in range(nbr_column):
                tk.Button(root,text = etape[2][i_choix][0], wraplength = taille, font = forme[1], command = lambda x=etape[2][i_choix][1] : i.set(x), bg = "#87CEEB", activebackground = "#87CEEB").grid(row = 2, column = i_choix, sticky="NSEW")

        """
        grid() ne fonctionne pas :
            peut-être taille fenetre : modifier la taille de la fenetre à chaque fois
            grille déjà grande avant : créer une frame le contenu de la fenetre et on le supprime à la place d'enlever chaque élément / changer les zones de création et les suppressions et les grid(root)
        """
        grid(root, 1, nbr_column)

        root.wait_variable(i)
        if voix:
            parole = parole_fin[i.get()]
            parler(parole)

    # FIN
    if voix:
        parler("   FIN")

    tk.Button(root, text = "Fin", font = forme[1], command = lambda x=[dossier, root] : choix(x[0].split("/")[0], x[1]), bg = "#87CEEB", activebackground = "#87CEEB").grid(row = 2, column = 0, sticky="NSEW")

def ajout(root, dossier):
    """
    fonction permettant d'ajouter une histoire
    parametres:
        root, une fenetre tkinter
    """
    def plus():
        """
        sous-fonction qui permet d'ajouter un morceau à l'histoire
        """
        lettres = caracteres(texte.get("1.0", "end"))

        dif_choix = [i.split("/") for i in choice.get("1.0", "end").split("\n")][:-1]
        faire = []
        good = True
        if not fin.get():
            for i in dif_choix:
                if len(i) != 2: # trouver pour éviter qu'il n'y ait pas de reference
                    good = False

        if numero.get() == "":
            messagebox.showerror("Erreur numéro", "Mauvais numéro")
            """
            si checkbox image, vérifier qu'une image a été mise
            """
        elif len(lettres) < 2 and (" " in lettres or "\n" in lettres):
            messagebox.showerror("Erreur texte", "Il faut un texte")
        elif not good:
            messagebox.showerror("Erreur choix", 'Un choix par ligne avec le choix et le numero séparés par "/"')
        elif numero.get() in etapes.keys():
            if messagebox.askyesno("Changement", "Voulez-vous modifier ce numéro ?"):
                etapes[numero.get()] = [texte.get("1.0", "end"), choice.get("1.0", "end")]
        else:
            tk.Button(schema, text=numero.get(), command = lambda x="%s" % numero.get() : restaurer(x, etapes[x][0], etapes[x][1])).grid(row=ligne.get(), column=0, sticky="NSEW")
            grid(schema,ligne.get() ,0)
            ligne.set(ligne.get() + 1)
            if fin.get():
                etapes[numero.get()] = [texte.get("1.0", "end"), False]
            else:
                etapes[numero.get()] = [texte.get("1.0", "end"), choice.get("1.0", "end")]
            """
            si image, la mettre en 3
            """

    def restaurer(N, T, C):
        """
        sous-fonction qui permet d'afficher un morceau dans la fenetre
        parametres:
            N, la référence
            T, le texte
            C, les choix
        """
        numero.set(N)
        texte.delete("1.0", "end")
        if C == False:
            choice.configure(state = "normal")
            choice.delete("1.0", "end")
            choice.configure(state = "disabled")
            fin.set(True)
            f.select()
        else:
            fin.set(False)
            f.deselect()
            choice.configure(state = "normal")
            choice.delete("1.0", "end")
            choice.insert("1.0", C)

        texte.insert("1.0", T)
        """
        restaurez image
        """

    def valider():
        """
        sous-fonction qui permet de construire le dossier qui contiendrat l'histoire
        """
        if not "0" in etapes.keys():
            messagebox.showerror("Pas de début", "Il manque le début d'indice 0")
            """
            vérifier si tous peut fonctionner :
                les references dites existe dans etapes sinon erreur
                les images sont ouvrables
                # il y a une fin
            """
        else:
            titre = str(input("Quel est le titre de votre histoire ?"))
            while read.fichier_existe(dossier + "/" + titre):
                titre = str(input("Ce titre existe déjà, choissisez-en un autre."))
            """
            demander image de l'histoire
            """
            chemin = dossier + "/" + titre
            read.add_repertoire(dossier, titre)

            read.add_repertoire(chemin, "images")

            """
            mettres les images enregistrées
            """

            # changer etapes en 1 fichier
            narration = ""

            for reference, contenu in etapes.items():
                narration += "#" + reference + "\r"
                narration += "False"
                """
                remplacer "False" par "image" si checkbox image
                """
                for L in contenu[0].split("\n"):
                    if L != "":
                        narration += "\r" + L

                if contenu[1] != False:
                    for C in [i.split("/") for i in contenu[1].split("\n")][:-1]:
                        if C != ['']:
                            narration += "\r/ " + C[0] + " /#" + C[1]

                narration += "\r!\r\r"

            read.add_fichier(chemin, "narration.md", narration)
            choix(dossier.split("/")[0], root)

    def vue():
        if fin.get():
            choice.configure(state = "normal")
            fin.set(False)
        else:
            choice.configure(state = "disabled")
            fin.set(True)

    etapes = {}
    root.title("Ajout")

    # on nettoie la fenetre
    for c in root.winfo_children():
        c.destroy()

    """
    schema visuel a  implementer
    schema sous forme de Canvas
    """
    schema = tk.Frame(root, bg = "#87CEEB", borderwidth=3)
    ligne = tk.IntVar()
    ligne.set(0)

    schema.grid(row = 0, rowspan = 6, column = 1, sticky='NSEW')

    # numero
    tk.Label(root, text = "Numéro :", bg = "#87CEEB").grid(row = 0, column = 0, sticky="w")
    numero = tk.StringVar()
    tk.Entry(root, textvariable = numero, width = 40).grid(row = 1, column = 0, sticky='NSEW')

    """
    mettre checkbox image
    si cocher, il faut ouvrir une image
    sinon case désactiver

    on ouvre l'image avec un ouvrir puis on parcours les fichiers
    """

    # texte
    label_texte = tk.Label(root, text = "Texte :", bg = "#87CEEB").grid(row = 2, column = 0, sticky="w")
    texte = tk.Text(root, height = 10, width = 30)
    texte.grid(row = 3, column = 0, sticky='NSEW')

    # choix
    fin = tk.BooleanVar()
    fin.set(False)
    f = tk.Checkbutton(root, text='Choix possible :', width='10', borderwidth=2, bg='#87CEEB', command = lambda x=fin : vue())
    f.grid(row=4, column=0, sticky="w")

    tk.Label(root, text="texte_choix / reference", bg = "#87CEEB").grid(row = 4, column = 0, sticky="e")

    choice = tk.Text(root, height = 10, width = 30)
    choice.grid(row = 5, column = 0, sticky='NSEW')

    # plus
    tk.Button(root, text="+", bg = "#87CEEB", command=plus).grid(row=6, column=0, sticky="NSEW")

    # validation
    tk.Button(root, text="Valider", bg = "#87CEEB", command=valider).grid(row=6, column=1, sticky="NSEW")

    grid(root, 6, 2)
    root.minsize(width=700, height=600)

def grid(root, R, C):
    for i in range(R):
        root.grid_rowconfigure(i, weight=1)
    for i in range(C):
        root.grid_columnconfigure(i, weight=1)

def parler(texte):
    """
    fonction permettant de dire un texte --> Text-to-Speech
    parametres:
        texte, une chaine de caracteres à dire
    """
    import pyttsx3

    engine = pyttsx3.init()
    engine.setProperty('rate', 150) # mettre rate à 150 permet d'avoir un débit raisonnable

    engine.say(texte)
    engine.runAndWait()

def caracteres(texte):
    """
    fonction permettant d'obtenir une liste de tous les caracteres distinct présent dans une chaine de caracteres
    parametres:
        texte, une chaine de caracteres
    renvoie une liste de caracteres
    """
    lettres = []

    for caractere in texte:
        if caractere not in lettres:
            lettres += [caractere]

    return lettres

if __name__ == '__main__':
    choix("histoires")


import os
from azureml.pipeline.steps import PythonScriptStep
from azureml.core.runconfig import RunConfiguration
from azureml.core.conda_dependencies import CondaDependencies
from azureml.pipeline.core import PipelineData
from azureml.pipeline.core import PipelineParameter
from azureml.pipeline.steps import EstimatorStep
from azureml.train.dnn import PyTorch

def evaluate_step(model_dir, test_dir, compute_target):
    '''
    This step evaluates the trained model on the testing data and outputs the accuracy.

    :param model_dir: The reference to the directory containing the trained model
    :type model_dir: DataReference
    :param test_dir: The reference to the directory containing the testing data
    :type test_dir: DataReference
    :param compute_target: The compute target to run the step on
    :type compute_target: ComputeTarget

    :return: The evaluate step, step outputs dictionary (keys: accuracy_file)
    :rtype: EstimatorStep, dict
    '''

    accuracy_file = PipelineData(
        name='accuracy_file',
        pipeline_output_name='accuracy_file',
        datastore=test_dir.datastore,
        output_mode='mount',
        is_directory=False)

    outputs = [accuracy_file]
    outputs_map = { 'accuracy_file': accuracy_file }

    estimator = PyTorch(
        source_directory=os.path.dirname(os.path.abspath(__file__)),
        entry_script='evaluate.py',
        framework_version='1.3',
        compute_target=compute_target,
        use_gpu=True)

    step = EstimatorStep(
        name="Evaluate Model",
        estimator=estimator,
        estimator_entry_script_arguments=[
            '--test_dir', test_dir,
            '--model_dir', model_dir,
            '--accuracy_file', accuracy_file
        ],
        inputs=[model_dir, test_dir],
        outputs=outputs,
        compute_target=compute_target,
        allow_reuse=True)

    return step, outputs_map


import sys
from  random import randint
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QTableWidget, \
    QHBoxLayout, QVBoxLayout, QWidget, QLabel, QLineEdit, QPushButton
from PyQt5.QtGui import QColor
import csv

class MyWidget(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setGeometry(300, 300, 500, 400)
        self.tableWidget = QTableWidget(self)
        self.loadTable('price.csv')

    def loadTable(self, table_name):
        self.w = QWidget()
        self.setCentralWidget(self.w)
        self.vbox = QVBoxLayout(self.w)
        with open(table_name, encoding="utf8") as csvfile:
            reader = csv.reader(csvfile, delimiter=';', quotechar='"')
            title = next(reader)
            self.tableWidget.setColumnCount(3)
            self.tableWidget.setHorizontalHeaderLabels(title + ['Количество'])
            self.tableWidget.setRowCount(0)
            for i, row in enumerate(reader):
                self.tableWidget.setRowCount(self.tableWidget.rowCount() + 1)
                for j, elem in enumerate(row):
                    self.tableWidget.setItem(i, j, QTableWidgetItem(elem))
        for i in range(self.tableWidget.rowCount()):
            self.tableWidget.setItem(i, 2, QTableWidgetItem('0'))
        self.tableWidget.itemSelectionChanged.connect(self.recount)
        self.vbox.addWidget(self.tableWidget)
        self.hbox = QHBoxLayout(self)
        self.vbox.addLayout(self.hbox)
        self.label = QLabel('итого', self)
        self.line = QLineEdit(self)
        self.line.setDisabled(True)
        self.hbox.addWidget(self.label)
        self.hbox.addWidget(self.line)
        self.btn = QPushButton('обновить', self)
        self.hbox.addWidget(self.btn)
        self.btn.clicked.connect(self.updt)

    def recount(self):
        s = 0
        for i in range(self.tableWidget.rowCount()):
            s += int(self.tableWidget.item(i, 1).text()) * int(self.tableWidget.item(i, 2).text())
        self.line.setText(str(s))

    def updt(self):
        # rows = sorted([self.tableWidget.row(i) for i in range(self.tableWidget.rowCount())], key=lambda x: int(x[1]))
        rows = []
        for i in range(self.tableWidget.rowCount()):
            rows.append([self.tableWidget.item(i, j).text() for j in range(self.tableWidget.columnCount())])
        rows.sort(key=lambda x: int(x[1]), reverse=True)
        for i, row in enumerate(rows):
            for j, elem in enumerate(row):
                self.tableWidget.setItem(i, j, QTableWidgetItem(elem))
        if len(rows) >= 5:
            for i in range(5):
                self.rand_color_row(i)
        else:
            for i in range(len(rows)):
                self.rand_color_row(i)

    def rand_color_row(self, row):
        color = QColor(randint(0, 255), randint(0, 255), randint(0, 255))
        for i in range(self.tableWidget.columnCount()):
            self.tableWidget.item(row, i).setBackground(color)

app = QApplication(sys.argv)
ex = MyWidget()
ex.show()
sys.exit(app.exec_())


import xarray as xr

def join_new(dsets, dim_name, coord_value, varname, options={}):
    if isinstance(varname, str):
        varname = [varname]
    concat_dim = xr.DataArray(coord_value, dims=(dim_name), name=dim_name)
    return xr.concat(dsets, dim=concat_dim, data_vars=varname, **options)

def join_existing(dsets, options={}):
    return xr.concat(dsets, **options)

def union(dsets, options={}):
    return xr.merge(dsets, **options)

def _to_nested_dict(df):
    """Converts a multiindex series to nested dict"""
    if hasattr(df.index, 'levels') and len(df.index.levels) > 1:
        ret = {}
        for k, v in df.groupby(level=0):
            ret[k] = _to_nested_dict(v.droplevel(0))
        return ret
    else:
        return df.to_dict()

def _create_asset_info_lookup(
    df, path_column_name, variable_column_name=None, data_format=None, format_column_name=None
):

    if data_format:
        data_format_list = [data_format] * len(df)
    elif format_column_name is not None:
        data_format_list = df[format_column_name]

    if variable_column_name is None:
        varname_list = [None] * len(df)
    else:
        varname_list = df[variable_column_name]

    return dict(zip(df[path_column_name], tuple(zip(varname_list, data_format_list))))

def _aggregate(
    aggregation_dict,
    agg_columns,
    n_agg,
    v,
    lookup,
    mapper_dict,
    zarr_kwargs,
    cdf_kwargs,
    preprocess,
):
    def apply_aggregation(v, agg_column=None, key=None, level=0):
        """Recursively descend into nested dictionary and aggregate items.
        level tells how deep we are."""

        assert level <= n_agg

        if level == n_agg:
            # bottom of the hierarchy - should be an actual path at this point
            # return open_dataset(v)
            data_format = lookup[v][1]
            # Get varname in order to specify data_vars=[varname] during concatenation
            # See https://github.com/NCAR/intake-esm/issues/172#issuecomment-549001751
            varname = lookup[v][0]
            ds = _open_asset(
                mapper_dict[v],
                data_format=data_format,
                zarr_kwargs=zarr_kwargs,
                cdf_kwargs=cdf_kwargs,
                preprocess=preprocess,
            )
            ds.attrs['intake_esm_varname'] = varname
            return ds

        else:
            agg_column = agg_columns[level]

            agg_info = aggregation_dict[agg_column]
            agg_type = agg_info['type']

            if 'options' in agg_info:
                agg_options = agg_info['options']
            else:
                agg_options = {}

            dsets = [
                apply_aggregation(value, agg_column, key=key, level=level + 1)
                for key, value in v.items()
            ]
            keys = list(v.keys())

            attrs = dict_union(*[ds.attrs for ds in dsets])

            # copy encoding for each variable from first encounter
            variables = set([v for ds in dsets for v in ds.variables])

            encoding = {}
            for ds in dsets:
                for v in variables:
                    if v in ds.variables and v not in encoding:
                        if ds[v].encoding:
                            encoding[v] = ds[v].encoding
                            # get rid of the misleading file-specific attributes
                            # github.com/pydata/xarray/issues/2550
                            for enc_attrs in ['source', 'original_shape']:
                                if enc_attrs in encoding[v]:
                                    del encoding[v][enc_attrs]

            if agg_type == 'join_new':
                varname = dsets[0].attrs['intake_esm_varname']
                ds = join_new(
                    dsets,
                    dim_name=agg_column,
                    coord_value=keys,
                    varname=varname,
                    options=agg_options,
                )

            elif agg_type == 'join_existing':
                ds = join_existing(dsets, options=agg_options)

            elif agg_type == 'union':
                ds = union(dsets, options=agg_options)

            ds.attrs = attrs
            for v in ds.variables:
                if v in encoding and not ds[v].encoding:
                    ds[v].encoding = encoding[v]

            return ds

    return apply_aggregation(v)

def _open_asset(path, data_format, zarr_kwargs, cdf_kwargs, preprocess):

    if data_format == 'zarr':
        ds = xr.open_zarr(path, **zarr_kwargs)

    else:
        ds = xr.open_dataset(path, **cdf_kwargs)

    if preprocess is None:
        return ds
    else:
        return preprocess(ds)

def dict_union(*dicts, merge_keys=['history', 'tracking_id'], drop_keys=[]):
    """Return the union of two or more dictionaries."""
    from functools import reduce

    if len(dicts) > 2:
        return reduce(dict_union, dicts)
    elif len(dicts) == 2:
        d1, d2 = dicts
        d = type(d1)()
        # union
        all_keys = set(d1) | set(d2)
        for k in all_keys:
            v1 = d1.get(k)
            v2 = d2.get(k)
            if (v1 is None and v2 is None) or k in drop_keys:
                pass
            elif v1 is None:
                d[k] = v2
            elif v2 is None:
                d[k] = v1
            elif v1 == v2:
                d[k] = v1
            elif k in merge_keys:
                d[k] = '\n'.join([v1, v2])
        return d
    elif len(dicts) == 1:
        return dicts[0]


import numpy as np
import pandas as pd
import statsmodels.api as sm

loansData = pd.read_csv('loansData.csv')
intrate = loansData['Interest.Rate']
loanamt = loansData['Amount.Requested']
fico = loansData['FICO.Score']

# The dependent variable
y = np.matrix(intrate).transpose()
# The independent variables shaped as columns
x1 = np.matrix(fico).transpose()
x2 = np.matrix(loanamt).transpose()
x = np.column_stack([x1,x2])

X = sm.add_constant(x)
model = sm.OLS(y,X)
f = model.fit()


# %%
import pyspark
from pyspark import SparkContext
from pyspark.sql import SparkSession, Row
from pyspark.sql.types import StructField, StringType, StructType, LongType
from pyspark.sql.functions import col, column, expr

# %%
def get_spark_context():
    sc = SparkContext()
    sc.stop()
    conf = pyspark.SparkConf().setAll(
        [('spark.executor.cores', '4'),
         ('spark.cores.max', '4'),
         ('spark.executor.memory', '16g'),
         ('spark.driver.extraJavaOptions', '-Xms4096m -Xmx4096m -XX:MaxPermSize=4096m -XX:MaxNewSize=4096')])
    spark = SparkSession.builder.config(conf=conf).getOrCreate()
    return spark

# %%
sc = get_spark_context()

# %%
my_manual_schema = StructType([
    StructField('DEST_COUNTRY_NAME', StringType(), True),
    StructField('ORIGIN_COUNTRY_NAME', StringType(), True),
    StructField('count', LongType(), False, metadata={'hello': 'world'})
])
df = sc.read.format('json').schema(my_manual_schema).load('data/flight-data/json/2015-summary.json')
# %%
df.printSchema()
print(df.schema)
# %%
df.columns
# %%
df.first()
# %%
r_1 = Row('Hejka', 12, 1, False, None)
r_1[0]
r_1[2]
# %%


# -*- coding: utf-8 -*-
from flask import Flask,render_template
from flask.ext.bootstrap import Bootstrap, WebCDN, ConditionalCDN, BOOTSTRAP_VERSION, JQUERY_VERSION, HTML5SHIV_VERSION, RESPONDJS_VERSION
from flask.ext.moment import Moment
from datetime import datetime
import sys

#py2 unicode
reload(sys)
sys.setdefaultencoding('utf-8')
app = Flask(__name__)
bootstrap = Bootstrap(app)
moment = Moment(app)

def change_cdn_domestic(tar_app):
    """
    中国特色 flask-bootstrap
    源码来自 新浪微博 @蛋-壳-酱 万分感谢！
    :param tar_app:
    :return:
    """
    static = tar_app.extensions['bootstrap']['cdns']['static']
    local = tar_app.extensions['bootstrap']['cdns']['local']

    def change_one(tar_lib, tar_ver, fallback):
        tar_js = ConditionalCDN('BOOTSTRAP_SERVE_LOCAL', fallback,
                                WebCDN('//cdn.bootcss.com/' + tar_lib + '/' + tar_ver + '/'))
        tar_app.extensions['bootstrap']['cdns'][tar_lib] = tar_js

    libs = {'jquery': {'ver': JQUERY_VERSION, 'fallback': local},
            'bootstrap': {'ver': BOOTSTRAP_VERSION, 'fallback': local},
            'html5shiv': {'ver': HTML5SHIV_VERSION, 'fallback': static},
            'respond.js': {'ver': RESPONDJS_VERSION, 'fallback': static}}
    for lib, par in libs.items():
        change_one(lib, par['ver'], par['fallback'])

change_cdn_domestic(app)

@app.route('/')
def index():
    return render_template('index.html', current_time=datetime.utcnow())

@app.route('/user/<name>')
def hello_world(name):
    return render_template('user.html', name=name)

@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404

@app.errorhandler(500)
def internal_server_error(e):
    return render_template('500.html'), 500

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


import itertools as it

import numpy as np
import pandas as pd

from utils.statistics import significance_test, fdr_corrected_pvals

def initialize_empty_columns_at_index(dataframe, row_index):
    # I have to do this ugly thing here because initializing with 3 nans is somehow not possible because pandas sets
    # the dtype of the cell as float instead ob object
    dataframe.loc[row_index, 'config_has_run'] = False
    dataframe.loc[row_index, 'mse_train'] = False
    dataframe.loc[row_index, 'mse_valid'] = False
    dataframe.loc[row_index, 'mse_test'] = False
    dataframe.loc[row_index, 'corr_train'] = False
    dataframe.loc[row_index, 'corr_valid'] = False
    dataframe.loc[row_index, 'corr_test'] = False
    dataframe.loc[row_index, 'corr_p_train'] = False
    dataframe.loc[row_index, 'corr_p_valid'] = False
    dataframe.loc[row_index, 'corr_p_test'] = False
    dataframe.loc[row_index, 'r^2_train'] = False
    dataframe.loc[row_index, 'r^2_valid'] = False
    dataframe.loc[row_index, 'r^2_test'] = False
    return dataframe

def prefill_columns_configuration_at_index(dataframe, row_index, has_run):
    dataframe.loc[row_index, 'config_has_run'] = has_run
    dataframe.loc[row_index, 'mse_train'] = [[np.nan], [np.nan], [np.nan]]
    dataframe.loc[row_index, 'mse_valid'] = [[np.nan], [np.nan], [np.nan]]
    dataframe.loc[row_index, 'mse_test'] = [[np.nan], [np.nan], [np.nan]]
    dataframe.loc[row_index, 'corr_train'] = [[np.nan], [np.nan], [np.nan]]
    dataframe.loc[row_index, 'corr_valid'] = [[np.nan], [np.nan], [np.nan]]
    dataframe.loc[row_index, 'corr_test'] = [[np.nan], [np.nan], [np.nan]]
    dataframe.loc[row_index, 'corr_p_train'] = [[np.nan], [np.nan], [np.nan]]
    dataframe.loc[row_index, 'corr_p_valid'] = [[np.nan], [np.nan], [np.nan]]
    dataframe.loc[row_index, 'corr_p_test'] = [[np.nan], [np.nan], [np.nan]]
    dataframe.loc[row_index, 'r^2_train'] = [[np.nan], [np.nan], [np.nan]]
    dataframe.loc[row_index, 'r^2_valid'] = [[np.nan], [np.nan], [np.nan]]
    dataframe.loc[row_index, 'r^2_test'] = [[np.nan], [np.nan], [np.nan]]
    return dataframe

def fill_results_in_configurations_at_index(dataframe, row_index, df, i_subject):
    if len(df) == 12:
        dataframe.loc[row_index, 'mse_train'][i_subject] = df.values[0, 1]
        dataframe.loc[row_index, 'mse_valid'][i_subject] = df.values[4, 1]
        dataframe.loc[row_index, 'mse_test'][i_subject] = df.values[8, 1]
        dataframe.loc[row_index, 'corr_train'][i_subject] = df.values[1, 1]
        dataframe.loc[row_index, 'corr_valid'][i_subject] = df.values[5, 1]
        dataframe.loc[row_index, 'corr_test'][i_subject] = df.values[9, 1]
        dataframe.loc[row_index, 'corr_p_train'][i_subject] = df.values[2, 1]
        dataframe.loc[row_index, 'corr_p_valid'][i_subject] = df.values[6, 1]
        dataframe.loc[row_index, 'corr_p_test'][i_subject] = df.values[10, 1]
        dataframe.loc[row_index, 'r^2_train'][i_subject] = df.values[3, 1]
        dataframe.loc[row_index, 'r^2_valid'][i_subject] = df.values[7, 1]
        dataframe.loc[row_index, 'r^2_test'][i_subject] = df.values[11, 1]
    elif len(df) == 9:
        print('WARNING! Residual result df missing r^2 (len = 9)!')
        dataframe.loc[row_index, 'mse_train'][i_subject] = df.values[0, 1]
        dataframe.loc[row_index, 'mse_valid'][i_subject] = df.values[3, 1]
        dataframe.loc[row_index, 'mse_test'][i_subject] = df.values[6, 1]
        dataframe.loc[row_index, 'corr_train'][i_subject] = df.values[1, 1]
        dataframe.loc[row_index, 'corr_valid'][i_subject] = df.values[4, 1]
        dataframe.loc[row_index, 'corr_test'][i_subject] = df.values[7, 1]
        dataframe.loc[row_index, 'corr_p_train'][i_subject] = df.values[2, 1]
        dataframe.loc[row_index, 'corr_p_valid'][i_subject] = df.values[5, 1]
        dataframe.loc[row_index, 'corr_p_test'][i_subject] = df.values[8, 1]
    else:
        print('Unknown result df format of len: {}'.format(len(df)))
        exit()
    # if configurations.loc[i_config, 'model_name'] in ['deep4', 'eegnet', 'resnet']:
    #     for column_name in df.columns:
    #         if column_name == 'train_loss':
    #             configurations.loc[i_config, 'mse_train'][i_subject] = df.tail(1)[column_name].values[0]#, 1]
    #         if column_name == 'valid_loss':
    #             configurations.loc[i_config, 'mse_valid'][i_subject] = df.tail(1)[column_name].values[0]#, 2]
    #         if column_name == 'test_loss':
    #             configurations.loc[i_config, 'mse_test'][i_subject] = df.tail(1)[column_name].values[0]#, 3]
    #         if column_name == 'train_corr':
    #             configurations.loc[i_config, 'corr_train'][i_subject] = df.tail(1)[column_name].values[0]#, 4]
    #         if column_name == 'valid_corr':
    #             configurations.loc[i_config, 'corr_valid'][i_subject] = df.tail(1)[column_name].values[0]#, 5]
    #         if column_name == 'test_corr':
    #             configurations.loc[i_config, 'corr_test'][i_subject] = df.tail(1)[column_name].values[0]#, 6]
    # elif configurations.loc[i_config, 'model_name'] in ['lin_reg', 'lin_svr', 'rbf_svr', 'rf_reg']:
    #     dataframe.loc[row_index, 'mse_train'][i_subject] = df.values[0, 1]
    #     dataframe.loc[row_index, 'mse_valid'][i_subject] = df.values[4, 1]
    #     dataframe.loc[row_index, 'mse_test'][i_subject] = df.values[8, 1]
    #     dataframe.loc[row_index, 'corr_train'][i_subject] = df.values[1, 1]
    #     dataframe.loc[row_index, 'corr_valid'][i_subject] = df.values[5, 1]
    #     dataframe.loc[row_index, 'corr_test'][i_subject] = df.values[9, 1]
    #     dataframe.loc[row_index, 'corr_p_train'][i_subject] = df.values[2, 1]
    #     dataframe.loc[row_index, 'corr_p_valid'][i_subject] = df.values[6, 1]
    #     dataframe.loc[row_index, 'corr_p_test'][i_subject] = df.values[10, 1]
    # else:
    #     print('Unknown model name: {}'.format(configurations.loc[i_config, 'model_name']))
    #     break
    return dataframe

def max_of_each_entry(df, label_key, value_key):
    max_value = []
    for unique_label in np.unique(df[label_key]):
        max_value.append(np.max(df[df[label_key] == unique_label][value_key]))

    return max_value

def get_dataframe_values_matching_two_criteria_in_two_columns(dataframe, condition_col, condition_name,
                                                              metric_name_col, metric_name, metric_value_col):
    return dataframe[(dataframe[condition_col] == condition_name)
                     & (dataframe[metric_name_col] == metric_name)][metric_value_col].values

def dataframe_significance_test(dataframe, condition_col, condition_name_a, condition_name_b, metric_name_col,
                                metric_name, metric_value_col):
    a = get_dataframe_values_matching_two_criteria_in_two_columns(dataframe, condition_col, condition_name_a,
                                                                  metric_name_col, metric_name, metric_value_col)
    b = get_dataframe_values_matching_two_criteria_in_two_columns(dataframe, condition_col, condition_name_b,
                                                                  metric_name_col, metric_name, metric_value_col)

    return significance_test(a, b, alpha=0.5, alternative='two-sided', use_continuity=True)

def single_value_row_configurations(configurations, subject_values):
    # Reformat configuration dataframe to have one row per metric value
    single_value_configurations = pd.DataFrame()
    for i_config in range(len(configurations)):
        for metric in ['mse', 'corr', 'corr_p', 'r^2']:
            for data_split in ['train', 'valid', 'test']:
                for i_subject in range(len(subject_values)):
                    single_value_configurations = single_value_configurations.append(
                        pd.DataFrame({'subject_train': subject_values[i_subject],
                                      'subject_apply': subject_values[i_subject],
                                      'data_split': data_split,
                                      'metric_value': configurations[metric + '_' + data_split][i_config][i_subject],
                                      'metric_name': metric,
                                      'data': configurations.loc[i_config, 'data'],
                                      'electrodes': configurations.loc[i_config, 'electrodes'],
                                      'band_pass': configurations.loc[i_config, 'band_pass'],
                                      'model_name': configurations.loc[i_config, 'model_name'],
                                      'unique_id': configurations.loc[i_config, 'unique_id'],
                                      'data_folder': configurations.loc[i_config, 'data_folder'],
                                      'batch_size': configurations.loc[i_config, 'batch_size'],
                                      'max_epochs': configurations.loc[i_config, 'max_epochs'],
                                      'cuda': configurations.loc[i_config, 'cuda'],
                                      'result_folder': configurations.loc[i_config, 'result_folder'],
                                      'init_lr': configurations.loc[i_config, 'init_lr'],
                                      'weight_decay': configurations.loc[i_config, 'weight_decay'],
                                      'sampling_rate': configurations.loc[i_config, 'sampling_rate'],
                                      'n_seconds_valid_set': configurations.loc[i_config, 'n_seconds_valid_set'],
                                      'n_seconds_test_set': configurations.loc[i_config, 'n_seconds_test_set'],
                                      'config_has_run': configurations.loc[i_config, 'config_has_run']}, index=[0]),
                        ignore_index=True)
    return single_value_configurations

def remove_columns_with_same_value(df, exclude=('train',)):
    cols_multiple_vals = []
    for col in df.columns:
        try:
            values_set = set(df[col])
            has_multiple_vals = len(values_set) > 1
            if has_multiple_vals:
                all_nans = np.all(np.isnan(values_set))
        except TypeError:
            all_nans = False
            # transform to string in case there are lists
            # since lists not hashable to set
            has_multiple_vals = len(set([str(val) for val in df[col]])) > 1
        cols_multiple_vals.append((has_multiple_vals and (not all_nans)))
    cols_multiple_vals = np.array(cols_multiple_vals)
    excluded_cols = np.array([c in exclude for c in df.columns])
    df = df.iloc[:, (cols_multiple_vals | excluded_cols)]
    return df

def print_performance_matrix(dataframe,
                             x_col,
                             y_col,
                             metric_name_col,
                             metric_name,
                             metric_value_col,
                             averaging_func=np.median,
                             transformation_func=lambda x: x,
                             fmt=':3f'):
    performance_matrix = compute_performance_matrix(dataframe,
                                                    x_col,
                                                    y_col,
                                                    metric_name_col,
                                                    metric_name,
                                                    metric_value_col,
                                                    averaging_func=averaging_func,
                                                    transformation_func=transformation_func)[0]
    # format(performance_matrix, fmt)
    # latex_tabular = " \\\\\n".join([" & ".join(map(str, line)) for line in performance_matrix])
    print(" \\\\\n".join([" & ".join(map('{0:.3f}'.format, line)) for line in performance_matrix]))
    # print(latex_tabular.)

def compute_performance_matrix(dataframe,
                               x_col,
                               y_col,
                               metric_name_col,
                               metric_name,
                               metric_value_col,
                               averaging_func=np.median,
                               transformation_func=lambda x: x):
    x_values, x_indices = np.unique(dataframe[x_col], return_index=True)
    x_values = x_values[np.argsort(x_indices)]
    x_indices = range(len(x_values))
    y_values, y_indices = np.unique(dataframe[y_col], return_index=True)
    y_values = y_values[np.argsort(y_indices)]
    y_indices = range(len(y_values))
    performance_matrix = np.ndarray((len(x_indices), len(y_indices)))
    for x, y in it.product(range(len(x_indices)), range(len(y_indices))):
        a = transformation_func(dataframe[(dataframe[x_col] == x_values[x]) &
                                          (dataframe[y_col] == y_values[y]) &
                                          (dataframe[metric_name_col] == metric_name)][metric_value_col].values)
        if np.size(a) > 1:
            performance_matrix[x, y] = averaging_func(a)
        else:
            performance_matrix[x, y] = a
    return performance_matrix, x_values, y_values

def compute_diff_matrix(dataframe, condition_col, metric_name_col='metric_name', metric_name='rmse',
                        metric_value_col='metric_value', averaging_func=np.median):
    condition_values, condition_indices = np.unique(dataframe[condition_col], return_index=True)
    condition_values = condition_values[np.argsort(condition_indices)]
    condition_indices = range(len(condition_values))
    diff_matrix = np.ndarray((len(condition_indices), len(condition_indices)))
    significance_matrix = np.ndarray(diff_matrix.shape)
    for x, y in it.product(range(len(condition_indices)), range(len(condition_indices))):
        a = get_dataframe_values_matching_two_criteria_in_two_columns(
            dataframe,
            condition_col,
            condition_values[x],
            metric_name_col,
            metric_name,
            metric_value_col)
        b = get_dataframe_values_matching_two_criteria_in_two_columns(
            dataframe,
            condition_col,
            condition_values[y],
            metric_name_col,
            metric_name,
            metric_value_col)
        if np.size(a) >= 10:
            diff_matrix[x, y] = averaging_func(a) - averaging_func(b)
        else:
            diff_matrix[x, y] = averaging_func(a - b)
        significance_matrix[x, y] = significance_test(a, b, alpha=0.5, alternative='two-sided', use_continuity=True)
    tril_indices = np.tril_indices_from(significance_matrix, k=-1)
    significance_matrix[tril_indices] = fdr_corrected_pvals(significance_matrix[tril_indices])
    return diff_matrix, significance_matrix, condition_values

def expand_row_with_multiple_values(df, column):
    new_df = df
    for row in df.index:
        for column in df.iloc[row]:
            tmp = np.size(column)
            if tmp > 1:
                new_df


from django.db import models
from api.managers import InvitationManager
from django.contrib.auth.models import User
from api.models import Curso

class Invitation(models.Model):

    code = models.CharField(max_length=50, unique=True)

    issued_by = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='issued_by'
    )
    used_by = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        null=True,
    )

    curso = models.ForeignKey(Curso, on_delete=models.CASCADE)

    used = models.BooleanField(default=False)
    used_at = models.DateTimeField(blank=True, null=True)

    # Manager
    objects = InvitationManager()

    def __str__(self):

        return '#{}: {}'.format(self.curso.curso, self.code)


import tensorflow.keras.backend as K
import tensorflow as tf

from tensorflow_addons.layers import InstanceNormalization
from tensorflow.keras.layers import Layer, Input, Conv2D, Activation, add, BatchNormalization, UpSampling2D, ZeroPadding2D, Conv2DTranspose, Flatten, MaxPooling2D, AveragePooling2D, InputSpec, LeakyReLU, Dense

from tensorflow.keras.initializers import RandomNormal
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.backend import mean
from tensorflow.keras.models import Model, model_from_json
from tensorflow.keras.utils import plot_model
from tensorflow.python.keras.engine.network import Network

import random
import datetime
import time
import json
import math
import csv
import sys
from os.path import join, exists
from os import mkdir, makedirs
import numpy as np

# sys.path.append('../')
#import load_data

from factories.optimizer_factory import Optimizer_Factory
from layers.reflection_padding_2d import ReflectionPadding2D
from metrics.loss_functions import lse, cycle_loss

def save_img(img, fname):
    if len(tf.shape(img)) > 3:
        img = img[tf.constant(0),:,:,:]
    img = (img + 1) / 2.0
    result_img = tf.image.encode_png(tf.image.convert_image_dtype(img, dtype=tf.uint8))
    tf.io.write_file(tf.constant(fname), result_img)

class ImagePool():
    def __init__(self, pool_size):
        self.pool_size = pool_size
        if self.pool_size > 0:
            self.num_imgs = 0
            self.images = []

    def query(self, images):
        if self.pool_size == 0:
            return images
        return_images = []
        for image in images:
            if len(image.shape) == 3:
                image = image[np.newaxis, :, :, :]

            if self.num_imgs < self.pool_size:  # fill up the image pool
                self.num_imgs = self.num_imgs + 1
                if len(self.images) == 0:
                    self.images = image
                else:
                    self.images = np.vstack((self.images, image))

                if len(return_images) == 0:
                    return_images = image
                else:
                    return_images = np.vstack((return_images, image))

            else:  # 50% chance that we replace an old synthetic image
                p = random.uniform(0, 1)
                if p > 0.5:
                    random_id = random.randint(0, self.pool_size - 1)
                    tmp = self.images[random_id, :, :, :]
                    tmp = tmp[np.newaxis, :, :, :]
                    self.images[random_id, :, :, :] = image[0, :, :, :]
                    if len(return_images) == 0:
                        return_images = tmp
                    else:
                        return_images = np.vstack((return_images, tmp))
                else:
                    if len(return_images) == 0:
                        return_images = image
                    else:
                        return_images = np.vstack((return_images, image))

        return return_images

class CycleGAN():
    """docstring for CycleGAN."""

    def __init__(self, cf):
        self.model = None
        self.cf = cf

        # from Keras documentation: Total number of steps (batches of samples) to yield from generator before declaring one epoch finished and starting the next epoch. It should typically be equal to the number of unique samples of your dataset divided by the batch size.
        if(cf.n_images_train is not None):
            self.steps_per_epoch = int(np.ceil(cf.n_images_train / float(cf.batch_size_train)))
        else:
            samplesTrainA = self.get_file_len(cf.trainA_file_path_full)
            samplesTrainB = self.get_file_len(cf.trainB_file_path_full)
            samplesTrain = max(samplesTrainA, samplesTrainB)
            self.steps_per_epoch = int(np.ceil(samplesTrain / float(cf.batch_size_train)))
            # zzh
            # self.steps_per_epoch = int(np.ceil(get_file_len(cf.train_file_path_full) / float(cf.batch_size_train)))
            # self.validation_steps = int(np.ceil(get_file_len(cf.valid_file_path_full) / float(cf.batch_size_valid)))
            # samplesTestA = self.get_file_len(cf.testA_file_path_full)
            # samplesTestB = self.get_file_len(cf.testB_file_path_full)
            # samplesTest = max(samplesTestA, samplesTestB)
            # self.test_steps = int(np.ceil(samplesTest / float(cf.batch_size_valid)))

    def get_file_len(self, file_path_full):
        return len(["" for line in open(file_path_full, "r")])

    def make_discriminators(self):
        # ======= Discriminator model ==========
        if self.cf.use_multiscale_discriminator:
            D_A = self.modelMultiScaleDiscriminator()
            D_B = self.modelMultiScaleDiscriminator()
            loss_weights_D = [0.5, 0.5] # 0.5 since we train on real and synthetic images
        else:
            D_A = self.modelDiscriminator()
            D_B = self.modelDiscriminator()
            loss_weights_D = [0.5]  # 0.5 since we train on real and synthetic images

        # Discriminator builds
        image_A = Input(shape=self.cf.input_shape)
        image_B = Input(shape=self.cf.input_shape)
        guess_A = D_A(image_A)
        guess_B = D_B(image_B)
        self.D_A = Model(inputs=image_A, outputs=guess_A, name='D_A_model')
        self.D_B = Model(inputs=image_B, outputs=guess_B, name='D_B_model')

        # self.D_A.summary()
        # self.D_B.summary()
        optimizer_D = Optimizer_Factory().make(self.cf.optimizer, self.cf.learning_rate_D)
        self.D_A.compile(optimizer=optimizer_D,
                         loss=lse,
                         loss_weights=loss_weights_D)
        self.D_B.compile(optimizer=optimizer_D,
                         loss=lse,
                         loss_weights=loss_weights_D)

        # Use Networks to avoid falsy keras error about weight descripancies
        self.D_A_static = Network(inputs=image_A, outputs=guess_A, name='D_A_static_model')
        self.D_B_static = Network(inputs=image_B, outputs=guess_B, name='D_B_static_model')

        # Do note update discriminator weights during generator training
        self.D_A_static.trainable = False
        self.D_B_static.trainable = False

    def make_generators(self):
        # Generators
        self.G_A2B = self.modelGenerator(name='G_A2B_model')
        self.G_B2A = self.modelGenerator(name='G_B2A_model')
        # self.G_A2B.summary()

        optimizer_G = Optimizer_Factory().make(self.cf.optimizer, self.cf.learning_rate_G)

        if self.cf.use_identity_learning:
            self.G_A2B.compile(optimizer=optimizer_G, loss='MAE')
            self.G_B2A.compile(optimizer=optimizer_G, loss='MAE')

        # Generator builds
        real_A = Input(shape=self.cf.input_shape, name='real_A')
        real_B = Input(shape=self.cf.input_shape, name='real_B')
        synthetic_B = self.G_A2B(real_A)
        synthetic_A = self.G_B2A(real_B)
        dA_guess_synthetic = self.D_A_static(synthetic_A)
        dB_guess_synthetic = self.D_B_static(synthetic_B)
        reconstructed_A = self.G_B2A(synthetic_B)
        reconstructed_B = self.G_A2B(synthetic_A)

        model_outputs = [reconstructed_A, reconstructed_B]
        compile_losses = [cycle_loss, cycle_loss,
                          lse, lse]
        compile_weights = [self.cf.lambda_1, self.cf.lambda_2,
                           self.cf.lambda_D, self.cf.lambda_D]

        if self.cf.use_multiscale_discriminator:
            for _ in range(2):
                compile_losses.append(lse)
                compile_weights.append(self.cf.lambda_D)  # * 1e-3)  # Lower weight to regularize the model
            for i in range(2):
                model_outputs.append(dA_guess_synthetic[i])
                model_outputs.append(dB_guess_synthetic[i])
        else:
            model_outputs.append(dA_guess_synthetic)
            model_outputs.append(dB_guess_synthetic)

        if self.cf.use_supervised_learning:
            model_outputs.append(synthetic_A)
            model_outputs.append(synthetic_B)
            compile_losses.append('MAE')
            compile_losses.append('MAE')
            compile_weights.append(self.cf.supervised_weight)
            compile_weights.append(self.cf.supervised_weight)

        self.model = Model(inputs=[real_A, real_B],
                             outputs=model_outputs,
                             name='G_model')

        self.model.compile(optimizer=optimizer_G,
                             loss=compile_losses,
                             loss_weights=compile_weights)
        # self.G_A2B.summary()

    def make(self):
        # Build model
        self.make_discriminators()
        print(' Build discriminators successfully...')
        # make generators
        self.make_generators()
        print(' Build generators successfully...')

        # Load pretrained weights
        # zzh
        if not self.cf.load_pretrained:
            print(' No loading pretrained weights...')
        elif not exists(join(self.cf.savepath, 'pretrained_weights')):
            print(' No pretrained weights exist...')
            return
        else:
            self.load_pretrained_weights(self.G_A2B)
            self.load_pretrained_weights(self.G_B2A)
            self.load_pretrained_weights(self.D_A)
            self.load_pretrained_weights(self.D_B)
            print(' Load pretrained weights successfully...')

        # if self.cf.resume_training:
        #     model.load_weights(cf.checkpoint_path)

        # Show model structure
        if self.cf.show_model:
            model.summary()
            plot_model(model, to_file=join(self.cf.savepath, 'model.png'))

        # Output the model
        print('   Model: ' + self.cf.model_name)

    # Learning rate #
    def get_lr_linear_decay_rate(self, max_nr_images):
        # Calculate decay rates
        updates_per_epoch_D = 2 * max_nr_images + self.cf.discriminator_iterations - 1
        updates_per_epoch_G = max_nr_images + self.cf.generator_iterations - 1
        if self.cf.use_identity_learning:
            updates_per_epoch_G *= (1 + 1 / self.cf.identity_mapping_modulus)
        denominator_D = (self.cf.n_epochs - self.cf.decay_epoch) * updates_per_epoch_D
        denominator_G = (self.cf.n_epochs - self.cf.decay_epoch) * updates_per_epoch_G
        decay_D = self.cf.learning_rate_D / denominator_D
        decay_G = self.cf.learning_rate_G / denominator_G

        return decay_D, decay_G

    def update_lr(self, model, decay):
        new_lr = K.get_value(model.optimizer.lr) - decay
        if new_lr < 0:
            new_lr = 0
        # print(K.get_value(model.optimizer.lr))
        K.set_value(model.optimizer.lr, new_lr)

    # Images #
    def save_tmp_images(self, real_image_A, real_image_B, synthetic_image_A, synthetic_image_B):
        try:
            reconstructed_image_A = self.G_B2A.predict(synthetic_image_B)
            reconstructed_image_B = self.G_A2B.predict(synthetic_image_A)

            real_images = np.vstack((real_image_A[0], real_image_B[0]))
            synthetic_images = np.vstack((synthetic_image_B[0], synthetic_image_A[0]))
            reconstructed_images = np.vstack((reconstructed_image_A[0], reconstructed_image_B[0]))

            # save path
            result_path = join(self.cf.savepath, 'tmp_images')
            if exists(result_path) == False:
                mkdir(result_path)

            # write images
            save_img(real_image_A[0,:,:,:], join(result_path, 'realA.png'))
            save_img(real_image_B[0,:,:,:], join(result_path, 'realB.png'))
            save_img(synthetic_image_A[0,:,:,:], join(result_path, 'syntheticA.png'))
            save_img(synthetic_image_B[0,:,:,:], join(result_path, 'syntheticB.png'))
            save_img(reconstructed_image_A[0,:,:,:], join(result_path, 'reconstructedA.png'))
            save_img(reconstructed_image_B[0,:,:,:], join(result_path, 'reconstructedB.png'))

        except: # Ignore if file is open
            pass

    def saveImages(self, epoch, real_image_A, real_image_B, num_saved_images=1):
        result_path = join(self.cf.savepath, 'images')
        # if not exists(join(result_path, 'A')):
        #     makedirs(join(result_path, 'A'))
        #     makedirs(join(result_path, 'B'))
        #     makedirs(join(result_path, 'Atest'))
        #     makedirs(join(result_path, 'Btest'))

        for i in range(num_saved_images):
            # if i == num_saved_images:
            #     real_image_A = self.A_test[0]
            #     real_image_B = self.B_test[0]
            #     real_image_A = np.expand_dims(real_image_A, axis=0)
            #     real_image_B = np.expand_dims(real_image_B, axis=0)
            #     testString = 'test'
            #
            # else:
            #     #real_image_A = self.A_train[rand_A_idx[i]]
            #     #real_image_B = self.B_train[rand_B_idx[i]]
            #     if len(real_image_A.shape) < 4:
            #         real_image_A = np.expand_dims(real_image_A, axis=0)
            #         real_image_B = np.expand_dims(real_image_B, axis=0)

            synthetic_image_B = self.G_A2B.predict(real_image_A)
            synthetic_image_A = self.G_B2A.predict(real_image_B)
            reconstructed_image_A = self.G_B2A.predict(synthetic_image_B)
            reconstructed_image_B = self.G_A2B.predict(synthetic_image_A)

            # write images
            print("SHAPE")
            print(tf.shape(real_image_A))
            save_img(real_image_A[i,:,:,:], join(result_path, str(epoch) + '_' + str(i) + '_realA.png'))
            save_img(real_image_B[i,:,:,:], join(result_path, str(epoch) + '_' + str(i) + '_realB.png'))
            save_img(synthetic_image_A[i,:,:,:], join(result_path, str(epoch) + '_' + str(i) + '_syntheticA.png'))
            save_img(synthetic_image_B[i,:,:,:], join(result_path, str(epoch) + '_' + str(i) + '_syntheticB.png'))
            save_img(reconstructed_image_A[i,:,:,:], join(result_path, str(epoch) + '_' + str(i) + '_reconstructedA.png'))
            save_img(reconstructed_image_B[i,:,:,:], join(result_path, str(epoch) + '_' + str(i) + '_reconstructedB.png'))

    # Training #
    def print_ETA(self, start_time, epoch, loop_index):
        passed_time = time.time() - start_time

        iterations_so_far = ((epoch - 1) * self.steps_per_epoch + loop_index) / self.cf.batch_size_train
        iterations_total = self.cf.n_epochs * self.steps_per_epoch / self.cf.batch_size_train
        iterations_left = iterations_total - iterations_so_far
        eta = round(passed_time / (iterations_so_far + 1e-5) * iterations_left)

        passed_time_string = str(datetime.timedelta(seconds=round(passed_time)))
        eta_string = str(datetime.timedelta(seconds=eta))
        print('Time passed', passed_time_string, ': ETA in', eta_string)

    def _run_training_iteration(self, loop_index, epoch, real_images_A, real_images_B, ones, zeros, synthetic_pool_A, synthetic_pool_B):
        # ======= Discriminator training ==========
            # Generate batch of synthetic images
        synthetic_images_B = self.G_A2B.predict(real_images_A)
        synthetic_images_A = self.G_B2A.predict(real_images_B)
        synthetic_images_A = synthetic_pool_A.query(synthetic_images_A)
        synthetic_images_B = synthetic_pool_B.query(synthetic_images_B)

        for _ in range(self.cf.discriminator_iterations):
            DA_loss_real = self.D_A.train_on_batch(x=real_images_A, y=ones)
            DB_loss_real = self.D_B.train_on_batch(x=real_images_B, y=ones)
            DA_loss_synthetic = self.D_A.train_on_batch(x=synthetic_images_A, y=zeros)
            DB_loss_synthetic = self.D_B.train_on_batch(x=synthetic_images_B, y=zeros)
            if self.cf.use_multiscale_discriminator:
                DA_loss = sum(DA_loss_real) + sum(DA_loss_synthetic)
                DB_loss = sum(DB_loss_real) + sum(DB_loss_synthetic)
                print('DA_losses: ', np.add(DA_loss_real, DA_loss_synthetic))
                print('DB_losses: ', np.add(DB_loss_real, DB_loss_synthetic))
            else:
                DA_loss = DA_loss_real + DA_loss_synthetic
                DB_loss = DB_loss_real + DB_loss_synthetic
            D_loss = DA_loss + DB_loss

            if self.cf.discriminator_iterations > 1:
                print('D_loss:', D_loss)
                sys.stdout.flush()

        '''
        # zzh
        directory = join(self.cf.savepath, 'saved_models')
        if not exists(directory):
            makedirs(directory)
        temp_D_A_PATH = join(directory,'temp_D_A')
        temp_D_B_PATH = join(directory, 'temp_D_B')
        self.D_A.save_weights(temp_D_A_PATH)
        self.D_A_static.load_weights(temp_D_A_PATH)
        self.D_B.save_weights(temp_D_B_PATH)
        self.D_B_static.load_weights(temp_D_B_PATH)
        '''
        # ======= Generator training ==========
        target_data = [real_images_A, real_images_B]  # Compare reconstructed images to real images
        if self.cf.use_multiscale_discriminator:
            for i in range(2):
                target_data.append(ones[i])
                target_data.append(ones[i])
        else:
            target_data.append(ones)
            target_data.append(ones)

        if self.cf.use_supervised_learning:
            target_data.append(real_images_A)
            target_data.append(real_images_B)

        for _ in range(self.cf.generator_iterations):
            G_loss = self.model.train_on_batch(x=[real_images_A, real_images_B], y=target_data)
            if self.cf.generator_iterations > 1:
                print('G_loss:', G_loss)
                sys.stdout.flush()

        gA_d_loss_synthetic = G_loss[1]
        gB_d_loss_synthetic = G_loss[2]
        reconstruction_loss_A = G_loss[3]
        reconstruction_loss_B = G_loss[4]

        # Identity training
        if self.cf.use_identity_learning and loop_index % self.cf.identity_mapping_modulus == 0:
            G_A2B_identity_loss = self.G_A2B.train_on_batch(
                x=real_images_B, y=real_images_B)
            G_B2A_identity_loss = self.G_B2A.train_on_batch(
                x=real_images_A, y=real_images_A)
            print('G_A2B_identity_loss:', G_A2B_identity_loss)
            print('G_B2A_identity_loss:', G_B2A_identity_loss)

        # Update learning rates
        if self.cf.use_linear_decay and epoch > self.cf.decay_epoch:
            self.update_lr(self.D_A, self.decay_D)
            self.update_lr(self.D_B, self.decay_D)
            self.update_lr(self.model, self.decay_G)

        # Store training data
        self.training_history['DA_losses'].append(DA_loss)
        self.training_history['DB_losses'].append(DB_loss)
        self.training_history['gA_d_losses_synthetic'].append(gA_d_loss_synthetic)
        self.training_history['gB_d_losses_synthetic'].append(gB_d_loss_synthetic)
        self.training_history['gA_losses_reconstructed'].append(reconstruction_loss_A)
        self.training_history['gB_losses_reconstructed'].append(reconstruction_loss_B)

        GA_loss = gA_d_loss_synthetic + reconstruction_loss_A
        GB_loss = gB_d_loss_synthetic + reconstruction_loss_B
        reconstruction_loss = reconstruction_loss_A + reconstruction_loss_B

        self.training_history['D_losses'].append(D_loss)
        self.training_history['G_losses'].append(G_loss)
        self.training_history['reconstruction_losses'].append(reconstruction_loss)

        # GA_losses.append(GA_loss)
        # GB_losses.append(GB_loss)

        print('\n')
        print('Epoch----------------', epoch, '/', self.cf.n_epochs)
        print('Loop index----------------', loop_index + 1, '/', self.steps_per_epoch)
        print('D_loss: ', D_loss)
        print('G_loss: ', G_loss[0])
        print('reconstruction_loss: ', reconstruction_loss)
        print('DA_loss:', DA_loss)
        print('DB_loss:', DB_loss)

        if loop_index % 20 == 0:
            # Save temporary images continously
            #self.save_tmp_images(real_images_A, real_images_B, synthetic_images_A, synthetic_images_B)
            self.print_ETA(self.start_time, epoch, loop_index)

    def train(self, train_gen, cb):
        if (not self.cf.train_model):
            return None

        print('\n > Training the model...')
        # ======================================================================
        # Begin training
        # ======================================================================
        training_history = {}

        DA_losses = []
        DB_losses = []
        gA_d_losses_synthetic = []
        gB_d_losses_synthetic = []
        gA_losses_reconstructed = []
        gB_losses_reconstructed = []

        GA_losses = []
        GB_losses = []
        reconstruction_losses = []
        D_losses = []
        G_losses = []

        self.training_history = {
            'DA_losses': DA_losses,
            'DB_losses': DB_losses,
            'gA_d_losses_synthetic': gA_d_losses_synthetic,
            'gB_d_losses_synthetic': gB_d_losses_synthetic,
            'gA_losses_reconstructed': gA_losses_reconstructed,
            'gB_losses_reconstructed': gB_losses_reconstructed,
            'D_losses': D_losses,
            'G_losses': G_losses,
            'reconstruction_losses': reconstruction_losses}

        # Image pools used to update the discriminators
        synthetic_pool_A = ImagePool(self.cf.synthetic_pool_size)
        synthetic_pool_B = ImagePool(self.cf.synthetic_pool_size)

        # self.saveImages('(init)')

        # Tweaks
        self.REAL_LABEL = 1.0  # Use e.g. 0.9 to avoid training the discriminators to zero loss

        # labels
        if self.cf.use_multiscale_discriminator:
            label_shape1 = (self.cf.batch_size_train,) + self.D_A.output_shape[0][1:]
            label_shape2 = (self.cf.batch_size_train,) + self.D_A.output_shape[1][1:]
            #label_shape4 = (self.cf.batch_size_train,) + self.D_A.output_shape[2][1:]
            ones1 = np.ones(shape=label_shape1) * self.REAL_LABEL
            ones2 = np.ones(shape=label_shape2) * self.REAL_LABEL
            #ones4 = np.ones(shape=label_shape4) * self.REAL_LABEL
            ones = [ones1, ones2]  # , ones4]
            zeros1 = ones1 * 0
            zeros2 = ones2 * 0
            #zeros4 = ones4 * 0
            zeros = [zeros1, zeros2]  # , zeros4]
        else:
            label_shape = (self.cf.batch_size_train,) + self.D_A.output_shape[1:]
            ones = np.ones(shape=label_shape) * self.REAL_LABEL
            zeros = ones * 0

        # Linear decay
        if self.cf.use_linear_decay:
            self.decay_D, self.decay_G = self.get_lr_linear_decay_rate(self.steps_per_epoch * self.cf.n_epochs)

        # Start stopwatch for ETAs
        self.start_time = time.time()

        for epoch in range(1, self.cf.n_epochs + 1):
            loop_index = 1
            for images in train_gen:
                real_images_A = images[0]
                real_images_B = images[1]

                # Run all training steps
                self._run_training_iteration(loop_index, epoch, real_images_A, real_images_B, ones, zeros, synthetic_pool_A, synthetic_pool_B)

                # Store models
                if loop_index % 20000 == 0:
                    self.save_model(self.D_A, loop_index)
                    self.save_model(self.D_B, loop_index)
                    self.save_model(self.G_A2B, loop_index)
                    self.save_model(self.G_B2A, loop_index)

                # Break if loop has ended
                if loop_index >= self.steps_per_epoch:
                    break

                loop_index += 1

            #================== within epoch loop end ==========================

            if epoch % self.cf.save_interval == 0:
                print('\n', '\n', '-------------------------Saving images for epoch', epoch, '-------------------------', '\n', '\n')
                self.saveImages(epoch, real_images_A, real_images_B, tf.shape(real_images_A)[0])

            if epoch % 5 == 0:
                # self.save_model(self.model)
                self.save_model(self.D_A, epoch)
                self.save_model(self.D_B, epoch)
                self.save_model(self.G_A2B, epoch)
                self.save_model(self.G_B2A, epoch)

            self.writeLossDataToFile(self.training_history)

            # Flush out prints each loop iteration
            sys.stdout.flush()

        self.save_model(self.D_A, epoch)
        self.save_model(self.D_B, epoch)
        self.save_model(self.G_A2B, epoch)
        self.save_model(self.G_B2A, epoch)
        print('Training finished.')

    def predict(self, test_gen, tag='pred'):
        pass

    def test(self, test_gen):
        if not self.cf.test_model:
            return
        else:
            test_save_path = join(self.cf.savepath, 'test_results')
            if not exists(test_save_path):
                makedirs(test_save_path)
            print(test_save_path)

        print('\n > Testing the model...')

        # Load best trained model

        # zzh
        start_time = time.time()
        load_epoch = self.cf.load_epoch_for_test
        self.load_model_weights(self.G_A2B, load_epoch)
        self.load_model_weights(self.G_B2A, load_epoch)
        # self.load_model_weights(self.D_A, load_epoch)
        # self.load_model_weights(self.D_B, load_epoch)

        # get correct number of test samples depending on debugging or not
        # if debug, will use n_images_test
        if self.cf.n_images_test is not None:
            nb_test_samples = self.cf.n_images_test
        else:
            samplesTestA = self.get_file_len(self.cf.testA_file_path_full)
            samplesTestB = self.get_file_len(self.cf.testB_file_path_full)
            nb_test_samples = max(samplesTestA, samplesTestB)

        test_steps = int(np.ceil(nb_test_samples / float(self.cf.batch_size_test)))
        # Evaluate model
        index = 0
        for images in test_gen:

            real_images_A_test = images[0]
            real_images_B_test = images[1]

            synthetic_images_B = self.G_A2B.predict_on_batch(real_images_A_test)
            synthetic_images_A = self.G_B2A.predict_on_batch(real_images_B_test)

            recon_images_A = self.G_B2A.predict_on_batch(synthetic_images_B)
            recon_images_B = self.G_A2B.predict_on_batch(synthetic_images_A)

            save_img(real_images_A_test[0,:,:,:], join(test_save_path, 'test_' + str(index) + '_realA.png'))
            save_img(real_images_B_test[0,:,:,:], join(test_save_path, 'test_' + str(index) + '_realB.png'))
            save_img(synthetic_images_A[0,:,:,:], join(test_save_path, 'test_' + str(index) + '_syntheticA.png'))
            save_img(synthetic_images_B[0,:,:,:], join(test_save_path, 'test_' + str(index) + '_syntheticB.png'))
            save_img(recon_images_A[0,:,:,:], join(test_save_path, 'test_' + str(index) + '_reconstructedA.png'))
            save_img(recon_images_B[0,:,:,:], join(test_save_path, 'test_' + str(index) + '_reconstructedB.png'))

            print('\n')
            print('Generate synthetic images for testing---------', index, '/', nb_test_samples)

            index += 1

            if index > test_steps:
                break

        # y_predictions = self.model.predict(test_gen.make_one_shot_iterator(), steps=nb_test_samples)
        # total_time = time.time() - start_time
        # fps = float(nb_test_samples) / total_time
        # s_p_f = total_time / float(nb_test_samples)
        # print ('   Testing time: {}. FPS: {}. Seconds per Frame: {}'.format(total_time, fps, s_p_f))
        #
        # # store predicted labels
        # result_path = join(self.cf.savepath, 'predicted_labels')
        # if exists(result_path) == False:
        #     mkdir(result_path)
        #
        # results = []
        # fp = open(self.cf.test_file_path_full)
        # image_names = fp.readlines()
        # fp.close()
        # for (idx, img_num) in enumerate(image_names):
        #     if idx > nb_test_samples-1:
        #         continue
        #     y_sample_prediction = y_predictions[idx,:,:,:,:]
        #
        #     # print('sample: ' + img_num + ', idx: ' + str(idx))
        #     # print('min: ' + str(np.min(y_sample_prediction)))
        #     # print('max: ' + str(np.max(y_sample_prediction)))
        #
        #     # compress to top probabilty
        #
        #     result = np.argmax(y_sample_prediction, axis=-1)
        #     z=np.shape(result)[-1]
        #     for i in range(z):
        #         img_num = img_num.strip('\n')
        #         save_img(result[:,:,i:i+1], join(result_path, img_num + '_slice'+str(i)+'.png'))

        print('{} pairs of synthetic images have been generated and placed in {}'
              .format(nb_test_samples, test_save_path))
        total_time = time.time() - start_time
        print('Testing time: {}'.format(total_time))
#===============================================================================
# Architecture functions

    def ck(self, x, k, use_normalization):
        # zzh: add init
        init = RandomNormal(stddev=0.02)
        x = Conv2D(filters=k, kernel_size=4, strides=2, padding='same', kernel_initializer=init)(x)
        # Normalization is not done on the first discriminator layer
        if use_normalization:
            x = InstanceNormalization(axis=3, center=True, epsilon=1e-5)(x, training=True)
        x = LeakyReLU(alpha=0.2)(x)
        return x

    def c7Ak(self, x, k):
        init = RandomNormal(stddev=0.02)
        x = Conv2D(filters=k, kernel_size=7, strides=1, padding='valid', kernel_initializer=init)(x)
        x = InstanceNormalization(axis=3, center=True, epsilon=1e-5)(x, training=True)
        x = Activation('relu')(x)
        return x

    def dk(self, x, k):
        init = RandomNormal(stddev=0.02)
        x = Conv2D(filters=k, kernel_size=3, strides=2, padding='same', kernel_initializer=init)(x)
        x = InstanceNormalization(axis=3, center=True, epsilon=1e-5)(x, training=True)
        x = Activation('relu')(x)
        return x

    def Rk(self, x0):
        init = RandomNormal(stddev=0.02)

        k = int(x0.shape[-1])
        # first layer
        x = ReflectionPadding2D((1,1))(x0)
        x = Conv2D(filters=k, kernel_size=3, strides=1, padding='valid', kernel_initializer=init)(x)
        x = InstanceNormalization(axis=3, center=True, epsilon=1e-5)(x, training=True)
        x = Activation('relu')(x)
        # second layer
        x = ReflectionPadding2D((1, 1))(x)
        x = Conv2D(filters=k, kernel_size=3, strides=1, padding='valid', kernel_initializer=init)(x)
        x = InstanceNormalization(axis=3, center=True, epsilon=1e-5)(x, training=True)
        # merge
        x = add([x, x0])
        return x

    def uk(self, x, k):
        init = RandomNormal(stddev=0.02)
        # (up sampling followed by 1x1 convolution <=> fractional-strided 1/2)
        if self.cf.use_resize_convolution:
            x = UpSampling2D(size=(2, 2))(x)  # Nearest neighbor upsampling
            x = ReflectionPadding2D((1, 1))(x)
            x = Conv2D(filters=k, kernel_size=3, strides=1, padding='valid', kernel_initializer=init)(x)
        else:
            x = Conv2DTranspose(filters=k, kernel_size=3, strides=2, padding='same', kernel_initializer=init)(x)  # this matches fractinoally stided with stride 1/2
        x = InstanceNormalization(axis=3, center=True, epsilon=1e-5)(x, training=True)
        x = Activation('relu')(x)
        return x

#===============================================================================
# Models

    def modelMultiScaleDiscriminator(self, name=None):
        x1 = Input(shape=self.cf.input_shape)
        x2 = AveragePooling2D(pool_size=(2, 2))(x1)
        #x4 = AveragePooling2D(pool_size=(2, 2))(x2)

        out_x1 = self.modelDiscriminator('D1')(x1)
        out_x2 = self.modelDiscriminator('D2')(x2)
        #out_x4 = self.modelDiscriminator('D4')(x4)

        return Model(inputs=x1, outputs=[out_x1, out_x2], name=name)

    def modelDiscriminator(self, name=None):
        # Specify input
        input_img = Input(shape=self.cf.input_shape)
        # Layer 1 (#Instance normalization is not used for this layer)
        # C64
        x = self.ck(input_img, 64, False)
        # Layer 2
        # C 128
        x = self.ck(x, 128, True)
        # Layer 3
        # C 256
        x = self.ck(x, 256, True)
        # Layer 4
        # C 512
        x = self.ck(x, 512, True)
        # Output layer
        if self.cf.use_patchgan:
            init = RandomNormal(stddev=0.02)
            x = Conv2D(filters=1, kernel_size=4, strides=1, padding='same', kernel_initializer=init)(x)
        else:
            x = Flatten()(x)
            x = Dense(1)(x)
        #x = Activation('sigmoid')(x) - No sigmoid to avoid near-fp32 machine epsilon discriminator cost
        return Model(inputs=input_img, outputs=x, name=name)

    def modelGenerator(self, name=None):
        init = RandomNormal(stddev=0.02)
        # Specify input
        input_img = Input(shape=self.cf.input_shape)
        # Layer 1
        x = ReflectionPadding2D((3, 3))(input_img)
        '''
        # zzh
        x = self.c7Ak(x, 32)
        # Layer 2
        x = self.dk(x, 64)
        # Layer 3
        x = self.dk(x, 128)

        if self.cf.use_multiscale_discriminator:
            # Layer 3.5
            x = self.dk(x, 256)

        # Layer 4-12: Residual layer
        for _ in range(4, 13):
            x = self.Rk(x)

        if self.cf.use_multiscale_discriminator:
            # Layer 12.5
            x = self.uk(x, 128)

        # Layer 13
        x = self.uk(x, 64)
        # Layer 14
        x = self.uk(x, 32)
        x = ReflectionPadding2D((3, 3))(x)
        x = Conv2D(self.cf.channel_size, kernel_size=7, strides=1)(x)
        x = Activation('tanh')(x)  # They say they use Relu but really they do not
        return Model(inputs=input_img, outputs=x, name=name)
        # zzh
        '''
        # c7s1-64
        x = self.c7Ak(x, 64)
        # Layer 2, d128
        x = self.dk(x, 128)
        # Layer 3, d256
        x = self.dk(x, 256)

        if self.cf.use_multiscale_discriminator:
            # Layer 3.5
            x = self.dk(x, 512)

        # Layer 4-12: Residual layer
        for _ in range(4, 13):
            x = self.Rk(x)

        if self.cf.use_multiscale_discriminator:
            # Layer 12.5
            x = self.uk(x, 256)

        # Layer 13, u128
        x = self.uk(x, 128)
        # Layer 14, u64
        x = self.uk(x, 64)
        x = ReflectionPadding2D((3, 3))(x)
        x = Conv2D(self.cf.channel_size, kernel_size=7, strides=1, padding='valid', kernel_initializer=init)(x)
        x = Activation('tanh')(x)  # They say they use Relu but really they do not
        return Model(inputs=input_img, outputs=x, name=name)
#===============================================================================
# Loading / Saving

    def save_model(self, model, epoch):
        # Create folder to save model architecture and weights
        directory = join(self.cf.savepath, 'saved_models')
        if not exists(directory):
            makedirs(directory)

        # model_path_w = 'saved_models/{}_weights_epoch_{}.hdf5'.format(model.name, epoch)
        model_path_w = join(directory, '{}_weights_epoch_{}.hdf5'.format(model.name, epoch))
        model.save_weights(model_path_w)
        #model_path_m = 'saved_models/{}_model_epoch_{}.json'.format(model.name, epoch)
        model_path_m = join(directory, '{}_model_epoch_{}.json'.format(model.name, epoch))
        model.save_weights(model_path_m)
        json_string = model.to_json()
        with open(model_path_m, 'w') as outfile:
            json.dump(json_string, outfile)
        print('{} has been saved in saved_models'.format(model.name))

    def writeLossDataToFile(self, history):
        keys = sorted(history.keys())
        out_file = join(self.cf.savepath, 'loss_output.csv')
        with open(out_file, 'w') as csv_file:
            writer = csv.writer(csv_file, delimiter=',')
            writer.writerow(keys)
            writer.writerows(zip(*[history[key] for key in keys]))

    #zzh
    def load_model_weights(self, model, epoch):
        # The saved model folder
        directory = join(self.cf.savepath, 'saved_models')
        model_path_w = join(directory, '{}_weights_epoch_{}.hdf5'.format(model.name, epoch))
        model.load_weights(model_path_w)

    def load_pretrained_weights(self, model):
        # The pretrained model folder
        directory = join(self.cf.savepath, 'pretrained_weights')
        # all pretrained models should be save by 'save_weights' with name of 'pretrained_xxx'.
        model_path_w = join(directory, 'pretrained_{}.hdf5'.format(model.name))
        model.load_weights(model_path_w)


import hashlib, random, time, json

def convert_base(num, to_base=10, from_base=10):
    # first convert to decimal number
    if isinstance(num, str):
        n = int(num, from_base)
    else:
        n = int(num)
    # now convert decimal to 'to_base' base
    alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    if n < to_base:
        return alphabet[n]
    else:
        return convert_base(n // to_base, to_base) + alphabet[n % to_base]

block_time = 5 * 60
start = time.time()
finish = start + block_time

print(start)
print(finish)

#exit()

hash_arr = []
obj = json.loads('{"miner_adress": "XIhhtD5BprFlsnObmDyxL5xc5QUCX4uKn6839Y4DBpKsnZRMtmhdeMDfVtkKRIZn", "hash_last_block": "hashaaaaaaaaa", "timestamp": 1513948552.0508235, "difficulty": 50, "bust": 87700948419, "transaction": {"from": "XIhhtD5BprFlsnObmDyxL5xc5QUCX4uKn6839Y4DBpKsnZRMtmhdeMDfVtkKRIZn", "to": "yMqqoiz28LIvvyvJ2VDFOHbd2ggASSTiEBssUSkC9QRZ7Fy3p6LCySh/ok4yWqH0", "count": 10, "fee": 0, "sign": "wnERxJEqC5OWxOGBwelJx0CgDSDpv3T6iFmsK2AOiMG8mSisXKbHieDvVJHwxwyQ"}}')

print(obj)

a = -1

while True:
    a += 1

    obj['bust'] = str(a)
    msg = json.dumps(obj)

    m = hashlib.sha1()
    m.update(msg.encode('utf-8'))
    hash = m.hexdigest()

    digit = convert_base(hash, 10, 16)
    print(digit)
    hash_arr.append(int(digit))

    if (time.time() > finish):
        break

print(len(hash_arr))
print(a)
hash_arr.sort()
print(hash_arr[0])


#hmm_CAD
#Author: Sarah A. Mounho
#Created: 11/18/2019
#Last edited: 12/9/2019
#Description:
#Script to create a bar chart to compare sampled sequences to predicted sequences
#for validation of model
#input:
#transition state matrix where one variable is manipulated to test response to treatment

#Package dependencies: numpy (1.16.4), matplotlib (3.1.1), hmmlearn (0.2.2)
#download instructions for hmmlearn: https://pypi.org/project/hmmlearn/
#Python 3.7.0

#load packages
import numpy as np
from hmmlearn import hmm
import matplotlib.pyplot as plt
import pandas as pd

#set up transition matrixes
#transition matrix
#states:
#healthy_start(0), high bp(1), high ldl(2), smoker(3), heart attack(4), stable/no stent(5), stent(6)
transmat_nobp = np.array([[0.162944787, 0.335688062, 0.329781527, 0.15553875, 0.001300225, 0.014746649, 0],#0
                          [1.0, 0, 0, 0, 0, 0, 0],#1
                          [0.354175611, 0, 0.60305577, 0, 0.003464699, 0.03930392, 0], #2
                          [0.292883373, 0, 0, 0.683394538, 0.001921803, 0.021800286, 0],#3
                          [0, 0, 0, 0, 0.003619055, 0.149457142, 0.846923803],#4
                          [0.612, 0, 0, 0, 0.081, 0, 0.307],#5
                          [0.697, 0, 0, 0, 0.089, 0, 0.214]])#6
transmat_noldl = np.array([[0.162944787, 0.335688062, 0.329781527, 0.15553875, 0.001300225, 0.014746649, 0],#0
                           [0.634635493, 0.298651997, 0, 0, 0.005404855, 0.061307655, 0],#1
                           [1.0, 0, 0, 0, 0, 0, 0], #2
                           [0.292883373, 0, 0, 0.683394538, 0.001921803, 0.021800286, 0],#3
                           [0, 0, 0, 0, 0.003619055, 0.149457142, 0.846923803],#4
                           [0.612, 0, 0, 0, 0.081, 0, 0.307],#5
                           [0.697, 0, 0, 0, 0.089, 0, 0.214]])#6
transmat_nosmoker = np.array([[0.162944787, 0.335688062, 0.329781527, 0.15553875, 0.001300225, 0.014746649, 0],#0
                              [0.634635493, 0.298651997, 0, 0, 0.005404855, 0.061307655, 0],#1
                              [0.354175611, 0, 0.60305577, 0, 0.003464699, 0.03930392, 0], #2
                              [1.0, 0, 0, 0, 0, 0, 0],#3
                              [0, 0, 0, 0, 0.003619055, 0.149457142, 0.846923803],#4
                              [0.612, 0, 0, 0, 0.081, 0, 0.307],#5
                              [0.697, 0, 0, 0, 0.089, 0, 0.214]])#6

def hmm_CAD_inverse(transmat, name):

    #settings for plots
    plt.rcParams.update({'font.size': 25})
    plt.rc('xtick', labelsize=30)
    plt.rc('ytick', labelsize=30)

    #set seed
    np.random.seed(1998)

    #always start healthy
    #when setting random seed, observed that starting state
    #did not have an impact on samples/predictions
    startprob = np.array([1.0, 0, 0, 0, 0, 0, 0])

    #emission states healthy_end(1), hospitilization(2), death(3)
    emission_prob = np.array([[0, 0, 0], #1
                              [0, 0, 0], #2
                              [0, 0, 0], #3
                              [0, 0, 0], #4
                              [0, 0, 0.14], #5
                              [0.279, 0.325, 0.091], #6
                              [0.35, 0.357, 0.089]]) #7
    #create an instance of the model
    model = hmm.MultinomialHMM(n_components=7)
    model.startprob_ = startprob
    model.transmat_ = transmat
    model.emissionprob_ = emission_prob
    #draw samples given the startprob, transmat and emissionprob
    X, Z = model.sample(100)
    X_array = np.array(X)

    #plt the emmission data
    plt.plot(X, '.-', label='observations', ms=6,
             mfc='orange', alpha=0.7)
    #indicate emission
    emit = ['Healthy', 'Hospitalized', 'Dead']
    plt.xlabel('Iteration')
    ticks = [0, 1, 2]
    plt.yticks(ticks, emit, rotation = 60)
    plt.legend(loc='best')
    plt.title('Observation Sampled Sequence')
    plt.show()

    #train the model
    #training HMM parameters and inferring the hidden state sequence
    #based on the sampled outcome sequence
    remodel = hmm.MultinomialHMM(n_components=7, n_iter=100)
    remodel.fit(X)

    #predict hidden states
    prob, sequence = remodel.decode(X)
    #log probabilitity of the produced state sequence (only meaningful in comparison of models)
    #may use to discern differences in different random seeds on model accuracy
    ##print('prob:\n',prob) #uncomment if testing different random seeds.

    #visualize sampled hidden state sequence and predicted hidden state sequence
    #plot the sampled data (transition-hidden states)
    plt.plot(Z, '.-', label='sampled', ms=6,
             mfc = 'orange', alpha=0.7)
    plt.plot(sequence, '.-', label='predicted', ms=6,
              mfc='black', alpha=0.7)
    #indicate component numbers
    states = ['Healthy', 'High BP', 'High LDL', 'Smoker', 'Heart\nattack', 'Stable\nno stent', 'Stent']
    plt.xlabel('Iteration')
    ticks = [0, 1, 2, 3, 4, 5, 6]
    plt.yticks(ticks, states)
    plt.legend(loc='best')
    plt.title('Hidden State Sampled and Predicted Sequence')
    plt.show()

    #validate the results
    print()
    sample_outcome_count = pd.value_counts(X_array.flatten())
    print('Counts for', name,':')
    print('Counts for sampled outcomes:\n', sample_outcome_count)
    print()
    sample_state_count = pd.value_counts(Z)
    print('Counts for sampled states:\n', sample_state_count)
    print()
    predict_state_count = pd.value_counts(sequence)
    print('Counts for predicted outcomes:\n', predict_state_count)
hmm_CAD_inverse(transmat_nobp, 'Managed BP')
hmm_CAD_inverse(transmat_noldl, 'Managed LDL Cholesterol')
hmm_CAD_inverse(transmat_nosmoker, 'Managed Smoking')

#Function Treatment_Response
#input: counts for [healthy, hospitalized, dead] for
#normal, managed bp, managed ldl, and managed smoking
#outputs from hmm_CAD.py and inverseMC_CAD hmm_CAD_inverse
#output:
#bar chart comparing observation count

#inputs
all_risk = [93, 6, 1]
no_bp = [95, 4, 1]
no_ldl = [96, 3, 1]
no_smoke = [93, 6, 1]

def Treatment_Response(all_risk, no_bp, no_ldl, no_smoke):
    #bar charts
    import matplotlib
    import matplotlib.pyplot as plt
    import numpy as np
    #settings for plots
    plt.rcParams.update({'font.size': 25})
    plt.rc('xtick', labelsize=30)
    plt.rc('ytick', labelsize=30)

    labels = ['Healthy', 'Hospitalized', 'Dead']
    x = np.arange(len(labels))
    width = 0.1

    fig, ax = plt.subplots()
    rects1 = ax.bar(x -0.15, all_risk, width, label='Normal')
    rects2 = ax.bar(x-0.05, no_bp, width, label='Managed blood pressure')
    rects3 = ax.bar(x+0.05, no_ldl, width, label='Managed LDL cholesterol')
    rects4 = ax.bar(x+0.15, no_smoke, width, label='Managed smoking')

    ax.set_ylabel('Count')
    ax.set_title('Counts of observations')
    ax.set_xticks(x)
    ax.set_xticklabels(labels)
    ax.legend()

    def autolabel(rects):
        for rect in rects:
            height = rect.get_height()
            ax.annotate('{}'.format(height),
                        xy=(rect.get_x() + rect.get_width() / 2, height),
                        xytext=(0, 3),  # 3 points vertical offset
                        textcoords="offset points",
                        ha='center', va='bottom')
    autolabel(rects1)
    autolabel(rects2)
    autolabel(rects3)
    autolabel(rects4)
    plt.show()

Treatment_Response(all_risk, no_bp, no_ldl, no_smoke)


import unittest
from datetime import datetime

from dateutil.tz import tzutc, tzlocal

from t77_date.tz import to_utc

class ToUtcTestCase(unittest.TestCase):
    def test_datetime_in_utc(self):
        value_in = datetime.now(tz=tzutc())
        value_out = to_utc(value_in)
        self.assertIsInstance(value_out, datetime)
        self.assertEqual(value_out.tzinfo, tzutc())
        self.assertEqual(value_out, value_in)

    def test_datetime_in_local(self):
        value_in = datetime.now(tz=tzlocal())
        value_out = to_utc(value_in)
        self.assertIsInstance(value_out, datetime)
        self.assertEqual(value_out.tzinfo, tzutc())

    def test_datetime_without_tzinfo(self):
        value_in = datetime.now()
        value_out = to_utc(value_in)
        self.assertIsInstance(value_out, datetime)
        self.assertEqual(value_out.tzinfo, tzutc())

    def test_invalid_input(self):
        now = datetime.now()
        with self.assertRaises(ValueError):
            to_utc(None)
        with self.assertRaises(ValueError):
            to_utc(now.toordinal())
        with self.assertRaises(ValueError):
            to_utc(now.isoformat())