# Run this app with `python app.py` and
# visit http://127.0.0.1:8050/ in your web browser.

import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
import plotly.graph_objects as go
import plotly.express as px
import pandas as pd
import json
import numpy as np
import pandas as pd
import io
import requests

########################################################################################
## Download the data
########################################################################################
def get_data_from_url(url):
    content = requests.get(url).content
    return pd.read_csv(io.StringIO(content.decode('utf-8')))

# COVID-19 Cases Data
phu_data_rolling = get_data_from_url('https://data.ontario.ca/dataset/1115d5fe-dd84-4c69-b5ed-05bf0c0a0ff9/resource/d1bfe1ad-6575-4352-8302-09ca81f7ddfc/download/cases_by_status_and_phu.csv')
ontario_daily = get_data_from_url('https://data.ontario.ca/dataset/f4f86e54-872d-43f8-8a86-3892fd3cb5e6/resource/ed270bb8-340b-41f9-a7c6-e8ef587e6d11/download/covidtesting.csv')
# COVID-19 Testing Data
df_test = get_data_from_url('https://data.ontario.ca/dataset/a2dfa674-a173-45b3-9964-1e3d2130b40f/resource/07bc0e21-26b5-4152-b609-c1958cb7b227/download/testing_metrics_by_phu.csv')
# COVID-19 Ontario ICU Data
df_ICU = get_data_from_url('https://data.ontario.ca/dataset/8f3a449b-bde5-4631-ada6-8bd94dbc7d15/resource/e760480e-1f95-4634-a923-98161cfb02fa/download/region_hospital_icu_covid_data.csv')
# COVID-19 Ontario Vaccine Data
df_Vaccine = get_data_from_url('https://raw.githubusercontent.com/ccodwg/Covid19Canada/master/timeseries_prov/vaccine_administration_timeseries_prov.csv')
# COVID-19 Ontario Age and Gender Data
df_age_gender = get_data_from_url('https://data.ontario.ca/dataset/f4112442-bdc8-45d2-be3c-12efae72fb27/resource/455fd63b-603d-4608-8216-7d8647f43350/download/conposcovidloc.csv')
# COVID-19 Testing Centers
df_testing_centre = get_data_from_url('https://data.ontario.ca/dataset/covid-19-assessment-centre-locations/resource/c60993bb-3988-4648-9be9-398dee480514/download/assessment_centre_locations.csv')

########################################################################################
## Modify the Data and Make Plot
########################################################################################

########################################################################################
# COVID-19 Statistics

# necessary global variables
ontario_daily.loc[:,'new_positive'] = ontario_daily['Confirmed Positive'].diff()
ontario_daily.loc[:,'new_cases']= ontario_daily['Total Cases'].diff()
ontario_daily.loc[:,'new_resolved']= ontario_daily['Resolved'].diff()
ontario_daily.loc[:,'new_death']= ontario_daily['Deaths'].diff()

today = ontario_daily.loc[ontario_daily['Reported Date']==ontario_daily['Reported Date'].max(),:]
active_cases = int(today['Confirmed Positive'])
total_cases = int(today['Total Cases'])
total_deaths = int(today['Deaths'])
total_recoveries = int(today['Resolved'])
total_tests = int(ontario_daily['Total tests completed in the last day'].sum())

new_positive_today = int(today['new_cases'])
new_recovered_today = int(today['new_resolved'])
new_deaths_today = int(today['new_death'])
tests_today = int(today['Total tests completed in the last day'])

if(new_positive_today < 0):
    new_positive_today = 0

########################################################################################
# Map Plot

# COVID-19 Cases Data for map plot
df = phu_data_rolling.groupby('PHU_NAME')['FILE_DATE'].max().reset_index()
df = df.merge(phu_data_rolling, on = ['PHU_NAME', 'FILE_DATE'])
df.reset_index(inplace=True, drop=True)

# modify testing centres to only contain currently active testing centres
df_testing_centre = df_testing_centre.loc[df_testing_centre['active']=='Yes']
df_testing_centre = df_testing_centre.loc[(df_testing_centre['latitude'].isna()==False)&(df_testing_centre['longitude'].isna()==False)]
df_testing_centre['longitude'] = pd.to_numeric(df_testing_centre['longitude'].str.strip())
df_testing_centre.loc[df_testing_centre['phone'].isna(),'phone'] = 'N/A'
df_testing_centre = df_testing_centre.loc[df_testing_centre['longitude'] != 0]

with open("Ministry_of_Health_Public_Health_Unit_Boundary Simplified.json") as f:
    boundary_data = json.load(f)

fig = px.choropleth_mapbox(df, geojson=boundary_data, featureidkey='properties.PHU_ID',
                           locations='PHU_NUM', color='ACTIVE_CASES',
                           color_continuous_scale="purpor",
                           #color_continuous_scale="agsunset",
                           range_color=(0, 4000),
                           mapbox_style="carto-positron",
                           zoom=4, center = {"lat": 48.31, "lon": -84.73},
                           opacity=0.5,
                           labels={'PHU_NUM': 'PHU Number'},
                           hover_data = ['PHU_NAME']
                          )

fig2 = px.scatter_mapbox(df_testing_centre,lat='latitude',lon='longitude',
                         hover_name='location_name',hover_data=['phone','website'],
                         mapbox_style="carto-positron",zoom=4, center = {"lat": 48.31, "lon": -84.73})

fig.add_trace(fig2.data[0])
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0}, dragmode=False)

########################################################################################
# PHU Bar Plot

# Needed for plotting phu bars
phu_dict_list = [{'label':name, 'value':name} for name in phu_data_rolling['PHU_NAME'].unique() if name is not np.nan]
phu_dict_list.append({'label':'ONTARIO','value':'ONTARIO'})

# Bar plot for phu data
colors = ['#d9534f','#5cb85c','#7289da']

phu_bar = go.Figure(data=[go.Bar(
    x=['Active', 'Recovered', 'Deaths'],
    y=[active_cases, total_recoveries, total_deaths],
    marker_color=colors # marker color can be a single color value or an iterable
)])
phu_bar.update_layout(
    yaxis_title="Number of Cases")

########################################################################################
# ICU Line Plot

## compute the ICU cases by different region
df_ICU_ONTARIO = df_ICU.groupby('date')['date', 'ICU'].agg('sum')
df_ICU_ONTARIO.reset_index(inplace = True)

# get icu dropdown list
icu_dict_list = [{'label':name + ' ONTARIO', 'value':name + ' ONTARIO'} for name in df_ICU['oh_region'].unique()]
icu_dict_list.append({'label':'ONTARIO','value':'ONTARIO'})

fig_ICU = go.Figure(data=[go.Scatter(
    x=df_ICU_ONTARIO.date,
    y=df_ICU_ONTARIO.ICU,
    name="ONTARIO",
    line=dict(color="#7289da"))])
fig_ICU.update_layout(
    xaxis_title="Date",
    yaxis_title="Number of ICU Cases")

########################################################################################
# Age and Gender Bar Plot

# modify gender feature to only contain female, male and other
df_age_gender.Client_Gender = df_age_gender.Client_Gender.replace(
    {'FEMALE': 'FEMALE', 'MALE': 'MALE',
    'UNSPECIFIED': 'OTHER',
    'GENDER DIVERSE': 'OTHER'})

# drop the missing age group and
df_age_gender = df_age_gender.loc[df_age_gender.Age_Group != 'UNKNOWN']
df_age_gender.Age_Group.dropna(inplace = True)
# change age group names
df_age_gender.Age_Group = df_age_gender.Age_Group.replace(
    {'<20': '0-19', '20s': '20-29', '30s': '30-39',
    '40s': '40-49', '50s': '50-59', '60s': '60-69',
    '70s': '70-79', '80s': '80-89', '90s': '90-99'})

# only keep case report date, gender and age
df_age_gender = df_age_gender[['Case_Reported_Date', 'Age_Group', 'Client_Gender']]
df_age_only = df_age_gender[['Case_Reported_Date', 'Age_Group']]

# create bar plots of total cases, cases by age groups, cases by exposure:
df_age_gender_date = df_age_gender[['Case_Reported_Date', 'Age_Group', 'Client_Gender']]
bar_df = df_age_gender_date.groupby('Case_Reported_Date')['Client_Gender'].agg(['count'])
bar_df.reset_index(inplace = True)

fig_bar1 = px.bar(x= pd.to_datetime(bar_df.iloc[:, 0]), y= bar_df.iloc[:, 1])
fig_bar1.update_layout(
    title="",
    xaxis_title="Case Reported Date",
    yaxis_title="Number of Reported Cases")
