import datetime
import math
import multiprocessing
from typing import List, Any, Union
from logic.compartment import Compartment
import pandas as pd
import numpy as np
import threading
from threading import Thread, Lock
from tqdm import tqdm
import warnings
import time
from root import DIR_INPUT, DIR_OUTPUT

warnings.simplefilter('error')

beta_f = (0.022007606119173795, 0.017863980243733434, 0.018196130566806898, 0.018457626077325776, 0.01748616435199459,
          0.016227115077950355)
dc_f = (1.1323965306925503, 0.7125429486836731, 1.0444436705577909, 1.0455277531926157, 0.8937395613665182,
        0.9248158502415792)
arrival_f = (15.610984192361858, 7.118033263153407, 13.580052334837838, 6.872622856121195, 19.179202373513895,
             23.821317070305813)
spc_f = 0.2761426379037166
# error_cases : (0.01144914782225527, 0.04633153074628225, 0.035662564790543826, 0.01663383341316379,
# 0.044033713992227476, 0.05507748681553992)
# error_deaths : (0.027622229848766704, 0.009587082330408638, 0.012646483805184615, 0.01921871618354314,
# 0.062333297880331026, 0.07248222923337995)
# error : 0.03471753964393546

def calculate_vaccine_assignments(population: dict, day: int, vaccine_priority: list, vaccine_capacity: dict,
                                  candidates_indexes: list):
    """
    Calculates the daily vaccination assignments for every group.
    :param population: Resulting population in the simulation.
    :param day: Day to obtain information
    :param vaccine_priority: list of priorities. Each group contains a list of tuples indicating the groups that
    comprehend the priorities.
    :param vaccine_capacity: dictionary with amount for each type of vaccine and target group.
    :param candidates_indexes: indexes for states (infection related) that are candidates to the vaccine.
    :return:
    """
    day_population = dict()
    assignation = dict()
    age_groups = list(population.keys())
    work_groups = list(population[age_groups[0]].keys())
    health_groups = list(population[age_groups[0]][work_groups[0]].keys())
    vaccine_groups = list(population[age_groups[0]][work_groups[0]][health_groups[0]].keys())
    for ev in age_groups:
        for wv in work_groups:
            for hv in health_groups:
                for vv in vaccine_groups:
                    for cv in candidates_indexes:
                        day_population[(ev, wv, hv, vv, cv)] = population[ev][wv][hv][vv][cv].values[day]
    for vaccine in vaccine_capacity:
        # Diccionario con el siguiente orden: {'cual':[a_quien, cantidad]}
        current_vac = vaccine_capacity[vaccine]
        vv = current_vac[0]
        total_candidates = 0
        for ev in age_groups:
            for wv in work_groups:
                for hv in health_groups:
                    for cv in candidates_indexes:
                        total_candidates += day_population[(ev, wv, hv, vv, cv)]
        vaccines_to_use = min(total_candidates, current_vac[1])
        # Van en el orden de las listas
        for groups in vaccine_priority:
            # group = [[ev, wv, hv]]
            group_candidates = 0
            for group in groups:
                ev, wv, hv, p = group
                group_candidates += sum(day_population[(ev, wv, hv, vv, cv)] for cv in candidates_indexes)
            vaccines_for_group = min(vaccines_to_use, group_candidates)
            vaccines_to_use -= vaccines_for_group
            if group_candidates > 0:
                for group in groups:
                    ev, wv, hv, p = group
                    for cv in candidates_indexes:
                        assignation[(ev, wv, hv, vv, cv, vaccine)] = min(vaccines_for_group *
                                                                         day_population[(ev, wv, hv, vv, cv)] /
                                                                         group_candidates,
                                                                         day_population[(ev, wv, hv, vv, cv)])
                        day_population[(ev, wv, hv, vv, cv)] -= assignation[(ev, wv, hv, vv, cv, vaccine)]
    return assignation

def create_vaccine_assignation(start_date: int, end_date: int, vaccines_information: dict, population: dict,
                               vaccine_priority: list):
    """
    Creates the daily vaccine assignation considering a time period and the required information to determine dosage.
    :param population: Population information to determine the distribution
    :param start_date: Starting date of the vaccination program.
    :param end_date: End date of the vaccination program (time to reach the limit).
    :param vaccines_information: Considers the information of each vaccine ordered by name: 1) total_doses considered,
    2) period between first and second dose.
    :param vaccine_priority: Priority information to calculate the vaccine candidate population.
    :return: dictionary with the vaccine time assignation.
    """
    total_candidates = dict()
    result_information = dict()
    for gv in population.keys():
        total_candidates[gv] = 0
        for groups in vaccine_priority:
            for group in groups:
                ev, wv, hv, p = group
                total_candidates[gv] += population[gv][(ev, wv, hv)]*p
        result_information[gv] = dict()
        for day in range(start_date, end_date + 1):
            result_information[gv][day] = dict()
    total_n = sum(total_candidates[gv] for gv in population.keys())
    for gv in population.keys():
        total_candidates[gv] = total_candidates[gv]/total_n
    time_period = end_date - start_date + 1
    for v in vaccines_information.keys():
        # v is the name of the vaccine
        vac_info = vaccines_information[v]
        total_number = vac_info['total_doses']
        inter_dose_time = vac_info['inter_dose_time']
        if inter_dose_time == 0:
            daily_number = total_number/time_period
            for gv in population.keys():
                for day in range(start_date, end_date+1):
                    result_information[gv][day][v] = ['V0', daily_number*total_candidates[gv]]
        else:
            total_individuals = total_number / 2
            daily_number = total_individuals/(time_period-inter_dose_time)
            for gv in population.keys():
                for day in range(start_date, end_date + 1 - inter_dose_time):
                    result_information[gv][day][v+str(1)] = ['V0', daily_number*total_candidates[gv]]
                    result_information[gv][day+inter_dose_time][v + str(2)] = [v+str(1),
                                                                               daily_number*total_candidates[gv]]
    return result_information

