from openpyxl import load_workbook, Workbook
from django.core.management import BaseCommand
from django.db.utils import IntegrityError
from nomenclature.models import *

SERVICE_TYPES = [
    'Not defined',
    'ПРОФ',
    'Лабораторное исследование',
    'Коммерческий профиль',
    'Услуга'
]

class Command(BaseCommand):

    def handle(self, *args, **kwargs):

        ServiceType.objects.all().delete()

        for type in SERVICE_TYPES:
            new_type = ServiceType(name=type)
            new_type.save()

        Group.objects.all().delete()
        SubGroup.objects.all().delete()

        wb = load_workbook('nomenclature/data/Список групп и подгрупп.xlsx', read_only=True)
        first_sheet = wb.worksheets[0]
        groups = {}

        for row in first_sheet.rows:
            if str(row[0].value) not in groups.keys():
                groups[str(row[0].value)] = {'name':str(row[1].value), 'subgroups':[]}
                groups[str(row[0].value)]['subgroups'].append({'number':str(row[2].value), 'name':str(row[3].value)})
                continue

            groups[str(row[0].value)]['subgroups'].append({'number':str(row[2].value), 'name':str(row[3].value)})

        for group in groups.keys():
            new_group = Group(number=group, name=groups[group]['name'])
            new_group.save()
            for sg in groups[group]['subgroups']:
                new_sg = SubGroup(number=sg['number'], name=sg['name'], group=new_group)
                new_sg.save()

        new_group = Group(number='99', name='не определена!')
        new_group.save()
        new_sg = SubGroup(number='99', name='не определена!', group=new_group)
        new_sg.save()

        Service.objects.all().delete()
        wb = load_workbook('nomenclature/data/nomenclature.xlsx', read_only=True)
        first_sheet = wb.worksheets[0]

        for row in first_sheet:
            if row[0].value is not None:
                try:
                    gr = Group.objects.get(number=str(row[0].value))
                except:
                    print(f'группа {row[0].value} не найдена, для теста {row[7].value}')
            else:
                try:
                    gr = Group.objects.get(number='99')
                except:
                    print(f'группа 99 не найдена, для теста {row[7].value}')

            if row[1].value is not None:
                try:
                    sg = SubGroup.objects.get(number=str(row[1].value), group=gr)
                except:
                    print(f'подгруппа {row[1].value} не найдена, для теста {row[7].value}')
            else:
                try:
                    sg = SubGroup.objects.get(number='99')
                except:
                    print(f'подгруппа 99 не найдена, для теста {row[7].value}')

            if row[3].value is not None:
                type = ServiceType.objects.get(name=row[3].value)
            else:
                type = ServiceType.objects.get(name='Not defined')

            if type.name == 'Коммерческий профиль':
                new_record = Profile()
            else:
                new_record = Service()

            try:
                new_record.subgroup=sg
                new_record.salesability=True
                new_record.clients_group=row[2].value
                new_record.type=type
                new_record.classifier_1с=row[4].value
                new_record.tcle_code=row[5].value
                new_record.tcle_abbreviation=row[6].value
                new_record.code=row[7].value
                new_record.name=row[8].value
                new_record.blanks=row[9].value
                new_record.biomaterials=row[10].value
                new_record.container=row[11].value
                new_record.result_type=row[12].value
                new_record.due_date=row[13].value

                new_record.save()
            except IntegrityError:
                print(f'код {row[7].value} - не уникальный, второй раз не добавлен')

        profiles = Profile.objects.all()
        for profile in profiles:
            profile.services.clear()

        wb = load_workbook('nomenclature/data/profile.xlsx', read_only=True)
        first_sheet = wb.worksheets[0]

        for row in first_sheet.rows:
            try:
                profile = Profile.objects.get(code=row[0].value)
            except:
                print(f'Профиля {row[0].value} нет в номенклатуре')

            try:
                service = Service.objects.get(code=row[1].value)
            except:
                print(f'Услуги {row[1].value} нет в номенклатуре')
                continue

            profile.services.add(service)

        wb = load_workbook('nomenclature/data/test_set.xlsx', read_only=True)
        first_sheet = wb.worksheets[0]

        for row in first_sheet.rows:
            test_set = TestSet(key_code=row[1].value, name=row[2].value, department=row[3].value, addendum_key=row[4].value)
            test_set.save()

            try:
                service = Service.objects.get(code=row[0].value)
            except:
                print(f'Услуги {row[0].value} - нет в номенклатуре')

            service.test_set=test_set
            service.save()

        wb = load_workbook('nomenclature/data/test.xlsx', read_only=True)
        first_sheet = wb.worksheets[0]

        for num, row in enumerate(first_sheet.rows):

            check_test = Test.objects.filter(keycode=row[0].value)
            if not check_test:
                test = Test(
                    keycode=row[0].value,
                    name=row[1].value,
                    short_name=row[1].value[:50],
                    result_type=row[4].value,
                    decimal_places=5,
                    kdl_test_key=row[2].value,
                    measure_unit=row[3].value,
                )

                test.save()

            if row[10].value is not None:
                test = Test.objects.get(keycode=row[0].value)
                new_reference = Reference(
                    test=test,
                    position=int(row[10].value[:-4])
                )

                if row[5].value is None:
                    new_reference.sex = 'Любой'
                if row[6].value is not None:
                    if '.' in row[6].value:
                        age = row[6].value.split('.')
                        yy = '00' if not age[0] else age[0]
                        mm = age[1][:2]
                        dd = age[1][2:]
                        age_from = f'{yy}:{mm}:{dd}'
                        new_reference.age_from = age_from
                    else:
                        new_reference.age_from = f'{row[6].value}:00:00'
                if row[7].value is not None:
                    if '.' in row[7].value:
                        age = row[7].value.split('.')
                        yy = '00' if not age[0] else age[0]
                        mm = age[1][:2]
                        dd = age[1][2:]
                        age_to = f'{yy}:{mm}:{dd}'
                        new_reference.age_to = age_to
                    else:
                        new_reference.age_to = f'{row[7].value}:00:00'
                if row[8].value is not None:
                    new_reference.lower_normal_value = row[8].value
                if row[9].value is not None:
                    new_reference.upper_normal_value = row[9].value
                if row[13].value is not None:
                    new_reference.normal_text = row[13].value
                if row[11].value is not None:
                    new_reference.normal_text = row[13].value
                if row[11].value is not None:
                    new_reference.clinic_interpretation_key = row[11].value
                if row[12].value is not None:
                    new_reference.clinic_interpretation_text = row[12].value

                new_reference.save()

        wb = load_workbook('nomenclature/data/med.xlsx', read_only=True)
        first_sheet = wb.worksheets[0]

        for row in first_sheet.rows:
            try:
                service = Service.objects.get(code=row[0].value)
            except:
                print(f'Услуги {row[0].value} - нет в номенклатуре')
                continue
            new_record = MadicineData(
                service=service,
                alter_name_KC=row[1].value,
                alter_name=row[2].value,
                note=row[3].value,
                volume_pp=row[4].value,
                container_pp=row[5].value,
                guide_pp=row[6].value,
                transport_conditions=row[7].value,
                term_assign=row[8].value,
                description=row[9].value,
                method=row[10].value,
                factors=row[11].value,
                preparation=row[12].value,
            )

            new_record.save()


from __future__ import print_function
import sys
import json
import collections
import getopt

g_debug = False
g_indent = 4

def debug(s):
    if g_debug:
        print("DEBUG> " + s)

def usage(s):
    sys.stderr.write("Usage: %s [-t <indent>] [-d] <[-f <json file>] | txt>\n"
                     % s)
    sys.stderr.write("\t-t: --indent\n")
    sys.stderr.write("\t-d: --debug\n")
    sys.stderr.write("\t-f: --file\n")
    sys.stderr.write("e.g.\n")
    sys.stderr.write("       %s -t 8 -d -f foo.json\n" % s)
    sys.stderr.write("       %s --indent=4 --debug -f foo.json\n" % s)
    sys.stderr.write("       %s '{\"A\": 123, \"B\": \"bcd\"}'\n" % s)

def main(argc, argv):
    json_file = None

    options, rargv = getopt.getopt(argv[1:],
                                   ":f:t:dh",
                                   ["file=", "indent=", "debug", "help"])
    for opt, arg in options:
        if opt in ("-d", "--debug"):
            global g_debug
            g_debug = True
        elif opt in ("-t", "--indent"):
            global g_indent
            g_indent = int(arg)
        elif opt in ("-f", "--file"):
            json_file = arg
        elif opt in ("-h", "--help"):
            usage(argv[0])
            return 1
        else:
            usage(argv[0])
            return 1

    argc = len(rargv)
    if json_file is None:
        if argc == 0:
            usage(argv[0])
            return 1
        txt = rargv[0]
    else:
        with open(json_file, 'r') as f:
            txt = ''.join(f.readlines())

    obj = json.loads(txt, object_pairs_hook=collections.OrderedDict)

    debug(str(type(txt)))
    debug(txt)
    debug(str(type(obj)))
    debug(str(obj))

    out = json.dumps(obj, indent=g_indent)
    print(out)

    return 0

if __name__ == '__main__':
    sys.exit(main(len(sys.argv), sys.argv))


import covasim as cv
import pandas as pd
import sciris as sc
import pylab as pl
import numpy as np
from matplotlib import ticker
import datetime as dt
import matplotlib.patches as patches
import seaborn as sns
import matplotlib as mpl
from matplotlib.colors import LogNorm

# Filepaths
resultsfolder = 'sweeps'
sensfolder = 'sweepssens'
figsfolder = 'figs'
process = False

# Parameter levels
T = sc.tic()
tlevels = [0.067, 0.1, 0.15, 0.19]
vlevels = np.arange(0, 5) / 4
mlevels = np.arange(0, 4) / 4
nt, nv, nm = len(tlevels), len(vlevels), len(mlevels)

# Fonts and sizes for all figures
font_size = 26
font_family = 'Proxima Nova'
pl.rcParams['font.size'] = font_size
pl.rcParams['font.family'] = font_family