fig_bar1.update_traces(hovertemplate='Date: %{x}
Count: %{y}', selector=dict(type='bar'))

age_bar_df = df_age_gender_date.groupby(['Case_Reported_Date', 'Age_Group'])['Client_Gender'].agg(['count'])
age_bar_df.reset_index(inplace = True)
age_bar_df['Age_Group'] = age_bar_df['Age_Group'].astype(object)
fig_bar2 = px.bar(x= pd.to_datetime(age_bar_df['Case_Reported_Date']), y= age_bar_df['count'], color = age_bar_df['Age_Group'])
fig_bar2.update_layout(
    title="",
    xaxis_title="Case Reported Date",
    yaxis_title="Number of Reported Cases",
    legend_title_text='Age Group')
fig_bar2.update_traces(hovertemplate='Date: %{x}
Count: %{y}', selector=dict(type='bar'))

gender_bar_df = df_age_gender_date.groupby(['Case_Reported_Date', 'Client_Gender'])['Client_Gender'].agg(['count'])
gender_bar_df.reset_index(inplace = True)

fig_bar3 = px.bar(x= pd.to_datetime(gender_bar_df['Case_Reported_Date']), y= gender_bar_df['count'], color = gender_bar_df['Client_Gender'])
fig_bar3.update_layout(
    title="",
    xaxis_title="Case Reported Date",
    yaxis_title="Number of Reported Cases",
    legend_title_text='Gender')

fig_bar3.update_traces(hovertemplate='Date: %{x}
Count: %{y}', selector=dict(type='bar'))

# compute total count groupby age and gender
df_age_gender = df_age_gender.groupby(by=['Age_Group', 'Client_Gender']).count()
df_age_gender = df_age_gender.groupby(level = 0).apply(lambda x: 100 * x / float(x.sum()))
df_age_gender.reset_index(inplace = True)

# compute total count groupby age
df_age_only = df_age_only.groupby(by=['Age_Group']).count()
df_age_only = df_age_only.apply(lambda x: 100 * x / float(x.sum()))
df_age_only.reset_index(inplace = True)
# merge the df_age_gender and df_age_only
df_age_gender = df_age_gender.merge(df_age_only, on = 'Age_Group')
# compute the distribution of age and gender
df_age_gender['percent'] = df_age_gender['Case_Reported_Date_x'] * df_age_gender['Case_Reported_Date_y']/100

fig_age_gender = px.bar(df_age_gender, x="percent", y="Age_Group", color="Client_Gender",
             labels={'percent':'Proportion (%)', 'Age_Group': 'Age Group (Years)',
                    'Client_Gender': 'Gender'})

########################################################################################
# COVID-19 Positive Rate Bar Plot

## compute the population in each Public Health Unit
# convert string to integer
df_test['test_volumes_7d_avg'] = df_test['test_volumes_7d_avg'].apply(lambda x: int(x.replace(',', '')))
df_test['DATE']= pd.to_datetime(df_test['DATE'], dayfirst = True)

current_date = max(df_test['DATE'].unique())
df_test_current = df_test.loc[df_test['DATE'] == current_date]
df_test_current.reset_index(inplace=True, drop=True)

# compute the population for each PHU
df_test_current['pop'] = (df_test_current['test_volumes_7d_avg'] / df_test_current['tests_per_1000_7d_avg']) * 1000

## compute the COVID-19 positive rate by Public Health Unit and generate bar plot
df = df.merge(df_test_current, left_on='PHU_NUM', right_on='PHU_num')
df['positive_rate'] = (df['ACTIVE_CASES']/df['pop']) * 100
df = df.sort_values(by = 'positive_rate')
fig_positive_rate = px.bar(df, x='positive_rate', y='PHU_NAME', height=700,
                           # color='positive_rate',
                           #color_continuous_scale="purpor",
                           labels={'positive_rate': 'COVID-19 Active Cases Rate %',
                                   'PHU_NAME': 'Public Health Unit'})
fig_positive_rate.update_layout(margin=dict(l=4,r=4))
fig_positive_rate.update_traces(marker_color="#7289da")

########################################################################################
# Vaccine Administration Line Plot

# compute Ontario Vaccine Administration
df_Vaccine = df_Vaccine.loc[df_Vaccine['province'] == 'Ontario']
df_Vaccine['date_vaccine_administered']= pd.to_datetime(df_Vaccine['date_vaccine_administered'], dayfirst = True)
df_Vaccine.reset_index(inplace = True, drop = True)
fig_Vaccine = px.line(df_Vaccine, x = 'date_vaccine_administered', y = 'avaccine',
              labels={
                  'date_vaccine_administered': 'Date',
                  'avaccine': 'Vaccine Administered'
              })
fig_Vaccine.update_layout(margin=dict(r=8))

########################################################################################
# HTML Components

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

# HTML components go here, control the heights using h classes with percent of screen height ##########
app.layout = dbc.Container(
    [
        #### Header
        dbc.Row([dbc.Col(html.H1("Ontario COVID-19 Dashboard")),
                dbc.Col(dbc.Button(
                            "Reference Data",
                            id="link-centered",
                            className="ml-auto",
                            href='https://data.ontario.ca/dataset/'
                            ), md=2, width=6)]),
        html.Hr(),

        #### COVID-19 Statistics
        dbc.Row(
            [
                dbc.Col(dbc.Card(
                    dbc.CardBody(
                        [dbc.Row([dbc.Col([html.H4("New Cases Today", className="card-title"),
                            html.H1('{:,}'.format(new_positive_today)),
                            ], width=6),
                            dbc.Col([html.H4("Total Cases", className="card-title"),
                            html.H1('{:,}'.format(total_cases)),
                            ], width=6)
                        ])

                        ]
                    ),
                    style={'text-align':'center',
                           'margin-top': '10px',
                           'margin-bottom': '5px',
                           'margin-left': '15px'},outline=True),md=6, width=6),
                dbc.Col(dbc.Card(
                    dbc.CardBody(
                        [dbc.Row([dbc.Col([html.H4("Deaths Today", className="card-title"),
                            html.H1('{:,}'.format(new_deaths_today)),
                            ], width=6),
                            dbc.Col([html.H4("Total Deaths", className="card-title"),
                            html.H1('{:,}'.format(total_deaths)),
                            ], width=6)
                        ])

                        ]
                    ),
                    style={'text-align':'center',
                           'margin-top': '10px',
                           'margin-bottom': '5px',
                           'margin-right': '15px'},outline=True),md=6, width=6),
            ]),
        dbc.Row(
            [
                dbc.Col(dbc.Card(
                    dbc.CardBody(
                        [dbc.Row([dbc.Col([html.H4("Recovered Today", className="card-title"),
                            html.H1('{:,}'.format(new_recovered_today)),
                            ], width=6),
                            dbc.Col([html.H4("Total Recovered", className="card-title"),
                            html.H1('{:,}'.format(total_recoveries)),
                            ], width=6)
                        ])

                        ]
                    ),
                    style={'text-align':'center',
                           'margin-top': '10px',
                           'margin-bottom': '5px',
                           'margin-left': '15px'},outline=True),md=6, width=6),
                dbc.Col(dbc.Card(
                    dbc.CardBody(
                        [dbc.Row([dbc.Col([html.H4("Tests Completed Today", className="card-title"),
                            html.H1('{:,}'.format(tests_today)),
                            ], width=6),
                            dbc.Col([html.H4("Total Tests Completed", className="card-title"),
                            html.H1('{:,}'.format(total_tests)),
                            ], width=6)
                        ])

                        ]
                    ),
                    style={'text-align':'center',
                           'margin-top': '10px',
                           'margin-bottom': '5px',
                           'margin-right': '15px'}, outline=True),md=6, width=6),
            ]),

        # main choropleth map
        dbc.Row(html.H3("Ontario COVID-19 Active Cases and Test Locations"),
               style={'margin-left': '15px'}),
        dbc.Row(
            dbc.Col(dcc.Graph(id='ontario-map',figure=fig),id="map-box"),
            style={'text-align':'center',
                           'margin-top': '10px',
                           'margin-bottom': '10px',
                           'margin-left': '20px',
                           'margin-right': '10px'}),

        # COVID-19 Cases and ICU plots
        dbc.Row(
            [
                dbc.Col(dbc.Card(
                    dbc.CardBody(
                        [dbc.Row([dbc.Col(html.H5('Number of Cases in'),md=4,width=3),
                                  dbc.Col(dcc.Dropdown(
                    options=phu_dict_list,
                    value='ONTARIO',
                    clearable=False,
                id="phu_dropdown"),md=8,width=9, align = "start")], align="start", form=True),
                         dbc.Row([dbc.Col(dcc.Graph(id='phu-bar',figure=phu_bar),id="phu-zone")])
                         ]
                    ),
                    style={'text-align': 'start',
                           'margin-top': '20px',
                           'margin-bottom': '5px',
                           'margin-left': '15px'}, outline=True), md=6, width=6),
                dbc.Col(dbc.Card(
                    dbc.CardBody(
                        [dbc.Row([dbc.Col(dcc.Dropdown(
                    options=icu_dict_list,
                    value='ONTARIO',
                    clearable=False,
                id="icu_dropdown"),md=4,width=4, align = "start"),
                            dbc.Col(html.H5('COVID-19 ICU Cases'),md=6,width=8)], align="start", form=True),
                         dbc.Row([dbc.Col(dcc.Graph(id='covid19-icu',figure=fig_ICU),id="line-box")])
                         ]
                    ),
                    style={'text-align': 'start',
                           'margin-top': '20px',
                           'margin-bottom': '5px',
                           'margin-right': '15px'}, outline=True), md=6, width=6),
            ]),

        # Age and Gender plots
        dbc.Row(
            [
                dbc.Col(dbc.Card(
                    dbc.CardBody(
                        [dbc.Row([dbc.Col(html.H5('COVID-19 Cases in Ontario by Reporting Date'))], align="start"),
                         dbc.Row([dbc.Col(dcc.Dropdown(
                                      options=[
                                          {'label': 'Total Cases', 'value': 'all'},
                                          {'label': 'by Age Group', 'value': 'age'},
                                          {'label': 'by Gender', 'value': 'gender'}
                                      ],
                                      value='all',
                                      clearable=False,
                                      id="dropdown"), md=4, width=4, align = "start")

                         ], align="start"),
                         dbc.Row([dbc.Col(dcc.Graph(id='covid19-casebar',figure=fig_bar1),id="ovid19-casebar")])
                         ]
                    ),
                    style={'text-align': 'start',
                           'margin-top': '20px',
                           'margin-bottom': '5px',
                           'margin-left': '15px'}, outline=True), md=6, width=6),
                dbc.Col(dbc.Card(
                    dbc.CardBody(
                        [dbc.Row([dbc.Col(html.H5('Age and Gender Distribution of COVID-19 Cases in Ontario'))]),
                         dbc.Row([dbc.Col(dcc.Graph(id='covid19-ageGender',figure=fig_age_gender),id="ageGender-box")])
                         ]
                    ),
                    style={'text-align': 'start',
                           'margin-top': '20px',
                           'margin-bottom': '5px',
                           'margin-right': '15px',
                           'height': '35rem'}, outline=True), md=6, width=6),
            ]),

        # COVID-19 Positive Rate and Vaccine plots
        dbc.Row(
            [
                dbc.Col(dbc.Card(
                    dbc.CardBody(
                        [dbc.Row([dbc.Col(html.H5('PHU Ranked by COVID-19 Positive Rate'))]),
                         dbc.Row([dbc.Col(dcc.Graph(id='covid19-positive',figure=fig_positive_rate),id="bar-box")]),
                        ]
                    ),
                    style={'text-align': 'start',
                           'margin-top': '20px',
                           'margin-bottom': '5px',
                           'margin-left': '15px'}, outline=True), md=7, width=8),
                dbc.Col(dbc.Card(
                    dbc.CardBody(
                        [dbc.Row([dbc.Col(html.H5('Ontario Daily Vaccine Administration'))], align="start"),
                         dbc.Row([dbc.Col(dcc.Graph(id='covid19-vaccine',figure=fig_Vaccine),id="vaccine-box")])
                        ]
                    ),
                    style={'text-align': 'center',
                           'margin-top': '20px',
                           'margin-bottom': '5px',
                           'margin-right': '15px'}, outline=True), md=5, width=4),
            ]),
    ],
    fluid=True,
    style={"height":"100vh"}
)

@app.callback(
    Output('phu-bar', 'figure'),
    [Input('phu_dropdown', 'value')])
def update_phu_bar(value):
    #too many plots to precompute. Compute plot dynamically
    if value is not None:
        if value=='ONTARIO':
            phu_bar.update_layout(
                margin=dict(t=50))
            return phu_bar
        else:
            #compute new plot
            phu_df = phu_data_rolling.loc[phu_data_rolling['PHU_NAME']==value]
            phu_df = phu_df.loc[phu_df['FILE_DATE'] == phu_df['FILE_DATE'].max()]
            phu_bar2 = go.Figure(data=[go.Bar(
                x=['Active', 'Recovered', 'Deaths'],
                y=[int(phu_df['ACTIVE_CASES']), int(phu_df['RESOLVED_CASES']), int(phu_df['DEATHS'])],
                marker_color=colors
            )])
            phu_bar2.update_layout(
                margin=dict(t=50), yaxis_range=[0,100000])
            phu_bar.update_layout(
                yaxis_title="Number of Cases")
            return phu_bar2
    return phu_bar

# ICU Scatter Plot
@app.callback(
    Output('covid19-icu', 'figure'),
    [Input('icu_dropdown', 'value')])
def update_icu_scatter(value):
    color_dict = {'CENTRAL ONTARIO': "#7f8bf5", 'TORONTO ONTARIO': "#445bab",
                 'WEST ONTARIO': "#0fba7c", 'EAST ONTARIO': "#4b9cfc", 'NORTH ONTARIO': "#d461f2"}

    #too many plots to precompute. Compute plot dynamically
    if value is not None:
        if value=='ONTARIO':
            fig_ICU.update_layout(
                margin=dict(t=50))
            return fig_ICU
        else:
            #compute new plot
            df_ICU_temp= df_ICU.loc[df_ICU.oh_region == value.split()[0]]
            icu_temp = go.Figure(data=[go.Scatter(
                x=df_ICU_temp.date,
                y=df_ICU_temp.ICU,
                name=value,
                line=dict(color=color_dict[value]))])

            icu_temp.update_layout(
                margin=dict(t=50), yaxis_range=[0,450])
            icu_temp.update_layout(
                xaxis_title="Date",
                yaxis_title="Number of ICU Cases")
            return icu_temp
    return icu_temp

@app.callback(
    Output('covid19-casebar', 'figure'),
    [Input('dropdown', 'value')])
def update_figure(value):
    if value is not None:
        if value=='all':
            fig_bar1.update_layout(
                margin=dict(t=20))
            return fig_bar1
        elif value=='age':
            fig_bar2.update_layout(
                margin=dict(t=20))
            return fig_bar2
        else:
            fig_bar3.update_layout(
                margin=dict(t=20))
            return fig_bar3
    return fig_bar1

if __name__ == '__main__':
    # port=8000, host='127.0.0.1'
    # debug=True
    app.run_server(debug=True)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Aug  2 19:15:12 2019

@author: augusto
"""

import os
import pickle

import torch

import qrs_detector

import numpy as np
from scipy import signal

import matplotlib.pyplot as plt

def generate_artificial_signals(sample_freq, signal_freq, stop_time = 10):
    """
    Genera cuadrada triangualar y senoidal a la frecuencia de sampleo deseada.

    Parameters
    ----------
    sample_freq : int
        Frecuencia de sampleo deseada.
    signal_freq : int
        Frecuencia de la señal deseada.
    stop_time : int
        Largo del vector en segundos.

    Returns
    ----------
    data : dict
        Diccionario con los campos "sine" "square" y "triang".
    """

    # Vector temporal
    t = np.linspace(0, 1, stop_time * sample_freq)

    # Generacion de señales
    data = {}

    data['sine'] = np.sin(t * 2 * np.pi * signal_freq)
    data['triang'] = signal.sawtooth(t * 2 * np.pi * signal_freq, 0.5)
    data['square'] = signal.square(t * 2 * np.pi * signal_freq)

    return data

if __name__ == "__main__":
    slice_samples = 24

    # Ruta y nombre del modelo guardado
    ia_file_path = "/home/augusto/Desktop/GIBIO/Algoritmos/ia/trained_models/model_1_beta_large"
    ia_filename = "qrs_det_model_1_epoch_10.pt"

    # Señales a testear
    signal_freq = 50

    data = generate_artificial_signals(250, signal_freq, stop_time = 10)

    # Cargo modelo
    model = qrs_detector.qrs_det_1_beta(24)
    model.load_state_dict(torch.load(os.path.join(ia_file_path, ia_filename)))
    model.eval()

    counter = 0

    while True:
        this_square_data = torch.Tensor(data['square'][counter * slice_samples:counter * slice_samples + slice_samples])
        this_sin_data = torch.Tensor(data['sine'][counter * slice_samples:counter * slice_samples + slice_samples])
        this_triang_data = torch.Tensor(data['triang'][counter * slice_samples:counter * slice_samples + slice_samples])

        this_square_data = this_square_data.view(1, 1, 24)
        this_sin_data = this_sin_data.view(1, 1, 24)
        this_triang_data = this_triang_data.view(1, 1, 24)

        y_pred_square = model(this_square_data)
        y_pred_sin = model(this_sin_data)
        y_pred_triang = model(this_triang_data)

        print("Valor predecido cuadrada: ", y_pred_square.item())
        print("Valor predecido senoidal: ", y_pred_sin.item())
        print("Valor predecido triangular: ", y_pred_triang.item())

        if y_pred_square.item() >= 0.5:
            graph_color_square = 'b'
        else:
            graph_color_square = 'r'

        if y_pred_sin.item() >= 0.5:
            graph_color_sin = 'b'
        else:
            graph_color_sin = 'r'

        if y_pred_triang.item() >= 0.5:
            graph_color_triang = 'b'
        else:
            graph_color_triang = 'r'

        print("----------------------------------------------")

        plt.subplot(3,1,1)
        plt.plot(this_square_data[0][0].tolist(), graph_color_square)
        plt.grid(True)
        plt.ylabel("Cuadrada")

        plt.subplot(3,1,2)
        plt.plot(this_sin_data[0][0].tolist(), graph_color_sin)
        plt.grid(True)
        plt.ylabel("Senoidal")

        plt.subplot(3,1,3)
        plt.plot(this_triang_data[0][0].tolist(), graph_color_triang)
        plt.grid(True)
        plt.ylabel("Triangular")

        plt.show()

        counter += 1
        if counter * slice_samples + slice_samples >= len(data['square']):
            break


# Design/Program : Mehmet Berat Şenel ( mehmetberat.com )
import pygame
import random

pygame.init()

my_font = pygame.font.SysFont('Arial Bold', 30)

gameDisplay = pygame.display.set_mode((1280,720))
pygame.display.set_caption('SpaceShip (beta v1)')
programIcon = pygame.image.load('.icon/spaceship.png')
width = gameDisplay.get_width()
height = gameDisplay.get_height()

pygame.display.set_icon(programIcon)

clock = pygame.time.Clock()

crashed = False
shipa=pygame.image.load('.img/ship1.png')
shipb=pygame.image.load('.img/ship2.png')
monstera=pygame.image.load('.img/monstera.png')
monsterb=pygame.image.load('.img/monsterb.png')
bg=pygame.image.load('.img/background.png')
blltimg=pygame.image.load('.img/lazer.png')
mainbg=pygame.image.load(".img/mainbg.png")
overbg=pygame.image.load(".img/overbg.png")

LaserSound=pygame.mixer.Sound(".sound/laser.wav")
GameMusic=pygame.mixer.Sound(".sound/Kubbi - Digestive biscuit.wav")
MainMusic=pygame.mixer.Sound(".sound/c152 - Night Mission.wav")
BombSound=pygame.mixer.Sound(".sound/Bomb.wav")
CreditMusic=pygame.mixer.Sound(".sound/man-is-he-mega-glbml-22045.wav")

lightlist=list()
bullets=list()
monsters=list()
shipx=10
shipy=300
counter=0
up=False
down=False
left=False
right_=False
score=0
play=2
GameMusicPlay=0
MainMusicPlay=0
CreditMusicPlay=0
level=0
speed=-4

def GameOver():
    global GameMusicPlay,MainMusicPlay,CreditMusicPlay,play,crashed
    if CreditMusicPlay==0:
        GameMusicPlay=0
        MainMusicPlay=0
        CreditMusicPlay=1
        pygame.mixer.stop()
        pygame.mixer.Sound.play(CreditMusic)
    mouse = pygame.mouse.get_pos()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            crashed = True
        if event.type == pygame.MOUSEBUTTONDOWN:
              if 550 <= mouse[0] <= 730 and 600 <= mouse[1] <= 620:
                play=2
    gameDisplay.blit(overbg,(0,0))
    my_font = pygame.font.SysFont('Arial Bold', 70)
    text_surface = my_font.render('Score : '+str(score), True, (178, 238, 0))
    text_surface1 = my_font.render('Level  : '+str(level), True, (178, 238, 0))
    my_font1 = pygame.font.SysFont('Arial Bold', 30)
    text_surface6 = my_font1.render('< BACK TO MENU >', True, (178, 238, 0))
    gameDisplay.blit(text_surface, (500,10+300))
    gameDisplay.blit(text_surface1, (500,100+300))
    gameDisplay.blit(text_surface6, (550,300+300))

def credit():
    global GameMusicPlay,MainMusicPlay,CreditMusicPlay,play,crashed
    if CreditMusicPlay==0:
        GameMusicPlay=0
        MainMusicPlay=0
        CreditMusicPlay=1
        pygame.mixer.stop()
        pygame.mixer.Sound.play(CreditMusic)
    mouse = pygame.mouse.get_pos()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            crashed = True
        if event.type == pygame.MOUSEBUTTONDOWN:
              if 550 <= mouse[0] <= 730 and 600 <= mouse[1] <= 620:
                play=2
    gameDisplay.fill((22,22,22))
    text_surface = my_font.render('Programmer / Game Designer', True, (178, 238, 0))
    text_surface1 = my_font.render('* Mehmet Berat ŞENEL ( mehmetberat.com )', True, (178, 238, 0))
    text_surface2 = my_font.render('Sounds', True, (178, 238, 0))
    text_surface3 = my_font.render('* c152 - Night Mission Synthwave', True, (178, 238, 0))
    text_surface4 = my_font.render('* Kubbi - Digestive biscuit', True, (178, 238, 0))
    text_surface5 = my_font.render('* Man is He Mega - GLBML by GeoffreyBurch', True, (178, 238, 0))
    text_surface6 = my_font.render('< BACK TO MENU >', True, (178, 238, 0))
    gameDisplay.blit(text_surface, (400,10+200))
    gameDisplay.blit(text_surface1, (450,60+200))
    gameDisplay.blit(text_surface2, (400,110+200))
    gameDisplay.blit(text_surface3, (450,160+200))
    gameDisplay.blit(text_surface4, (450,210+200))
    gameDisplay.blit(text_surface5, (450,260+200))
    gameDisplay.blit(text_surface6, (550,300+300))

def MainMenu():
    global GameMusicPlay,MainMusicPlay,my_font,play,mainbg,CreditMusicPlay,crashed,lightlist,bullets,monsters,shipx,shipy,counter,score,level,speed,up,down,left,right_
    lightlist=list()
    bullets=list()
    monsters=list()
    shipx=10
    shipy=300
    counter=0
    score=0
    level=0
    speed=-4
    up=False
    down=False
    left=False
    right_=False
    if MainMusicPlay==0:
        GameMusicPlay=0
        MainMusicPlay=1
        CreditMusicPlay=0
        pygame.mixer.stop()
        pygame.mixer.Sound.play(MainMusic)
    mouse = pygame.mouse.get_pos()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            crashed = True
        if event.type == pygame.MOUSEBUTTONDOWN:
              if width/2-90 <= mouse[0] <= width/2+50 and height/2-50 <= mouse[1] <= height/2+30:
                play=0
        if event.type == pygame.MOUSEBUTTONDOWN:
              if width/2-150 <= mouse[0] <= width/2+120 and height/2+50 <= mouse[1] <= height/2+100:
                play=1
    gameDisplay.fill((0,0,0))
    gameDisplay.blit(mainbg,(0,0))

def Game():
    global crashed,up,down,left,right_,GameMusicPlay,MainMusicPlay,CreditMusicPlay
    if GameMusicPlay==0:
        GameMusicPlay=1
        MainMusicPlay=0
        CreditMusicPlay=0
        pygame.mixer.stop()
        pygame.mixer.Sound.play(GameMusic)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            crashed = True
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                up=True
            elif event.key == pygame.K_LEFT:
                left=True
            elif event.key == pygame.K_DOWN:
                down=True
            elif event.key == pygame.K_RIGHT:
                right_=True
            elif event.key== pygame.K_x:
                if level>=5:
                    bullets.append((shipx+68,shipy+15))
                    bullets.append((shipx+68,shipy+70))
                else:
                    bullets.append((shipx+68,shipy+40))
                pygame.mixer.Sound.play(LaserSound)
        if event.type==pygame.KEYUP:
            if event.key == pygame.K_UP:
                up=False
            elif event.key == pygame.K_LEFT:
                left=False
            elif event.key == pygame.K_DOWN:
                down=False
            elif event.key == pygame.K_RIGHT:
                right_=False

    gameDisplay.fill((0,0,0))
    BGControl()
    ship(shipx,shipy)
    Mnstrcrt()
    bullet()
    text_surface = my_font.render('Score : '+str(score), True, (178, 238, 0))
    text_surface1 = my_font.render('Level : '+str(level), True, (178, 238, 0))
    gameDisplay.blit(text_surface, (10,10))
    gameDisplay.blit(text_surface1, (10,50))

def BGCreater():
    rdcount=1
    for i in range(rdcount):
        rdx=random.randint(1,10000)
        rdy=random.randint(1,720)
        lightlist.append((rdx+1280,rdy))

def BGControl():
    for i in range(len(lightlist)):
        gameDisplay.blit(bg,lightlist[i])
        lightlist[i]=(lightlist[i][0]-3,lightlist[i][1])
    BGCreater()

def bullet():
    global speed,score
    for i in range(len(bullets)):
        try:
            gameDisplay.blit(blltimg,bullets[i])
            bullets[i]=(bullets[i][0]+10+level,bullets[i][1])
            for cords in monsters:
                if bullets[i][1] in list(range(cords[1],cords[1]+100)) and cords[0]<bullets[i][0]:
                    pygame.mixer.Sound.play(BombSound)
                    bullets.remove(bullets[i])
                    monsters.remove(cords)
                    score+=level
                    speed=-level*0.5-3
        except:
            pass

def monster(x,y):
    global counter,speed
    if counter<4:
        gameDisplay.blit(monstera,(x,y))
    else:
        gameDisplay.blit(monsterb,(x,y))

def Mnstrcrt():
    global play
    MonsterControl()
    for i in range(len(monsters)):
        if monsters[i][0]<0:
            play=3
        monster(monsters[i][0],monsters[i][1])
        monsters[i]=(monsters[i][0]+speed,monsters[i][1])

def MonsterControl():
    global level
    if len(monsters)==0:
        level+=1
        for i in range(random.randint(level+2,level+5)):
            monsters.append((random.randint(10,500)+1280,random.randint(20,700)))

def ship(x,y):
    global counter,up,down,left,right_,shipx,shipy
    if counter<4:
        gameDisplay.blit(shipa,(x,y))
        counter+=1
    elif counter==9:
        gameDisplay.blit(shipb,(x,y))
        counter=0
    else:
        gameDisplay.blit(shipb,(x,y))
        counter+=1
    if up:
        shipy-=level+5
    if down:
        shipy+=level+5
    if left:
        shipx-=level+5
    if right_:
        shipx+=level+5

while not crashed:

    if play==0:
        Game()
    elif play==1:
        credit()
    elif play==2:
        MainMenu()
    else:
        GameOver()

    pygame.display.update()
    clock.tick(60)


from aqml.cheminfo.core import *

from rdkit import Chem
from rdkit.Chem.Draw import IPythonConsole
from rdkit.Chem import Draw

from openeye import oechem
from aqml.cheminfo.oechem.oechem import *

from IPython.display import SVG, display, HTML
from rdkit.Chem import AllChem as Chem
from rdkit.Chem.Draw import rdMolDraw2D
from rdkit.Chem.Draw import DrawingOptions

from rdkit.Chem import rdDepictor
from rdkit.Chem.Draw import rdMolDraw2D

import tempfile as tpf

import imolecule as imol

#DrawingOptions.atomLabelFontSize = 105
#DrawingOptions.dotsPerAngstrom = 2000
#DrawingOptions.bondLineWidth = 3.0

T,F = True,False

class draw_rdkit(object):

    def __init__(self): #, objs, istereo=False, woH=True, wo3d=False):
        #self.objs = objs
        #self.istereo = istereo
        #self.woH = woH
        #self.wo3d = wo3d
        #self.wo3d = wo3d
        return

    @staticmethod # @classmethod
    def str2mol(objs, istereo=False, woH=True, wo3d=False):
        mols = []
        labs = []
        if not isinstance(objs, (list,tuple)): objs=[objs]
        for obj in objs:
            if type(obj) is str:
                if os.path.exists(obj):
                    mol = Chem.MolFromMolFile(obj, removeHs=woH)
                    if wo3d:
                        string = Chem.MolToSmiles(mol, isomericSmiles=istereo)
                        mol = Chem.MolFromSmiles(string)
                else:
                    mol = Chem.MolFromSmiles(obj)
                labs.append( obj )
            elif type(obj) is Chem.rdchem.Mol:
                mol = obj
                labs.append( Chem.MolToSmiles(mol) )
            else:
                raise Exception('#ERROR: input not supported')
            mols.append(mol)
        return mols, labs

    @staticmethod # @classmethod
    def viewm0(strings, size=(200,200)):
        return Draw.MolsToImage(draw_rdkit.str2mol(strings), includeAtomNumbers=True, subImgSize=size)

    @staticmethod # @classmethod
    def viewm(string,molSize=(450,150),woH=True,wo3d=False,kekulize=True,atsh=[],bsh=[],colors=[]):
        """
        vars
        atsh : atoms to be highlighted (list)
        bsh: bonds to be highlighted (list)
        woH: without H atoms displayed
        wo3d: without 3d coordinates embeded
        """
        mol = draw_rdkit.str2mol(string,woH=woH,wo3d=wo3d)[0][0]
        mc = Chem.Mol(mol.ToBinary())
        if kekulize:
            try:
                Chem.Kekulize(mc)
            except:
                mc = Chem.Mol(mol.ToBinary())
        if not mc.GetNumConformers():
            rdDepictor.Compute2DCoords(mc)
        drawer = rdMolDraw2D.MolDraw2DSVG(molSize[0],molSize[1])

        opts = drawer.drawOptions()
        for i in range(mol.GetNumAtoms()):
            opts.atomLabels[i] = mol.GetAtomWithIdx(i).GetSymbol()+str(i)

        opts.legendFontSize=16

        _colors={ (1,0,0), (0,1,0), (0,0,1), (1,0,1)}

        if len(colors) > 0:
            drawer.DrawMolecule(mc,highlightAtoms=atsh,highlightBonds=bsh,highlightAtomColors=colors)
        else:
            drawer.DrawMolecule(mc,highlightAtoms=atsh,highlightBonds=bsh)

        drawer.FinishDrawing()
        svg = drawer.GetDrawingText()
        # It seems that the svg renderer used doesn't quite hit the spec.
        # Here are some fixes to make it work in the notebook, although I think
        # the underlying issue needs to be resolved at the generation step
        return SVG( svg.replace('svg:','') )

    @staticmethod # @classmethod
    def viewms(objs,wo3d=F,nmr=8,molSize=(100,80),wlgd=T,wlgd_text='smiles', labels=None, \
               wia=T,woH=T,kekulize=T,atsh=[],bsh=[],colors=[],filename=None):
        """
        vars
        atsh : atoms to be highlighted (list)
        """
        mols, strings = draw_rdkit.str2mol(objs,woH=woH)
        mcs = []
        _labels = []
        nat = 0
        nm = len(mols)
        smis = []
        for mol in mols:
            labels_i = [ chemical_symbols[ai.GetAtomicNum()]+'%d'%(ai.GetIdx()+1) for ai in mol.GetAtoms() ]
            nat += len(labels_i)
            _labels += labels_i
            mc = Chem.Mol(mol.ToBinary())
            if kekulize:
                try:
                    Chem.Kekulize(mc)
                except:
                    mc = Chem.Mol(mol.ToBinary())
            c2d = F
            if mc.GetNumConformers():
                if wo3d:
                    c2d = T
            else:
                c2d = T
            if c2d: rdDepictor.Compute2DCoords(mc)
            smis.append( Chem.MolToSmiles(mc) )
            mcs.append(mc)
        #print('labels=',labels)

        molsPerRow = nmr #5
        subImgSize= molSize

        nRows = len(mols) // molsPerRow
        if len(mols) % molsPerRow:
            nRows += 1
        fsize = (molsPerRow * subImgSize[0], nRows * subImgSize[1])

        dw, dh = 0, 0
        drawer = rdMolDraw2D.MolDraw2DSVG(fsize[0]+dw,fsize[1]+dh, subImgSize[0], subImgSize[1])

        opts = drawer.drawOptions()
        ## [bad news] opts seems to be able to accept only the first `na1 labels (where na1=len(mols[0]))
        #for i in range(nat):
        #    opts.atomLabels[i] = labels[i]

        if labels:
            labs = labels
        else:
            if wlgd_text in ['id']:
                labs = [ str(i+1) for i in range(nm) ] #rows*cols) ]
            elif wlgd_text in ['smiles',]:
                labs = smis
            elif wlgd_text in ['file','filename']:
                assert len(fs) > 1, '#ERROR: input objs are not files!!'
                labs = [ fi.split('/')[-1] for fi in fs ]
            else:
                raise Exception('invalid `wlgd_text')

        drawer.DrawMolecules(mcs, legends=labs)

        drawer.FinishDrawing()
        svg = drawer.GetDrawingText()
        # It seems that the svg renderer used doesn't quite hit the spec.
        # Here are some fixes to make it work in the notebook, although I think
        # the underlying issue needs to be resolved at the generation step

        if filename is not None:
            open(filename+'.svg','w').write(svg)
            try:
                import cairosvg
                cairosvg.svg2pdf(url='%s.svg'%filename, write_to='%s.pdf'%filename)
            except:
                raise Exception('#ERROR: svg to pdf failed, as cairosvg seems to be not installed?')
        return SVG( svg.replace('svg:','') )

class draw_oechem(object):

    def __init__(self): #, objs, istereo=False, woH=True, wo3d=False):
        #self.objs = objs
        #self.istereo = istereo
        #self.woH = woH
        #self.wo3d = wo3d
        return

    @staticmethod # @classmethod
    def str2mol(objs, istereo=False, woH=True, wo3d=False):
        mols = []
        smis = []
        fs = []
        if type(objs) is str: objs=[objs]
        for obj in objs:
            if type(obj) is str:
                if os.path.exists(obj):
                    fs.append(fs)
                    mol = sdf2oem(obj) #Chem.MolFromMolFile(obj, removeHs=woH)
                    #print('++mol=',mol)
                    #assert iok, '#ERROR: sdf2oem() failed??'
                    smi = oem2can(mol) # Chem.MolToSmiles(mol, isomericSmiles=istereo)
                    if wo3d:
                        iok, mol = smi2oem(smi)
                        assert iok, '#ERROR: smi2oem() failed?'
                else:
                    smi = obj
                    iok, mol = smi2oem(obj)
                    assert iok, '#ERROR: smi2oem() failed?'

            elif type(obj) is oechem.OEGraphMol:
                mol = obj
                smi = oem2can(mol)
            else:
                raise Exception('#ERROR: input not supported')
            mols.append(mol)
            smis.append( obj )
        return mols, smis, fs

    @staticmethod # @classmethod
    def viewms(objs, nmr=8, molSize=[100,80], woH=T, wo3d=F, wlgd_text='smiles',\
               wlgd=T, wia=F, filename=None, tdir='/tmp/'):

        """
        vars
        ====================
        nmr: num of mol per row
        woH: without Hydrogens displayed, T/F
        wo3d: without 3d coordinates? T/F
        wlgd: with legend displayed? T/F
        wlgd_text: 'smiles' or 'idx'
        wia: with idx of atom shown? T/F
        """
        mols, smis, fs = draw_oechem.str2mol(objs,woH=woH,wo3d=wo3d)
        nm = len(mols)
        cols = nmr #4 if nm < nmr else nmr # num mol per row
        rows = int(nm/cols) if nm%cols==0 else int(nm/cols)+1

        image = oedepict.OEImage(cols*molSize[0], rows*molSize[1])

        grid = oedepict.OEImageGrid(image, rows, cols)

        opts = oedepict.OE2DMolDisplayOptions(grid.GetCellWidth(), \
                           grid.GetCellHeight(), oedepict.OEScale_AutoScale)

        if wlgd_text in ['id']:
            labs = [ str(i+1) for i in range(nm) ] #rows*cols) ]
        elif wlgd_text in ['smiles',]:
            labs = smis
        elif wlgd_text in ['file','filename']:
            assert len(fs) > 1, '#ERROR: input objs are not files!!'
            labs = [ fi.split('/')[-1] for fi in fs ]
        else:
            raise Exception('invalid `wlgd_text')

        for i in range(nm):
            mol = mols[i]
            #print('mol=',mol)
            oedepict.OEPrepareDepiction(mol)

            irow, icol = int(i/cols)+1, i%cols+1
            cell = grid.GetCell(irow,icol)

            if wlgd:
                mol.SetTitle(labs[i])

            opts.SetAtomVisibilityFunctor(oechem.OEIsTrueAtom())  # explicitly set the default

            font = oedepict.OEFont()
            font.SetSize(16)
            font.SetStyle(oedepict.OEFontStyle_Normal) #_Bold)
            font.SetColor(oechem.OEDarkGreen)
            opts.SetAtomPropLabelFont(font)

            if wia:
                opts.SetAtomPropertyFunctor(oedepict.OEDisplayAtomIdx())

            opts.SetAtomLabelFont(font)
            #opts.SetAtomLabelFontScale(1.5)

            opts.SetAtomPropLabelFont(font) # atom idx
            opts.SetAtomPropLabelFontScale(2) # atom idx

            opts.SetTitleLocation(oedepict.OETitleLocation_Bottom)
            opts.SetTitleHeight(10.0)

            disp = oedepict.OE2DMolDisplay(mol, opts)
            clearbackground = True
            oedepict.OERenderMolecule(cell, disp, not clearbackground)

        save = F # save as pdf
        if filename is not None:
            tf = filename+'.svg'
            save = T
        else:
            tf = tpf.NamedTemporaryFile(dir=tdir).name + '.svg'
        oedepict.OEWriteImage(tf, image)

        if save:
            try:
                import cairosvg
                cairosvg.svg2pdf(url='%s.svg'%filename, write_to='%s.pdf'%filename)
            except:
                raise Exception('#ERROR: svg to pdf failed, as cairosvg seems to be not installed?')

        return SVG(tf)

class draw_imol(object):
    """
    draw 3d molecule by imolecule
    """

    def __init__(self):
        return

    @staticmethod
    def html(ms,fmt,size=(240,240),nmr=6):
        renders = (imol.draw(m,fmt,size=size,display_html=False) for m in ms)
        columns = ('
{}
'.format(r) for r in renders)
        return HTML('
{}
'.format("".join(columns)))

    @staticmethod
    def viewms(objs,molSize=(160,160),nmr=6):

        if not isinstance(objs, (tuple,list)):
            objs = [objs]

        # convert to a file format recognizable by imolecule, i.e., sdf
        ms = []
        for obj in objs:
            typ = type(obj)
            if typ is Chem.rdchem.Mol:
                ms.append( Chem.MolToMolBlock(obj) )
            elif typ is str: #oechem.OEGraphMol:
                if os.path.exists(obj):
                    assert obj[-3:] in ['sdf','mol'], '#ERROR: file format not supported'
                    ms.append( ''.join(open(obj).readlines()) )
                else:
                    print(' ** assume smiles string ')
                    ms.append( Chem.MolToMolBlock( Chem.MolFromSmiles(obj) ) )
        if len(ms) == 1:
            return [ imol.draw(ms[0],'sdf',size=molSize) ]
        else:
            return draw_imol.html(ms,'sdf',size=molSize,nmr=nmr)
            #raise Exception('not know what to do next!')

import ase
import ase.io as aio
from ase.visualize import view
from tempfile import NamedTemporaryFile as ntf

class draw_ase(object):

    def __init__(self):
        return

    @staticmethod
    def viewms(obj):
        """ return the html representation the atoms object as string """
        renders = []
        ms = []
        if isinstance(obj, ase.Atoms):
            ms.append(obj)
        elif isinstance(obj, (tuple,list)):
            for oi in obj:
                ms.append( aio.read(f) )
        else:
            raise Exception('##')
        for atoms in ms:
            with ntf('r+', suffix='.html') as fo:
                atoms.write(fo.name, format='html')
                fo.seek(0)
                renders.append( fo.read() )
        columns = ('
{}
'.format(r) for r in renders)
        return HTML('
{}
'.format("".join(columns)))


import logging
import os
import subprocess
import tempfile

import yaml

from autogluon.bench.benchmark import Benchmark

logger = logging.getLogger(__name__)

class TabularBenchmark(Benchmark):
    def __init__(self, benchmark_name: str, root_dir: str = "./benchmark_runs/tabular/"):
        super().__init__(
            benchmark_name=benchmark_name,
            root_dir=root_dir,
        )
        self.module = "tabular"

    def setup(
        self,
    ):
        setup_script_path = os.path.abspath(os.path.dirname(__file__)) + "/setup.sh"
        command = [setup_script_path, self.benchmark_dir]
        result = subprocess.run(command)
        if result.stdout:
            logging.info("Successfully set up the environment under %s/.venv.", self.benchmark_dir)
        elif result.stderr:
            logging.error(result.stderr)

    def run(
        self,
        framework: str = "AutoGluon:latest",
        benchmark: str = "test",
        constraint: str = "test",
        task: str = None,
        custom_branch: str = None,
    ):

        exec_script_path = os.path.abspath(os.path.dirname(__file__)) + "/exec.sh"
        command = [
            exec_script_path,
            framework,
            benchmark,
            constraint,
            self.benchmark_dir,
        ]

        if task is not None:
            command += ["-t", task]

        if custom_branch is not None:

            custom_repo, custom_branch_name = tuple(custom_branch.split("#"))

            temp_dirpath = tempfile.mkdtemp()
            custom_framework_name = "AutoGluon_dev"
            command[1] = custom_framework_name

            custom_config_contents = {
                "frameworks": {
                    "definition_file": ["{root}/resources/frameworks.yaml", "{user}/frameworks.yaml"],
                    "allow_duplicates": "true",
                }
            }

            with open(os.path.join(temp_dirpath, "config.yaml"), "w") as fo:
                yaml.dump(custom_config_contents, fo)

            custom_framework_contents = {
                custom_framework_name: {"extends": "AutoGluon", "repo": custom_repo, "version": custom_branch_name}
            }

            with open(os.path.join(temp_dirpath, "frameworks.yaml"), "w") as fo:
                yaml.dump(custom_framework_contents, fo)

            command += ["-c", temp_dirpath]

        subprocess.run(command)


from sortedcontainers import SortedList

class Solution:
  def advantageCount(self, A: List[int], B: List[int]) -> List[int]:
    sl = SortedList(A)

    for i, b in enumerate(B):
      index = 0 if sl[-1] <= b else sl.bisect_right(b)
      A[i] = sl[index]
      del sl[index]

    return A


import os
import argparse
from model import *
import torch
import torch.optim as optim
from torch.utils.data import DataLoader
import json
import time
from datasets import Datasets, TestKodakDataset
from Meter import AverageMeter
from pytorch_msssim import ms_ssim

torch.backends.cudnn.enabled = True
gpu_num = torch.cuda.device_count()
cur_lr = base_lr = 1e-4
print_freq = 100
cal_step = 50
batch_size = 16
tot_epoch = 1000000
tot_step = 1800000
decay_interval = 1500000
lr_decay = 0.1
image_size = 256
logger = logging.getLogger("ImageCompression")
global_step = 0
save_model_freq = 100000
test_step = 10000
parser = argparse.ArgumentParser(description='Pytorch reimplement for variational image compression with a scale hyperprior')

parser.add_argument('-n', '--name', default='compress_base', help='experiment name')
parser.add_argument('-p', '--pretrain', default='', help='load pretrain model')
parser.add_argument('--seed', default=234, type=int, help='seed for random functions, and network initialization')
parser.add_argument('--train', dest='train', default='/home/dataset/coco2017', help='the path of training dataset')
parser.add_argument('--val', dest='val', default='/home/dataset/Kodak', help='the path of validation dataset')
parser.add_argument("--lmbda",dest="lmbda",type=float,default=0.013,help="Bit-rate distortion parameter (default: %(default)s)",)
parser.add_argument("--metrics",type=str,default="mse",help="Optimized for (default: %(default)s)",)

def adjust_learning_rate(optimizer, global_step):
    global cur_lr
    if global_step < decay_interval:
        lr = base_lr
    else:
        lr = base_lr * lr_decay
    cur_lr = lr
    for param_group in optimizer.param_groups:
        param_group['lr'] = lr

def train(epoch, global_step):
    logger.info("Epoch {} begin".format(epoch))
    net.train()
    global optimizer
    elapsed, losses, psnrs, bpps, bpp_features, bpp_zs, mse_losses = [AverageMeter(print_freq) for _ in range(7)]

    for batch_idx, input in enumerate(train_loader):
        start_time = time.time()
        global_step += 1
        clipped_recon_image, mse_loss,ms_ssim_loss, bpp_feature, bpp_z, bpp = net(input)

        distribution_loss = bpp
        if args.metrics=='mse':
            rd_loss = args.lmbda * 255 * 255 * mse_loss + distribution_loss
        elif args.metrics=='ms-ssim':
            rd_loss = args.lmbda * ms_ssim_loss + distribution_loss

        optimizer.zero_grad()
        rd_loss.backward()

        def clip_gradient(optimizer, grad_clip):
            for group in optimizer.param_groups:
                for param in group["params"]:
                    if param.grad is not None:
                        param.grad.data.clamp_(-grad_clip, grad_clip)

        clip_gradient(optimizer, 5)
        optimizer.step()

        if (global_step % cal_step) == 0:
            if mse_loss.item() > 0:
                psnr = 10 * (torch.log(1 * 1 / mse_loss) / np.log(10))
                psnrs.update(psnr.item())
            else:
                psnrs.update(100)

            elapsed.update(time.time() - start_time)
            losses.update(rd_loss.item())
            bpps.update(bpp.item())
            bpp_features.update(bpp_feature.item())
            bpp_zs.update(bpp_z.item())
            mse_losses.update(mse_loss.item())

        if (global_step % print_freq) == 0:
            process = global_step / tot_step * 100.0
            log = (' | '.join([
                f'Step [{global_step}/{tot_step}={process:.2f}%]',
                f'Epoch {epoch}',
                f'Time {elapsed.val:.3f} ({elapsed.avg:.3f})',
                f'Lr {cur_lr}',
                f'Total Loss {losses.val:.3f} ({losses.avg:.3f})',
                f'PSNR {psnrs.val:.3f} ({psnrs.avg:.3f})',
                f'Bpp {bpps.val:.5f} ({bpps.avg:.5f})',
                f'Bpp_feature {bpp_features.val:.5f} ({bpp_features.avg:.5f})',
                f'Bpp_z {bpp_zs.val:.5f} ({bpp_zs.avg:.5f})',
                f'MSE {mse_losses.val:.5f} ({mse_losses.avg:.5f})',
            ]))
            logger.info(log)

        if (global_step % save_model_freq) == 0:
            save_model(model, global_step, save_path)
        if (global_step % test_step) == 0:
            testKodak(global_step)
            net.train()
        if global_step >= tot_step:
            save_model(model, global_step, save_path)
            logger.info("训练结束")
            sys.exit(0)

    return global_step

def testKodak(step):
    with torch.no_grad():
        net.eval()
        sumBpp = 0
        sumPsnr = 0
        sumMsssim = 0
        sumMsssimDB = 0
        cnt = 0
        for batch_idx, input in enumerate(test_loader):
            clipped_recon_image, mse_loss, ms_ssim_loss, bpp_feature, bpp_z, bpp = net(input)
            mse_loss, bpp_feature, bpp_z, bpp = torch.mean(mse_loss), torch.mean(bpp_feature), torch.mean(bpp_z), torch.mean(bpp)

            mse_loss = torch.mean((clipped_recon_image.cpu() - input.cpu()).pow(2))

            psnr = 10 * (torch.log(1. / mse_loss) / np.log(10))
            sumBpp += bpp
            sumPsnr += psnr
            msssim = ms_ssim(clipped_recon_image.cpu().detach(), input, data_range=1.0,size_average=True)
            msssimDB = -10 * (torch.log(1-msssim) / np.log(10))
            sumMsssimDB += msssimDB
            sumMsssim += msssim
            logger.info("Bpp:{:.6f}, PSNR:{:.6f}, MS-SSIM:{:.6f}, MS-SSIM-DB:{:.6f}".format(bpp, psnr, msssim, msssimDB))
            cnt += 1

        logger.info("Test on Kodak dataset: model-{}".format(step))
        sumBpp /= cnt
        sumPsnr /= cnt
        sumMsssim /= cnt
        sumMsssimDB /= cnt
        logger.info("Dataset Average result---Bpp:{:.6f}, PSNR:{:.6f}, MS-SSIM:{:.6f}, MS-SSIM-DB:{:.6f}".format(sumBpp, sumPsnr, sumMsssim, sumMsssimDB))

if __name__ == "__main__":
    args = parser.parse_args()
    torch.manual_seed(seed=args.seed)
    formatter = logging.Formatter('%(asctime)s - %(levelname)s] %(message)s')
    formatter = logging.Formatter('[%(asctime)s][%(filename)s][L%(lineno)d][%(levelname)s] %(message)s')
    stdhandler = logging.StreamHandler()
    stdhandler.setLevel(logging.INFO)
    stdhandler.setFormatter(formatter)
    logger.addHandler(stdhandler)
    save_path = os.path.join('checkpoints', args.name+'_'+args.metrics+'_'+str(args.lmbda))
    if args.name != '':
        os.makedirs(save_path, exist_ok=True)
        filehandler = logging.FileHandler(os.path.join(save_path, 'log.txt'))
        filehandler.setLevel(logging.INFO)
        filehandler.setFormatter(formatter)
        logger.addHandler(filehandler)
    logger.setLevel(logging.INFO)
    logger.info("image compression training")

    model = ImageCompressor()
    if args.pretrain != '':
        logger.info("loading model:{}".format(args.pretrain))
        global_step = load_model(model, args.pretrain)

    net = torch.nn.DataParallel(model.cuda(), device_ids=[0])
    logger.info(net)

    parameters = net.parameters()
    global test_loader
    test_dataset = TestKodakDataset(data_dir=args.val)
    test_loader = DataLoader(dataset=test_dataset, shuffle=False, batch_size=1, pin_memory=True, num_workers=1)
    optimizer = optim.Adam(parameters, lr=base_lr)
    global train_loader
    train_data_dir = args.train
    train_dataset = Datasets(train_data_dir, image_size)
    train_loader = DataLoader(dataset=train_dataset,
                              batch_size=batch_size,
                              shuffle=True,
                              pin_memory=True,
                              num_workers=2)
    steps_epoch = global_step // (len(train_dataset) // (batch_size))
    save_model(model, global_step, save_path)
    for epoch in range(steps_epoch, tot_epoch):
        adjust_learning_rate(optimizer, global_step)
        global_step = train(epoch, global_step)


import torch.nn as nn
from common import *
from data.cifar10 import build_cifar10_data
from pretrained.PyTorch_CIFAR10.cifar10_models.resnet import resnet18
from quant import *
from myVisualize import *
import torch
# import linklink as link
from quant.quant_layer import QuantModule, StraightThrough, lp_loss
from quant.quant_model import QuantModel
from quant.block_recon import LinearTempDecay
from quant.adaptive_rounding import AdaRoundQuantizer
from quant.channelQuant import ChannelQuant
from quant.data_utils import save_grad_data, save_inp_oup_data
from tqdm import tqdm
import pickle

class LossFunction:
    def __init__(self,
                 layer: QuantModule,
                 round_loss: str = 'relaxation',
                 weight: float = 1.,
                 rec_loss: str = 'mse',
                 max_count: int = 2000,
                 b_range: tuple = (10, 2),
                 decay_start: float = 0.0,
                 warmup: float = 0.0,
                 p: float = 2.):

        self.layer = layer
        self.round_loss = round_loss
        self.weight = weight
        self.rec_loss = rec_loss
        self.loss_start = max_count * warmup
        self.p = p

        self.temp_decay = LinearTempDecay(max_count, rel_start_decay=warmup + (1 - warmup) * decay_start,
                                          start_b=b_range[0], end_b=b_range[1])
        self.count = 0

    def __call__(self, pred, tgt, grad=None):
        """
        Compute the total loss for adaptive rounding:
        rec_loss is the quadratic output reconstruction loss, round_loss is
        a regularization term to optimize the rounding policy

        :param pred: output from quantized model
        :param tgt: output from FP model
        :param grad: gradients to compute fisher information
        :return: total loss function
        """
        self.count += 1
        if self.rec_loss == 'mse':
            rec_loss = lp_loss(pred, tgt, p=self.p)
        elif self.rec_loss == 'fisher_diag':
            rec_loss = ((pred - tgt).pow(2) * grad.pow(2)).sum(1).mean()
        elif self.rec_loss == 'fisher_full':
            a = (pred - tgt).abs()
            grad = grad.abs()
            batch_dotprod = torch.sum(a * grad, (1, 2, 3)).view(-1, 1, 1, 1)
            rec_loss = (batch_dotprod * a * grad).mean() / 100
        else:
            raise ValueError('Not supported reconstruction loss function: {}'.format(self.rec_loss))

        b = self.temp_decay(self.count)
        if self.count < self.loss_start or self.round_loss == 'none':
            b = round_loss = 0
        elif self.round_loss == 'relaxation':
            round_loss = 0
            round_vals = self.layer.weight_quantizer.get_soft_targets()
            round_loss += self.weight * (1 - ((round_vals - .5).abs() * 2).pow(b)).sum()
        else:
            raise NotImplementedError

        total_loss = rec_loss + round_loss
        if self.count % 500 == 0:
            print('Total loss:\t{:.3f} (rec:{:.3f}, round:{:.3f})\tb={:.2f}\tcount={}'.format(
                  float(total_loss), float(rec_loss), float(round_loss), b, self.count))
        return total_loss

def layer_channelGreedy(model: QuantModel, layer: QuantModule, cali_data: torch.Tensor,
                         batch_size: int = 32, iters: int = 20000, weight: float = 0.001, opt_mode: str = 'mse',
                         asym: bool = False, include_act_func: bool = True, b_range: tuple = (20, 2),
                         warmup: float = 0.0, act_quant: bool = False, lr: float = 4e-5, p: float = 2.0,
                         multi_gpu: bool = False, eval: bool = False, shuffle_ratio: float = 0.0, qscale: float = 1.0):
    # Replace weight quantizer to channelWiseQuantizer
    layer.weight_quantizer = ChannelQuant(uaq=layer.weight_quantizer, weight_tensor=layer.org_weight.data, shuffle_ratio=0.0, qscale=qscale)
    cached_inps, cached_outs = save_inp_oup_data(model, layer, cali_data, asym, act_quant, batch_size)

    idx = torch.randperm(cached_inps.size(0))[:batch_size]
    cur_inp = cached_inps[idx]
    cur_out = cached_outs[idx]
    out_quant = layer(cur_inp)
    errPrv = lp_loss(out_quant, cur_out, p=2.4).detach().cpu().data
    # print("Original err: ", errPrv)
    numChannel = layer.weight_quantizer.nchannel
    errOfChannel = np.zeros(numChannel)
    for nc in range(numChannel[0]):
        for ic in range(numChannel[1]):
            layer.weight_quantizer.changeResol(nc, ic)
            out_quant = layer(cur_inp)
            errOfChannel[nc,ic] = lp_loss(out_quant, cur_out, p=2.4).detach().cpu().data

    sorted_idx = np.argsort(errOfChannel.ravel())

    layer.weight_quantizer.resetResol()
    for idx in tqdm(sorted_idx):
        nc, ic = idx//numChannel[1], idx%numChannel[1]
        layer.weight_quantizer.setResol(nc, ic, 1)
        out_quant = layer(cur_inp)
        scaledLoss = lp_loss(out_quant, cur_out, p=2.4).detach().cpu().data
        if scaledLoss < errPrv:
            errPrv = scaledLoss
        else:
            layer.weight_quantizer.setResol(nc, ic, 1)
    print(layer.weight_quantizer.simpleScale)

def layer_channelRandomize(model: QuantModel, layer: QuantModule, cali_data: torch.Tensor,
                         batch_size: int = 32, iters: int = 20000, weight: float = 0.001, opt_mode: str = 'mse',
                         asym: bool = False, include_act_func: bool = True, b_range: tuple = (20, 2),
                         warmup: float = 0.0, act_quant: bool = False, lr: float = 4e-5, p: float = 2.0,
                         multi_gpu: bool = False, eval: bool = False, shuffle_ratio: float = 0.0, qscale: float = 1.0):
    # Replace weight quantizer to channelWiseQuantizer
    layer.weight_quantizer = ChannelQuant(uaq=layer.weight_quantizer, weight_tensor=layer.org_weight.data, shuffle_ratio=shuffle_ratio, qscale=qscale)

def channelGreedyTest(qnn, test_loader, cali_data, args):
    kwargs = dict(cali_data=cali_data, iters=args.iters_w, weight=args.weight, asym=True,
                b_range=(args.b_start, args.b_end), warmup=args.warmup, act_quant=False, opt_mode='mse', eval=True, shuffle_ratio=0.0, qscale=1/2)

    def channelGreedy(model: nn.Module, prv_name=""):
        for name, module in model.named_children():
            if isinstance(module, QuantModule):
                if module.ignore_reconstruction is True:
                    continue
                else:
                    print("Running layer channel greedy ", prv_name+'.'+name)
                    if prv_name+'.'+name == '.model.layer1.0.conv1':
                        layer_channelGreedy(qnn, module, **kwargs)
            else:
                channelGreedy(module, prv_name+'.'+name)

    # Start calibration
    def printGreedy(model: nn.Module):
        for name, module in model.named_children():
            if isinstance(module, QuantModule):
                if module.ignore_reconstruction is True:
                    continue
                else:
                    # print(name, module.weight_quantizer.simpleScale)
                    print(module.use_weight_quant)
            else:
                printGreedy(module)

    qnn.set_quant_state(weight_quant=True, act_quant=False)
    channelGreedy(qnn)
    qnn.set_quant_state(weight_quant=True, act_quant=False)
    accuracy = validate_model(test_loader, qnn).data.cpu().numpy()
    print(f'Quantized accuracy After  brecq: {accuracy:.3f}')
    dumpResol(qnn, "results/bestResol/GreedyResult_resol.pkl")
    with open(f'./results/GreedyResult.pkl', 'wb') as f:
        pickle.dump(accuracy, f)

def dumpResol(qnn, filename):
    data = {}
    searchResol(qnn, data, '')
    with open(filename, 'wb') as f:
        pickle.dump(data, f)

def extractWeights(qnn, filename):
    data = {}
    searchWeights(qnn, data, '')
    with open(filename, 'wb') as f:
        pickle.dump(data, f)

def searchWeights(model: nn.Module, data, prv_name):
    for name, module in model.named_children():
        if isinstance(module, QuantModule):
            if module.ignore_reconstruction is True:
                continue
            else:
                data[prv_name+'.'+name] = module.weight.data.cpu().numpy()
                # print(name, module.weight_quantizer.sel_resol)
        else:
            searchWeights(module, data, prv_name+'.'+name)

def searchResol(model: nn.Module, data, prv_name=""):
    for name, module in model.named_children():
        if isinstance(module, QuantModule):
            if module.ignore_reconstruction is True:
                continue
            else:
                if prv_name+'.'+name == '.model.layer1.0.conv1':
                    data[prv_name+'.'+name] = module.weight_quantizer.sel_resol.data.cpu().numpy()
                # print(name, module.weight_quantizer.sel_resol)
        else:
            searchResol(module, data, prv_name+'.'+name)

def channelRandomizeTest(qnn, test_loader, cali_data, shuffle_ratio, args):
    kwargs = dict(cali_data=cali_data, iters=args.iters_w, weight=args.weight, asym=True,
                b_range=(args.b_start, args.b_end), warmup=args.warmup, act_quant=False, opt_mode='mse', eval=True, shuffle_ratio=shuffle_ratio, qscale=1/2)

    def channelRandomize(model: nn.Module, prv_name=""):
        for name, module in model.named_children():
            if isinstance(module, QuantModule):
                if module.ignore_reconstruction is True:
                    continue
                else:
                    if prv_name+'.'+name == '.model.layer1.0.conv1':
                        layer_channelRandomize(qnn, module, **kwargs)
            else:
                channelRandomize(module, prv_name+'.'+name)

    qnn.set_quant_state(weight_quant=True, act_quant=False)

    bestResult = 0.0
    testResult = []
    t = tqdm(range(3000), desc=f'random value={shuffle_ratio}')
    for i in t:
        channelRandomize(qnn, '')
        qnn.set_quant_state(weight_quant=True, act_quant=False)
        testResult.append(validate_model(test_loader, qnn, print_result=False).data.cpu().numpy())
        # extractWeights(qnn, f'./results/weights/rawWeights.pkl')
        if testResult[-1] > bestResult:
            bestResult = testResult[-1]
            dumpResol(qnn, "results/bestResol/channelRandomL0_only_1.2_resol.{shuffle_ratio}.pkl")
        t.set_description(f"best {bestResult:.3f} cur {testResult[-1]:.3f}")

    print("Best Accuracy : ", max(testResult))
    with open(f'./results/channelRandomL0_only_1.2_fixed.{shuffle_ratio}.pkl', 'wb') as f:
        pickle.dump(testResult, f)

# if __name__ == '__main__':
#     ratios = [0.01, 0.02, 0.04, 0.08, 0.1, 0.2, 0.3, 0.4, 0.5, 0.8, 1.0]
#     # ratios = [0.1]
#     SKIP_TEST = False
#     QUANT_INIT = True

#     args = loadArgments()
#     seed_all(args.seed)
#     train_loader, test_loader = build_cifar10_data(batch_size=args.batch_size, workers=args.workers,
#                                                     data_path=args.data_path)

#     for shuffle_ratio in ratios:
#         cnn = resnet18(pretrained=True, device='cuda:0')
#         cnn.cuda()
#         cnn.eval()
#         if not SKIP_TEST:
#             print(f'accuracy of original : {validate_model(test_loader, cnn):.3f}')

#         # build quantization parameters
#         wq_params = {'n_bits': args.n_bits_w, 'channel_wise': args.channel_wise, 'scale_method': 'mse', 'CWQ':True}
#         aq_params = {'n_bits': args.n_bits_a, 'channel_wise': False, 'scale_method': 'mse', 'leaf_param': args.act_quant}
#         qnn = QuantModel(model=cnn, weight_quant_params=wq_params, act_quant_params=aq_params)
#         qnn.cuda()
#         qnn.eval()
#         if not args.disable_8bit_head_stem:
#             print('Setting the first and the last layer to 8-bit')
#             qnn.set_first_last_layer_to_8bit()
#         cali_data = get_train_samples(train_loader, num_samples=args.num_samples)
#         device = next(qnn.parameters()).device

#         # # Initialize weight quantization parameters
#         qnn.set_quant_state(True, False)
#         if QUANT_INIT:
#             _ = qnn(cali_data[:64].to(device))
#             torch.save(qnn.state_dict(), f'./checkPoint/QNN_CW_W{args.n_bits_w}_FP32.pth')
#             qnn.set_quant_init_state()
#         else:
#             qnn.load_state_dict(torch.load(f'./checkPoint/QNN_CW_W{args.n_bits_w}_FP32.pth'))

#         # st = torch.load(f'./checkPoint/QNN_CW_W{args.n_bits_w}_FP32.pth')
#         if not SKIP_TEST:
#             print(f'Quantized accuracy before brecq: {validate_model(test_loader, qnn):.3f}')
#         exit(1)
#         #Load Weight
#         # channelRandomizeTest(qnn, test_loader, cali_data, shuffle_ratio, args)
#         # channelGreedyTest(qnn, test_loader, cali_data, args)
#         # break


from cloudinary.forms import CloudinaryFileField
from django import forms

from TripShareProject.photos.models import Photo

class PhotoCreateForm(forms.ModelForm):
    class Meta:
        model = Photo
        exclude = ['owner', ]
        widgets = {
            'description': forms.Textarea()
        }

class PhotoEditForm(PhotoCreateForm):
    class Meta:
        model = Photo
        exclude = ['owner', 'photo', ]
        widgets = {
            'description': forms.Textarea()
        }


import json
import tweepy

with open('credentials.json', 'r') as f:
    creds = json.load(f)

auth = tweepy.OAuthHandler(creds["CONSUMER_KEY"], creds["CONSUMER_SECRET"])
auth.set_access_token(creds["ACCESS_TOKEN"], creds["ACCESS_SECRET"])

api = tweepy.API(auth, wait_on_rate_limit=True, \
                 wait_on_rate_limit_notify=True, compression=True)

def searchTweets(search="interstate"):
    with open("tweets.json", "w") as f:
        tweets = tweepy.Cursor(api.search, q=search)
        for status in tweets.items(200):
            f.write(str(status._json))
            f.write('\n')

def printTweets():
    with open("tweets.json", "r") as f:
        for line in f:
            try:
                tweetLine = line.strip("'<>() ").replace("\"", chr(17)).replace("'", "\"").replace(chr(17), "'").replace("True", "true").replace("False", "false")
                tweet = eval(line)

                print("ID:", tweet['id'])
                print("Date:", tweet['created_at'])
                print("Contents:", tweet['text'])
                print("User:", tweet['user']['name'], "(@" + tweet['user']['screen_name'] + ")", "ID:", tweet['user']['id'])

                hashtags = []
                for hashtag in tweet['entities']['hashtags']:
                    hashtags.append(hashtag['text'])
                print("Hashtags:", hashtags)

                print()

            except Exception as e:
                print(e)

option = input("1 for search, 2 for print: ")
if option.strip() == "1":
    searchTweets(search=input("Keywords: "))
else:
    printTweets()


import smbus2
import time

bus = smbus2.SMBus(1)
i2c_address = 0x49

while True:
    rd = bus.read_word_data(i2c_address, 0)
    data = ((rd & 0xFF) << 8) | ((rd & 0xFF00) >> 8)
    data = data >> 2
    print("Data: ", data)
    time.sleep(1)


import os
import sys, getopt
from collections import defaultdict
from gensim import corpora
import spacy

PROG_NAME = "conv-to-doc.py"

nlp = spacy.load("en_core_web_sm")

def usage(out):
    print("Usage: "+PROG_NAME+" [options] <tsv conv file> <output dir>",file=out)
    print("",file=out)
    print("  TODO",file=out)
    print("",file=out)
    print("  Options:")
    print("    -h: print this help message.",file=out)
#    print("    -o <min overlap>: include user if at least this number of initial users follow them",file=out)
#    print("    -b: do not add default query filter: '"+default_filters+"'",file=out)
#    print("    -c <cities file>: list of accepted place names.",file=out)
#    print("    -a: no filtering on location at all.",file=out)

    print("",file=out)

def read_input_files(filenames):
    data = {}
    for file_no, filename in enumerate(filenames):
        with open(filename, newline="\n") as infile:
            data_this_user = defaultdict(list)
            text_col = None
            conv_col = None
            for line in infile:
                fields = line.rstrip().replace("\r", " ").split('\t')
                if len(fields) > 1:
                    if text_col is None:
                        for col_no,col_name in enumerate(fields):
                            if col_name == 'text':
                                text_col = col_no
                            if col_name == 'conversation_id':
                                conv_col = col_no
                        if text_col is None or conv_col is None:
                            raise Exception(f"Col name 'text' not found in supposed header [{','.join(fields)}] in file '{filename}'")
                    else:
                        try:
                            data_this_user[fields[conv_col]].append(fields[text_col])
                        except IndexError:
                            print(conv_col)
                            print(text_col)
                else:
                    print('Weird line??', fields,file=sys.stderr)
            for conv_id, text_list in data_this_user.items():
                if data.get(conv_id) is None:
                    data[conv_id] = text_list
#                    print(conv_id, text_list)
                else:
                    if len(data[conv_id]) != len(text_list):
                        raise Exception(f"Unexpected: same conversation id {conv_id} but different content.")
    return data

def preprocess(data, remove_stop=True, keep_pos=["NOUN", "VERB", "PROPN", "ADJ", "ADV", "INTJ" ], use_lemma=True, min_freq=3):

    frequency = defaultdict(int)
    processed = []
    no = 0
    for conv,tweets in data.items():
        no += 1
        print(f"preprocessing conv {no}/{len(data)}")
        new_doc = []
        for tweet in tweets:
            spacy_doc = nlp(tweet)
            for token in spacy_doc:
                #                print(token.text, token.lemma_, token.pos_, token.shape_, token.is_alpha, token.is_stop)
                if not remove_stop or not token.is_stop:
                    if keep_pos is None or token.pos_ in keep_pos:
                        val = token.text
                        if use_lemma:
                            val = token.lemma_
                        frequency[val] += 1
                        new_doc.append(val)
        processed.append(new_doc)
    texts = []
    for doc in processed:
        texts.append([ token for token in doc if frequency[token] >= min_freq ])
    return texts

def save_data(corpus, fname):
    #dictionary.filter_extremes(no_below=20, no_above=0.5)
    dictionary = corpora.Dictionary(corpus)
    bow = [ dictionary.doc2bow(doc) for doc in corpus ]
    corpora.MmCorpus.serialize(fname, bow, dictionary)  # store to disk, for later use
    dictionary.save(fname+".dict")

def process(input_file, output_dir):
    header = False
    with open(input_file, newline="\n") as f:
        for line in f:
            fields = line.rstrip().replace("\r", " ").split("\t")
            if not header:
                col_conv_id = fields.index("conversation_id")
                col_text = fields.index("text")
                header = True
            else:
                conv_id = fields[col_conv_id]
                text = fields[col_text]
                target_file = os.path.join(output_dir, conv_id)
                with open(target_file, "a") as output:
                    output.write(text+"\n")

def main():
    try:
        opts, args = getopt.getopt(sys.argv[1:],"ho:")
    except getopt.GetoptError:
        usage(sys.stderr)
        sys.exit(2)
    for opt, arg in opts:
        if opt == "-h":
            usage(sys.stdout)
            sys.exit()
#        elif opt == "-o":
#            overlap_min = int(arg)
#        elif opt == "-b":
#            basic = True
#        elif opt == "-c":
#            with open(arg) as infile:
#                accepted_places = [ line.rstrip() for line in infile ]
#        elif opt == '-a':
#            filter_loc = False
#           with open(arg) as infile:
#                accepted_places = [ line.rstrip() for line in infile ]

    if len(args) != 2:
        usage(sys.stderr)
        sys.exit(2)

    input_file = args[0]
    output_dir = args[1]

    if os.path.exists(input_file):
        if not os.path.exists(output_dir):
            os.mkdir(output_dir)
        process(input_file, output_dir)
    else:
        print('Error input file not found')

if __name__ == "__main__":
    main()


import psutil
import sys

if __name__ == '__main__':

    if len(sys.argv) != 2:
        print("Usage: python %s <PID>" % sys.argv[0])
        exit(1)

    PID = int(sys.argv[1])

    try:
        p = psutil.Process(PID)
    except:
        print("No process found with PID %s" % PID)
        exit(1)

    while True:
        cpu = p.cpu_percent(interval=1.0)
        ram = p.memory_percent()
        rss = p.memory_info()[0]
        # vms = p.memory_info()[1]

        for child in p.children(recursive=True):
            cpu += child.cpu_percent()
            ram += child.memory_percent()
            rss += p.memory_info()[0]

        with open('usage_data', 'a+') as f_usage:
            # f_usage.write(' '.join([str(cpu), str(ram)]) + '\n')
            f_usage.write(' '.join([str(cpu), str(ram), str(rss / float(2 ** 20))]) + '\n')
            # f_usage.write(' '.join([str(cpu), str(rss / float(2 ** 20)), str(vms / float(2 ** 20))]) + '\n')


import json
from datetime import datetime, timedelta, date

from django.http import HttpResponse, Http404, HttpResponseBadRequest

from bts.models.constants import DATE_TIME_FORMAT, EM_INVALID_OR_MISSING_PARAMETERS, EM_NO_SUCH_CUSTOMER
from bts.models.customer import Customer
from bts.models.loan import LoanRecord, LoanRepay
from bts.services.system.token import fetch_bank_teller_by_token, TOKEN_HEADER_KEY
from bts.utils.request_processor import fetch_parameter_dict

def _calculate_fine(loan_record: LoanRecord):
    updated = False
    while loan_record.next_overdue_date <= date.today():
        loan_record.left_fine += 0.05 * loan_record.left_payment
        loan_record.next_overdue_date += timedelta(days=loan_record.repay_cycle)
        updated = True

    if updated:
        loan_record.save()

def request_loan(request):
    if not fetch_bank_teller_by_token(request.META[TOKEN_HEADER_KEY]):
        return HttpResponse(content='Unauthorized', status=401)

    try:
        parameter_dict = fetch_parameter_dict(request, 'POST')
        customer_id = int(parameter_dict['customer_id'])
        # print(parameter_dict['customer_id'])
        payment = float(parameter_dict['payment'])
        # print(parameter_dict['payment'])
        repay_cycle = int(parameter_dict['repay_cycle'])
        # print(parameter_dict['repay_cycle'])
        created_time = datetime.strptime(parameter_dict['created_time'], DATE_TIME_FORMAT).date()
        # print(parameter_dict['created_time'])

    except (KeyError, ValueError, TypeError):
        return HttpResponseBadRequest(EM_INVALID_OR_MISSING_PARAMETERS)

    if payment <= 0:
        return HttpResponseBadRequest(EM_INVALID_OR_MISSING_PARAMETERS)

    try:
        customer = Customer.objects.get(customer_id=customer_id)
    except Customer.DoesNotExist:
        raise Http404(EM_NO_SUCH_CUSTOMER)

    new_loan_record = LoanRecord(customer=customer, payment=payment, current_deposit=customer.deposit,
                                 repay_cycle=repay_cycle, due_date=created_time + timedelta(days=repay_cycle),
                                 next_overdue_date=created_time + timedelta(days=repay_cycle),
                                 left_payment=payment, left_fine=0.0, created_time=created_time)
    new_loan_record.save()
    response_data = {'msg': 'loan request success', 'loan_record_id': new_loan_record.loan_record_id}
    return HttpResponse(json.dumps(response_data))

def _loan_repay(loan_record: LoanRecord, repay: float, is_from_deposit: bool = True):
    if repay > loan_record.left_fine + loan_record.left_payment or repay <= 0:
        return False
    left_payment_before = loan_record.left_payment
    left_fine_before = loan_record.left_fine
    if repay > loan_record.left_fine:
        loan_record.left_payment -= repay - loan_record.left_fine
        loan_record.left_fine = 0
    else:
        loan_record.left_fine -= repay

    if is_from_deposit:
        loan_record.customer.deposit -= repay

    new_loan_repay = LoanRepay(loan_record=loan_record,
                               left_payment_before=left_payment_before,
                               left_fine_before=left_fine_before,
                               repay=repay, current_deposit=loan_record.customer.deposit)
    loan_record.customer.save()
    loan_record.save()
    new_loan_repay.save()  # repay record saved after real load record is modified
    return True

def loan_repay(request):
    if not fetch_bank_teller_by_token(request.META[TOKEN_HEADER_KEY]):
        return HttpResponse(content='Unauthorized', status=401)

    try:
        parameter_dict = fetch_parameter_dict(request, 'POST')
        loan_record_id = int(parameter_dict['loan_record_id'])
        repay = float(parameter_dict['repay'])
    except (KeyError, ValueError, TypeError):
        return HttpResponseBadRequest(EM_INVALID_OR_MISSING_PARAMETERS)

    if repay <= 0:
        return HttpResponseBadRequest(EM_INVALID_OR_MISSING_PARAMETERS)

    try:
        loan_record = LoanRecord.objects.get(loan_record_id=loan_record_id)
    except LoanRecord.DoesNotExist:
        raise Http404('No such loan record')

    _calculate_fine(loan_record)
    if _loan_repay(loan_record, repay, False):
        response_data = {'msg': 'loan repay success'}
        return HttpResponse(json.dumps(response_data))
    return HttpResponseBadRequest('too much repay')

def auto_repay_process(request):
    if not fetch_bank_teller_by_token(request.META[TOKEN_HEADER_KEY]):
        return HttpResponse(content='Unauthorized', status=401)

    load_record_query_set = LoanRecord.objects.all()
    for loan_record in load_record_query_set:
        _calculate_fine(loan_record)
        if loan_record.left_payment > 0 and datetime.now().date() >= loan_record.due_date:
            customer = loan_record.customer
            curr_repay = 0
            left_payment_before = loan_record.left_payment
            left_fine_before = loan_record.left_fine
            if customer.deposit >= loan_record.left_fine:
                curr_repay += loan_record.left_fine
                customer.deposit -= loan_record.left_fine
                loan_record.left_fine = 0
                if customer.deposit >= loan_record.left_payment:
                    curr_repay += loan_record.left_payment
                    customer.deposit -= loan_record.left_payment
                    loan_record.left_payment = 0

            loan_record.save()
            customer.save()
            if curr_repay > 0:
                new_loan_repay = LoanRepay(loan_record=loan_record,
                                           left_payment_before=left_payment_before,
                                           left_fine_before=left_fine_before,
                                           repay=curr_repay, current_deposit=customer.deposit)
                new_loan_repay.save()

    response_data = {'msg': 'auto repay process success'}
    return HttpResponse(json.dumps(response_data))