class Model(object):
    age_groups: List[Any]
    departments: List[Any]
    work_groups: List[Any]

    def __init__(self):
        self.compartments = dict()
        initial_pop = pd.read_csv(DIR_INPUT + 'initial_population.csv', sep=';')
        self.departments = list(initial_pop.DEPARTMENT.unique())
        self.age_groups = list(initial_pop.AGE_GROUP.unique())
        self.work_groups = list(initial_pop.WORK_GROUP.unique())
        self.health_groups = list(initial_pop.HEALTH_GROUP.unique())
        self.initial_population = dict()
        self.regions = pd.read_csv(DIR_INPUT + 'department_regions.csv', sep=';', index_col=0).to_dict(orient='index')
        for gv in self.departments:
            self.regions[gv] = self.regions[gv]['REGION']
            self.initial_population[gv] = dict()
            for ev in self.age_groups:
                for wv in self.work_groups:
                    for hv in self.health_groups:
                        self.initial_population[gv][(ev, wv, hv)] = \
                            float(initial_pop[(initial_pop['DEPARTMENT'] == gv) & (initial_pop['AGE_GROUP'] == ev)
                                              & (initial_pop['WORK_GROUP'] == wv) & (initial_pop['HEALTH_GROUP'] == hv)
                                              ].POPULATION.sum())
        self.daly_vector = {'Home': {'INF_VALUE': 0.002, 'BASE_VALUE': 0.006, 'MAX_VALUE': 0.012},
                            'Hosp': {'INF_VALUE': 0.032, 'BASE_VALUE': 0.051, 'MAX_VALUE': 0.074},
                            'ICU': {'INF_VALUE': 0.088, 'BASE_VALUE': 0.133, 'MAX_VALUE': 0.190},
                            'InRecovery': {'INF_VALUE': 0, 'BASE_VALUE': 0, 'MAX_VALUE': 0.012},
                            'Death': {'e0': 72.11, 'e1': 62.11, 'e2': 52.11, 'e3': 42.11, 'e4': 32.11, 'e5': 22.11,
                                      'e6': 12.11, 'e7': 2.11}}
        self.vaccine_cost = {'INF_VALUE': 37167*0.8, 'BASE_VALUE': 37167, 'MAX_VALUE': 37167*1.2}
        self.contact_matrix = {'HOME': {}, 'WORK': {}, 'SCHOOL': {}, 'OTHER': {}}
        con_matrix_home = pd.read_excel(DIR_INPUT + 'contact_matrix.xlsx', sheet_name='Home', engine="openpyxl")
        con_matrix_other = pd.read_excel(DIR_INPUT + 'contact_matrix.xlsx', sheet_name='Other', engine="openpyxl")
        con_matrix_work = pd.read_excel(DIR_INPUT + 'contact_matrix.xlsx', sheet_name='Work', engine="openpyxl")
        con_matrix_school = pd.read_excel(DIR_INPUT + 'contact_matrix.xlsx', sheet_name='School', engine="openpyxl")
        self.attention_costs = pd.read_csv(DIR_INPUT+'attention_costs.csv', sep=';',
                                           index_col=[0, 1, 2]).to_dict(orient='index')

        for c in con_matrix_home.columns:
            self.contact_matrix['HOME'][c] = con_matrix_home[c].to_list()
            self.contact_matrix['OTHER'][c] = con_matrix_other[c].to_list()
            self.contact_matrix['WORK'][c] = con_matrix_work[c].to_list()
            self.contact_matrix['SCHOOL'][c] = con_matrix_school[c].to_list()
        del con_matrix_home
        del con_matrix_other
        del con_matrix_work
        del con_matrix_school
        contact_matrix_coefficients = pd.read_csv(DIR_INPUT + 'contact_matrix_coefficients.csv')
        self.max_cm_days = int(contact_matrix_coefficients.SIM_DAY.max())
        self.contact_matrix_coefficients = dict()
        for reg in contact_matrix_coefficients['REGIONS'].unique():
            cur_contact_matrix_coefficients = contact_matrix_coefficients[
                contact_matrix_coefficients['REGIONS'] == reg].copy()
            cur_contact_matrix_coefficients.drop(columns='REGIONS', inplace=True)
            cur_contact_matrix_coefficients.set_index(['SIM_DAY'], inplace=True)
            self.contact_matrix_coefficients[reg] = cur_contact_matrix_coefficients.to_dict(orient='index')

        self.birth_rates = pd.read_csv(DIR_INPUT + 'birth_rate.csv', sep=';', index_col=0).to_dict()['BIRTH_RATE']
        morbidity_frac = pd.read_csv(DIR_INPUT + 'morbidity_fraction.csv', sep=';', index_col=0)
        self.morbidity_frac = morbidity_frac.to_dict()['COMORBIDITY_RISK']
        del morbidity_frac
        death_rates = pd.read_csv(DIR_INPUT + 'death_rate.csv', sep=';')
        med_degrees = pd.read_csv(DIR_INPUT + 'medical_degrees.csv', sep=';')
        self.death_rates = dict()
        self.med_degrees = dict()
        for gv in death_rates['DEPARTMENT'].unique():
            cur_death_rate = death_rates[death_rates['DEPARTMENT'] == gv].copy()
            cur_death_rate.drop(columns='DEPARTMENT', inplace=True)
            cur_death_rate.set_index('AGE_GROUP', inplace=True)
            self.death_rates[gv] = cur_death_rate.to_dict()['DEATH_RATE']
            del cur_death_rate
            cur_med_degrees = med_degrees[med_degrees['DEPARTMENT'] == gv].copy()
            cur_med_degrees.drop(columns='DEPARTMENT', inplace=True)
            cur_med_degrees.set_index('AGE_GROUP', inplace=True)
            self.med_degrees[gv] = cur_med_degrees.to_dict(orient='index')
            del cur_med_degrees
        self.arrival_rate = pd.read_csv(DIR_INPUT + 'arrival_rate.csv', sep=';', index_col=0).to_dict()

        time_params_load = pd.read_csv(DIR_INPUT + 'input_time.csv', sep=';')
        self.time_params = dict()
        for pv1 in time_params_load['PARAMETER'].unique():
            current_param = time_params_load[time_params_load['PARAMETER'] == pv1]
            for ev in current_param.AGE_GROUP.unique():
                current_age_p = current_param[current_param['AGE_GROUP'] == ev]
                age = {'INF_VALUE': float(current_age_p['INF_VALUE'].sum()),
                       'BASE_VALUE': float(current_age_p['BASE_VALUE'].sum()),
                       'MAX_VALUE': float(current_age_p['MAX_VALUE'].sum())}
                del current_age_p
                self.time_params[(pv1, ev)] = age
                del age
            del current_param

        del time_params_load
        prob_params_load = pd.read_csv(DIR_INPUT + 'input_probabilities.csv', sep=';')
        self.prob_params = dict()
        for pv1 in prob_params_load['PARAMETER'].unique():
            current_param = prob_params_load[prob_params_load['PARAMETER'] == pv1]
            for ev in current_param.AGE_GROUP.unique():
                current_age_p = current_param[current_param['AGE_GROUP'] == ev]
                for hv in current_age_p['HEALTH_GROUP'].unique():
                    current_health = current_age_p[current_age_p['HEALTH_GROUP'] == hv]
                    values = {'INF_VALUE': float(current_health['INF_VALUE'].sum()),
                              'BASE_VALUE': float(current_health['BASE_VALUE'].sum()),
                              'MAX_VALUE': float(current_health['MAX_VALUE'].sum())}
                    self.prob_params[(pv1, ev, hv)] = values
                    del current_health
                del current_age_p
            del current_param

    def run(self, type_params: dict, name: str = 'Iteration', run_type: str = 'vaccination',
            beta: tuple = beta_f, death_coefficient: tuple = dc_f, arrival_coefficient: tuple = arrival_f,
            symptomatic_coefficient: float = spc_f, vaccine_priority: list = None, vaccine_information: dict = None,
            vaccine_start_days: dict = None, vaccine_end_days: dict = None, sim_length: int = 365 * 3,
            use_tqdm: bool = False, t_lost_imm: int = 0, n_parallel: int = multiprocessing.cpu_count()-1,
            exporting_information: Union[str, list] = 'All', vaccine_effectiveness_params: list = None,
            future_variation: float = None):

        # run_type:
        #   1) 'calibration': no vaccination status - returns the daily results of measurement (cases, deaths,
        #   seroprevalence)
        #   2) 'vaccination': model with vaccine states - requires the vaccines information characteristics.
        #   3) 'non-vaccination': model without vaccines - [0V] is the only vaccination states
        # vaccine_information debe_tener {'vacuna':{'total_doses', 'inter_dose_time', 'effectivity',
        # 'symptomatic_prob_reduction'}}
        # export_type = {'all', 'json', 'csv', 'xlsx'}
        if type(exporting_information) is str:
            if exporting_information == 'All':
                exporting_information = ['Department', 'Health', 'Work', 'Age', 'Vaccine']
            else:
                exporting_information = [exporting_information]
        vaccine_start_day = sim_length + 5
        vaccine_end_day = sim_length + 6
        if vaccine_start_days is not None and vaccine_end_days is not None:
            vaccine_start_day = vaccine_start_days['BASE_VALUE']
            vaccine_end_day = vaccine_end_days[type_params.get('vaccine_day', 'BASE_VALUE')]
        if vaccine_information is not None:
            for vac in vaccine_information:
                vaccine_eff = vaccine_information[vac]['effectivity']
                if vaccine_effectiveness_params is not None:
                    if vaccine_effectiveness_params[0] == 'R':
                        vaccine_eff *= (1-vaccine_effectiveness_params[1])
                        if vaccine_eff > 1:
                            vaccine_eff = 1
                    elif vaccine_effectiveness_params[0] == 'V':
                        vaccine_eff = vaccine_effectiveness_params[1]
                vaccine_information[vac]['dose_effectivity'] = 1 - math.sqrt(
                    1 - vaccine_eff) if vaccine_information[vac]['inter_dose_time'] > 0 else \
                    vaccine_eff

        vaccination_calendar = create_vaccine_assignation(start_date=vaccine_start_day,
                                                          end_date=vaccine_end_day,
                                                          vaccines_information=vaccine_information,
                                                          vaccine_priority=vaccine_priority,
                                                          population=self.initial_population) \
            if run_type == 'vaccination' else None
        departments = self.departments
        age_groups = self.age_groups
        work_groups = self.work_groups
        health_groups = self.health_groups
        vaccination_groups = ['V0']
        if run_type == 'vaccination':
            if 'P' in vaccine_information.keys():
                vaccination_groups.append('P1')
                vaccination_groups.append('P2')
            if 'J' in vaccine_information.keys():
                vaccination_groups.append('J')
            if 'S' in vaccine_information.keys():
                vaccination_groups.append('S1')
                vaccination_groups.append('S2')
            if 'M' in vaccine_information.keys():
                vaccination_groups.append('M1')
                vaccination_groups.append('M2')
            if 'A' in vaccine_information.keys():
                vaccination_groups.append('A1')
                vaccination_groups.append('A2')
            vaccination_groups.append('R')
        daly_vector = dict()
        for dv in self.daly_vector:
            if dv == 'Death':
                daly_vector[dv] = self.daly_vector[dv]
            else:
                daly_vector[dv] = self.daly_vector[dv][type_params.get('daly', 'BASE_VALUE')]
        t_e = self.time_params[('t_e', 'ALL')][type_params.get('t_e', 'BASE_VALUE')]
        t_p = self.time_params[('t_p', 'ALL')][type_params.get('t_p', 'BASE_VALUE')]
        t_sy = self.time_params[('t_sy', 'ALL')][type_params.get('t_sy', 'BASE_VALUE')]
        t_a = self.time_params[('t_a', 'ALL')][type_params.get('t_a', 'BASE_VALUE')]
        t_ri = self.time_params[('t_ri', 'ALL')][type_params.get('t_ri', 'BASE_VALUE')]
        initial_sus = self.prob_params[('initial_sus', 'ALL', 'ALL')][type_params.get('initial_sus', 'BASE_VALUE')]
        attention_costs = dict()
        for acv in self.attention_costs:
            attention_costs[acv] = self.attention_costs[acv][type_params.get('attention_cost', 'BASE_VALUE')]
        t_d = dict()
        t_r = dict()
        p_s = dict()
        p_c = dict()
        p_h = dict()
        p_i = dict()
        for ev in age_groups:
            t_d[ev] = self.time_params[('t_d', ev)][type_params.get('t_d', 'BASE_VALUE')]
            t_r[ev] = max(self.time_params[('t_r', ev)][type_params.get('t_r', 'BASE_VALUE')] - t_d[ev], 1)
            p_s[('V0', ev)] = min(self.prob_params[('p_s', ev, 'ALL')][type_params.get(('p_s', ev), 'BASE_VALUE')] *
                                  symptomatic_coefficient, 1.0)
            for hv in health_groups:
                p_i[(ev, 'V0', hv)] = self.prob_params[('p_i', ev, hv)][type_params.get('p_i', 'BASE_VALUE')]
                p_h[(ev, 'V0', hv)] = self.prob_params[('p_h', ev, hv)][type_params.get('p_h', 'BASE_VALUE')]
                p_c[(ev, 'V0', hv)] = 1 - p_h[(ev, 'V0', hv)] - p_i[(ev, 'V0', hv)]

        if run_type == 'vaccination':
            for ev in age_groups:
                p_s[('R', ev)] = p_s[('V0', ev)]
                for hv in health_groups:
                    p_c[(ev, 'R', hv)] = p_c[(ev, 'V0', hv)]
                    p_h[(ev, 'R', hv)] = p_h[(ev, 'V0', hv)]
                    p_i[(ev, 'R', hv)] = p_i[(ev, 'V0', hv)]
            for vv in ['P2', 'J', 'S2', 'M2', 'A2']:  # Complete process
                if vv in vaccination_groups:
                    for ev in age_groups:
                        p_s[(vv, ev)] = p_s[('V0', ev)] * vaccine_information[vv[0]]['symptomatic_prob_coef']
            for vv in ['P1', 'S1', 'M1', 'A1']:  # Half process
                if vv in vaccination_groups:
                    for ev in age_groups:
                        p_s[(vv, ev)] = (p_s[('V0', ev)] + p_s[(vv[0] + str(2), ev)]) / 2
            for ev in age_groups:
                for hv in health_groups:
                    for vv in ['P2', 'J', 'S2', 'M2', 'A2']:  # Complete process
                        if vv in vaccination_groups:
                            p_i[(ev, vv, hv)] = p_i[(ev, 'V0', hv)] * vaccine_information[vv[0]]['icu_prob_coef']
                            p_h[(ev, vv, hv)] = p_h[(ev, 'V0', hv)] * vaccine_information[vv[0]]['hosp_prob_coef']
                            p_c[(ev, vv, hv)] = 1 - p_i[(ev, vv, hv)] - p_h[(ev, vv, hv)]
                    for vv in ['P1', 'S1', 'M1', 'A1']:  # Half process
                        if vv in vaccination_groups:
                            p_i[(ev, vv, hv)] = (p_i[(ev, 'V0', hv)] + p_i[(ev, vv[0] + str(2), hv)]) / 2
                            p_h[(ev, vv, hv)] = (p_h[(ev, 'V0', hv)] + p_h[(ev, vv[0] + str(2), hv)]) / 2
                            p_c[(ev, vv, hv)] = 1 - p_i[(ev, vv, hv)] - p_h[(ev, vv, hv)]
        percentages = dict()
        if vaccine_priority is not None:
            for phase in vaccine_priority:
                for group in phase:
                    ev, wv, hv, percent = group
                    percentages[(ev, wv, hv)] = percent
        result_queue = dict()
        initial_threads = threading.active_count()
        max_threads = initial_threads + n_parallel
        workers = dict()
        results_array = np.zeros(shape=(sim_length + 1, 18)) if run_type == 'calibration' else None
        seroprevalence_array = np.zeros(shape=(sim_length + 1, 12)) if run_type == 'calibration' else None
        integrated_departments = [] if run_type == 'calibration' else None
        params = dict()
        params['run_type'] = run_type
        params['sim_length'] = sim_length
        params['groups'] = age_groups, work_groups, health_groups, vaccination_groups
        params['contact_matrix'] = self.contact_matrix
        params['t_lost_imm'] = t_lost_imm
        params['morbidity_frac'] = self.morbidity_frac
        params['exporting_information'] = exporting_information
        params['attention_costs'] = attention_costs
        params['max_cm_days'] = self.max_cm_days if future_variation is None else self.max_cm_days + 1
        if run_type == 'vaccination':
            # Vaccination run type info
            params['vaccine_information'] = vaccine_information
            params['vaccine_priority'] = vaccine_priority
            params['vaccine_cost'] = self.vaccine_cost[type_params.get('vaccine_cost', 'BASE_VALUE')]
        params['vaccination_period'] = [vaccine_start_day, vaccine_end_day]
        # All type information
        params['daly_vector'] = daly_vector
        params['time_params'] = dict()
        params['time_params']['t_e'] = t_e
        params['time_params']['t_p'] = t_p
        params['time_params']['t_sy'] = t_sy
        params['time_params']['t_a'] = t_a
        params['time_params']['t_ri'] = t_ri
        params['time_params']['t_d'] = t_d
        params['time_params']['t_r'] = t_r

        # Prob params
        params['prob_params'] = dict()
        params['prob_params']['initial_sus'] = initial_sus
        params['prob_params']['p_s'] = p_s
        params['prob_params']['p_c'] = p_c
        params['prob_params']['p_h'] = p_h
        params['prob_params']['p_i'] = p_i
        iterator = tqdm(departments) if use_tqdm else departments
        for gv in iterator:
            cur_region = self.regions[gv] - 1
            params['initial_population'] = self.initial_population[gv]
            params['contact_matrix_coefficients'] = self.contact_matrix_coefficients[self.regions[gv]].copy()
            if future_variation is not None:
                params['contact_matrix_coefficients'][self.max_cm_days+1] = dict()
                for cv in params['contact_matrix_coefficients'][self.max_cm_days]:
                    params['contact_matrix_coefficients'][self.max_cm_days + 1][cv] = future_variation
            params['beta'] = beta[cur_region]
            arrival_rate = {'START_DAY': self.arrival_rate['START_DAY'][gv],
                            'END_DAY': self.arrival_rate['START_DAY'][gv],
                            'ARRIVAL_RATE': self.arrival_rate['ARRIVAL_RATE'][gv] * arrival_coefficient[cur_region]}
            params['arrival_rate'] = arrival_rate
            params['birth_rate'] = self.birth_rates[gv]
            params['death_rate'] = self.death_rates[gv]
            params['med_degrees'] = self.med_degrees[gv]
            params['gv'] = gv
            if run_type == 'vaccination':
                # Vaccination run type info
                params['vaccination_calendar'] = vaccination_calendar[gv]
            p_c_d = dict()
            p_h_d = dict()
            p_i_d = dict()
            for ev in age_groups:
                for hv in health_groups:
                    p_c_d[(ev, 'V0', hv)] = min(death_coefficient[cur_region] * self.prob_params[('p_c_d', ev, hv)][
                        type_params.get(('p_c_d', hv), 'BASE_VALUE')], 1.0)
                    p_h_d[(ev, 'V0', hv)] = min(death_coefficient[cur_region] * self.prob_params[('p_h_d', ev, hv)][
                        type_params.get(('p_h_d', hv), 'BASE_VALUE')], 1.0)
                    p_i_d[(ev, 'V0', hv)] = min(death_coefficient[cur_region] * self.prob_params[('p_i_d', ev, hv)][
                        type_params.get(('p_i_d', hv), 'BASE_VALUE')], 1.0)
            if run_type == 'vaccination':
                vac_death_coef = 'death_coef_' + type_params.get('vac_death', 'BASE_VALUE')
                for ev in age_groups:
                    for hv in health_groups:
                        p_c_d[(ev, 'R', hv)] = p_c_d[(ev, 'V0', hv)]
                        p_h_d[(ev, 'R', hv)] = p_h_d[(ev, 'V0', hv)]
                        p_i_d[(ev, 'R', hv)] = p_i_d[(ev, 'V0', hv)]
                        for vv in ['P2', 'J', 'S2', 'M2', 'A2']:  # Half process
                            if vv in vaccination_groups:
                                p_c_d[(ev, vv, hv)] = p_c_d[(ev, 'V0', hv)] * vaccine_information[vv[0]][vac_death_coef]
                                p_h_d[(ev, vv, hv)] = p_h_d[(ev, 'V0', hv)] * vaccine_information[vv[0]][vac_death_coef]
                                p_i_d[(ev, vv, hv)] = p_i_d[(ev, 'V0', hv)] * vaccine_information[vv[0]][vac_death_coef]
                        for vv in ['P1', 'S1', 'M1', 'A1']:  # Half process
                            if vv in vaccination_groups:
                                p_c_d[(ev, vv, hv)] = (p_c_d[(ev, 'V0', hv)] + p_c_d[(ev, vv[0] + str(2), hv)]) / 2
                                p_h_d[(ev, vv, hv)] = (p_h_d[(ev, 'V0', hv)] + p_h_d[(ev, vv[0] + str(2), hv)]) / 2
                                p_i_d[(ev, vv, hv)] = (p_i_d[(ev, 'V0', hv)] + p_i_d[(ev, vv[0] + str(2), hv)]) / 2
            params['prob_params']['p_c_d'] = p_c_d
            params['prob_params']['p_h_d'] = p_h_d
            params['prob_params']['p_i_d'] = p_i_d
            if run_type == 'calibration':
                for gv2 in result_queue:
                    if gv2 not in integrated_departments:
                        gv_region = self.regions[gv2] - 1
                        results_array[:, gv_region] += result_queue[gv2][:, 0]
                        results_array[:, gv_region + 6] += result_queue[gv2][:, 1]
                        seroprevalence_array[:, gv_region] += result_queue[gv2][:, 2]
                        seroprevalence_array[:, gv_region + 6] += result_queue[gv2][:, 3]
                        integrated_departments.append(gv2)
            workers[gv] = DepartmentRun(params=params.copy(), result_queue=result_queue)
            while threading.active_count() >= max_threads:
                time.sleep(0.00001)
            workers[gv].start()
        current_threads = threading.active_count()
        while len(result_queue) < len(workers):
            while current_threads == threading.active_count() and current_threads > initial_threads and \
                    len(result_queue) < len(workers):
                time.sleep(0.000001)
            if run_type == 'calibration':
                for gv2 in result_queue:
                    if gv2 not in integrated_departments:
                        gv_region = self.regions[gv2] - 1
                        results_array[:, gv_region] += result_queue[gv2][:, 0]
                        results_array[:, gv_region + 6] += result_queue[gv2][:, 1]
                        seroprevalence_array[:, gv_region] += result_queue[gv2][:, 2]
                        seroprevalence_array[:, gv_region + 6] += result_queue[gv2][:, 3]
                        integrated_departments.append(gv2)
            current_threads = threading.active_count()
        if run_type == 'calibration':
            for gv2 in result_queue:
                if gv2 not in integrated_departments:
                    gv_region = self.regions[gv2] - 1
                    results_array[:, gv_region] += result_queue[gv2][:, 0]
                    results_array[:, gv_region + 6] += result_queue[gv2][:, 1]
                    seroprevalence_array[:, gv_region] += result_queue[gv2][:, 2]
                    seroprevalence_array[:, gv_region + 6] += result_queue[gv2][:, 3]
                    integrated_departments.append(gv2)
            for region in range(6):
                results_array[:, region + 12] = seroprevalence_array[:, region] / seroprevalence_array[:, region + 6]
            return results_array
        else:
            pop_pandas = pd.concat(result_queue.values())
            if 'Department' not in exporting_information:
                if 'day' not in exporting_information:
                    exporting_information.append('day')
                pop_pandas = pop_pandas.groupby(exporting_information).sum().reset_index(drop=False)
            pop_pandas['Total_Cost'] = pop_pandas['vac_cost'] + pop_pandas['home_cost'] + pop_pandas['hosp_cost'] + \
                                       pop_pandas['uci_cost']
            pop_pandas['Total_Daly'] = pop_pandas['home_daly'] + pop_pandas['hosp_daly'] + pop_pandas['uci_daly'] + \
                                       pop_pandas['death_daly']
            pop_pandas['Date'] = pop_pandas['day'].apply(lambda x: datetime.datetime(2020, 2, 21) +
                                                                   datetime.timedelta(days=x))
            print('Begin CSV exportation', datetime.datetime.now())
            pop_pandas = pop_pandas.round(decimals=2)
            pop_pandas.to_csv(DIR_OUTPUT + name + '.csv', index=False)
            print('CSV ', DIR_OUTPUT + name + '.csv', 'exported', datetime.datetime.now())
            return pop_pandas

class DepartmentRun(Thread):
    __lock = Lock()

    def __init__(self, params: dict, result_queue: dict):
        Thread.__init__(self)
        self.params = params
        self.result_queue = result_queue

    def run(self):
        # Model Params
        initial_population = self.params['initial_population']
        run_type = self.params['run_type']
        sim_length = self.params['sim_length']
        age_groups, work_groups, health_groups, vaccination_groups = self.params['groups']
        contact_matrix_coefficients = self.params['contact_matrix_coefficients']
        contact_matrix = self.params['contact_matrix']
        max_cm_days = self.params['max_cm_days']
        beta = self.params['beta']
        t_lost_imm = self.params['t_lost_imm']
        arrival_rate = self.params['arrival_rate']
        birth_rate = self.params['birth_rate']
        death_rate = self.params['death_rate']
        morbidity_frac = self.params['morbidity_frac']
        med_degrees = self.params['med_degrees']
        exporting_information = self.params['exporting_information']
        ignore_columns = [item for item in ['Department', 'Health', 'Work', 'Age', 'Vaccine'] if item not in
                          exporting_information]
        gv = self.params['gv']

        # Vaccination run type info
        vaccine_information = self.params.get('vaccine_information', None)
        vaccination_calendar = self.params.get('vaccination_calendar', None)
        vaccination_candidates = ['V0', 'P1', 'S1', 'M1', 'A1'] if run_type == 'vaccination' else None
        vaccine_priority = self.params.get('vaccine_priority', None)
        vaccine_cost = self.params.get('vaccine_cost', None)
        vaccine_start_day, vaccine_end_day = self.params['vaccination_period']

        # All type information
        daly_vector = self.params['daly_vector']
        attention_costs = self.params['attention_costs']

        t_e = self.params['time_params']['t_e']
        t_p = self.params['time_params']['t_p']
        t_sy = self.params['time_params']['t_sy']
        t_a = self.params['time_params']['t_a']
        t_ri = self.params['time_params']['t_ri']
        t_d = self.params['time_params']['t_d']
        t_r = self.params['time_params']['t_r']

        # Prob params
        initial_sus = self.params['prob_params']['initial_sus']
        p_s = self.params['prob_params']['p_s']
        p_c = self.params['prob_params']['p_c']
        p_h = self.params['prob_params']['p_h']
        p_i = self.params['prob_params']['p_i']
        p_c_d = self.params['prob_params']['p_c_d']
        p_h_d = self.params['prob_params']['p_h_d']
        p_i_d = self.params['prob_params']['p_i_d']

        # 0) SU, 1) E, 2) P, 3) SYM, 4) C, 5) HOS, 6) ICU, 7) R_S, 8) A, 9) R, 10) I, 11) Death
        # 12) Cases, 13) Seroprevalence 14) Total_pob 15) New
        i_1_indexes = [2, 3, 4, 7, 10]
        i_2_indexes = [5, 6]
        candidates_indexes = [0, 1, 8, 10]
        alive_compartments = list(range(11))
        percentages = dict()
        if vaccine_priority is not None:
            for phase in vaccine_priority:
                for group in phase:
                    ev, wv, hv, p = group
                    percentages[(ev, wv, hv)] = p
        population = dict()
        covered_percentage = dict()
        for ev in age_groups:
            population_e = dict()
            for wv in work_groups:
                population_w = dict()
                for hv in health_groups:
                    population_h = dict()
                    initial_population_value = initial_population[(ev, wv, hv)]
                    covered_percentage[(ev, wv, hv)] = 1
                    if run_type == 'vaccination':
                        covered_percentage[(ev, wv, hv)] = percentages.get((ev, wv, hv), 0)
                    for vv in vaccination_groups:
                        if vv == 'V0':
                            first_value = initial_population_value * covered_percentage[(ev, wv, hv)]
                        elif vv == 'R':
                            first_value = initial_population_value * (1-covered_percentage[(ev, wv, hv)])
                        else:
                            first_value = 0
                        compartments = list()
                        su = Compartment(name='Susceptible', initial_value=first_value * initial_sus)
                        compartments.append(su)
                        e = Compartment('Exposed')
                        compartments.append(e)
                        p = Compartment('Presymptomatic')
                        compartments.append(p)
                        sy = Compartment('Symptomatic')
                        compartments.append(sy)
                        c = Compartment('Home')
                        compartments.append(c)
                        h = Compartment('Hospitalization')
                        compartments.append(h)
                        i = Compartment('ICU')
                        compartments.append(i)
                        r_s = Compartment('In_recovery')
                        compartments.append(r_s)
                        a = Compartment('Asymptomatic')
                        compartments.append(a)
                        r = Compartment(name='Recovered', initial_value=first_value * (1 - initial_sus))
                        compartments.append(r)
                        imm = Compartment('Immune')
                        compartments.append(imm)
                        d = Compartment('Death')
                        compartments.append(d)
                        cases = Compartment('Cases')
                        compartments.append(cases)
                        seroprevalence = Compartment('Seroprevalence_n')
                        compartments.append(seroprevalence)
                        total_pob = Compartment('total_pob', initial_value=first_value)
                        compartments.append(total_pob)
                        new_home = Compartment('new_home')
                        compartments.append(new_home)
                        new_hosp = Compartment('new_hosp')
                        compartments.append(new_hosp)
                        new_uci = Compartment('new_uci')
                        compartments.append(new_uci)
                        vac_cost = Compartment('vac_cost')
                        compartments.append(vac_cost)
                        home_cost = Compartment('home_cost')
                        compartments.append(home_cost)
                        hosp_cost = Compartment('hosp_cost')
                        compartments.append(hosp_cost)
                        uci_cost = Compartment('uci_cost')
                        compartments.append(uci_cost)
                        home_daly = Compartment('home_daly')
                        compartments.append(home_daly)
                        hosp_daly = Compartment('hosp_daly')
                        compartments.append(hosp_daly)
                        uci_daly = Compartment('uci_daly')
                        compartments.append(uci_daly)
                        death_daly = Compartment('death_daly')
                        compartments.append(death_daly)
                        population_h[vv] = compartments
                    population_w[hv] = population_h
                population_e[wv] = population_w
            population[ev] = population_e
        day = -1
        for t in range(sim_length):
            if day < max_cm_days:
                day += 1
            cur_pob = 0
            for ev in age_groups:
                for wv in work_groups:
                    for hv in health_groups:
                        for vv in vaccination_groups:
                            try:
                                cur_pob += sum(population[ev][wv][hv][vv][state].values[t]
                                               for state in alive_compartments)
                            except Exception as exc:
                                print(ev, wv, hv, vv)
                                print(exc)
                                return
            # Modelo epidemiológico primero
            i_1 = list()
            i_2 = list()
            age_pob = dict()
            for ev in age_groups:
                tot = 0.0
                inf1 = 0.0
                inf2 = 0.0
                for wv in work_groups:
                    for hv in health_groups:
                        for vv in vaccination_groups:
                            tot += sum(population[ev][wv][hv][vv][state].values[t] for state in
                                       alive_compartments)
                            inf1 += sum(population[ev][wv][hv][vv][state].values[t] for state in i_1_indexes)
                            inf2 += sum(population[ev][wv][hv][vv][state].values[t] for state in i_2_indexes)
                            if tot < inf1 + inf2:
                                print(t, gv, ev, wv, hv, vv)
                                print('TOT')
                                for comp in population[ev][wv][hv][vv]:
                                    print(comp.name, comp.values[t])
                                print('i_1')
                                for state in i_1_indexes:
                                    print(population[ev][wv][hv][vv][state].name,
                                          population[ev][wv][hv][vv][state].values[t])
                                print('i_2')
                                for state in i_2_indexes:
                                    print(population[ev][wv][hv][vv][state].name,
                                          population[ev][wv][hv][vv][state].values[t])
                                return None
                cur_pob += tot
                age_pob[ev] = tot
                if tot > 0:
                    i_1.append(inf1 / tot)
                    i_2.append(inf2 / tot)
                    if inf1 + inf2 > tot:
                        print(t, ev, inf1, inf2, inf1 + inf2, tot)
                else:
                    i_1.append(0.0)
                    i_2.append(0.0)
            for ev in age_groups:
                contacts = np.zeros(len(age_groups))
                for cv in contact_matrix:
                    contacts += (1+contact_matrix_coefficients[day][cv]) * np.array(contact_matrix[cv][ev])
                for wv in work_groups:
                    for hv in health_groups:
                        for vv in vaccination_groups:
                            # Bring relevant population
                            su, e, p, sy, c, h, i, r_s, a, r, imm, d, cases, seroprevalence, total_pob, new_home, \
                            new_hosp, new_uci, vac_cost, home_cost, hosp_cost, uci_cost, home_daly, hosp_daly, \
                            uci_daly, death_daly = population[ev][wv][hv][vv]
                            cur_su = su.values.get(t, 0)
                            if cur_su < 0:
                                print('Su', gv, ev, wv, hv, vv, t, cur_su)
                            cur_e = e.values.get(t, 0)
                            if cur_e < 0:
                                print('E', gv, ev, wv, hv, vv, t, cur_e)
                            cur_p = p.values.get(t, 0)
                            if cur_p < 0:
                                print('P', gv, ev, wv, hv, vv, t, cur_p)
                            cur_sy = sy.values.get(t, 0)
                            if cur_sy < 0:
                                print('Sy', gv, ev, wv, hv, vv, t, cur_sy)
                            cur_c = c.values.get(t, 0)
                            if cur_c < 0:
                                print('C', gv, ev, wv, hv, vv, t, cur_c)
                            cur_h = h.values.get(t, 0)
                            if cur_h < 0:
                                print('H', gv, ev, wv, hv, vv, t, cur_h)
                            cur_i = i.values.get(t, 0)
                            if cur_i < 0:
                                print('I', gv, ev, wv, hv, vv, t, cur_i)
                            cur_r_s = r_s.values.get(t, 0)
                            if cur_r_s < 0:
                                print('R_S', gv, ev, wv, hv, vv, t, cur_r_s)
                            cur_a = a.values.get(t, 0)
                            if cur_a < 0:
                                print('A', gv, ev, wv, hv, vv, t, cur_a)
                            cur_r = r.values.get(t, 0)
                            if cur_r < 0:
                                print('R', gv, ev, wv, hv, vv, t, cur_r)
                            cur_imm = imm.values.get(t, 0)
                            if cur_imm < 0:
                                print('Imm', gv, ev, wv, hv, vv, t, cur_imm)
                            cur_d = d.values.get(t, 0)
                            if cur_d < 0:
                                print('D', gv, ev, wv, hv, vv, t, cur_d)
                            cur_cases = cases.values.get(t, 0)
                            if cur_cases < 0:
                                print('Cases', gv, ev, wv, hv, vv, t, cur_cases)
                            cur_seroprevalence = seroprevalence.values.get(t, 0)
                            if cur_seroprevalence < 0:
                                print('Seroprevalence', gv, ev, wv, hv, vv, t, cur_seroprevalence)

                            percent = np.array(i_1) + np.array(i_2) if wv == 'M' else np.array(i_1)
                            percent_change = min(beta * np.dot(percent, contacts), 1.0)
                            contagion_sus = cur_su * percent_change
                            finished_exposed = cur_e / t_e
                            finished_presymptomatic = cur_p / t_p
                            define_treatment = cur_sy / t_sy
                            asymptomatic_recovery = cur_a / t_a
                            home_death_threshold = cur_c / t_d[ev]
                            hosp_death_threshold = cur_h / t_d[ev]
                            icu_death_threshold = cur_i / t_d[ev]
                            new_recovered = cur_r_s/t_r[ev]
                            new_immune = cur_r/t_ri
                            lost_immunity = cur_imm*t_lost_imm if t_lost_imm > 0 else 0
                            arrivals = 0.0
                            if arrival_rate['START_DAY'] <= t <= arrival_rate['END_DAY']:
                                arrivals = arrival_rate['ARRIVAL_RATE']
                                arrivals = arrivals*(total_pob.values.get(t, 0)-d.values.get(t, 0))/cur_pob
                            dsu_dt = {-contagion_sus,
                                      lost_immunity}
                            de_dt = {contagion_sus,
                                       arrivals,
                                       -finished_exposed}
                            dp_dt = {finished_exposed * p_s[(vv, ev)],
                                      -finished_presymptomatic}
                            dsy_dt = {finished_presymptomatic,
                                       -define_treatment}
                            dc_dt = {define_treatment * p_c[(ev, vv, hv)],
                                      -home_death_threshold}
                            dh_dt = {define_treatment * p_h[(ev, vv, hv)],
                                      -hosp_death_threshold}
                            di_dt = {define_treatment * p_i[(ev, vv, hv)],
                                      -icu_death_threshold}
                            dr_s_dt = {home_death_threshold*(1 - p_c_d[(ev, vv, hv)]),
                                        hosp_death_threshold*(1-p_h_d[(ev, vv, hv)]),
                                        icu_death_threshold*(1-p_i_d[(ev, vv, hv)]),
                                        -new_recovered}
                            da_dt = {finished_exposed * (1-p_s[(vv, ev)]),
                                      -asymptomatic_recovery}
                            dr_dt = {new_recovered,
                                      -new_immune}
                            dimm_dt = {asymptomatic_recovery,
                                       new_immune,
                                       -lost_immunity}
                            dd_dt = {home_death_threshold*p_c_d[(ev, vv, hv)],
                                     hosp_death_threshold*p_h_d[(ev, vv, hv)],
                                     icu_death_threshold*p_i_d[(ev, vv, hv)]}
                            if sum(dd_dt) < 0:
                                print('Death decrease', gv, ev, wv, hv, vv, t, 'home', home_death_threshold,
                                      p_c_d[(ev, vv, hv)], 'hosp', hosp_death_threshold, p_h_d[(ev, vv, hv)],
                                      'icu_death_threshold', icu_death_threshold, p_i_d[(ev, vv, hv)])
                            dcases_dt = {finished_exposed * p_s[(vv, ev)]}
                            dseroprevalence_dt = {finished_exposed}

                            su.values[t + 1] = cur_su + float(sum(dsu_dt))
                            e.values[t + 1] = cur_e + float(sum(de_dt))
                            p.values[t + 1] = cur_p + float(sum(dp_dt))
                            sy.values[t + 1] = cur_sy + float(sum(dsy_dt))
                            c.values[t + 1] = cur_c + float(sum(dc_dt))
                            h.values[t + 1] = cur_h + float(sum(dh_dt))
                            i.values[t + 1] = cur_i + float(sum(di_dt))
                            r_s.values[t + 1] = cur_r_s + float(sum(dr_s_dt))
                            a.values[t + 1] = cur_a + float(sum(da_dt))
                            r.values[t + 1] = cur_r + float(sum(dr_dt))
                            imm.values[t + 1] = cur_imm + float(sum(dimm_dt))
                            d.values[t + 1] = cur_d + float(sum(dd_dt))
                            if d.values[t+1] < cur_d:
                                print('Death difference', gv, ev, wv, hv, vv, t, d.values[t + 1], cur_d,
                                      float(sum(dd_dt)))
                            cases.values[t + 1] = cur_cases + float(sum(dcases_dt))
                            seroprevalence.values[t + 1] = cur_seroprevalence + float(sum(dseroprevalence_dt))
                            total_pob.values[t+1] = su.values[t + 1] + e.values[t + 1] + p.values[t + 1] + \
                                                    sy.values[t + 1] + c.values[t + 1] + h.values[t + 1] + \
                                                    i.values[t + 1] + r_s.values[t + 1] + a.values[t + 1] + \
                                                    r.values[t + 1] + imm.values[t + 1] + d.values[t + 1]
                            new_home.values[t + 1] = define_treatment * p_c[(ev, vv, hv)]
                            new_hosp.values[t + 1] = define_treatment * p_h[(ev, vv, hv)]
                            new_uci.values[t + 1] = define_treatment * p_i[(ev, vv, hv)]
                            vac_cost.values[t + 1] = 0
                            if t >=419:
                                home_cost.values[t + 1] = new_home.values[t + 1] * attention_costs[(ev, hv, 'C')]
                                hosp_cost.values[t + 1] = new_hosp.values[t + 1] * attention_costs[(ev, hv, 'H')]
                                uci_cost.values[t + 1] = new_uci.values[t + 1] * attention_costs[(ev, hv, 'I')]
                                home_daly.values[t + 1] = c.values[t + 1] * daly_vector['Home'] / 365 +\
                                                          home_death_threshold*(1 - p_c_d[(ev, vv, hv)]) * \
                                                          daly_vector['Home']*t_r[ev]/365 + \
                                                          r_s.values[t + 1] * daly_vector['InRecovery']/365
                                hosp_daly.values[t + 1] = h.values[t + 1] * daly_vector['Hosp'] / 365 + \
                                                          hosp_death_threshold * (1 - p_h_d[(ev, vv, hv)]) * \
                                                          daly_vector['Hosp'] * t_r[ev] / 365
                                uci_daly.values[t + 1] = i.values[t + 1] * daly_vector['ICU'] / 365 + \
                                                         icu_death_threshold * (1 - p_i_d[(ev, vv, hv)]) * \
                                                          daly_vector['ICU'] * t_r[ev] / 365
                                death_daly.values[t+1] = float(sum(dd_dt)) * daly_vector['Death'][ev]

            # Vaccination dynamics
            if vaccine_start_day <= t <= vaccine_end_day:
                vaccine_capacity = vaccination_calendar[t]
                assignation = calculate_vaccine_assignments(population=population, day=t+1,
                                                                 vaccine_priority=vaccine_priority,
                                                                 vaccine_capacity=vaccine_capacity,
                                                                 candidates_indexes=candidates_indexes)
                for o_vv in vaccination_calendar[t].keys():
                    cur_vaccine_cost = vaccine_cost if o_vv == 'J' else vaccine_cost / 2
                    for ev in age_groups:
                        for wv in work_groups:
                            for hv in health_groups:
                                for i_vv in vaccination_candidates:
                                    # Susceptible:
                                    assigned_s = assignation.get((ev, wv, hv, i_vv, 0, o_vv), 0)
                                    assigned_e = assignation.get((ev, wv, hv, i_vv, 1, o_vv), 0)
                                    assigned_a = assignation.get((ev, wv, hv, i_vv, 8, o_vv), 0)
                                    assigned_im = assignation.get((ev, wv, hv, i_vv, 10, o_vv), 0)
                                    if assigned_s + assigned_e + assigned_a + assigned_im > 0:
                                        d_i_su = {-assigned_s}
                                        d_i_e = {-assigned_e}
                                        d_i_a = {-assigned_a}
                                        d_i_im = {-assigned_im}
                                        d_o_su = {assigned_s*(1-vaccine_information[o_vv[0]]['dose_effectivity'])}
                                        d_o_p = {assigned_e*p_s[(i_vv, ev)]}
                                        d_o_a = {assigned_e*(1-p_s[(i_vv, ev)])}
                                        d_o_im = {assigned_s*vaccine_information[o_vv[0]]['dose_effectivity'],
                                                   assigned_a,
                                                   assigned_im}
                                        population[ev][wv][hv][i_vv][0].values[t + 1] += sum(d_i_su)
                                        population[ev][wv][hv][i_vv][1].values[t + 1] += sum(d_i_e)
                                        population[ev][wv][hv][i_vv][8].values[t + 1] += sum(d_i_a)
                                        population[ev][wv][hv][i_vv][10].values[t + 1] += sum(d_i_im)

                                        population[ev][wv][hv][o_vv][0].values[t + 1] += sum(d_o_su)
                                        population[ev][wv][hv][o_vv][2].values[t + 1] += sum(d_o_p)
                                        population[ev][wv][hv][o_vv][8].values[t + 1] += sum(d_o_a)
                                        population[ev][wv][hv][o_vv][10].values[t + 1] += sum(d_o_im)
                                        population[ev][wv][hv][o_vv][18].values[t + 1] = cur_vaccine_cost * \
                                                                                (assigned_s +
                                                                                assigned_e +
                                                                                assigned_a +
                                                                                assigned_im)

            # Demographics / Health degrees
            if run_type != 'calibration':
                births = birth_rate*cur_pob
                for state in alive_compartments:
                    previous_growing_o_s = births if state == 0 else 0.0
                    previous_growing_o_h = 0.0
                    previous_growing_m_s = 0.0
                    previous_growing_m_h = 0.0
                    for vv in vaccination_groups:
                        for el in range(len(age_groups)):
                            cur_m_s = population[age_groups[el]]['M']['S'][vv][state].values[t+1]
                            cur_m_h = population[age_groups[el]]['M']['H'][vv][state].values[t+1]
                            cur_o_s = population[age_groups[el]]['O']['S'][vv][state].values[t + 1]
                            cur_o_h = population[age_groups[el]]['O']['H'][vv][state].values[t + 1]
                            growing_m_s = cur_m_s / 1826 if el < len(age_groups)-1 else 0.0
                            growing_m_h = cur_m_h / 1826 if el < len(age_groups)-1 else 0.0
                            growing_o_s = cur_o_s / 1826 if el < len(age_groups) - 1 else 0.0
                            growing_o_h = cur_o_h / 1826 if el < len(age_groups) - 1 else 0.0
                            dying_m_s = cur_m_s*death_rate[age_groups[el]] if state not in \
                                                                                i_2_indexes else 0.0
                            dying_m_h = cur_m_h * death_rate[age_groups[el]] if state not in \
                                                                                i_2_indexes else 0.0
                            dying_o_s = cur_o_s * death_rate[age_groups[el]] if state not in \
                                                                                i_2_indexes else 0.0
                            dying_o_h = cur_o_h * death_rate[age_groups[el]] if state not in \
                                                                                i_2_indexes else 0.0
                            dm_s_dt = {previous_growing_m_s * (1-morbidity_frac[age_groups[el]]) *
                                       (1-med_degrees[age_groups[el]]['M_TO_O']),
                                       previous_growing_o_s * (1 - morbidity_frac[age_groups[el]]) *
                                       (med_degrees[age_groups[el]]['O_TO_M']),
                                       -growing_m_s,
                                       -dying_m_s}
                            do_s_dt = {previous_growing_o_s * (1 - morbidity_frac[age_groups[el]]) *
                                       (1 - med_degrees[age_groups[el]]['O_TO_M']),
                                       previous_growing_m_s * (1 - morbidity_frac[age_groups[el]]) *
                                       (med_degrees[age_groups[el]]['M_TO_O']),
                                       -growing_o_s,
                                       -dying_o_s}

                            dm_h_dt = {previous_growing_m_s * morbidity_frac[age_groups[el]] *
                                       (1-med_degrees[age_groups[el]]['M_TO_O']),
                                       previous_growing_m_h *
                                       (1 - med_degrees[age_groups[el]]['M_TO_O']),
                                       previous_growing_o_h * (med_degrees[age_groups[el]]['O_TO_M']),
                                       previous_growing_o_s * (1-morbidity_frac[age_groups[el]]) *
                                       (med_degrees[age_groups[el]]['O_TO_M']),
                                        -growing_m_h,
                                        -dying_m_h}

                            do_h_dt = {previous_growing_o_s * morbidity_frac[age_groups[el]] *
                                       (1 - med_degrees[age_groups[el]]['O_TO_M']),
                                       previous_growing_m_h *
                                       (1 - med_degrees[age_groups[el]]['M_TO_O']),
                                       previous_growing_o_h * (med_degrees[age_groups[el]]['O_TO_M']),
                                       previous_growing_m_s * morbidity_frac[age_groups[el]] *
                                       med_degrees[age_groups[el]]['M_TO_O'],
                                       -growing_o_h,
                                       -dying_o_h}

                            population[age_groups[el]]['M']['S'][vv][state].values[t + 1] += sum(dm_s_dt)
                            population[age_groups[el]]['M']['H'][vv][state].values[t + 1] += sum(dm_h_dt)
                            population[age_groups[el]]['O']['S'][vv][state].values[t + 1] += sum(do_s_dt)
                            population[age_groups[el]]['O']['H'][vv][state].values[t + 1] += sum(do_h_dt)

                            previous_growing_o_s = growing_o_s
                            previous_growing_o_h = growing_o_h
                            previous_growing_m_s = growing_m_s
                            previous_growing_m_h = growing_m_h
        if run_type == 'calibration':
            results_array = np.zeros(shape=(sim_length + 1, 4))
            for ev in age_groups:
                for wv in work_groups:
                    for hv in health_groups:
                        for vv in vaccination_groups:
                            results_array[:, 0] += np.array(list(population[ev][wv][hv][vv][12].values.values()),
                                                            dtype=float)  # Cases
                            results_array[:, 1] += np.array(list(population[ev][wv][hv][vv][11].values.values()),
                                                            dtype=float)  # Deaths
                            results_array[:, 2] += np.array(list(population[ev][wv][hv][vv][13].values.values()),
                                                            dtype=float)  # Seroprevalence n
                            results_array[:, 3] += np.array(list(population[ev][wv][hv][vv][14].values.values()),
                                                            dtype=float)  # Total pob
            self.result_queue[gv] = results_array
        else:
            pop_pandas = pd.DataFrame()
            for wv in work_groups:
                pop_pandas_w = pd.DataFrame()
                for hv in health_groups:
                    pop_pandas_h = pd.DataFrame()
                    for vv in vaccination_groups:
                        pop_pandas_v = pd.DataFrame()
                        for ev in age_groups:
                            pop_dict = dict()
                            for comp in population[ev][wv][hv][vv]:
                                pop_dict[comp.name] = comp.values
                            del population[ev][wv][hv][vv]
                            cur_pop_pandas = pd.DataFrame.from_dict(pop_dict).reset_index(drop=False).rename(
                                columns={'index': 'day'})
                            cur_pop_pandas['Age'] = ev
                            if len(pop_pandas_v) > 0:
                                pop_pandas_v = pd.concat([pop_pandas_v, cur_pop_pandas], ignore_index=True)
                            else:
                                pop_pandas_v = cur_pop_pandas.copy()
                            del cur_pop_pandas
                        pop_pandas_v['Vaccine'] = vv
                        if len(pop_pandas_h) > 0:
                            pop_pandas_h = pd.concat([pop_pandas_h, pop_pandas_v], ignore_index=True)
                        else:
                            pop_pandas_h = pop_pandas_v.copy()
                        del pop_pandas_v
                    pop_pandas_h['Health'] = hv
                    if len(pop_pandas_w) > 0:
                        pop_pandas_w = pd.concat([pop_pandas_w, pop_pandas_h], ignore_index=True)
                    else:
                        pop_pandas_w = pop_pandas_h.copy()
                    del pop_pandas_h
                pop_pandas_w['Work'] = wv
                if len(pop_pandas) > 0:
                    pop_pandas = pd.concat([pop_pandas, pop_pandas_w], ignore_index=True)
                else:
                    pop_pandas = pop_pandas_w.copy()
                del pop_pandas_w
            pop_pandas = pop_pandas[pop_pandas['total_pob'] > 0]
            if 'Department' in exporting_information:
                pop_pandas['Department'] = gv
            else:
                ignore_columns.remove('Department')
            if 'day' not in exporting_information:
                exporting_information.append('day')
            if len(ignore_columns) > 0:
                pop_pandas = pop_pandas.drop(columns=ignore_columns)
            pop_pandas = pop_pandas.groupby(exporting_information).sum().reset_index(drop=False)
            self.result_queue[gv] = pop_pandas