################################################################################################
# Do processing if required
################################################################################################
if process:
    for thisfig in [resultsfolder,sensfolder]:
        results = {'cum_infections': {}, 'r_eff': {}, 'new_infections':{}, 'cum_quarantined':{}}
        for future_test_prob in tlevels:
            for name in ['cum_infections', 'r_eff', 'new_infections','cum_quarantined']: results[name][future_test_prob] = {}
            for venue_trace_prob in vlevels:
                for name in ['cum_infections', 'r_eff', 'new_infections','cum_quarantined']: results[name][future_test_prob][venue_trace_prob] = []
                for mask_uptake in mlevels:
                    print(f'mask_uptake: {mask_uptake}, venue_trace_prob: {venue_trace_prob}, future_test_prob: {future_test_prob}')
                    msim = sc.loadobj(f'{thisfig}/nsw_tracingsweeps_T{int(future_test_prob * 100)}_M{int(mask_uptake * 100)}_V{int(venue_trace_prob * 100)}.obj')
                    results['cum_quarantined'][future_test_prob][venue_trace_prob].append(msim.results['cum_quarantined'].values[-1]-msim.results['cum_quarantined'].values[244])
                    results['cum_infections'][future_test_prob][venue_trace_prob].append(msim.results['cum_infections'].values[-1]-msim.results['cum_infections'].values[244])
                    results['r_eff'][future_test_prob][venue_trace_prob].append(msim.results['r_eff'].values[-1])
                    results['new_infections'][future_test_prob][venue_trace_prob].append(msim.results['new_infections'].values)
        sc.saveobj(f'{thisfig}/nsw_sweep_results.obj', results)
#else:
#    results = sc.loadobj(f'{resultsfolder}/nsw_sweep_results.obj')

################################################################################################################
# Figure 2 and S2: grids of new infections
################################################################################################################