from django.shortcuts import render
from houseofapps.hackathon.models import Hackathon, Navigation, Sponsors, Prize, Program, Committee, Sss
from django.db.models import Count
from django.contrib import messages
from django.core.mail import send_mail, BadHeaderError
from django.http import HttpResponse, HttpResponseRedirect
from datetime import datetime
import locale

def starting_date(start_date):
    locale.setlocale(locale.LC_ALL, '')
    a = datetime.strftime(start_date, '%d,%B,%Y')
    date = a.split(",")
    return date

def hackathon_view(request):
    hack = Hackathon.objects.get(active=True)
    navs = Navigation.objects.filter(hackathon=hack).order_by('order')
    spons = Sponsors.objects.filter(hackathon=hack)
    prize = Prize.objects.filter(hackathon=hack).order_by('order')
    days = Program.objects.values('day').annotate(dcount=Count('day')).order_by('day')
    first_prog = Program.objects.filter(hackathon=hack, day=1).order_by('order')
    second_prog = Program.objects.filter(hackathon=hack, day=2).order_by('order')
    third_prog = Program.objects.filter(hackathon=hack, day=3).order_by('order')
    jury = Committee.objects.filter(jury=True, hackathon=hack)
    mentor = Committee.objects.filter(mentor=True, hackathon=hack)
    sss = Sss.objects.filter(hackathon=hack).order_by('order')
    return render(request, 'hackathon/index.html', {'hack': hack,
                                                    'navs': navs,
                                                    'spons': spons,
                                                    'prize': prize,
                                                    'days': days,
                                                    'first_prog': first_prog,
                                                    'second_prog': second_prog,
                                                    'third_prog': third_prog,
                                                    'jury': jury,
                                                    'mentor': mentor,
                                                    'sss': sss,
                                                    'start_date':starting_date(hack.starting_date)
                                                    })

def send_mail_hackathon(request):
    name = request.POST.get('name', '')
    subject = request.POST.get('subject', '')
    from_email = request.POST.get('from_email', '')
    message = request.POST.get('message')

    if message is not None and message != "" and message != 'Message':
        try:
            send_mail(subject, message, from_email, ['info@houseofapps.com'])

            messages.success(request,'Mesaj gönderildi.')
            return HttpResponseRedirect('/hackathon')
        except BadHeaderError:
            return HttpResponse('Invalid header found.')
        return HttpResponseRedirect('/send_email')
    else:

        messages.warning(request,'Mesaj gönderilemedi.')
        return HttpResponseRedirect('/hackathon')


# %%
from djitellopy import Tello
from cv2 import cv2 as cv
import facedetect
from time import sleep

if __name__ == "__main__":
	tello = Tello()
	face_cascade = facedetect.get_face_cascade()

	try:
		tello.connect()
		tello.streamon()
		print(f"Battery: {tello.get_battery()}")

		frame = tello.get_frame_read()
		print("[INFO] dronecontrol.py - Got Frame Reader")

		while True:
			faces = facedetect.face_cascade_detect(frame.frame, face_cascade)
			detected_frame = facedetect.draw_face_box(frame.frame, faces)

			if detected_frame is None:
				raise ValueError("Error in dronecontrol.py - Frame not found")

			cv.imshow('frame', detected_frame)

			if cv.waitKey(1) & 0xFF == ord('q'):
				break

	except Exception as e:
		print("Error in dronecontrole.py")
		print(type(e))
		print(e)

	finally:
		cv.destroyAllWindows()
		tello.end()
# %%


import sentry_sdk
from fastapi import Query, status

from callback.constants.error_code import Error
from callback.ctx import CTX_USER
from callback.dao import secret_keys, users
from callback.exception import ApiHTTPException

async def check_secret_key(
        secret_key: str = Query(..., min_length=1, max_length=32, alias="secretKey", description="密钥")):
    result, user_id = await secret_keys.get_by_secret_key_to_user_id(secret_key)
    if not result:
        code, message = Error.secret_key_error.unpack()
        raise ApiHTTPException(message=message, code=code, status_code=status.HTTP_401_UNAUTHORIZED)

    result, user = await users.get_by_id(user_id)
    if not result:
        code, message = Error.secret_key_error.unpack()
        raise ApiHTTPException(message=message, code=code, status_code=status.HTTP_401_UNAUTHORIZED)

    sentry_sdk.set_user({
        "id": user.id,
        "phone": user.phone,
        "username": user.username,
    })
    CTX_USER.set(user)

async def check_root():
    user = CTX_USER.get()
    if not user.is_root:
        code, message = Error.forbidden_error.unpack()
        raise ApiHTTPException(message=message, code=code, status_code=status.HTTP_403_FORBIDDEN)


import paths
#from torchnlp.encoders.text import StaticTokenizerEncoder, stack_and_pad_tensors, pad_tensor
import json
import dill
import pickle
import pandas as pd
import numpy as np
from keras import preprocessing

embedding_matrix_path = "embedding_matrix.pkl"

def create_embedding_matrix(word_index,embedding_dict,dimension):
    embedding_matrix=np.zeros((len(word_index)+1,dimension))

    for word, index in word_index.items():
        if word in embedding_dict:
            embedding_matrix[index]=embedding_dict[word]
    return embedding_matrix

glove = pd.read_csv(paths.embedding, sep=" ", quoting=3, header=None, index_col=0)
glove_embedding = {key: val.values for key, val in glove.T.items()}

with open("E:/Datasets/Wikihop/train.json", "r") as read_file:
    dataset = json.load(read_file)

#text=["The cat sat on mat","we can play with model"]

text = list()
for item in dataset:
    text.append(item["query"])
    text.append(item["answer"])
    text.append(item["supports"])

tokenizer = preprocessing.text.Tokenizer(split=" ", num_words=50000, oov_token='OOV')
tokenizer.fit_on_texts(text)

text_token=tokenizer.texts_to_sequences(text)
print(len(text_token))

#encoder = StaticTokenizerEncoder(text, min_occurrences=1, tokenize=lambda s: s.split())
#print(encoder.token_to_index)

print(len(tokenizer.word_index))

embedding_matrix=create_embedding_matrix(tokenizer.word_index, embedding_dict=glove_embedding,dimension=50)

print(embedding_matrix.shape)

file = open("tokenizer_glove.pkl", "wb")
dill.dump(tokenizer, file)
file.close()

with open(embedding_matrix_path, 'wb') as f:
        pickle.dump(embedding_matrix, f)


"""
1033. 移动石子直到连续

三枚石子放置在数轴上，位置分别为 a，b，c。
每一回合，你可以从两端之一拿起一枚石子（位置最大或最小），并将其放入两端之间的任一空闲位置。形式上，
假设这三枚石子当前分别位于位置 x, y, z 且 x < y < z。那么就可以从位置 x 或者是位置 z 拿起一枚石子，
并将该石子移动到某一整数位置 k 处，其中 x < k < z 且 k != y。
当你无法进行任何移动时，即，这些石子的位置连续时，游戏结束。
要使游戏结束，你可以执行的最小和最大移动次数分别是多少？ 以长度为 2 的数组形式返回答案：answer = [minimum_moves, maximum_moves]
"""
from typing import List

class Solution:
    def numMovesStones(self, a: int, b: int, c: int) -> List[int]:
        a, b, c = list(sorted([a, b, c]))
        result1, result2 = 0, 0
        if b - a > 1:
            result1 += 1
        if c - b > 1:
            result1 += 1
        if b - a == 2 or c - b == 2:
            result1 = 1
        result2 += c - a - 2
        return [result1, result2]

Solution().numMovesStones(3, 5, 1)

1033. 移动石子直到连续.py


"""预处理"""
from jieba import posseg as pseg
from jieba import analyse
from gensim import corpora
import os

# 数据标准化
def tokenization(content):
    '''
    {形容词（a）、连词(c)、副词(d)、叹词（e）、方位词(f)、数词(m)、量词（q）、标点符号(w)、时间词（t）}
    去除文章中特定词性的词
    :content 需要标准化的数据
    :return list[str]
    '''
    # stop_flags = {'x', 'c', 'u', 'd', 'p', 't', 'uj', 'm', 'f', 'r'}
    stop_flags = {'x','q','w','t','m'}              #除去对应词性的词
    words = pseg.cut(content)
    words = ''.join([word for word, flag in words if flag not in stop_flags])
    # stop_words_path = os.path.split(os.getcwd())[0] + '/lib/stop_words.txt'    #加载停用词
    stop_words_path = 'lib/stop_words.txt'
    analyse.set_stop_words(stop_words_path)         #除去停用词
    return analyse.extract_tags(words)

def consturctWordVec(texts):
    """
    构建词向量
    :param text: 所有文章构成的数组
    :return:
    """

    dictionary = corpora.Dictionary(texts)
    corpus = [dictionary.doc2bow(text) for text in texts]
    print(corpus)
if __name__ == '__main__':
    print(tokenization("在得到每一篇文档对应的主题向量后，我们就可以计算文档之间的相似度，进而完成如文本聚类、信息检索之类的任务。在Gensim中，也提供了这一类任务的API接口。"))


import random
import re
import string
from collections import OrderedDict
from datetime import datetime, timedelta, timezone
from pathlib import Path

import numpy as np

class FinalYield(Exception): pass

BYTES_PER_KB = 1024
BYTES_PER_MB = 1024**2
BYTES_PER_GB = 1024**3
BYTES_PER_CHAR = 1
# BASE52 are distinguishable ascii characters (e.g. 1, l are easily confused in some typefaces)
BASE52 = "2346789abcdefghijmnpqrstuvwxyzABCDEFGHJLMNPQRTUVWXYZ"
BASE94 = string.ascii_letters + string.digits + string.punctuation
_TXT_FILE_WARNING_MESSAGE = "DO NOT EDIT THIS FILE.\n"
_TXT_FILE_WARNING_MESSAGE_LEN = len(_TXT_FILE_WARNING_MESSAGE)
NAME_REGEX = re.compile("[_a-zA-Z]\w*")

try:
    LOCAL_TIMEZONE = datetime.now(timezone(timedelta(0))).astimezone().tzinfo

except RuntimeError:
    LOCAL_TIMEZONE = timezone.utc

def intervals_overlap(int1, int2):
    """Check if the half-open interval [int1[0], int1[0] + int1[1]) has a non-empty intersection with
    [int2[0], int2[0] + int2[1])"""

    if int1[1] == 0 or int2[1] == 0:
        return False
    if int1[1] < 0 or int2[1] < 0:
        raise ValueError

    a1,l1 = int1
    a2,l2 = int2
    return a1 <= a2 < a1 + l1 or a1 < a2 + l2 <= a1 + l1 or a2 <= a1 < a2 + l2 or a2 < a1 + l1 <= a2 + l2

def intervals_subset(int1, int2):
    return int2[0] <= int1[0] and int1[0] + int1[1] <= int2[0] + int2[1]

def random_unique_filename(directory, suffix = "", length = 6, alphabet = BASE52, num_attempts = 10):

    directory = Path(directory)

    for n in range(num_attempts):

        filename =  directory / "".join(random.choices(alphabet, k = length + n))

        if suffix != "":
            filename = filename.with_suffix(suffix)

        if not filename.exists():
            return filename

    raise RuntimeError("buy a lottery ticket fr")

def check_has_method(instance, method_name):
    return hasattr(instance.__class__, method_name) and callable(getattr(instance.__class__, method_name))

def write_txt_file(txt, file, overwrite = False):

    with file.open("w" if overwrite else "x") as fh:
        fh.write(_TXT_FILE_WARNING_MESSAGE + txt)

def read_txt_file(file):

    with file.open("r") as fh:
        return fh.read()[_TXT_FILE_WARNING_MESSAGE_LEN : ]

# def safe_overwrite_file(filename, new_content):
#     tempfile = random_unique_filename(filename.parent)
#     try:
#         with tempfile.open("w") as fh:
#             fh.write(new_content)
#         Path.unlink(filename)
#         Path.rename(tempfile, filename)
#     except OSError:
#         raise OSError(
#             "An error occured somewhere while updating data. A copy of the data can be found in either the "
#             f"file `{str(filename)}` or the file `{str(tempfile)}`."
#         )

def sort_intervals(intervals):
    return sorted(list(intervals), key = lambda t: (t[0], -t[1]))

def combine_intervals(intervals_sorted):

    yield_ = None

    for startn, length in intervals_sorted:

        if yield_ is None:
            yield_ = (startn, length)

        elif startn <= yield_[0] + yield_[1]:
            yield_ = (yield_[0], max(startn + length - yield_[0], yield_[1]))

        else:

            yield yield_
            yield_ = (startn, length)

    if yield_ is not None:
        yield yield_

def replace_lists_with_tuples(obj):

    if isinstance(obj, dict):
        return {key: replace_lists_with_tuples(val) for key, val in obj.items()}

    elif isinstance(obj, list) or isinstance(obj, tuple):
        return tuple([replace_lists_with_tuples(x) for x in obj])

    else:
        return obj

def replace_tuples_with_lists(obj):

    if isinstance(obj, dict):
        return {key: replace_tuples_with_lists(val) for key, val in obj.items()}

    elif isinstance(obj, tuple) or isinstance(obj, list):
        return [replace_tuples_with_lists(x) for x in obj]

    else:
        return obj

def justify_slice(slc, min_index, max_index):
    """If a slice has negative or `None` indices, then this function will return a new slice with equivalent,
    non-`None`, positive indices.

    :param slc: (type `slice`) The `slice` to justify.
    :param min_index: (type non-negative `int`) The minimum index of the justified slice.
    :param max_index: (type non-negative `int`) The maximum index of the justified slice.
    :return: The justified `slice`.
    """

    if max_index < min_index:
        raise ValueError("max_index < min_index")
    if max_index < 0:
        raise ValueError("max_index < 0")
    if min_index < 0:
        raise ValueError("min_index < 0")

    start = slc.start   if slc.start    else min_index
    stop =  slc.stop    if slc.stop     else max_index + 1
    step =  slc.step    if slc.step     else 1

    start = _justify_slice_start_stop(start, min_index, max_index)
    stop =  _justify_slice_start_stop(stop, min_index, max_index)

    return slice(start, stop, step)

def _justify_slice_start_stop(num, min_index, max_index):

    mod = max_index - min_index + 1

    if num < 0:
        num += mod + min_index

    if num < min_index:
        return 0

    elif num > max_index:
        return mod

    else:
        return num - min_index

def order_json_obj(json_obj):

    if isinstance(json_obj, dict):

        ordered_items = sorted(list(json_obj.items()), key=lambda t: t[0])
        return OrderedDict([
            (key, order_json_obj(val))
            for key, val in ordered_items
        ])

    elif isinstance(json_obj, list):
        return list(map(order_json_obj, json_obj))

    else:
        return json_obj

def is_signed_int(num):
    return isinstance(num, (int, np.int8, np.int16, np.int32, np.int64))

def is_int(num):
    return isinstance(num, (int, np.int8, np.int16, np.int32, np.int64, np.uint8, np.uint16, np.uint32, np.uint64))

def bytify_int(num, num_zeros = None):

    if num_zeros is None:
        return str(num).encode("ASCII")

    else:
        return f"{num:0{num_zeros}d}".encode("ASCII")

def intify_bytes(bytes_):
    return int(bytes_.decode("ASCII"))

def check_type(obj, name, expected_type):

    if not isinstance(obj, expected_type):
        raise TypeError(f"`{name}` must be of type `{expected_type.__name__}`, not `{type(obj).__name__}`.")

def check_type_None_default(obj, name, expected_type, default):

    if obj is not None and not isinstance(obj, expected_type):
        raise TypeError(f"`{name}` must be of type `{expected_type.__name__}`, not `{type(obj).__name__}`.")

    elif obj is not None:
        return obj

    else:
        return default

def check_return_int(obj, name):

    if not is_int(obj):
        raise TypeError(f"`{name}` must be of type `int`, not `{type(obj).__name__}`.")

    else:
        return int(obj)

def check_return_int_None_default(obj, name, default):

    if obj is not None and not is_int(obj):
        raise TypeError(f"`{name}` must be of type `int`, not `{type(obj).__name__}`.")

    elif obj is not None:
        return int(obj)

    else:
        return default

def check_Path(obj, name):

    if not isinstance(obj, (str, Path)):
        raise TypeError(f"`{name}` must be either of type `str` or `pathlib.Path`, not `{type(obj).__name__}`.")

def resolve_path(path):
    """
    :param path: (type `pathlib.Path`)
    :raise FileNotFoundError: If the path could not be resolved.
    :return: (type `pathlib.Path`) Resolved.
    """

    try:
        resolved = path.resolve(True) # True raises FileNotFoundError

    except FileNotFoundError:
        raise_error = True

    else:
        return resolved

    if raise_error:

        resolved = path.resolve(False) # False suppressed FileNotFoundError

        for parent in reversed(resolved.parents):

            if not parent.exists():
                raise FileNotFoundError(
                    f"Resolved path : `{resolved}`\n" +
                    f"The file or directory `{str(parent)}` could not be found."
                )

        else:
            raise FileNotFoundError(f"The file or directory `{path}` could not be found.")

def is_deletable(path):

    try:

        with path.open("a") as _: pass
        return True

    except OSError:
        return False

    except Exception as e:
        raise e

# def get_leftmost_layer(s, begin = 0):
#
#     if begin >= len(s):
#         return len(s), len(s)
#
#     symbs_re = re.compile("[()\[\]{}\"']")
#     opening_symbs = {"}" : "{", "]" : "[", ")" : "("}
#     non_escaped_single_quote = re.compile("(\\\\)*'")
#     non_escaped_double_quote = re.compile('(\\\\)*"')
#     stack = []
#
#     found_leftmost_layer = False
#     curr_symb_index = begin - 1
#
#     start_index = None
#
#     while not found_leftmost_layer:
#
#         if len(stack) > 0 and stack[-1] == "'":
#             string_end_index = non_escaped_single_quote.search(s, curr_symb_index + 1)
#
#         elif len(stack) > 0 and stack[-1] == '"':
#             string_end_index = non_escaped_double_quote.search(s, curr_symb_index + 1)
#
#         else:
#             string_end_index = -1
#
#         if string_end_index is None:
#             raise ValueError
#
#         elif string_end_index.start(0) >= 0:
#             stack.pop()
#             curr_symb_index = string_end_index.start(0)
#
#         else:
#             match = symbs_re.search(s, curr_symb_index + 1)
#
#             if match is None and len(stack) > 0:
#                 raise ValueError
#
#             elif match is not None:
#                 symb = match.group(0)
#                 symb_index = match.start(0)
#
#                 if symb in opening_symbs.keys():
#                     # if `symb` is a closing symbol
#
#                     if len(stack) == 0 or stack[-1] != opening_symbs[symb]:
#                         raise ValueError
#
#                     else:
#                         stack.pop()
#                         curr_symb_index = symb_index
#
#                 else:
#                     # if `symb` is an opening symbol or a single or double quote
#
#                     if len(stack) == 0:
#                         start_index = symb_index
#                     stack.append(symb)
#                     curr_symb_index = symb_index
#
#         found_leftmost_layer = len(stack) == 0
#
#     if start_index is None or curr_symb_index == -1:
#         return 0, len(s)-1
#
#     else:
#         return start_index, curr_symb_index


"""Entity Module

This module defines the Entity concept. An Entity is an object that will be displayed on the screen
"""

import weakref
from random import random

import glm

class Entity:

    entities = {}

    def __init__(self, model_mesh, pos = glm.vec3(0.0, 0.0, 0.0), angle = glm.vec3(0.0, 0.0, 0.0),scale = glm.vec3(1.0) ):
        self.model_mesh = model_mesh
        self.pos = pos
        self.angle = angle
        self.scale = scale
        self.update()
        #model_name = str(self.model).split('.')[-1].split()[0]

        print(f"XXX -> {[str(id(x)) for x in self.model_mesh.mesh_list]}")
        for mesh_id in [id(x) for x in self.model_mesh.mesh_list]:
            if mesh_id not in Entity.entities:
                Entity.entities[mesh_id] = [self,]
            else:
                Entity.entities[mesh_id].append(self)

        print(f"ENTITIES = [{Entity.entities}]")

    def scale_by(self, v: glm.vec3):
        self.scale = v
        self.update()

    def rotate_by_vector(self, v: glm.vec3):
        self.angle.x += v.x
        self.angle.y += v.y
        self.angle.z += v.z
        self.update()

    def rotate(self, x: float, y: float, z: float):
        self.angle.x += x
        self.angle.y += y
        self.angle.z += z
        self.update()

    def move_to(self, v: glm.vec3):
        self.pos = v
        self.update()

    def move(self, dx: float, dy: float, dz: float):
        self.pos += glm.vec3(dx, dy, dz)
        self.update()

    def update(self):
        self.model_matrix = glm.mat4(1.0)
        self.model_matrix = glm.translate(self.model_matrix, self.pos)
        self.model_matrix = glm.scale(self.model_matrix, self.scale)
        self.model_matrix = glm.rotate(self.model_matrix,\
             glm.radians(self.angle.x), glm.vec3(1.0, 0.0, 0.0))
        self.model_matrix = glm.rotate(self.model_matrix,\
             glm.radians(self.angle.y), glm.vec3(0.0, 1.0, 0.0))
        self.model_matrix = glm.rotate(self.model_matrix,\
             glm.radians(self.angle.z), glm.vec3(0.0, 0.0, 1.0))

    #def draw(self, shader):

    #    self.model.draw(shader)


#import copy
import random
from collections import Counter

class Hat:
    def __init__(self,**kwargs):
        self.contents = []
        self.total = 0
        self.drawn = []
        for key,value in kwargs.items():
            self.total += value
            for i in range(1,value+1):
                self.contents.append(key)
        self.original = list(self.contents) #copy
        self.oritotal = int(self.total) #copy

    def draw(self,to_draw = 1): #reoccuring draw loop
        if self.total == 0: #returns to original bag contents and draws one
            self.reset()
            self.draw()
            return self.drawn
        else:
            r = random.randint(0,self.total-1)
            ball = self.contents[r]
            self.contents.pop(r)
            self.total-=1
            self.drawn.append(ball)
            if to_draw > 1:
                self.draw()
            return self.drawn

    def reset(self):
        self.contents = list(self.original)
        self.total = self.oritotal

def experiment(hat, expected_balls, num_balls_drawn, num_experiments):
    n = int(num_experiments) #copy

    success = 0
    successes = 0

    while num_experiments > 0:
        num_experiments -= 1
        hat.drawn = []
        for i in range(0,num_balls_drawn):
            hat.draw()
        d = Counter(hat.drawn)
        for key in expected_balls:
            if d[key] >= expected_balls[key]:
                success = 1
            else:
                success = 0
                break
        if success == 1:
            successes += 1
        hat.reset()

    prob = successes/n
    return prob

'''
TESTS
hat3 = Hat(blue=3,red=2,green=6)
probability = experiment(hat=hat3, expected_balls={"blue":2,"green":1}, num_balls_drawn=4, num_experiments=1000)
print(probability) #0.272 expected

hat = Hat(yellow=5,red=1,green=3,blue=9,test=1)
probability=experiment(hat=hat, expected_balls={"yellow":2,"blue":3,"test":1}, num_balls_drawn=20, num_experiments=100)
print(probability) #1.0 expected
'''


import cv2
import numpy as np

class clarify():

    def __init__(self, path=None, img=None):
        # open file into image array or use image itself
        if img is None:
            if path is not None:
                self.img = cv2.imread(path, cv2.IMREAD_UNCHANGED)
            else:
                raise Exception('You have to provide a path or image itself.')
        else:
            self.img = img

    # clear image.
    # mybb captcha.php seems make its color palette of string between 0 and 200.
    # anything above 200 is noise.
    # also completely black pixels in edges must filtered
    def clarify_img(self):
        self.img[np.logical_or(np.max(self.img, axis=2)>200, np.sum(self.img, axis=2)==0)] = [255, 255, 255]

    # RGB to GRAY
    def gray(self):
        self.img = cv2.cvtColor(self.img, cv2.COLOR_RGB2GRAY)

    def resize(self, size):
        self.img = cv2.resize(self.img, size)
    # clear and gray
    def clarify_and_gray(self):
        self.clarify_img()
        self.resize((48, 48))
        self.gray()

if __name__ == "__main__":
    clr = clarify(path="test.png")
    clr.clarify_img()
    clr.gray()
    img = clr.img
    cv2.imwrite("test_clarified.png", img)
    cv2.imshow('clarified', img)

    cv2.waitKey(0)
    cv2.destroyAllWindows()


import json
import numpy as np
import triton_python_backend_utils as pb_utils

from pathlib import Path
from transformers import AutoTokenizer

class TritonPythonModel:
    """Your Python model must use the same class name. Every Python model
    that is created must have "TritonPythonModel" as the class name.
    """

    def initialize(self, args):
        """`initialize` is called only once when the model is being loaded.
        Implementing `initialize` function is optional. This function allows
        the model to initialize any state associated with this model.

        Parameters
        ----------
        args : dict
          Both keys and values are strings. The dictionary keys and values are:
          * model_config: A JSON string containing the model configuration
          * model_instance_kind: A string containing model instance kind
          * model_instance_device_id: A string containing model instance device ID
          * model_repository: Model repository path
          * model_version: Model version
          * model_name: Model name
        """
        self.config = json.loads(args["model_config"])
        self.current_dir = Path(__file__).parent
        model_max_length = int(self.config["parameters"]["model_max_length"]["string_value"])
        reference_model  = self.config["parameters"]["reference_model"]["string_value"]
        self.tokenizer = AutoTokenizer.from_pretrained(reference_model,
                                                       model_max_length=model_max_length,
                                                       cache_dir=self.current_dir / ".cache")
        print('Initialized...')

    def execute(self, requests):
        """`execute` must be implemented in every Python model. `execute`
        function receives a list of pb_utils.InferenceRequest as the only
        argument. This function is called when an inference is requested
        for this model.

        Parameters
        ----------
        requests : list
          A list of pb_utils.InferenceRequest

        Returns
        -------
        list
          A list of pb_utils.InferenceResponse. The length of this list must
          be the same as `requests`
        """

        responses = []

        # Every Python backend must iterate through list of requests and create
        # an instance of pb_utils.InferenceResponse class for each of them. You
        # should avoid storing any of the input Tensors in the class attributes
        # as they will be overridden in subsequent inference requests. You can
        # make a copy of the underlying NumPy array and store it if it is
        # required.
        for request in requests:
            # Perform inference on the request and append it to responses list...
            query = pb_utils.get_input_tensor_by_name(request, "query")
            query = [sentence[0] for sentence in query.as_numpy().astype(str)]

            ret = self.tokenizer(query, padding=True, return_tensors="np")

            ids = pb_utils.Tensor("input_ids", ret["input_ids"].astype(np.uint32))

            len = np.array([[size] for size in np.sum(ret["attention_mask"], axis=1)])
            len = pb_utils.Tensor("request_input_len", len.astype(np.uint32))
            responses.append(pb_utils.InferenceResponse(output_tensors=[ids, len]))

        # You must return a list of pb_utils.InferenceResponse. Length
        # of this list must match the length of `requests` list.
        return responses


# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

import os
import os.path
import unittest
from shutil import rmtree
from tempfile import mkdtemp

import mozunit

from mozbuild.action.buildlist import addEntriesToListFile

class TestBuildList(unittest.TestCase):
    """
    Unit tests for buildlist.py
    """

    def setUp(self):
        self.tmpdir = mkdtemp()

    def tearDown(self):
        rmtree(self.tmpdir)

    # utility methods for tests
    def touch(self, file, dir=None):
        if dir is None:
            dir = self.tmpdir
        f = os.path.join(dir, file)
        open(f, "w").close()
        return f

    def assertFileContains(self, filename, l):
        """Assert that the lines in the file |filename| are equal
        to the contents of the list |l|, in order."""
        l = l[:]
        f = open(filename, "r")
        lines = [line.rstrip() for line in f.readlines()]
        f.close()
        for line in lines:
            self.assertTrue(
                len(l) > 0,
                "ran out of expected lines! (expected '{0}', got '{1}')".format(
                    l, lines
                ),
            )
            self.assertEqual(line, l.pop(0))
        self.assertTrue(
            len(l) == 0,
            "not enough lines in file! (expected '{0}'," " got '{1}'".format(l, lines),
        )

    def test_basic(self):
        "Test that addEntriesToListFile works when file doesn't exist."
        testfile = os.path.join(self.tmpdir, "test.list")
        l = ["a", "b", "c"]
        addEntriesToListFile(testfile, l)
        self.assertFileContains(testfile, l)
        # ensure that attempting to add the same entries again doesn't change it
        addEntriesToListFile(testfile, l)
        self.assertFileContains(testfile, l)

    def test_append(self):
        "Test adding new entries."
        testfile = os.path.join(self.tmpdir, "test.list")
        l = ["a", "b", "c"]
        addEntriesToListFile(testfile, l)
        self.assertFileContains(testfile, l)
        l2 = ["x", "y", "z"]
        addEntriesToListFile(testfile, l2)
        l.extend(l2)
        self.assertFileContains(testfile, l)

    def test_append_some(self):
        "Test adding new entries mixed with existing entries."
        testfile = os.path.join(self.tmpdir, "test.list")
        l = ["a", "b", "c"]
        addEntriesToListFile(testfile, l)
        self.assertFileContains(testfile, l)
        addEntriesToListFile(testfile, ["a", "x", "c", "z"])
        self.assertFileContains(testfile, ["a", "b", "c", "x", "z"])

    def test_add_multiple(self):
        """Test that attempting to add the same entry multiple times results in
        only one entry being added."""
        testfile = os.path.join(self.tmpdir, "test.list")
        addEntriesToListFile(testfile, ["a", "b", "a", "a", "b"])
        self.assertFileContains(testfile, ["a", "b"])
        addEntriesToListFile(testfile, ["c", "a", "c", "b", "c"])
        self.assertFileContains(testfile, ["a", "b", "c"])

if __name__ == "__main__":
    mozunit.main()