for thisfig in [resultsfolder, sensfolder]:

    # Fonts and sizes
    fig = pl.figure(figsize=(24,16))
    results = sc.loadobj(f'{thisfig}/nsw_sweep_results.obj')

    # Subplot sizes
    xgapl = 0.05
    xgapm = 0.017
    xgapr = 0.05
    ygapb = 0.05
    ygapm = 0.017
    ygapt = 0.05
    nrows = nt
    ncols = nv
    dx = (1-(ncols-1)*xgapm-xgapl-xgapr)/ncols
    dy = (1-(nrows-1)*ygapm-ygapb-ygapt)/nrows
    nplots = nrows*ncols
    ax = {}
    colors = pl.cm.GnBu(np.array([0.4,0.6,0.8,1.]))
    labels = ['0% masks', '25% masks', '50% masks', '75% masks']

    epsx = 0.003
    epsy = 0.008
    llpad = 0.01
    rlpad = 0.005

    if thisfig==resultsfolder:
        pl.figtext(xgapl+dx*nv+xgapm*(nv-1)+rlpad, ygapb+(ygapm+dy)*0+epsy, '      90% testing      ', rotation=90, fontsize=30, fontweight='bold', bbox={'edgecolor':'none', 'facecolor':'silver', 'alpha':0.5, 'pad':4})
        pl.figtext(xgapl+dx*nv+xgapm*(nv-1)+rlpad, ygapb+(ygapm+dy)*1+epsy, '      80% testing      ', rotation=90, fontsize=30, fontweight='bold', bbox={'edgecolor':'none', 'facecolor':'silver', 'alpha':0.5, 'pad':4})
        pl.figtext(xgapl+dx*nv+xgapm*(nv-1)+rlpad, ygapb+(ygapm+dy)*2+epsy, '      65% testing      ', rotation=90, fontsize=30, fontweight='bold', bbox={'edgecolor':'none', 'facecolor':'silver', 'alpha':0.5, 'pad':4})
        pl.figtext(xgapl+dx*nv+xgapm*(nv-1)+rlpad, ygapb+(ygapm+dy)*3+epsy, '      50% testing      ', rotation=90, fontsize=30, fontweight='bold', bbox={'edgecolor':'none', 'facecolor':'silver', 'alpha':0.5, 'pad':4})

    elif thisfig==sensfolder:
        pl.figtext(xgapl+dx*nv+xgapm*(nv-1)+rlpad, ygapb+(ygapm+dy)*0+epsy, '  90% symp. testing \n 60% contact testing ', rotation=90, fontsize=26, fontweight='bold', bbox={'edgecolor':'none', 'facecolor':'silver', 'alpha':0.5, 'pad':4})
        pl.figtext(xgapl+dx*nv+xgapm*(nv-1)+rlpad, ygapb+(ygapm+dy)*1+epsy, '  80% symp. testing \n 50% contact testing ', rotation=90, fontsize=26, fontweight='bold', bbox={'edgecolor':'none', 'facecolor':'silver', 'alpha':0.5, 'pad':4})
        pl.figtext(xgapl+dx*nv+xgapm*(nv-1)+rlpad, ygapb+(ygapm+dy)*2+epsy, '  65% symp. testing \n 40% contact testing ', rotation=90, fontsize=26, fontweight='bold', bbox={'edgecolor':'none', 'facecolor':'silver', 'alpha':0.5, 'pad':4})
        pl.figtext(xgapl+dx*nv+xgapm*(nv-1)+rlpad, ygapb+(ygapm+dy)*3+epsy, '  50% symp. testing \n 30% contact testing ', rotation=90, fontsize=26, fontweight='bold', bbox={'edgecolor':'none', 'facecolor':'silver', 'alpha':0.5, 'pad':4})

    pl.figtext(xgapl+(dx+xgapm)*0+epsx, ygapb+dy*nm+ygapm*(nm-1)+llpad, '        0% tracing           ', fontsize=30, fontweight='bold', bbox={'edgecolor':'none', 'facecolor':'silver', 'alpha':0.5, 'pad':4})
    pl.figtext(xgapl+(dx+xgapm)*1+epsx, ygapb+dy*nm+ygapm*(nm-1)+llpad, '        25% tracing          ', fontsize=30, fontweight='bold', bbox={'edgecolor':'none', 'facecolor':'silver', 'alpha':0.5, 'pad':4})
    pl.figtext(xgapl+(dx+xgapm)*2+epsx, ygapb+dy*nm+ygapm*(nm-1)+llpad, '        50% tracing         ', fontsize=30, fontweight='bold', bbox={'edgecolor':'none', 'facecolor':'silver', 'alpha':0.5, 'pad':4})
    pl.figtext(xgapl+(dx+xgapm)*3+epsx, ygapb+dy*nm+ygapm*(nm-1)+llpad, '        75% tracing          ', fontsize=30, fontweight='bold', bbox={'edgecolor':'none', 'facecolor':'silver', 'alpha':0.5, 'pad':4})
    pl.figtext(xgapl+(dx+xgapm)*4+epsx, ygapb+dy*nm+ygapm*(nm-1)+llpad, '        100% tracing        ', fontsize=30, fontweight='bold', bbox={'edgecolor':'none', 'facecolor':'silver', 'alpha':0.5, 'pad':4})

    # Extract plot values
    def plinf(pn, what='new_infections'):
        # Get series for this plot number
        t = list(results['new_infections'].keys())[(nplots-1-pn)//nv]
        v = list(results['new_infections'][t].keys())[pn%nv]
        if what =='new_infections':
            #return np.array(([results['new_infections'][t][v][mm][214:] for mm in range(nm)]))
            return np.array([[results['new_infections'][t][v][mm][200+i:214+i].sum() / 14 for i in range(306-214)] for mm in range(nm)])
        elif what == 'cum_infections':
            return results['cum_infections'][t][v]

    @ticker.FuncFormatter
    def date_formatter(x, pos):
        return (cv.date('2020-09-30') + dt.timedelta(days=x)).strftime('%d-%b')

    for pn in range(nplots):
        ax[pn] = pl.axes([xgapl+(dx+xgapm)*(pn%ncols), ygapb+(ygapm+dy)*(pn//ncols), dx, dy])
        data = plinf(pn)
        for mi,mval in enumerate(mlevels):
            ax[pn].plot(range(len(data[mi,:])), data[mi,:], '-', lw=4, c=colors[mi], label=labels[mi], alpha=1.0)
            val = sc.sigfig(plinf(pn, what='cum_infections')[mi],3) if plinf(pn, what='cum_infections')[mi]<100 else sc.sigfig(plinf(pn, what='cum_infections')[mi],2)
            ax[pn].text(0.1, 180-mi*15, val.rjust(6), fontsize=20, family='monospace', color=colors[mi])

        ax[pn].set_ylim(0, 200)
        ax[pn].xaxis.set_major_formatter(date_formatter)

        if pn==4: pl.legend(loc='upper right', frameon=False, fontsize=20)
        if pn not in [0,5,10,15]:
            ax[pn].set_yticklabels([])
        else:
            ax[pn].set_ylabel('New infections')
        if pn not in range(nv):
            ax[pn].set_xticklabels([])
        else:
            xmin, xmax = ax[pn].get_xlim()
            ax[pn].set_xticks(pl.arange(xmin+5, xmax, 40))

    if thisfig==resultsfolder: figname = figsfolder+'/fig2_grid.png'
    elif thisfig==sensfolder: figname = figsfolder+'/figS2_grid.png'

    cv.savefig(figname, dpi=100)

#d = {'testing': [0.067]*nv*nm+[0.1]*nv*nm+[0.15]*nv*nm+[0.19]*nv*nm, 'tracing': [0.0]*nm+[0.25]*nm+[0.5]*nm+[0.75]*nm+[1.0]*nm+[0.0]*nm+[0.25]*nm+[0.5]*nm+[0.75]*nm+[1.0]*nm+[0.0]*nm+[0.25]*nm+[0.5]*nm+[0.75]*nm+[1.0]*nm+[0.0]*nm+[0.25]*nm+[0.5]*nm+[0.75]*nm+[1.0]*nm, 'masks': [0.0,0.25,0.5,0.75]*nt*nv}
#d['val'] = []
#for t in tlevels:
#    for v in vlevels:
#        d['val'].extend(sc.sigfig(results['cum_infections'][t][v],3))
#import pandas as pd
#df = pd.DataFrame(d)
#df.to_excel('sweepresults.xlsx')

################################################################################################################
# Figure 3: bar plot of cumulative infections
################################################################################################################
mainres = sc.loadobj(f'{resultsfolder}/nsw_sweep_results.obj')
sensres = sc.loadobj(f'{sensfolder}/nsw_sweep_results.obj')

# Subplot sizes
xgapl = 0.07
xgapm = 0.02
xgapr = 0.02
ygapb = 0.1
ygapm = 0.02
ygapt = 0.08
nrows = 1
ncols = 2
dx = (1-(ncols-1)*xgapm-xgapl-xgapr)/ncols
dy = (1-(nrows-1)*ygapm-ygapb-ygapt)/nrows
nplots = nrows*ncols
ax = {}
colors = pl.cm.GnBu(np.array([0.4,0.6,0.8,1.]))
mlabels = ['0% masks', '25% masks', '50% masks', '75% masks']
tlabels = ['50%', '65%', '80%', '90%']

fig = pl.figure(figsize=(24,8*nrows))

x = np.arange(len(tlabels))
width = 0.2  # the width of the bars

# Extract data
datatoplot = {}

datatoplot[0] = np.array([[mainres['cum_infections'][t][1.0][mi] for t in tlevels] for mi in range(nm)])
datatoplot[1] = np.array([[sensres['cum_infections'][t][1.0][mi] for t in tlevels] for mi in range(nm)])
#datatoplot[2] = np.array([[mainres['cum_quarantined'][t][1.0][mi] for t in tlevels] for mi in range(nm)])
#datatoplot[3] = np.array([[sensres['cum_quarantined'][t][1.0][mi] for t in tlevels] for mi in range(nm)])

# Headings
pl.figtext(xgapl+0.001, ygapb+dy*nrows+ygapm*(nrows-1)+0.01, '     Asymptomatic testing equal to symptomatic testing         ',
           fontsize=30, fontweight='bold', bbox={'edgecolor':'none', 'facecolor':'silver', 'alpha':0.5, 'pad':4})
pl.figtext(xgapl+xgapm+dx+0.001, ygapb+dy*nrows+ygapm*(nrows-1)+0.01, '     Asymptomatic testing lower than symptomatic testing      ',
           fontsize=30, fontweight='bold', bbox={'edgecolor':'none', 'facecolor':'silver', 'alpha':0.5, 'pad':4})

# Make plots
for pn in range(nplots):
    ax[pn] = pl.axes([xgapl+(dx+xgapm)*(pn%ncols), ygapb+(ygapm+dy)*(pn//ncols), dx, dy])
    data = datatoplot[pn]
    for mi,mval in enumerate(mlevels):
        ax[pn].bar(x+width*(mval*4-1.5), data[mi,:], width, color=colors[mi], label=mlabels[mi], alpha=1.0)

    ax[pn].set_xticks(x)
    ax[pn].set_xticklabels(tlabels)
    if pn <2:
        ax[pn].set_ylim(0, 20e3)
        ax[pn].set_xlabel('Symptomatic testing rate')
    else:
        ax[pn].set_ylim(0, 250e3)
    sc.boxoff()

    if pn in [0,2]:
        ax[pn].set_ylabel('Cumulative infections')
    if pn==1:
        pl.legend(loc='upper right', frameon=False, fontsize=20)
        ax[pn].set_yticklabels([])

cv.savefig(f'{figsfolder}/fig3_bars.png', dpi=100)

################################################################################################################
# Figure X: trade-off heatmaps
################################################################################################################

# Subplot sizes
xgapl = 0.07
xgapm = 0.02
xgapr = 0.02
ygapb = 0.3
ygapm = 0.02
ygapt = 0.08
nrows = 1
ncols = nv
dx = (1-(ncols-1)*xgapm-xgapl-xgapr)/ncols
dy = (1-(nrows-1)*ygapm-ygapb-ygapt)/nrows
nplots = nrows*ncols
ax = {}

# Create figure
fig = pl.figure(figsize=(24,10))

colors = pl.cm.GnBu(np.array([0.4,0.6,0.8,1.]))
mlabels = ['0% masks', '25% masks', '50% masks', '75% masks']
tlabels = ['50%', '65%', '80%', '90%']
vlabels = ['0% tracing', '25% tracing', '50% tracing', '75% tracing', '100% tracing']

M, T = np.meshgrid(mlevels, tlevels)
mt = M.reshape(nt*nm,)
tt = T.reshape(nt*nm,)
cmin, cmax = 0., 5.
lev_exp = np.arange(0., 5.1, 0.1)
levs = np.power(10, lev_exp)

# Load objects
for pn,vl in enumerate(vlevels):

    # Load in scenario multisims
    zi1 = np.array([mainres['cum_infections'][ti][vl] for ti in tlevels])
    z = zi1.reshape(nt*nm,)

    # Set axis and plot
    ax[pn] = pl.axes([xgapl+(dx+xgapm)*(pn%ncols), ygapb+(ygapm+dy)*(pn//ncols), dx, dy])
    im = ax[pn].imshow(zi1, cmap='Oranges')

    # Annotate
    for i in range(nm):
        for j in range(nt):
            c = sc.sigfig(zi1[j, i],3)
            ax[pn].text(i, j, str(c), va='center', ha='center')

    # Axis and plot labelling
    if pn == 0:
        ax[pn].set_ylabel('Symptomatic testing rate', fontsize=24, labelpad=20)
    ax[pn].set_xlabel('Mask uptake')
    ax[pn].set_title(vlabels[pn])

    ax[pn*100] = pl.axes([xgapl+(dx+xgapm)*(pn%ncols), 0.05, dx, 0.1])
    cbar = pl.colorbar(im, cax=ax[pn*100])
cv.savefig(f'{figsfolder}/figX_heatmaps.png', dpi=100)

sc.toc(T)


from dgl.nn.pytorch.conv import SAGEConv

import torch
import torch.nn as nn
import torch.nn.functional as F

import time
import numpy as np

from dgl import DGLGraph
from dgl.data import citation_graph as citegrh
import networkx as nx

class GraphSAGE(nn.Module):
    def __init__(self,
                 in_feats,
                 n_hidden,
                 n_classes,
                 n_layers,
                 activation,
                 dropout,
                 aggregator_type):
        super(GraphSAGE, self).__init__()
        self.layers = nn.ModuleList()
        self.dropout = nn.Dropout(dropout)
        self.activation = activation

        # input layer
        self.layers.append(SAGEConv(in_feats, n_hidden, aggregator_type))
        # hidden layers
        for i in range(n_layers - 1):
            self.layers.append(SAGEConv(n_hidden, n_hidden, aggregator_type))
        # output layer
        self.layers.append(SAGEConv(n_hidden, n_classes, aggregator_type)) # activation None

    def forward(self, graph, inputs):
        h = self.dropout(inputs)
        for l, layer in enumerate(self.layers):
            h = layer(graph, h)
            if l != len(self.layers) - 1:
                h = self.activation(h)
                h = self.dropout(h)
        return h

def load_cora_data():
    data = citegrh.load_cora()
    features = torch.FloatTensor(data.features)
    labels = torch.LongTensor(data.labels)
    mask = torch.BoolTensor(data.train_mask)
    g = DGLGraph(data.graph)
    n_classes = data.num_classes
    return n_classes, g, features, labels, mask

n_classes, g, features, labels, mask = load_cora_data()

# create GraphSAGE model
model = GraphSAGE(in_feats=features.size()[1],
                  n_hidden=16,
                  n_classes=n_classes,
                  n_layers=1,
                  activation=F.relu,
                  dropout=0.5,
                  aggregator_type='gcn')

# use optimizer
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)

# initialize graph
dur = []
for epoch in range(50):
    model.train()
    if epoch >= 3:
        t0 = time.time()

    logits = model(g, features)
    loss = F.cross_entropy(logits[mask], labels[mask])

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if epoch >= 3:
        dur.append(time.time() - t0)

    print("Epoch {:05d} | Loss {:.4f} | Time(s) {:.4f}".format(epoch, loss.item()), np.mean(dur))


""" new visualizations 2020

Revision ID: 437ffc36a821
Revises: d73f1a3bccf3
Create Date: 2020-07-16 19:48:01.228630

"""
from alembic import op
from sqlalchemy import String, Integer
from sqlalchemy.sql import table, column, text
from caipirinha.migration_utils import get_enable_disable_fk_command

# revision identifiers, used by Alembic.
revision = '437ffc36a821'
down_revision = 'd73f1a3bccf3'
branch_labels = None
depends_on = None

def insert_visualization_type():
    tb = table(
        'visualization_type',
        column('id', Integer),
        column('name', String),
        column('help', String),
        column('icon', String))

    all_ops = [
        (130, 'indicator', 'Gauge', 'fa-chart'),
        (131, 'markdown', 'Markdown text', 'fa-chart'),
        (132, 'word-cloud', 'Word cloud', 'fa-chart'),
        (133, 'heatmap', 'Heatmap', 'fa-chart'),
        (134, 'bubble-chart', 'Bubble chart', 'fa-chart'),
        (135, 'force-direct', 'Network graphs', 'fa-chart'),
        (136, 'iframe', 'HTML iframe', 'fa-chart'),
        (137, 'treemap', 'Treemap', 'fa-chart'),
    ]
    rows = [dict(zip([c.name for c in tb.columns], operation)) for operation in
            all_ops]

    op.bulk_insert(tb, rows)

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    try:
        op.execute(text('BEGIN'))
        insert_visualization_type()
        op.execute(text('COMMIT'))
    except:
        op.execute(text('ROLLBACK'))
        raise

# noinspection PyBroadException
def downgrade():
    try:
        op.execute(text('BEGIN'))
        op.execute(text(get_enable_disable_fk_command(False)))
        op.execute(
            text("DELETE FROM visualization WHERE type_id IN (123, 124)"))
        op.execute(
            text("DELETE FROM visualization_type WHERE id IN (123, 124)"))
        op.execute(text(get_enable_disable_fk_command(True)))
        op.execute(text('COMMIT'))
    except:
        op.execute(text('ROLLBACK'))
        raise


from re import L
from flask import Flask
from flask import jsonify
from flask import request
from flask_restful import Api, Resource, reqparse
import json
import sys
from get_details import get_name
from process_swipe import process_swipe
import requests
import random
from eventlet import wsgi
import eventlet
from redis_instance import get_instance
from RecommendationEngine import get_swipe_stack
from mysql_connection import get_cursor
import traceback
import pymongo

mongod = pymongo.MongoClient("")
db = mongod["tat"]
collection = db["sessions"]
r = get_instance()

# 1 day
EXPIRATION_TIME = 86400

like_post_args = reqparse.RequestParser()
like_post_args.add_argument(
    "foodid", type=int, help="The ID of the food item swiped on")
like_post_args.add_argument("userid", type=str, help="Your UserID")
like_post_args.add_argument("restuarantid", type=int, help="The restaurants ID UserID")
like_post_args.add_argument("authtoken", type=str, help="Authorisation token")
like_post_args.add_argument(
    "islike", type=bool, help="If the like was like / dislike")
like_post_args.add_argument(
    "isfavourite", type=bool, help="If it was a super like")
like_post_args.add_argument("isGroup", type=bool, help="If the swipe stack you're getting is for a group")

swipestack_args = reqparse.RequestParser()
swipestack_args.add_argument(
    "lat", type=float, help="Lattitude of where to search recommendations"
)
swipestack_args.add_argument(
    "lng", type=float, help="Longitude of where to search recommendations"
)
swipestack_args.add_argument(
    "userid", type=str, help="The userID"
)
swipestack_args.add_argument("authtoken", type=str, help="Authorisation token")
swipestack_args.add_argument("code", type=int, help="Room code")
swipestack_args.add_argument("isGroup", help="If the swipe stack you're getting is for a group")
swipestack_args.add_argument(
    "distance", type=float, help="Radius of the circle to search within"
)

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

class RecommenderController(Resource):
    #get [/swipestack]
    def post(self):
        args = swipestack_args.parse_args()
        print(args)
        payload = {"authtoken": args.authtoken, "userid": args.userid}
        r = requests.post(
            'http://devapi.trackandtaste.com/user/authcheck', json=payload)
        if r.status_code != 200:
            return '', r.status_code
        try:
            data = get_swipe_stack(args.lat, args.lng, args.userid, args.distance, args.isGroup == "True", str(args.code))
        except Exception as e :
            print(e)
            print(traceback.format_exc())
            return '', 404 # We couldn't find any restaurants
        return json.loads(data), 200

class SwipeController(Resource):
    # post [/swipe]
    def post(self):
        args = like_post_args.parse_args()
        payload = {"authtoken": args.authtoken, "userid": args.userid}
        res = requests.post(
            'http://devapi.trackandtaste.com/user/authcheck', json=payload)
        if res.status_code != 200:
            return '', r.status_code
        try:
            process_swipe(args.userid, args.foodid,
                            args.islike, args.isfavourite)
            # If the swipe doesn't come from the group page, cache it
            # Else caching is handled by the websocket server and is saved in mongo
            if not args.isGroup:
                print(args)
                r.lpush(f"Recommendations-{args.userid}", args.foodid)
                r.expire(f"Recommendations-{args.userid}", 7200)
                if args.islike or args.isfavourite:
                    r.lpush(f"Likes-{args.userid}", f"{args.foodid},{args.restuarantid}")
                    r.expire(f"Likes-{args.userid}", 7200)
        except Exception as e:
            print(e)
            print(traceback.format_exc())
            # Food item not found
            return '', 404
        return '', 201

class ItemController(Resource):
    #get [/likeditems]
    def get(self):
        args = request.args
        # If we're dealing with a group
        filtered = []

        if(args["isGroup"] == "true"):
            print("is group")
            room = collection.find_one({"code" : args["room"]}, {"restaurantsLiked": 1})
            userid = str(args["userID"])
            restaurantid = int(args["restaurantID"])
            for restaurant in room["restaurantsLiked"]:
                if restaurant["restaurantID"] == restaurantid:
                    for user in restaurant["likes"]:
                        if user["userID"] == userid:
                            for item in user["items"]:
                                filtered.append(str(item))
        else:
            print("Nota group")
            # We're dealing with individual swipe
            likedItems = [i.decode("UTF-8") for i in r.lrange(f"Likes-{args['userID']}", 0, -1)]
            for item in likedItems:
                if item.split(',')[1] == str(args["restaurantID"]):
                    filtered.append(item.split(',')[0])

        if len(filtered) == 0:
            return '', 404
        cursor = get_cursor()
        cursor.execute(f"SELECT Price, FoodNameShort, FoodID FROM FoodItem WHERE FoodID IN({','.join(filtered)});")
        result = cursor.fetchall()
        items = []
        for item in result:
            items.append({"price": str(item[0]),"name": item[1], "id": item[2]})
        print(items)
        return items, 200

api.add_resource(SwipeController, "/swipe")
api.add_resource(RecommenderController, "/swipestack")
api.add_resource(ItemController, "/likeditems")
if __name__ == "__main__":
    wsgi.server(eventlet.listen(('', 8000)), app)


"""Initializes and checks the environment needed to run pytype."""

import logging
import sys
from typing import List

from pytype.imports import typeshed
from pytype.platform_utils import path_utils
from pytype.tools import runner

def check_pytype_or_die():
  if not runner.can_run("pytype", "-h"):
    logging.critical(
        "Cannot run pytype. Check that it is installed and in your path")
    sys.exit(1)

def check_python_version(exe: List[str], required):
  """Check if exe is a python executable with the required version."""
  try:
    # python --version outputs to stderr for earlier versions
    _, out, err = runner.BinaryRun(exe + ["--version"]).communicate()  # pylint: disable=unpacking-non-sequence
    version = out or err
    version = version.decode("utf-8")
    if version.startswith(f"Python {required}"):
      return True, None
    else:
      return False, version.rstrip()
  except OSError:
    return False, None

def check_python_exe_or_die(required) -> List[str]:
  """Check if a python executable with the required version is in path."""
  error = []
  if sys.platform == "win32":
    possible_exes = (["py", f"-{required}"], ["py3"], ["py"])
  else:
    possible_exes = ([f"python{required}"], ["python3"], ["python"])
  for exe in possible_exes:
    valid, out = check_python_version(exe, required)
    if valid:
      return exe
    elif out:
      error.append(out)
  logging.critical(
      "Could not find a valid python%s interpreter in path (found %s)",
      required, ", ".join(sorted(set(error))))
  sys.exit(1)

def initialize_typeshed_or_die():
  """Initialize a Typeshed object or die.

  Returns:
    An instance of Typeshed()
  """
  try:
    return typeshed.Typeshed()
  except OSError as e:
    logging.critical(str(e))
    sys.exit(1)

def compute_pythonpath(filenames):
  """Compute a list of dependency paths."""
  paths = set()
  for f in filenames:
    containing_dir = path_utils.dirname(f)
    if path_utils.exists(path_utils.join(containing_dir, "__init__.py")):
      # If the file's containing directory has an __init__.py, we assume that
      # the file is in a (sub)package. Add the containing directory of the
      # top-level package so that 'from package import module' works.
      package_parent = path_utils.dirname(containing_dir)
      while path_utils.exists(path_utils.join(package_parent, "__init__.py")):
        package_parent = path_utils.dirname(package_parent)
      p = package_parent
    else:
      # Otherwise, the file is a standalone script. Add its containing directory
      # to the path so that 'import module_in_same_directory' works.
      p = containing_dir
    paths.add(p)
  # Reverse sorting the paths guarantees that child directories always appear
  # before their parents. To see why this property is necessary, consider the
  # following file structure:
  #   foo/
  #     bar1.py
  #     bar2.py  # import bar1
  #     baz/
  #       qux1.py
  #       qux2.py  # import qux1
  # If the path were [foo/, foo/baz/], then foo/ would be used as the base of
  # the module names in both directories, yielding bar1 (good) and baz.qux1
  # (bad). With the order reversed, we get bar1 and qux1 as expected.
  return sorted(paths, reverse=True)


import os
import morfeusz2
import pandas as pd
from sklearn.metrics import classification_report

def lemmatize_text(text):
    if isinstance(text, str):
        text = text.split()
    morf = morfeusz2.Morfeusz(expand_dag=True, expand_tags=True)
    text_new = []
    for word in text:
        w = morf.analyse(word)[0][0][1].split(':')[0]
        if w == 'oko':
            w = 'ok'
        text_new.append(w)
    return " ".join(text_new)

def create_dir(directory):
    if not os.path.isdir(directory):
        _path = os.path.abspath(directory).split('\\')
        for i in range(1, len(_path) + 1):
            current_dir = "//".join(_path[:i])
            if not os.path.isdir(current_dir):
                os.mkdir(current_dir)

def mapping_from_clusters(x):
    if x == -1:
        return 'neg'
    else:
        return 'pos'

def classification_report_to_excel(y_test, y_pred, filename):
    cr = classification_report(y_test, y_pred, output_dict=True, target_names=['Negative', 'Positive'])
    pd.DataFrame(cr).T.to_excel(filename)


from unittest import TestCase
from collections import namedtuple
from P2_Sorting.HeapSort.heap_sort import heap_sort

class Task(object):
    def __init__(self, deadline, penalty):
        assert isinstance(deadline, int) and deadline > 0
        assert penalty > 0

        self._penalty = penalty
        self._deadline = deadline

    @property
    def deadline(self):
        return self._deadline

    @property
    def penalty(self):
        return self._penalty

def _check_input_or_error(tasks):
    if not tasks:
        return
    n = len(tasks)
    for task in tasks:
        assert task.deadline <= n

def _check_independent(tasks, deadline_counts, indices, length):
    """
    Ex 16.5-2. O(|A|) running time algorithm to check whether a set A of tasks are independent.
    :param tasks: all the tasks.
    :param deadline_counts: a helper array, where deadline_counts[i] denotes how many tasks have deadlines no greater
    than i + 1.
    :param indices: indices of tasks to consider.
    :param length: indices[0:length] will be considered, which means that length = |A|.
    :return: whether the tasks considered are independent.
    """

    for i in range(0, len(tasks)):
        deadline_counts[i] = 0

    for i in range(0, length):
        task = tasks[indices[i]]
        deadline_counts[task.deadline - 1] += 1

    cumulative_deadline_counts = 0
    for i in range(0, len(tasks)):
        cumulative_deadline_counts += deadline_counts[i]
        if cumulative_deadline_counts > i + 1:
            return False

    return True

def schedule_task(tasks):
    """
    O(n^2) running time algorithm to schedule unit-time tasks with deadlines and penalties to get the minimum total
    penalty.
    :param tasks: tasks to consider.
    :return: the optimal schedule of 'early' tasks.
    """
    _check_input_or_error(tasks)
    n = len(tasks)
    tasks = list(tasks)
    for i in range(0, n):
        tasks[i].index = i
    heap_sort(tasks, key=lambda t: -t.penalty)
    schedule_on_sorted = [-1] * n
    early_count = 0

    deadline_counts = [0] * n
    for i in range(0, n):
        schedule_on_sorted[early_count] = i
        if _check_independent(tasks, deadline_counts, schedule_on_sorted, early_count + 1):
            early_count += 1

    schedule = [-1] * early_count
    for i in range(0, early_count):
        schedule[i] = schedule_on_sorted[i]
    heap_sort(schedule, key=lambda index: tasks[index].deadline)
    for i in range(0, early_count):
        schedule[i] = tasks[schedule[i]].index

    return tuple(schedule)

class TestTaskScheduling(TestCase):
    def test_task_scheduling(self):
        case_class = namedtuple('Case', 'desc tasks schedules')
        cases = (
            case_class(desc='Empty', tasks=(), schedules=(
                (),
            )),
            case_class(desc='Single', tasks=(
                Task(1, 10),
            ), schedules=(
                (0,),
            )),
            case_class(desc='Two early', tasks=(
                Task(1, 10),
                Task(2, 20)
            ), schedules=(
                (0, 1),
            )),
            case_class(desc='Two late', tasks=(
                Task(1, 10),
                Task(1, 20)
            ), schedules=(
                (1,),
            )),
            case_class(desc='Example in textbook', tasks=(
                Task(4, 70),
                Task(2, 60),
                Task(4, 50),
                Task(3, 40),
                Task(1, 30),
                Task(4, 20),
                Task(6, 10),
            ), schedules=(
                (1, 3, 0, 2, 6),
            )),
            case_class(desc='Ex 16.5-1', tasks=(
                Task(4, 10),
                Task(2, 20),
                Task(4, 30),
                Task(3, 40),
                Task(1, 50),
                Task(4, 60),
                Task(6, 70),
            ), schedules=(
                (4, 3, 2, 5, 6),
                (4, 3, 5, 2, 6),
            )),
        )

        for case in cases:
            schedule = schedule_task(case.tasks)
            self.assertTrue(schedule in case.schedules, msg='%s, wrong schedule %s' % (case.desc, schedule))


from pyspark.sql import SparkSession
from pyspark.sql.functions import col
import boto3
session = boto3.Session(profile_name="***_AdministratorAccess",region_name="us-east-1")
s3 = boto3.resource('s3')

# Inicialize a sessão do Spark
spark = SparkSession.builder.getOrCreate()

# Leia os arquivos Parquet e crie os dataframes
df_imdb = spark.read.parquet("natalias-s3-bucket/Trusted/Parquet/Movies/CSV/")
df_tmdb = spark.read.parquet("natalias-s3-bucket/Trusted/Parquet/Movies/JSON/")

# Selecione as colunas necessárias do dataframe do IMDB
df_imdb = df_imdb.select(
    col("id").alias("idImdb"),
    col("anolancamento").alias("anoLancamento"),
    col("genero").alias("genero"),
    col("tituloprincipal").alias("tituloPrincipal"),
    col("notamedia").alias("notaMedia")
)

# Selecione as colunas necessárias do dataframe do TMDB
df_tmdb = df_tmdb.select(
    col("id").alias("idTmdb"),
    col("popularity").alias("popularity"),
    col("vote_average").alias("voteAverage"),
    col("vote_count").alias("voteCount"),
    col("release_date").alias("releaseDate")
)

# Crie a tabela FatoFilmes
df_fato_filmes = df_imdb.join(df_tmdb, "idImdb")

# Crie a tabela DimensaoTmdb
df_dimensao_tmdb = df_tmdb.select(
    col("idTmdb"),
    col("genre_ids").alias("generos"),
    col("original_language").alias("originalLanguage"),
    col("releaseDate")
)

# Crie a tabela DimensaoImdb
df_dimensao_imdb = df_imdb.select(
    col("idImdb"),
    col("anoLancamento"),
    col("genero"),
    col("tituloPrincipal")
)

# Salve os dataframes resultantes como tabelas temporárias
df_fato_filmes.createOrReplaceTempView("FatoFilmes")
df_dimensao_tmdb.createOrReplaceTempView("DimensaoTmdb")
df_dimensao_imdb.createOrReplaceTempView("DimensaoImdb")

# Execute uma consulta para visualizar os resultados
result = spark.sql("""
    SELECT
        FatoFilmes.idImdb,
        FatoFilmes.idTmdb,
        FatoFilmes.notaMedia,
        FatoFilmes.numeroVotos,
        FatoFilmes.popularity,
        FatoFilmes.voteAverage,
        FatoFilmes.voteCount,
        DimensaoTmdb.genres,
        DimensaoTmdb.originalLanguage,
        DimensaoTmdb.releaseDate,
        DimensaoImdb.anoLancamento,
        DimensaoImdb.genero,
        DimensaoImdb.tituloPrincipal
    FROM
        FatoFilmes
    JOIN
        DimensaoTmdb ON FatoFilmes.idTmdb = DimensaoTmdb.idTmdb
    JOIN
        DimensaoImdb ON FatoFilmes.idImdb = DimensaoImdb.idImdb
""")

# Salve o DataFrame resultante no S3 em formato Parquet
result.write.parquet("s3://natalias-s3-bucket/Processed-Trusted/Parquet/Movies/resultedparquet")


import subprocess
import pytest

from pipfile2req.requirements import requirement_from_pipfile

def compare_requirements(left, right):
    return len(set(left.splitlines()) - set(right.splitlines())) == 0

@pytest.mark.parametrize(
    "command,golden_file",
    [
        ("pipfile2req -p tests", "tests/requirements.txt"),
        ("cd tests && pipfile2req", "tests/requirements.txt"),
        ("pipfile2req -p tests -d", "tests/dev-requirements.txt"),
        ("pipfile2req -p tests Pipfile", "tests/requirements-pipfile.txt"),
        ("pipfile2req -d tests/Pipfile", "tests/dev-requirements-pipfile.txt"),
        ("pipfile2req -d tests/Pipfile.lock", "tests/dev-requirements.txt"),
        ("pipfile2req -p tests --sources", "tests/requirements-sources.txt"),
        ("pipfile2req -p tests Pipfile --sources", "tests/requirements-pipfile-sources.txt"),
    ],
)
def test_convert_pipfile(command, golden_file):
    proc = subprocess.Popen(
        command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
    )
    output, err = proc.communicate()
    with open(golden_file) as f:
        assert compare_requirements(
            output.decode("utf-8").strip().replace("\r\n", "\n"),
            f.read().strip().replace("\r\n", "\n"),
        )

def test_convert_include_hash():
    command = "pipfile2req -p tests --hashes"
    proc = subprocess.Popen(
        command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
    )
    _, err = proc.communicate()
    print(err)
    assert proc.returncode == 0

@pytest.mark.parametrize("name,package,req", [
    ("foo", "*", "foo"),
    ("foo", {"version": "*"}, "foo"),
    ("foo", {"version": ">=1.0", "extras": ["test", "sec"]}, "foo[test,sec]>=1.0"),
    ("foo", {"file": "file:///data/demo-0.0.1.tar.gz"}, "foo @ file:///data/demo-0.0.1.tar.gz"),
    ("foo", {"file": "file:///data/demo-0.0.1.tar.gz", "extras": ["test", "sec"]}, "foo[test,sec] @ file:///data/demo-0.0.1.tar.gz"),
    ("foo", {"path": ".", "editable": True, "extras": ["test", "sec"]}, "-e .[test,sec]"),
    ("foo", {"version": ">=1.0", "markers": "os_name=='nt'", "python_version": "~='3.7'"}, 'foo>=1.0; os_name == "nt" and python_version ~= "3.7"'),
    ("foo", {"git": "https://github.com/foo/foo.git", "ref": "master", "subdirectory": "sub"}, "git+https://github.com/foo/foo.git@master#egg=foo&subdirectory=sub")
])
def test_convert_requirement(name, package, req):
    result = requirement_from_pipfile(name, package)
    assert result == req


import requests
import pandas as pd
import numpy as np
import seaborn as sns
from bs4 import BeautifulSoup
import warnings
import nltk
#import surprise
import scipy as sp

from sklearn.metrics.pairwise import cosine_similarity
from sklearn.feature_extraction.text import CountVectorizer
from nltk.corpus import stopwords
from nltk import word_tokenize, RegexpTokenizer
from nltk.stem import SnowballStemmer
from sklearn.feature_extraction.text import TfidfVectorizer
from datetime import datetime, time

import movieMender

class Generos:

    def __init__(self):
        self.cargaDocumentos()

    def cargaDocumentos(self):
        self.df_usuaarioO = pd.read_csv('csv/Usuario_0.csv', sep=';')
        self.df_usuaarioO = self.df_usuaarioO.drop(columns=["title"])

        for usuario_nuevo in range(len(self.df_usuaarioO["movieId"])):
            self.df_usuaarioO["userId"] = 0
            self.df_usuaarioO["timestamp"] = datetime.now()

        self.df_movies = pd.read_csv('csv/movies.csv')
        # Carga del dataframe de las peliculas con su sinopsis

        self.df_movies = self.df_movies.dropna()
        self.df_ratings = pd.read_csv('csv/ratings.csv')
        self.df_ratings = self.df_ratings.dropna()
        self.df_tags = pd.read_csv('csv/tags.csv')
        self.df_tags = self.df_tags.dropna()

        self.df_ratings = pd.concat([self.df_usuaarioO, self.df_ratings], axis=0)

        self.df_movies_ratings = self.df_ratings.merge(self.df_movies)[
            ['userId', 'movieId', 'title', 'rating', 'genres']]

        self.df_movies_ratings_tags = pd.merge(self.df_movies_ratings, self.df_tags, how='outer')[
            ['userId', 'movieId', 'title', 'rating', 'genres', 'tag']]
        self.df_movies_ratings_tags["tag"] = self.df_movies_ratings_tags["tag"].str.lower()
        # self.df_movies_ratings_tags.fillna("vacio", inplace = True)

        self.ratings_table = self.df_movies_ratings.pivot_table(index='userId', columns='title', values='rating')
        # para cambiar los NAN por 0:
        self.ratings_table.fillna(0, inplace=True)

    def recomedacionPorGenero(self, nombrePelicula, n_similares):
        n_similares=int(n_similares)
        genres = list(set([genre for genres in self.df_movies["genres"].str.split("|") for genre in genres]))
        genre_matrix = []
        for index, row in self.df_movies.iterrows():
            genre_list = row["genres"].split("|")
            genre_vector = [1 if genre in genre_list else 0 for genre in genres]
            genre_matrix.append(genre_vector)
        genre_matrix = pd.DataFrame(genre_matrix, columns=genres)
        contador = 1
        selected_movie = self.df_movies[self.df_movies["title"] == nombrePelicula]
        selected_movie_index = selected_movie.index[0]
        #sacamos las similitudes de los generos
        similarities = cosine_similarity(genre_matrix[selected_movie_index:selected_movie_index+1], genre_matrix).flatten()

        #las metemos en una tupla y las ordenamos de mayor a menor
        movie_list = [(index, similarity) for index, similarity in enumerate(similarities)]
        movie_list.sort(key=lambda x: x[1], reverse=True)

        listaSimilar = []
        for i in movie_list[0:n_similares]:
            listaSimilar.append(i)

        #la bandera nos sirve para saltarnos la propia peli que buscamos
        #siempre esta a false y si nos encontramos la peli que estamos buscando la activamos a True
        #si esta en True al finalizar el bucle significa que ha saltado el titulo que buscabamos para no repetirse a si mismo
        #y por lo tanto hay que añadir uno mas para llegar al numero deseado por el usuario
        listaPeliculasMostrar = []
        bandera=False
        if(n_similares>len(self.df_movies)):
            n_similares=len(self.df_movies)-1
        for movie in movie_list[0:n_similares]:
            if(nombrePelicula != self.df_movies.iloc[movie[0]]["title"]):
                listaPeliculasMostrar.append(self.df_movies.iloc[movie[0]]["title"])
                contador+=1
            else:
                bandera=True
        if(bandera):

            mov=movie_list[n_similares][0]
            listaPeliculasMostrar.append(self.df_movies.iloc[mov]["title"])

        return listaPeliculasMostrar #listaSimilar

    def predecirRatingDeUserAPeliculaPorSusGeneros(self, nombrePelicula, user_id):
        user_id=int(user_id)
        yaVotado = self.df_movies_ratings[(self.df_movies_ratings['title']==nombrePelicula) & (self.df_movies_ratings['userId']==user_id)]["rating"].unique()
        if(len(yaVotado)!=0):
            prediction = yaVotado[0]

            return str(prediction)
        else:
            # obtener géneros de la película a predecir
            movie_genres = self.df_movies_ratings[self.df_movies_ratings['title']==nombrePelicula]["genres"].unique()
            generosPeli = movie_genres[0].split("|")
            # filtrar valoraciones del usuario para peliculas con generos en comun
            user_ratings_ID = self.df_movies_ratings[self.df_movies_ratings['userId'] == user_id]
            user_ratings = user_ratings_ID.loc[user_ratings_ID['genres'].str.split('|').apply(lambda x: any(i in x for i in generosPeli))]
            # calcular la media de valoraciones del usuario para las peliculas con generos en comun
            if user_ratings.empty:
                print()
                return "Vacio"
            else:
                #prediction = user_ratings_ID['rating'].mean()
                prediction = format(user_ratings['rating'].mean(), '.3f')

                return str(prediction)

    def recomendacionEnBaseGeneroPelisQueNoHaVistoUsuario(self, user_id, n_similares):
        warnings.filterwarnings('ignore')
        user_id=int(user_id)
        n_similares=int(n_similares)
        #warnings.filterwarnings('ignore')
        df_movies_rating_user = self.df_movies_ratings[self.df_movies_ratings['userId']==user_id]
        df_movies_rating_user = df_movies_rating_user.sort_values(by='rating',ascending=False)

        #cogemos los primeros 10 para ver que generos le gustan mas, anteriormente hemos ordenado por genero
        genero_mejor_rating_unicos = list(set([genre for genres in df_movies_rating_user.head(10)["genres"].str.split("|") for genre in genres]))

        # creamos un diccionario para guardar los generos y cuantas veces se repiten
        genre_count = {}
        for g in genero_mejor_rating_unicos:
            genre_count[g] = df_movies_rating_user.head(10)['genres'].str.count(g).sum()

        #ordenamos el diccionario de mayor a menor
        genero_mejor_rating = dict(sorted(genre_count.items(), key=lambda x: x[1], reverse=True))

        #sacamos las pelis que el usuario no ha visto
        df_movies_no_rating_user = self.df_movies[self.df_movies['movieId'].isin(df_movies_rating_user['movieId']) == False]
        #creamos en el df una columna por cada genero que le gusta al usuario y le agregamos cuanto le gusta
        for genre, weight in genero_mejor_rating.items():
            df_movies_no_rating_user[genre] = df_movies_no_rating_user["genres"].str.contains(genre).apply(lambda x: weight if x else 0)
        #creamos una nueva columna con la suma de cada fila para saber que peliculas le pueden gustar mas
        df_movies_no_rating_user["sumaPesos"] = df_movies_no_rating_user[genero_mejor_rating.keys()].sum(axis=1)
        #ordenamos por las pelis que tengan una mayor puntuacion en la columna sumaPesos ya que esto quiere decir que hay muchos generos que le gustan al usuario
        df_movies_no_rating_user = df_movies_no_rating_user.sort_values(by='sumaPesos',ascending=False)

        df_peliculas_mostrar = df_movies_no_rating_user['title'][0:n_similares]

        listaPeliculasMostrar = []
        contador = 1
        for movie in df_peliculas_mostrar:
            listaPeliculasMostrar.append(movie)
            contador+=1
        return listaPeliculasMostrar


from __future__ import absolute_import, division, print_function, unicode_literals

import logging
import os
import re
from builtins import open

from pants.backend.codegen.antlr.java.java_antlr_library import JavaAntlrLibrary
from pants.backend.jvm.targets.java_library import JavaLibrary
from pants.backend.jvm.tasks.nailgun_task import NailgunTask
from pants.base.exceptions import TaskError
from pants.java.jar.jar_dependency import JarDependency
from pants.task.simple_codegen_task import SimpleCodegenTask
from pants.util.dirutil import safe_mkdir, safe_walk
from pants.util.memo import memoized_method

logger = logging.getLogger(__name__)

def antlr4_jar(name):
  return JarDependency(org='org.antlr', name=name, rev='4.1')

_DEFAULT_ANTLR_DEPS = {
  'antlr3': ('//:antlr-3.4', [JarDependency(org='org.antlr', name='antlr', rev='3.4')]),
  'antlr4': ('//:antlr-4', [antlr4_jar(name='antlr4'),
                            antlr4_jar(name='antlr4-runtime')])
}

# TODO: Refactor this and AntlrPyGen to share a common base class with most of the functionality.
# See comments there for what that would take.
class AntlrJavaGen(SimpleCodegenTask, NailgunTask):
  """Generate .java source code from ANTLR grammar files."""
  gentarget_type = JavaAntlrLibrary

  sources_globs = ('**/*.java',)

  class AmbiguousPackageError(TaskError):
    """Raised when a java package cannot be unambiguously determined for a JavaAntlrLibrary."""

  # TODO: Do we need this?
  def find_sources(self, target, target_dir):
    sources = super(AntlrJavaGen, self).find_sources(target, target_dir)
    return [source for source in sources if source.endswith('.java')]

  @classmethod
  def register_options(cls, register):
    super(AntlrJavaGen, cls).register_options(register)
    for key, (classpath_spec, classpath) in _DEFAULT_ANTLR_DEPS.items():
      cls.register_jvm_tool(register, key, classpath=classpath, classpath_spec=classpath_spec)

  def is_gentarget(self, target):
    return isinstance(target, JavaAntlrLibrary)

  def synthetic_target_type(self, target):
    return JavaLibrary

  def execute_codegen(self, target, target_workdir):
    args = ['-o', target_workdir]
    compiler = target.compiler
    if target.package is None:
      java_package = self._get_sources_package(target)
    else:
      java_package = target.package

    if compiler == 'antlr3':
      if target.package is not None:
        logger.warn("The 'package' attribute is not supported for antlr3 and will be ignored.")
      java_main = 'org.antlr.Tool'
    elif compiler == 'antlr4':
      args.append('-visitor')  # Generate Parse Tree Visitor As Well
      # Note that this assumes that there is no package set in the antlr file itself,
      # which is considered an ANTLR best practice.
      args.append('-package')
      args.append(java_package)
      java_main = 'org.antlr.v4.Tool'
    else:
      raise TaskError('Unsupported ANTLR compiler: {}'.format(compiler))

    antlr_classpath = self.tool_classpath(compiler)
    sources = self._calculate_sources([target])
    args.extend(sources)
    result = self.runjava(classpath=antlr_classpath, main=java_main, args=args,
                          workunit_name='antlr')
    if result != 0:
      raise TaskError('java {} ... exited non-zero ({})'.format(java_main, result))

    self._rearrange_output_for_package(target_workdir, java_package)
    if compiler == 'antlr3':
      self._scrub_generated_timestamps(target_workdir)

  def synthetic_target_extra_dependencies(self, target, target_workdir):
    # Fetch the right java dependency from the target's compiler option
    return self._deps(target.compiler)

  @memoized_method
  def _deps(self, compiler):
    spec = self.get_options()[compiler]
    return list(self.resolve_deps([spec])) if spec else []

  # This checks to make sure that all of the sources have an identical package source structure, and
  # if they do, uses that as the package. If they are different, then the user will need to set the
  # package as it cannot be correctly inferred.
  def _get_sources_package(self, target):
    parents = {os.path.dirname(source) for source in target.sources_relative_to_source_root()}
    if len(parents) != 1:
      raise self.AmbiguousPackageError('Antlr sources in multiple directories, cannot infer '
                                       'package. Please set package member in antlr target.')
    return parents.pop().replace('/', '.')

  def _calculate_sources(self, targets):
    sources = set()

    def collect_sources(tgt):
      if self.is_gentarget(tgt):
        sources.update(tgt.sources_relative_to_buildroot())
    for target in targets:
      target.walk(collect_sources)
    return sources

  _COMMENT_WITH_TIMESTAMP_RE = re.compile(r'^//.*\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d')

  def _rearrange_output_for_package(self, target_workdir, java_package):
    """Rearrange the output files to match a standard Java structure.

    Antlr emits a directory structure based on the relative path provided
    for the grammar file. If the source root of the file is different from
    the Pants build root, then the Java files end up with undesired parent
    directories.
    """
    package_dir_rel = java_package.replace('.', os.path.sep)
    package_dir = os.path.join(target_workdir, package_dir_rel)
    safe_mkdir(package_dir)
    for root, dirs, files in safe_walk(target_workdir):
      if root == package_dir_rel:
        # This path is already in the correct location
        continue
      for f in files:
        os.rename(
          os.path.join(root, f),
          os.path.join(package_dir, f)
        )

    # Remove any empty directories that were left behind
    for root, dirs, files in safe_walk(target_workdir, topdown = False):
      for d in dirs:
        full_dir = os.path.join(root, d)
        if not os.listdir(full_dir):
          os.rmdir(full_dir)

  def _scrub_generated_timestamps(self, target_workdir):
    """Remove the first line of comment from each file if it contains a timestamp."""
    for root, _, filenames in safe_walk(target_workdir):
      for filename in filenames:
        source = os.path.join(root, filename)

        with open(source, 'r') as f:
          lines = f.readlines()
        if len(lines) < 1:
          return
        with open(source, 'w') as f:
          if not self._COMMENT_WITH_TIMESTAMP_RE.match(lines[0]):
            f.write(lines[0])
          for line in lines[1:]:
            f.write(line)


import constants
from flask import jsonify, make_response

def getData(request):
    body = request.json
    outlook = body['outlook']
    temp = body['temp']
    humidity = body['humidity']
    wind = body['wind']

    data = [
        constants.OUTLOOK_VALUES[outlook],
        constants.TEMP_VALUES[temp],
        constants.HUMIDITY_VALUES[humidity],
        constants.WIND_VALUES[wind]
    ]

    return data

def makeResponse(result, modelType):
    return make_response(jsonify(
        {
            'message': 'Success',
            'data': {
                'modelType': modelType,
                'play': constants.PLAY_VALUES[result]
            }
        }
    ))


import streamlit as st

from recipesnet.api import RecipesApi
from recipesnet.st_helpers import recip_ingr_widget

st.set_page_config("Recipes net", layout="wide")

st.title("Recipes similarity")
st.write(
    """
In this section you can search what recipes are similar to an specific one.
    """
)

with st.spinner("Loading data..."):
    if "api" not in st.session_state:
        st.session_state["api"] = RecipesApi()
    api: RecipesApi = st.session_state.api

c1, c2 = st.columns(2)

with c1:
    st.header("Similar recipes")

    recipes = api.recipes
    selected_recipe = st.selectbox(
        "Recipes similar to ...",
        recipes,
        recipes.index(st.session_state.recipe) if "recipe" in st.session_state else 0,
    )
    st.session_state.recipe = selected_recipe

    similar = api.similar_recipes(selected_recipe)
    i = 0
    for rec, score in similar:
        if st.button(f"{score:.1%}: {rec.capitalize()}", key=f"similarity_btn_{i}"):
            st.session_state.recipe = rec
        i += 1

with c2:
    recip_ingr_widget()


"""
firebase.py

This module caches video information in Firebase using the user's id as the key.
Cached video entries include duration, title, channel name, category, and timestamp.
The timestamp acts as a TTL of 24 hours, and entries older than the TTL are updated by requesting
the video information from the YouTube API.

Functions:
    - is_video_cached(): Checks if a video is cached in Firebase and not expired.
    - get_uncached_video_ids(): Returns a list of uncached or expired video IDs.
    - cache_video_data(): Caches video information in Firebase for a given video ID.
    - cache_request(): Caches video information in Firebase if not already cached or expired.
"""

# Necessary imports
import os
import sys
import json
from datetime import datetime, timedelta

# Add the parent directory to sys.path to import local modules
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

# Local modules
from utils.imports import *
from utils.youtube_utils import get_video_information

# Credentials
from config.credentials import *

def is_video_cached(video_id, data_from_cache):
    required_attributes = ['timestamp', 'duration', 'title', 'channel_name', 'category']
    if not data_from_cache or video_id not in data_from_cache:
        return False

    for attribute in required_attributes:
        if attribute not in data_from_cache[video_id]:
            return False

    timestamp = datetime.strptime(data_from_cache[video_id]['timestamp'], "%Y-%m-%dT%H:%M:%S.%f")
    return datetime.now() - timestamp < timedelta(days=1)

def get_uncached_video_ids(video_ids, data_from_cache):
    uncached_video_ids = []
    for video_id in video_ids:
        if not is_video_cached(video_id, data_from_cache):
            uncached_video_ids.append(video_id)
    return uncached_video_ids

def cache_video_data(user_email, video_id, video_data):
    url = f'{FIREBASE_DB_URL}/{user_email}/{video_id}.json?auth={FIREBASE_API_KEY}'
    response = requests.put(url, json.dumps(video_data))

def cache_request(youtube, video_ids):
    user_email = USER_ID.replace('@', '-').replace('.', '-')
    video_info = {}

    # Check if the video_ids are in Firebase cache
    url = f'{FIREBASE_DB_URL}/{user_email}.json?auth={FIREBASE_API_KEY}'
    response = requests.get(url)
    data_from_cache = response.json()

    if data_from_cache is None:
        data_from_cache = {}

    uncached_video_ids = get_uncached_video_ids(video_ids, data_from_cache)

    # If there are uncached videos, request the video information from YouTube API
    if uncached_video_ids:
        video_data = get_video_information(youtube, uncached_video_ids)

        # Update the cache with the new video information
        for video_id, data in video_data.items():
            # Convert duration to ISO 8601 format before storing in Firebase
            data['duration'] = isodate.duration_isoformat(data['duration'])

            # Add a timestamp to the video data
            data['timestamp'] = datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")

            # Cache the channel name and category
            data['channel_name'] = data['channel_name']
            data['category'] = data.get('category', 'Unknown')

            cache_video_data(user_email, video_id, data)

    # Build video_info from cache data and newly fetched data
    for video_id in video_ids:
        if video_id in data_from_cache:
            try:
                video_info[video_id] = {
                    'duration': timedelta(seconds=isodate.parse_duration(data_from_cache[video_id]['duration']).total_seconds()),
                    'title': data_from_cache[video_id]['title'],
                    'channel_name': data_from_cache[video_id]['channel_name'],
                    'category': data_from_cache[video_id].get('category', 'Unknown')  # Use .get() to handle the missing 'category' key
                }
            except isodate.isoerror.ISO8601Error:
                pass
        elif video_id in video_data:
            video_info[video_id] = {
                'duration': timedelta(seconds=isodate.parse_duration(video_data[video_id]['duration']).total_seconds()),
                'title': video_data[video_id]['title'],
                'channel_name': video_data[video_id]['channel_name'],
                'category': video_data[video_id]['category']
            }

    return video_info


import csv
import datetime
import pathlib
from typing import Generator

import click

from case_rate._types import Cases, CaseTesting, PathLike
from case_rate.sources._utilities import download_file
from case_rate.storage import InputSource

def _to_date(date: str) -> datetime.date:
    '''Converts a date string into a date object.

    Parameters
    ----------
    date : str
        input date string of the form "DD-MM-YYYY"

    Returns
    -------
    datetime.date
        output ``date`` object
    '''
    dt = datetime.datetime.strptime(date, '%d-%m-%Y')
    return dt.date()

def _to_int(number: str) -> int:
    '''Converts a numerical string into an integer.

    This performs an extra check to see if the input string is ``''``.  This is
    then treated as a zero.  Anything else will result in a ``ValueError``.

    Parameters
    ----------
    number : str
        input string as a number

    Returns
    -------
    int
        the string's integer value

    Throws
    ------
    :exc:`ValueError`
        if the string is not actually a number
    '''
    if len(number) == 0:
        return 0

    if number == 'N/A':
        return 0

    try:
        count = int(number)
    except ValueError:
        count = int(float(number))

    return count

class PublicHealthAgencyCanadaSource(InputSource):
    '''Uses reporting data published by the PHAC.

    This input source uses a CSV file that's regularly updated by the Public
    Health Agency of Canada (PHAC).  The default source is
    https://health-infobase.canada.ca/src/data/covidLive/covid19.csv.  The
    data source will link back to the original PHAC site rather than to the
    file.
    '''
    def __init__(self, path: PathLike, url: str, info: str,
                 update: bool = True):
        '''
        Parameters
        ----------
        path : path-like object
            the path (on disk) where the CSV file is located
        url : str
            the URL to the Government of Canada's COVID-19 report
        info : str optional
            the URL to the main information path (not the CSV file)
        update : bool, optional
            if ``True`` then updates an existing CSV file to the latest version
        '''
        path = pathlib.Path(path) / 'covid19.csv'
        if path.exists():
            if update:
                click.echo('Updating PHAC COVID-19 report.')
                download_file(url, path)
        else:
            click.echo('Accessing PHAC COVID-19 report.')
            download_file(url, path)

        self._info = info
        self._path = path

    @classmethod
    def name(cls) -> str:
        return 'public-health-agency-canada'

    @classmethod
    def details(cls) -> str:
        return 'Public Health Agency of Canada - Current Situation'

    def url(self) -> str:
        return self._info

    def cases(self) -> Generator[Cases, None, None]:
        with self._path.open() as f:
            contents = csv.DictReader(f)
            for entry in contents:
                if entry['prname'] == 'Canada':
                    continue

                # NOTE: PHAC doesn't report resolved cases as of 2022-08-26
                yield Cases(
                    date=_to_date(entry['date']),
                    province=entry['prname'],
                    country='Canada',
                    confirmed=_to_int(entry['totalcases']),
                    resolved=-1,
                    deceased=_to_int(entry['numdeaths'])
                )

    def testing(self) -> Generator[CaseTesting, None, None]:
        with self._path.open() as f:
            contents = csv.DictReader(f)
            for entry in contents:
                if entry['prname'] == 'Canada':
                    continue

                # NOTE: PHAC doesn't report testing counts as of 2022-08-26
                yield CaseTesting(
                    date=_to_date(entry['date']),
                    province=entry['prname'],
                    country='Canada',
                    tested=-1,
                    under_investigation=-1
                )


import time
from dataclasses import dataclass
from transmitter import sendEmail
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.firefox.options import Options as FFOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC

@dataclass()
class AutoWeb:
    url: str
    ff: bool = False
    headless: bool = False

    def start_session(self):
        options = FFOptions() if self.ff else Options()
        if self.headless: options.add_argument('--headless')
        dr = '/Users/ashhadghazi/scripts/python/webdrivers/geckodriver' if self.ff \
            else '/Users/ashhadghazi/scripts/python/webdrivers/chromedriver'
        self.br = webdriver.Firefox(executable_path=dr, options=options) if self.ff else webdriver.Chrome(dr, chrome_options=options)
        self.br.get(self.url)

    def get(self, url):
        self.br.get(url)

    def go_back(self):
        self.br.back()

    def refresh(self):
        self.br.refresh()

    def stop_session(self):
        self.br.quit()

    def get_key(self, key, only_check_if_special=False):
        key_map = {
            'up':    Keys.UP,
            'right': Keys.RIGHT,
            'down':  Keys.DOWN,
            'left':  Keys.LEFT,
            'enter': Keys.ENTER,
            'escape': Keys.ESCAPE
        }

        if only_check_if_special:
            return True if key in key_map.keys() else False
        return key_map[key] if key in key_map.keys() else key

    def get_by(self, by):
        by_map = {
            'id':                By.ID,
            'css':               By.CSS_SELECTOR,
            'name':              By.NAME,
            'xpath':             By.XPATH,
            'class':             By.CLASS_NAME,
            'link_text':         By.LINK_TEXT,
            'partial_link_text': By.PARTIAL_LINK_TEXT
        }

        return by_map[by]

    def element_exists(self, by, elem):
        by = self.get_by(by)
        return len(self.br.find_elements(by, elem))

    def get_element(self, by, elem):
        by = self.get_by(by)
        return WebDriverWait(self.br, 5).until(
                EC.presence_of_element_located((by, elem)))

    def get_elements(self, by, elem):
        by = self.get_by(by)
        return WebDriverWait(self.br, 5).until(
                EC.presence_of_all_elements_located((by, elem)))

    def get_element_text(self, elem, by):
        by = self.get_by(by)
        return WebDriverWait(self.br, 5).until(
                EC.presence_of_element_located((by, elem))).text

    def get_table_rows(self, by, elem):
        by = self.get_by(by)
        table = self.get_element(by, elem)
        return table.find_elements_by_tag_name('li')

    def notify(sbj, msg):
        email = "<email_address>"
        pwd = "<password>"
        sendEmail(email, pwd, [email], msg, sbj)

    def run_op(self, by, elem, op, op_value=''):
        by = self.get_by(by)
        if op == 'send':
            if not self.get_key(op_value, only_check_if_special=True):
                self.get_element(by, elem).clear()
            time.sleep(0.2)
            self.get_element(by, elem).send_keys(self.get_key(op_value))
        elif op == 'clear':
            self.get_element(by, elem).clear()
        elif op == 'click':
            self.get_element(by, elem).click()
        time.sleep(0.2)

    def run_ops(self, ops_map):
        for op in ops_map:
            self.run_op(op['by'], op['elem'], op['op'], op['op_value'])


from sqlalchemy import create_engine
from constants import get_nutrient_idx

def load_cache():
  db = create_engine('sqlite:///usda.sql3')

  cache = {}

  query = "SELECT food.id,food.long_desc,food_group.name,nutrient.tagname,nutrition.amount,weight.gm_weight,weight.gm_weight*nutrition.amount/100.0 as gm_amount,weight.description FROM food, food_group, nutrient, nutrition, weight  where food.food_group_id = food_group.id and food.id = nutrition.food_id and nutrient.id = nutrition.nutrient_id and weight.food_id = food.id and food.id < 1100 and weight.sequence_num = 1 and nutrient.tagname in ('ENERC_KCAL','CHOCDF','PROCNT','FAT','LACS','SUGAR','CAFFN') order by food.id, nutrient.tagname"

  conn = db.connect()
  result = conn.execute(query)

  nidx = get_nutrient_idx()

  rows = result.cursor.fetchall()

  for row in rows:
    fid = row[0]
    desc = row[1]
    group = row[2]
    nutrient = row[3]
    amount = row[4]
    gm_weight = row[5]
    gm_amount = row[6]
    serving_desc = row[7]

    if fid not in cache:
      cache[fid] = [fid,desc,group,serving_desc,gm_weight,0,0,0,0,0,0,0]

    cache[fid][nidx[nutrient]] = gm_amount

  return cache


#You'r a robot?
from random import randint, randrange
from PIL import Image, ImageDraw, ImageFont
import os
import textwrap

class CreateCaptcha:
    def __init__(self):
        self.valido = False
        self.l = []
        self.width = 300
        self.height = 150
        self.font_size = 60  # Tamanho maior da fonte

    def Gerar(self):
        y = randrange(4, 12, 4) #pega valores em um intervalo aleatório
        cont = y #Vai gerar o tamanho do capcha
        while cont > 0:
            n = randint(0, 1)
            if n == 0:
                val = chr(randint(65, 90))
            else:
                val = chr(randint(49, 57))
            self.l.append(val)
            cont -= 1
        #print(f"CARACETERES DE VERIFICAÇÃO: {l}") #Apenas para análise
        l = ''.join(self.l) #Uni as letras
        return l

    def Validar(self, MeuGerador, ValorUser):
        #Executa a validação
        if ValorUser == MeuGerador:
            self.valido = True
            return self.valido
        else:
             return self.valido

    def GerarImagem(self, text):
        # Cria uma imagem em branco
        image = Image.new('RGB', (self.width, self.height), color=(255, 255, 255))

        # Cria um objeto de desenho
        draw = ImageDraw.Draw(image)

        # Carrega uma fonte para o texto com tamanho maior
        font = ImageFont.load_default()
        font = ImageFont.truetype("arial.ttf", self.font_size)  # Use a fonte TrueType e defina o tamanho da fonte

        # Obtém as dimensões da caixa do texto
        text_bbox = draw.textbbox((0, 0), text, font)

        # Centraliza o texto na imagem
        x = (self.width - text_bbox[2] - text_bbox[0]) / 2
        y = (self.height - text_bbox[3] - text_bbox[1]) / 2

        # Desenha o texto na imagem
        draw.text((x, y), text, fill=(0, 0, 0), font=font)

        # Adiciona um risco à imagem
        for _ in range(10):
            x1 = randint(0, self.width - 1)
            y1 = randint(0, self.height - 1)
            x2 = randint(0, self.width - 1)
            y2 = randint(0, self.height - 1)
            draw.line([(x1, y1), (x2, y2)], fill=(0, 0, 0), width=2)

        # Adiciona um padrão de fundo aleatório (pontos)
        for _ in range(1000):
            x = randint(0, self.width - 1)
            y = randint(0, self.height - 1)
            draw.point((x, y), fill=(0, 0, 0))

        #Salve o arquivo na pasta image
        d = os.getcwd()
        i = "static\\image"
        caminho  = os.path.join(d, i)
        element_image_path = os.path.join(caminho, "element_image.png")

        # Salva a imagem como um arquivo
        image.save(element_image_path)

if __name__ == "__main__":
    c = CreateCaptcha()
    x = c.Gerar()
    c.GerarImagem(x)
    print(x)
    y = input("Copie aqui ou digite errado: ").upper()
    print(c.Validar(x, y))


#!/usr/bin/env python
# coding: utf-8

# 1. Compare and contrast the float and Decimal classes' benefits and drawbacks.
#

#  floats are faster and more memory-efficient, suitable for a wide range of values, but can have precision and rounding issues. Decimals provide precise decimal arithmetic, accurate representation of decimal numbers, but are slower and have a more limited value range. The choice between float and Decimal depends on the specific requirements of the application.

# 2. Decimal('1.200') and Decimal('1.2') are two objects to consider. In what sense are these the same object? Are these just two ways of representing the exact same value, or do they correspond to different internal states?
#

# Decimal('1.200') and Decimal('1.2') represent the same value of 1.2 mathematically. However, internally they have different representations due to the presence or absence of trailing zeros, making them distinct Decimal objects.

# 3. What happens if the equality of Decimal('1.200') and Decimal('1.2') is checked?
#

# In[6]:

from decimal import Decimal

decimal1 = Decimal('1.200')
decimal2 = Decimal('1.2')

print(decimal1 == decimal2)

# 4. Why is it preferable to start a Decimal object with a string rather than a floating-point value?
#

# In[10]:

#example
from decimal import Decimal

float_value = 0.1
decimal_float = Decimal(float_value)
decimal_string = Decimal('0.1')

# In[11]:

print(decimal_float)

# In[12]:

print(decimal_string)

# 5. In an arithmetic phrase, how simple is it to combine Decimal objects with integers?
#

# Decimal objects with integers in arithmetic operations is simple and straightforward. The Decimal class seamlessly handles the interoperability between Decimal objects and integers, allowing you to use standard arithmetic operators without any additional complexity.

# 6. Can Decimal objects and floating-point values be combined easily?
#

# Combining Decimal objects with floating-point values in arithmetic operations is easy and straightforward in Python. The Decimal class seamlessly supports interoperability between Decimal objects and floating-point values, allowing you to use standard arithmetic operators without any complications.

# 7. Using the Fraction class but not the Decimal class, give an example of a quantity that can be expressed with absolute precision.
#

# In[13]:

#The Fraction class in Python allows precise representation of rational numbers without any loss of precision. Here's an example of a quantity that can be expressed with absolute precision using the Fraction class

from fractions import Fraction
fraction = Fraction(4,8)

# In[15]:

print(fraction)

# 8. Describe a quantity that can be accurately expressed by the Decimal or Fraction classes but not by a floating-point value.
#

# In[16]:

#example

from decimal import Decimal
decimal = Decimal('2')/ Decimal('8')

# In[17]:

print(decimal)

# In[19]:

#example

from fractions import Fraction
fraction = Fraction(2,8)

# In[20]:

print(fraction)

# Q9.Consider the following two fraction objects: Fraction(1, 2) and Fraction(1, 2). (5, 10). Is the internal state of these two objects the same? Why do you think that is?
#

# In[25]:

#yes the internal state of these two object are same:

from fractions import Fraction

fractions1 = Fraction(1,2)
fractions2 = Fraction(5,10)

# In[26]:

print(fractions1)

# In[27]:

print(fractions2)

# Q10. How do the Fraction class and the integer type (int) relate to each other? Containment or inheritance?
#

# The Fraction class and the int type have a containment relationship. The Fraction class can work with and contain integer

# In[ ]: