"""Purpose: Define variables and their attributes.

Author: Stephanie Westerhuis

Date: 11/29/2021
"""
# Third-party
import pandas as pd
import seaborn as sns

vdf = pd.DataFrame(
    # variables
    columns=[
        "altitude",
        "cbh",
        "clc",
        "clct",
        "clcl",
        "ddt_t_lw",
        "ddt_t_sw",
        "dewp_temp",
        "hor_vis",
        "press",
        "qc",
        "qc_dia",
        "qi_dia",
        "qv",
        "qv_dia",
        "rel_hum",
        "lw_down",
        "lw_up",
        "sw_down",
        "sw_up",
        "temp",
        "2m_temp",
        "tqv",
        "ver_vis",
        "wind_dir",
        "wind_vel",
    ],
    # attributes
    index=[
        # mandatory entries
        "long_name",
        "short_name",
        "unit",
        # general
        "icon_name",
        "arome_name",
        "min_value",
        "max_value",
        "dwh_id",
        # line appearance
        "color",
        "marker",
        "linestyle",
        "colormap",
        # value transformations
        "mult",
        "mult_arome",
        "plus",
        "plus_arome",
        "avg",
        "avg_arome"
    ],
)

# set default values for certain attributes
vdf.loc["icon_name"] = None
vdf.loc["arome_name"] = None
vdf.loc["min_value"][:] = None
vdf.loc["max_value"][:] = None
vdf.loc["dwh_id"][:] = None
vdf.loc["color"] = "black"
vdf.loc["marker"][:] = "o"
vdf.loc["linestyle"] = "solid"
vdf.loc["colormap"] = sns.color_palette("viridis", as_cmap=True)
vdf.loc["mult"][:] = 1
vdf.loc["mult_arome"][:] = 1
vdf.loc["plus"][:] = 0
vdf.loc["plus_arome"][:] = 0
vdf.loc["avg"][:] = False
vdf.loc["avg_arome"][:] = False

# fill variable dataframe with specific values
##############################################

# altitude
vdf["altitude"].short_name = "altitude"
vdf["altitude"].long_name = "Altitude"
vdf["altitude"].unit = "m asl"
vdf["altitude"].min_value = 0
vdf["altitude"].max_value = 5000
vdf["altitude"].dwh_id = {"rs": "742"}

# cloud base height: cbh
vdf["cbh"].short_name = "cbh"
vdf["cbh"].long_name = "Cloud base height"
vdf["cbh"].unit = "m"
vdf["cbh"].min_value = 0
vdf["cbh"].max_value = 2000
vdf["cbh"].mult = 0.3048
vdf["cbh"].dwh_id = {"2m": "1541"}

# cloud cover: clc
vdf["clc"].short_name = "clc"
vdf["clc"].icon_name = "clc"
vdf["clc"].arome_name = "fCV"
vdf["clc"].long_name = "Cloud cover"
vdf["clc"].unit = ""
vdf["clc"].min_value = -0.05
vdf["clc"].max_value = 1.05
vdf["clc"].color = "yellowgreen"
vdf["clc"].colormap = "bone"

# cloud cover: clcl
vdf["clcl"].short_name = "clcl"
vdf["clcl"].icon_name = "CLCL"
vdf["clcl"].arome_name = "LCV"
vdf["clcl"].long_name = "Low cloud cover"
vdf["clcl"].unit = "%"
vdf["clcl"].min_value = -0.05
vdf["clcl"].max_value = 1.05

# cloud cover: clct
vdf["clct"].short_name = "clct"
vdf["clct"].icon_name = "CLCT"  # "clct"
vdf["clct"].arome_name = "fCV"
vdf["clct"].long_name = "Total cloud cover"
vdf["clct"].unit = ""
vdf["clct"].min_value = -0.05
vdf["clct"].max_value = 1.05

# temperature tendency due to longwave radiative heating
#  ddt_t_lw
vdf["ddt_t_lw"].short_name = "ddt_t_lw"
# vdf["ddt_t_lw"].icon_name = "THHR_RAD"
# TODO: various names from different configurations
vdf["ddt_t_lw"].icon_name = "ddt_temp_radlw"
vdf["ddt_t_lw"].long_name = "T-tend LW radiation"
vdf["ddt_t_lw"].unit = "K/h"
vdf["ddt_t_lw"].mult = 3600
vdf["ddt_t_lw"].min_value = -3.0
vdf["ddt_t_lw"].max_value = 3.0
vdf["ddt_t_lw"].color = "seagreen"
vdf["ddt_t_lw"].colormap = sns.color_palette("vlag", as_cmap=True)

# temperature tendency due to shortwave radiative heating:
#  ddt_t_sw
vdf["ddt_t_sw"].short_name = "ddt_t_sw"
# vdf["ddt_t_sw"].icon_name = "SOHR_RAD"
# TODO: various names from different configurations
vdf["ddt_t_sw"].icon_name = "ddt_temp_radsw"
vdf["ddt_t_sw"].long_name = "T-tend SW radiation"
vdf["ddt_t_sw"].unit = "K/h"
vdf["ddt_t_sw"].mult = 3600
vdf["ddt_t_sw"].min_value = -3.0
vdf["ddt_t_sw"].max_value = 3.0
vdf["ddt_t_sw"].color = "goldenrod"
vdf["ddt_t_sw"].colormap = sns.light_palette("goldenrod", as_cmap=True)

# dewpoint temperature: dewp_temp
vdf["dewp_temp"].short_name = "dewp_temp"
vdf["dewp_temp"].long_name = "Dew point temperature"
vdf["dewp_temp"].unit = "°C"
vdf["dewp_temp"].min_value = -5
vdf["dewp_temp"].max_value = 15
vdf["dewp_temp"].dwh_id = {"rs": "747", "2m": "194"}

# horizontal visiblity: hor_vis
vdf["hor_vis"].short_name = "hor_vis"
vdf["hor_vis"].long_name = "Horizontal visibility"
vdf["hor_vis"].unit = "m"
vdf["hor_vis"].min_value = 0
vdf["hor_vis"].max_value = 5000
vdf["hor_vis"].dwh_id = {"2m": "1547"}

# pressure: press
vdf["press"].short_name = "press"
vdf["press"].long_name = "Pressure"
vdf["press"].unit = "hPa"
vdf["press"].short_name = "press"
vdf["press"].dwh_id = {"rs": "744"}

# cloud water: qc
vdf["qc"].short_name = "qc"
vdf["qc"].icon_name = "QC"
vdf["qc"].long_name = "Cloud water"
vdf["qc"].unit = "g/kg"
vdf["qc"].min_value = -0.01
vdf["qc"].max_value = 0.07
vdf["qc"].color = "darkblue"
vdf["qc"].colormap = "YlGn"
vdf["qc"].mult = 1000

# diagnostic cloud water: qc_dia
vdf["qc_dia"].short_name = "qc_dia"
vdf["qc_dia"].icon_name = "tot_qc_dia"
vdf["qc_dia"].long_name = "Diagnostic cloud water"
vdf["qc_dia"].unit = "g/kg"
vdf["qc_dia"].min_value = -0.01
vdf["qc_dia"].max_value = 0.07
vdf["qc_dia"].color = "darkblue"
vdf["qc_dia"].mult = 1000

# diagnostic cloud ice: qi_dia
vdf["qi_dia"].short_name = "qi_dia"
vdf["qi_dia"].icon_name = "tot_qi_dia"
vdf["qi_dia"].long_name = "Diagnostic cloud ice"
vdf["qi_dia"].unit = "g/kg"
vdf["qi_dia"].min_value = -0.01
vdf["qi_dia"].max_value = 0.07
vdf["qi_dia"].color = "darkblue"
vdf["qi_dia"].mult = 1000

# specific humidity: qv
vdf["qv"].short_name = "qv"
vdf["qv"].icon_name = "QV"
vdf["qv"].long_name = "Specific humidity"
vdf["qv"].unit = "g/kg"
vdf["qv"].min_value = 0
vdf["qv"].max_value = 6
vdf["qv"].color = "skyblue"
vdf["qv"].colormap = "PuBu"
vdf["qv"].mult = 1000

# diagnostic humidity: qv_dia
vdf["qv_dia"].short_name = "qv_dia"
vdf["qv_dia"].icon_name = "tot_qv_dia"
vdf["qv_dia"].long_name = "Diagnostic humidity"
vdf["qv_dia"].unit = "g/kg"
vdf["qv_dia"].min_value = -0.01
vdf["qv_dia"].max_value = 0.07
vdf["qv_dia"].color = "darkblue"
vdf["qv_dia"].mult = 1000

# relative humidity: rel_hum
vdf["rel_hum"].short_name = "rel_hum"
vdf["rel_hum"].long_name = "Relative humidity"
vdf["rel_hum"].unit = "%"
vdf["rel_hum"].min_value = 0
vdf["rel_hum"].max_value = 100
vdf["rel_hum"].dwh_id = {
    "rs": "746",
    "2m_tower": "3698",
    "10m_tower": "4953",
    "30m_tower": "4961",
}

# radiation: longwave downward
vdf["lw_down"].short_name = "lw_down"
vdf["lw_down"].long_name = "Downward LW rad"
vdf["lw_down"].unit = "W/m2"
vdf["lw_down"].icon_name = "ATHD_S"
vdf["lw_down"].avg = True
vdf["lw_down"].dwh_id = {"2m": "175", "2m_tower": "3762"}

# radiation: longwave upward
vdf["lw_up"].short_name = "lw_up"
vdf["lw_up"].long_name = "Upward LW rad"
vdf["lw_up"].unit = "W/m2"
vdf["lw_up"].dwh_id = {
    "2m": "1531",
    "2m_tower": "5118",  # no data yet in DWH
    "30m_tower": "5181",  # no data yet in DWH
}

# radiation: shortwave downward
vdf["sw_down"].short_name = "sw_down"
vdf["sw_down"].long_name = "Downward SW rad"
vdf["sw_down"].unit = "W/m2"
vdf["sw_down"].dwh_id = {"2m": "96", "2m_tower": "3873"}
vdf["sw_down"].icon_name = "asod_s"  # "GLOB"
vdf["sw_down"].avg = True

# radiation: shortwave upward ("reflected")
vdf["sw_up"].short_name = "sw_up"
vdf["sw_up"].long_name = "Upward SW rad"
vdf["sw_up"].unit = "W/m2"
vdf["sw_up"].dwh_id = {"2m": "1871", "2m_tower": "4995"}

# temperature: temp
vdf["temp"].short_name = "temp"
vdf["temp"].icon_name = "T"
vdf["temp"].arome_name = "T"
vdf["temp"].long_name = "Temperature"
vdf["temp"].unit = "°C"
vdf["temp"].min_value = -3.0  # 275
vdf["temp"].max_value = 5  # 287
vdf["temp"].color = "orangered"
vdf["temp"].marker = "o"
vdf["temp"].linestyle = "-"
vdf["temp"].mult = 1
vdf["temp"].plus = -273
vdf["temp"].plus_arome = -273
vdf["temp"].avg = False
vdf["temp"].dwh_id = {
    "rs": "745",
    "2m": "91",
    "mwr": "3147",
    "5cm": "92",
    "2m_tower": "3702",
    "10m_tower": "4949",
    "30m_tower": "4957",
}

# 2m temperature: 2m_temp
vdf["2m_temp"].short_name = "2m_temp"
vdf["2m_temp"].icon_name = "T_2M"
vdf["2m_temp"].arome_name = "T2m"
vdf["2m_temp"].long_name = "2m Temperature"
vdf["2m_temp"].unit = "°C"
vdf["2m_temp"].min_value = -3.0  # 275
vdf["2m_temp"].max_value = 5  # 287
vdf["2m_temp"].color = "orangered"
vdf["2m_temp"].marker = "o"
vdf["2m_temp"].linestyle = "-"
vdf["2m_temp"].mult = 1
vdf["2m_temp"].plus = -273
vdf["2m_temp"].plus_arome = -273
vdf["2m_temp"].avg = False

# total water vapour: tqv
vdf["tqv"].short_name = "tqv"
vdf["tqv"].icon_name = "TQV"
vdf["tqv"].long_name = "Total water vapour"
vdf["tqv"].unit = "kg/m2"
vdf["tqv"].dwh_id = {"2m": "2537"}

# vertical visibility: ver_vis
vdf["ver_vis"].short_name = "ver_vis"
vdf["ver_vis"].long_name = "Vertical visibility"
vdf["ver_vis"].unit = "m"
vdf["ver_vis"].min_value = 0
vdf["ver_vis"].max_value = 1000
vdf["ver_vis"].mult = 0.3048
vdf["ver_vis"].dwh_id = {"2m": "6199"}

# wind direction: wind_dir
vdf["wind_dir"].short_name = "wind_dir"
vdf["wind_dir"].long_name = "Wind direction"
vdf["wind_dir"].unit = "°"
vdf["wind_dir"].min_value = 0
vdf["wind_dir"].max_value = 360
vdf["wind_dir"].dwh_id = {"rs": "743"}

# wind velocity: wind_vel
vdf["wind_vel"].short_name = "wind_vel"
vdf["wind_vel"].long_name = "Wind velocity"
vdf["wind_vel"].unit = "m/s"
vdf["wind_vel"].min_value = 0
vdf["wind_vel"].max_value = 30
vdf["wind_vel"].dwh_id = {"rs": "748"}

# !!! if adding new variable: don't forget to add at the top and in cli-file!!!

if __name__ == "__main__":
    print(vdf)


def is_float(n):
    try:
        float(n)
        return True
    except ValueError:
        return False

def temp_avg(file_name, state):
    file = open(file_name, "r")
    total = 0.0
    num_records = 0
    lines = file.readlines()
    is_first_record = True

    for current_line in lines:
        if is_first_record or len(current_line.strip()) == 0:
            is_first_record = False
            continue

        cur_line_list = current_line.split(',')
        curr_state = cur_line_list[0]
        curr_state_str = curr_state[1:-1]
        if curr_state_str == state:
            cur_temp_str = cur_line_list[2]
            cur_temp_str = cur_temp_str[1:-1]
            if is_float(cur_temp_str):
                num_records += 1
                total = float(cur_temp_str) + total
            else:
                continue
        else:
            continue
    avg = total / num_records
    return avg

x = "multi_state_temperatures.csv"
print(temp_avg(x, "VA"))


def look_and_say(input_string: str) -> str:

    def count_numbers(idx, input_str):
        cnt = 1
        val = input_str[idx]
        idx += 1
        while idx < len(input_str):
            if input_str[idx] == input_str[idx - 1]:
                cnt += 1
            else:
                break
            idx += 1

        return idx, cnt, val

    output_str = ''
    index = 0
    while index < len(input_string):
        index, count, value = count_numbers(index, input_string)
        output_str += str(count) + value

    return output_str

string = '1113122113'
for _ in range(40):
    string = look_and_say(string)

print(f"Part 1 Answer: {len(string)}")

for _ in range(10):
    string = look_and_say(string)

print(f"Part 2 Answer: {len(string)}")


# ----- CARREGANDO DADOS ----- #
dados_vendas = pd.read_excel('Vendas Copa.XLSX')

# ----- LIMPEZA (RETIRANDO COLUNAS) ----- #
dados_vendas.drop(['Nº documento refer.', 'Ordem do cliente', 'Item ord.cliente', 'Exercício', 'Tipo doc.vendas', 'Equipe de vendas',
                  'Código da cidade', 'Grupo de preço', 'BANDEIRA', 'Unid.medida básica', 'Condições pgto.', 'Taxa de imposto', 'Base do imposto',
                  'ICMS Compra', 'Dest.', 'Valor condição', 'Preço interno', 'ICM3', 'ICS3', 'PIS', 'COFINS', 'Complemento',
                  'Ressarcimento', 'Desc.PIS/COF'], axis=1, inplace=True)

# ----- RENOMEANDO COLUNAS ----- #
dados_vendas.rename(columns = {'Nota Fiscal': 'NF-E', 'Centro': 'FILIAL', 'Data de lançamento': 'DATA',
                               'Artigo': 'COD. MATERIAL', 'Material básico': 'MATERIAL', 'Denominação': 'VENDEDOR',
                               'Tp.doc.faturamento': 'TIPO DOC.', 'Nome 1': 'NOME FILIAL', 'Incoterms': 'TIPO FRETE',
                               'Escritório de vendas': 'ESCRITÓRIO', 'Denominação.1': 'DESCR. ESCRITÓRIO', 'Local expedição/recebimento': 'LOCAL EXPEDIÇÃO',
                               'Região': 'UF', 'Denominação.2': 'TIPO', 'Qtd.vendas': 'VOLUME 20º',
                               'Custo Final de Venda': 'CUSTO FINAL', 'Custo Produto': 'CUSTO PRODUTO', 'Acresc/Redução Fisca': 'FISCAL',
                               'Custo Financeiro': 'FINANCEIRO', 'Custo Frete': 'FRETE', 'Margem Comercial': 'MARGEM COMERCIAL',
                               'Custo de Partida': 'CUSTO PARTIDA', 'Quantidade-UMR': 'VOLUME AMB.', 'Custo Mix Compra': 'CUSTO MIX',
                               'Margem real': 'MARGEM REAL', 'ID parceiro': 'COD. CLIENTE', 'Nome': 'NOME CLIENTE',
                               'Rua': 'RUA', 'Local': 'MUNICÍPIO', 'Bairro': 'BAIRRO',
                               'Região.1': 'ESTADO', 'Código postal': 'CEP', 'Unnamed: 56': 'TOTAL NF-E',
                               'Unnamed: 57': 'MARGEM TOTAL', 'Unnamed: 58': 'MARGEM POR LITRO', 'Cidade Geo': 'CIDADE GEO',
                               'Mesorregião': 'MESORREGIÃO', 'Microrregião': 'MICRORREGIÃO', 'Latitude': 'LATITUDE',
                               'Longitude': 'LONGITUDE', 'Cidade': 'CIDADE'}, inplace=True)

# ----- CRIANDO COLUNAS (DIA | MÊS | ANO) ----- #
dados_vendas['DIA'] = pd.DatetimeIndex(dados_vendas['DATA']).day
dados_vendas['MÊS'] = pd.DatetimeIndex(dados_vendas['DATA']).month
dados_vendas['ANO'] = pd.DatetimeIndex(dados_vendas['DATA']).year
dados_vendas['ANO/MÊS'] = dados_vendas['DATA'].dt.to_period('M').astype(str)
dados_vendas['SEMANA'] = dados_vendas['DATA'].dt.to_period('W').astype(str)

# ----- VERIFICANDO - (QTD. LINHAS | COLUNAS) ----- #
print('{} Linhas - {} Colunas'.format(dados_vendas.shape[0], dados_vendas.shape[1]))

# ----- VERIFICANDO - DADOS NULOS ----- #
print('{} Dados sem valor'.format(dados_vendas[dados_vendas['COD. CLIENTE'].isnull()].shape[0]))

# ----- VERIFICANDO - (DATA INICIAL | DATA FINAL) ----- #
print('Datas de {} até {}'.format(dados_vendas['DATA'].min(), dados_vendas['DATA'].max()))

# ----- QTD. DIAS - (DATA INICIAL | DATA FINAL) ----- #
print(dados_vendas['DATA'].max() - dados_vendas['DATA'].min())

# ----- AGRUPAMENTO DADOS - (VOLUME | TOTAL NF-E | MARGEM TOTAL) ----- #
dados_agrupados = dados_vendas.groupby(['DATA', 'COD. CLIENTE', 'ESTADO', 'CIDADE',
                                       'MESORREGIÃO', 'MICRORREGIÃO', 'LATITUDE', 'LONGITUDE']).agg({'VOLUME 20º': lambda x: x.sum(),
                                                                                'TOTAL NF-E': lambda x: x.sum(),
                                                                                'MARGEM TOTAL': lambda x: x.sum()}).reset_index()

### ----- DEFININDO (DATA ATUAL). SERÁ UTILIZADA COMO REFERÊNCIA PARA CALCULAR A PONTUAÇÃO DA RECÊNCIA ----- ###

# ----- VERIFICANDO DATA ATUAL ----- #
data_atual = dados_agrupados['DATA'].max() + timedelta(days=1)

# ----- PERIODO (QTD. DIAS - (DATA INICIAL | DATA FINAL)) ----- #
qtd_dias = (dados_agrupados['DATA'].max() - dados_agrupados['DATA'].min()) / np.timedelta64(1, 'D')

# ----- CALCULANDO RECÊNCIA | FREQUÊNCIA | MONETÁRIO PARA CADA CLIENTE ----- #

# ----- CALCULANDO QTD. DIAS TOTAL (INICIAL - FINAL) ----- #
dados_agrupados['Nº DIAS'] = dados_agrupados['DATA'].apply(lambda x: (data_atual - x).days)

# ----- CALCULANDO QTD. DIAS TOTAL (DATA ÚLTIMA COMPRA) ----- #
dados_data = {'Nº DIAS': lambda x: x.min(), 'DATA': lambda x: len([d for d in x if d >= data_atual - timedelta(days=qtd_dias)])}

# ----- GERANDO NOVA DATAFRAME (RFM) ----- #
rfm = dados_agrupados.groupby(['COD. CLIENTE', 'ESTADO', 'CIDADE', 'MESORREGIÃO', 'MICRORREGIÃO', 'LATITUDE', 'LONGITUDE']).agg(dados_data).reset_index()
rfm.rename(columns={'Nº DIAS': 'RECÊNCIA', 'DATA': 'FREQUÊNCIA'}, inplace=True)

# ----- CALCULANDO VOLUME MÉDIO POR CLIENTE ----- #
rfm['MONTANTE'] = rfm['COD. CLIENTE'].apply(lambda x: dados_agrupados[(dados_agrupados['COD. CLIENTE'] == x) & \
                                                           (dados_agrupados['DATA'] >= data_atual - timedelta(days=qtd_dias))]\
                                                           ['VOLUME 20º'].sum())

# ----- CALCULANDO QTD. PRODUTOS POR CLIENTE ----- #
dados_mix = pd.crosstab(dados_vendas['COD. CLIENTE'], dados_vendas['MATERIAL'], dados_vendas['COD. MATERIAL'], aggfunc='count', margins=False, margins_name='Média Geral')
dados_mix = pd.DataFrame(dados_mix)
dados_mix.fillna(0)

# ----- UNINDO OS DATAFRAMES (DADOS_VENDA + RFM) ----- #
dados_final = pd.merge(left= rfm, right= dados_mix, on='COD. CLIENTE', how='outer')

# ----- RETIRANDO TODOS OS VALORES NULOS ----- #
dados_final['ANIDRO'] = dados_final['ANIDRO'].fillna(0)
dados_final['B100'] = dados_final['B100'].fillna(0)
dados_final['DIESEL S10'] = dados_final['DIESEL S10'].fillna(0)
dados_final['DIESEL S500'] = dados_final['DIESEL S500'].fillna(0)
dados_final['ETANOL'] = dados_final['ETANOL'].fillna(0)
dados_final['GASOLINA'] = dados_final['GASOLINA'].fillna(0)
dados_final['GASOLINA A'] = dados_final['GASOLINA A'].fillna(0)
dados_final['S10 A'] = dados_final['S10 A'].fillna(0)
dados_final['S500 A'] = dados_final['S500 A'].fillna(0)

# ----- LIMPEZA (RETIRANDO COLUNAS) ----- #
dados_final.drop(['ANIDRO', 'B100', 'GASOLINA A', 'S10 A', 'S500 A'], axis=1, inplace=True)

# ----- DIVISÃO EM QUINTIL (CADA QUINTIL CONTÉM 20% DA POPULAÇÃO) ----- #
divisao = dados_final[['RECÊNCIA', 'FREQUÊNCIA', 'MONTANTE', 'DIESEL S10', 'DIESEL S500', 'ETANOL', 'GASOLINA']].quantile([.2, .4, .6, .8]).to_dict()

### ----- CLASSIFICAÇÃO (RECÊNCIA | FREQUÊNCIA | MONTANTE | DIESEL S500 | DIESEL S10 | GASOLINA | ETANOL) ----- ###

# ----- DISTRIBUIÇÃO RECÊNCIA ----- #
def r_score(x):
  if x <= divisao['RECÊNCIA'][.2]:
    return 5
  elif x <= divisao['RECÊNCIA'][.4]:
    return 4
  elif x <= divisao['RECÊNCIA'][.6]:
    return 3
  elif x <= divisao['RECÊNCIA'][.8]:
    return 2
  else:
    return 1

# ----- DISTRIBUIÇÃO FREQUÊNCIA | MONTANTE ----- #
def fm_score(x, c):
  if x <= divisao[c][.2]:
    return 1
  elif x <= divisao[c][.4]:
    return 2
  elif x <= divisao[c][.6]:
    return 3
  elif x <= divisao[c][.8]:
    return 4
  else:
    return 5

# ----- DISTRIBUIÇÃO DIESEL S10 ----- #
def S10(x):
  if x <= divisao['DIESEL S10'][.2]:
    return 1
  elif x <= divisao['DIESEL S10'][.4]:
    return 2
  elif x <= divisao['DIESEL S10'][.6]:
    return 3
  elif x <= divisao['DIESEL S10'][.8]:
    return 4
  else:
    return 5

# ----- DISTRIBUIÇÃO DIESEL S500 ----- #
def S500(x):
  if x <= divisao['DIESEL S500'][.2]:
    return 1
  elif x <= divisao['DIESEL S500'][.4]:
    return 2
  elif x <= divisao['DIESEL S500'][.6]:
    return 3
  elif x <= divisao['DIESEL S500'][.8]:
    return 4
  else:
    return 5

# ----- DISTRIBUIÇÃO GASOLINA ----- #
def GMIX(x):
  if x <= divisao['GASOLINA'][.2]:
    return 1
  elif x <= divisao['GASOLINA'][.4]:
    return 2
  elif x <= divisao['GASOLINA'][.6]:
    return 3
  elif x <= divisao['GASOLINA'][.8]:
    return 4
  else:
    return 5

# ----- DISTRIBUIÇÃO ETANOL ----- #
def AEHC(x):
  if x <= divisao['ETANOL'][.2]:
    return 1
  elif x <= divisao['ETANOL'][.4]:
    return 2
  elif x <= divisao['ETANOL'][.6]:
    return 3
  elif x <= divisao['ETANOL'][.8]:
    return 4
  else:
    return 5

### ----- APLICANDO CLASSIFICAÇÃO ----- ###

# ----- RECÊNCIA ----- #
dados_final['R'] = dados_final['RECÊNCIA'].apply(lambda x: r_score(x))

# ----- FREQUÊNCIA ----- #
dados_final['F'] = dados_final['FREQUÊNCIA'].apply(lambda x: fm_score(x, 'FREQUÊNCIA'))

# ----- MONTANTE ----- #
dados_final['M'] = dados_final['MONTANTE'].apply(lambda x: fm_score(x, 'MONTANTE'))

### ----- GERAÇÃO SCORE RFM ----- ###

# ----- SCORE FV ----- #
dados_final['FV'] = round((dados_final['F'] + dados_final['M']) / 2, 0)

# ----- SCORE RFV ----- #
dados_final['RFV'] = dados_final['R'].map(str) + dados_final['FV'].map(str)

# ----- SCORE RFM ----- #
dados_final['RFM NOTA'] = dados_final['R'].map(str) + dados_final['F'].map(str) + dados_final['M'].map(str)

### ----- CLASSIFICAÇÃO SEGMENTAÇÃO ----- ###

# ----- GERAÇÃO SCORE RFM ----- #
mapa_segmentacao = {r'15.0': 'Não Podemos Perder', r'55.0': 'Campeão', r'33.0': 'Precisa de Atenção', r'41.0': 'Promissor', r'51.0': 'Novo',
                    r'22.0': 'Hibernando', r'52.0': 'Potencialmente Fiel', r'53.0': 'Potencialmente Fiel', r'42.0': 'Potencialmente Fiel',
                    r'43.0': 'Potencialmente Fiel', r'13.0': 'Em Risco', r'14.0': 'Em Risco', r'23.0': 'Em Risco', r'24.0': 'Em Risco',
                    r'25.0': 'Em Risco', r'34.0': 'Cliente Fiel', r'35.0': 'Cliente Fiel', r'44.0': 'Cliente Fiel', r'45.0': 'Cliente Fiel',
                    r'54.0': 'Cliente Fiel', r'11.0': 'Perdido', r'12.0': 'Perdido', r'21.0': 'Perdido', r'31.0': 'Prestes a Hibernar',
                    r'32.0': 'Prestes a Hibernar'}

dados_final['SEGMENTAÇÃO'] = dados_final['R'].map(str) + dados_final['FV'].map(str)
dados_final['SEGMENTAÇÃO'] = dados_final['SEGMENTAÇÃO'].replace(mapa_segmentacao, regex=True)

# ----- PRÉVIA ARQUIVO FINAL ----- #
dados_final.head(20)

# ----- GERANDO ARQUIVO EM EXCEL ----- #
dados_final.to_excel('Tabela RFM.xlsx')


from math import sqrt, gcd
from prime import factorize

def good_sqrt(x):
    return int(sqrt(x)) ** 2 == x

def fermat(n, k, iters):
    s = int(sqrt(k * n))
    idx = 1
    while True:
        s_new = s + idx
        t2 = (s_new * s_new) - (k * n)
        if good_sqrt(t2):
            d = gcd(k * n, s_new - int(sqrt(t2)))
            return d
        if idx % iters == 0 and idx > 0:
            ans = input('Прошло {} итераций. Продолжать? Y/N: '.format(idx))
            if ans != 'Y' and ans != 'y':
                return -1
        idx += 1

def main():
    n = int(input('Введите n = '))
    k = int(input('Введите k = '))
    iters = int(input('Введите l = '))

    factors = factorize(n, fermat, k, iters)
    print('\n'.join(map(str, factors.items())))

if __name__ == '__main__':
    main()


import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn import metrics
import joblib
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import classification_report, accuracy_score, f1_score, precision_score, recall_score, confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt
from models import Models
from sklearn.feature_selection import SequentialFeatureSelector as SFS
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_iris

pathToData = 'dataAfterProcessingCSV/'
pathToPictures = 'pictures/'
pathToModels = 'models/'
pathToRetrainModel = 'retrainModels/'
pathToRetrainPictures = 'retrainPictures/'
models = Models().models

def print_model(modelResultPath):
    modelResult = joblib.load(pathToModels + modelResultPath)
    print(modelResult)

def show_confusion_matrix(cm_test, title):
    print('Print confusion matrix for \"' + str(title) + '\"')
    plt.figure(figsize=(8,8))
    sns.heatmap(cm_test, annot=True, fmt="d", cmap="Blues")
    sns.set(font_scale=1.9)
    plt.title(title)
    plt.ylabel("Actual ")
    plt.xlabel("Predicted ")
    plt.tight_layout()
    plt.savefig(pathToPictures + title + ".png")
    #plt.show()
    plt.close()

def get_confusion_matrix(X_test, y_test, classifier):
    y_pred = classifier.predict(X_test)
    # print(y_pred)
    matrix = confusion_matrix(y_test, y_pred)
    # print(matrix)
    print("Accuracy Score:", accuracy_score(y_test, y_pred))
    print("Precision Score : ", precision_score(y_test, y_pred))
    print("Recall Score:", recall_score(y_test, y_pred))
    print("f1 Score:", f1_score(y_test, y_pred))
    return matrix

def split_data(pandas_data):
    X = pandas_data.loc[:, 'statuses_count':'description_length']
    y = pandas_data['is_bot']
    return X, y

def read_data():
    bots = pd.read_csv(pathToData + 'botsAfterProcessing.csv')
    real = pd.read_csv(pathToData + 'humansAfterProcessing.csv')

    data = pd.concat((bots, real), axis=0)
    data.to_excel('bots_and_humans.xls')
    data = data.sample(frac=1)
    data.to_excel('bots_and_humans_mixed.xls')
    return data

def build_and_evaluate_models(data):
    X, y = split_data(data)

    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
    numberOfAllAccounts = np.array(y_train).size
    numberOfBots = np.count_nonzero(np.array(y_train))
    numberOfHumans = numberOfAllAccounts - numberOfBots
    print('Number of bots in train data set: ' + str(numberOfBots))
    print('Number of humans in train data set: ' + str(numberOfHumans))
    print('Bots: {0}%, humans: {1}%'.format(numberOfBots/numberOfAllAccounts*100, numberOfHumans/numberOfAllAccounts*100))
    print('')

    bestScore = 0
    bestAlgName = ''

    for name, (model, parameters) in models.items():
        print('Results for \"' + str(name) + '\"')
        gs = GridSearchCV(model, parameters, cv=10, verbose=1, n_jobs=-1, scoring='roc_auc')
        gs.fit(X_train, y_train)
        print("Best Parameters:", gs.best_params_)
        print("")
        print("Best Score:", gs.best_score_)

        joblib.dump(gs.best_estimator_, pathToModels + f"{name}.pkl", compress=1)
        joblib.dump(gs.cv_results_, pathToModels + f"{name}_results.pkl", compress=1)

        y_pred = gs.predict(X_test)
        f1 = f1_score(y_test, y_pred)
        if bestScore < f1:
            bestScore = f1
            bestAlgName = name

        print("")
        show_confusion_matrix(get_confusion_matrix(X_test, y_test, gs), name)
        print('------------------------------------')

    print('"' + bestAlgName + '" ' + 'showed best results on test dataset')
    print('f1 score: ' + str(bestScore))
    return bestAlgName

def print_bots_and_humans_count(y):
    numberOfAllAccounts = np.array(y).size
    numberOfBots = np.count_nonzero(np.array(y))
    numberOfHumans = numberOfAllAccounts - numberOfBots
    print('Number of bots in train data set: ' + str(numberOfBots))
    print('Number of humans in train data set: ' + str(numberOfHumans))
    print('------------------------------------')

def test_retrain_model_on_unseen_data(model_name, list_to_drop):
    political_bots = pd.read_csv(pathToData + 'politicalBotsAfterProcessing.csv')
    real = pd.read_csv(pathToData + 'celebritiesAfterProcessing.csv')
    pron_bots = pd.read_csv(pathToData + 'pronBotsAfterProcessing.csv')
    vendor_bots = pd.read_csv(pathToData + 'vendorBotsAfterProcessing.csv')

    real_and_political_bots = pd.concat((political_bots, real), axis=0).sample(frac=1)
    real_and_pron_bots = pd.concat((pron_bots, real), axis=0).sample(frac=1)
    real_and_vendor_bots = pd.concat((vendor_bots, real), axis=0).sample(frac=1)

    best_model = joblib.load(pathToRetrainModel + model_name + '.pkl')

    X1, y1 = split_data(real_and_political_bots)
    X1.drop(X1.columns[list_to_drop], axis=1, inplace=True)
    show_confusion_matrix(get_confusion_matrix(X1, y1, best_model), model_name + 'CelebritiesAndPoliticalBots')
    print_bots_and_humans_count(y1)

    X2, y2 = split_data(real_and_pron_bots)
    X2.drop(X2.columns[list_to_drop], axis=1, inplace=True)
    show_confusion_matrix(get_confusion_matrix(X2, y2, best_model), model_name + 'CelebritiesAndPronBots')
    print_bots_and_humans_count(y2)

    X3, y3 = split_data(real_and_vendor_bots)
    X3.drop(X3.columns[list_to_drop], axis=1, inplace=True)
    show_confusion_matrix(get_confusion_matrix(X3, y3, best_model), model_name + 'CelebritiesAndVendorBots')
    print_bots_and_humans_count(y3)

def test_model_on_unseen_data(model_name):
    political_bots = pd.read_csv(pathToData + 'politicalBotsAfterProcessing.csv')
    real = pd.read_csv(pathToData + 'celebritiesAfterProcessing.csv')
    pron_bots = pd.read_csv(pathToData + 'pronBotsAfterProcessing.csv')
    vendor_bots = pd.read_csv(pathToData + 'vendorBotsAfterProcessing.csv')

    #unseen_data = pd.concat((political_bots, real, pron_bots, vendor_bots), axis=0).sample(frac=1)
    #unseen_data.to_excel('unseen_data.xls')

    real_and_political_bots = pd.concat((political_bots, real), axis=0).sample(frac=1)
    real_and_pron_bots = pd.concat((pron_bots, real), axis=0).sample(frac=1)
    real_and_vendor_bots = pd.concat((vendor_bots, real), axis=0).sample(frac=1)

    best_model = joblib.load(pathToModels + model_name + '.pkl')

    X1, y1 = split_data(real_and_political_bots)
    show_confusion_matrix(get_confusion_matrix(X1, y1, best_model), model_name + 'CelebritiesAndPoliticalBots')
    print_bots_and_humans_count(y1)

    X2, y2 = split_data(real_and_pron_bots)
    show_confusion_matrix(get_confusion_matrix(X2, y2, best_model), model_name + 'CelebritiesAndPronBots')
    print_bots_and_humans_count(y2)

    X3, y3 = split_data(real_and_vendor_bots)
    show_confusion_matrix(get_confusion_matrix(X3, y3, best_model), model_name + 'CelebritiesAndVendorBots')
    print_bots_and_humans_count(y3)

def select_features(model_name):
    data = read_data()
    X, y = split_data(data)
    model = joblib.load(pathToModels + model_name + '.pkl')

    all_features = X.columns.values
    print('Исходный набор:' + str(all_features))
    print('--------------------------------')

    print('First')
    sfs1 = SFS(model, n_features_to_select=16, direction='backward', scoring='f1', cv=10)
    result1 = sfs1.fit(X, y)
    part_of_features1 = all_features[result1.get_support(indices=True)]
    print(result1.get_support())
    print(result1.get_support(indices=True))
    print(str(part_of_features1))
    print('--------------------------------')

    print('Second')
    sfs2 = SFS(model, n_features_to_select=16, direction='forward', scoring='f1', cv=10)
    result2 = sfs2.fit(X, y)
    part_of_features2 = all_features[result2.get_support(indices=True)]
    print(result2.get_support())
    print(result2.get_support(indices=True))
    print(str(part_of_features2))
    print('--------------------------------')

    print('Third')
    sfs3 = SFS(model, direction='forward', scoring='f1', cv=10)
    result3 = sfs3.fit(X, y)
    part_of_features3 = all_features[result3.get_support(indices=True)]
    print(result3.get_support())
    print(result3.get_support(indices=True))
    print(str(part_of_features3))
    print('--------------------------------')

    print('Fourth')
    sfs4 = SFS(model, direction='backward', scoring='f1', cv=10)
    result4 = sfs4.fit(X, y)
    part_of_features4 = all_features[result4.get_support(indices=True)]
    print(result4.get_support())
    print(result4.get_support(indices=True))
    print(str(part_of_features4))

def retrain_model(data, model_name, lists_to_drop):
    cnt = 1
    name = model_name

    for l_to_drop in lists_to_drop:
        bestScore = 0
        bestAlgName = ''

        X, y = split_data(data)
        X.drop(X.columns[l_to_drop], axis=1, inplace=True)

        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

        (model, parameters) = models[model_name]
        name = model_name + str(cnt)
        print('Results for \"' + str(name) + '\"')
        gs = GridSearchCV(model, parameters, cv=10, verbose=1, n_jobs=-1, scoring='roc_auc')
        gs.fit(X_train, y_train)
        print("Best Parameters:", gs.best_params_)
        print("")
        print("Best Score:", gs.best_score_)

        joblib.dump(gs.best_estimator_, pathToRetrainModel + f"{name}.pkl", compress=1)
        joblib.dump(gs.cv_results_, pathToRetrainModel + f"{name}_results.pkl", compress=1)

        y_pred = gs.predict(X_test)
        f1 = f1_score(y_test, y_pred)
        if bestScore < f1:
            bestScore = f1
            bestAlgName = name

        print("")
        show_confusion_matrix(get_confusion_matrix(X_test, y_test, gs), name)
        print('------------------------------------')

        cnt += 1

    print('"' + bestAlgName + '" ' + 'showed best results on retrain datasets')
    print('f1 score: ' + str(bestScore))

if __name__ == '__main__':
    first_list = [0, 5, 10, 12]
    second_list = [12, 14, 15, 19]
    third_list = [0, 2, 3, 4, 8, 10, 14, 15, 17, 19]
    fourth_list = [1, 2, 5, 6, 9, 11, 12, 15, 16, 18]
    parse_list = [3, 4, 12, 13]
    list = [first_list, second_list, third_list, fourth_list]

    data = read_data()
    #retrain_model(data, "RandomForest", list)
    #build_and_evaluate_models(data)
    #for model_name in models.keys():
    #    test_model_on_unseen_data(model_name)
    #select_features('RandomForest')

    # for i in range(1, 5):
    #     name = "RandomForest" + str(i)
    #     test_retrain_model_on_unseen_data(name, list[i - 1])

    retrain_model(data, "RandomForest", [parse_list])
    test_retrain_model_on_unseen_data("RandomForest1", parse_list)


st = input()
st = st.lower()
a = []
for i in range(26):
    a.append(0)
for i in st:
    a[ord(i) - 97] += 1
mx = 0
res = ""
same = False
for i in range(len(a)):
    if a[i] != 0:
        if mx < a[i]:
            mx = a[i]
            res = i
            same = False
        elif mx == a[i]:
            res = "?"
            same = True
if not same:
    print(chr(res+65))
else:
    print (res)


from collections import Counter
import pandas as pd
import matplotlib as mpl
from matplotlib import gridspec
import matplotlib.colors as colors
import numpy as np
from game import Game
import matplotlib.pyplot as plt

def get_names(data):
    a = Counter([el[0] for el in data]).most_common(10)
    b = Counter([el[1] for el in data]).most_common(10)
    c = Counter([el[2] for el in data]).most_common(10)
    names = set([el[0] for el in a]).union(set([el[0] for el in b])).union(set([el[0] for el in c]))
    return names

def medalists(data):
    n_MC = len(data)
    rows = []
    for name in get_names(data):
        [el[0] for el in data].count('Beat Wartenweiler')
        rows.append({'Player':name,
                     'Gold':np.round([el[0] for el in data].count(name)*100/n_MC).astype(int),
                     'Silver':np.round([el[1] for el in data].count(name)*100/n_MC).astype(int),
                     'Bronze':np.round([el[2] for el in data].count(name)*100/n_MC).astype(int),
                    })
    df = pd.DataFrame(rows).sort_values(by=['Gold','Silver','Bronze'],ascending = False)

    return df

def getL(res):
    L = 0
    for p in res:
        L = max(L,p[0])
        L = max(L,p[1])
    return L+1

def plotGame(player1,player2,key,data,lanes, n_max):
    def wGame(p1,p2,k,MC = True):
        return Game(p1,p2,k,data,lanes,MC)

    def gen_Game(player1,player2,key,n_max, MC = True):
        for n in range(n_max):
            yield wGame(player1,player2,key, MC = MC)

    res = [el.score for el in gen_Game(player1,player2,key,n_max,MC = True) ]
    res_b = [el[0]>el[1] for el in res ]
    L = getL(res)
    counter = np.zeros((L,L))
    for p in res:
        counter[p[0],p[1]] = counter[p[0],p[1]] + 1

    fig = plt.figure(figsize=(5, 5))
    gs = gridspec.GridSpec(1, 2, width_ratios=[13, 1])
    ax = fig.add_axes([0.1, 0.1, 0.7, 0.7])
    img1 = ax.imshow(counter,origin='lower')
    plt.ylabel('{} {:.3} %'.format(player1,100*np.sum(res_b)/len(res) ))
    plt.xlabel('{} {:.3} %'.format(player2,100*(len(res_b)-np.sum(res_b))/len(res)))

    # Make a figure and axes with dimensions as desired.
    cNorm2  = colors.Normalize(vmin=0, vmax=np.max(counter) )
    #ax1 = fig.add_subplot(gs[1])
    ax2 = fig.add_axes([0.85, 0.1, 0.05, 0.7])
    viridis = cm = plt.get_cmap('viridis')
    cb1 = mpl.colorbar.ColorbarBase(ax2, cmap=viridis,
                                    norm=cNorm2,
                                    orientation='vertical')

    cb1.set_label('Realizations')
    f_name = player1+'_'+player2+'_'+key
    plt.savefig('../FIG/'+format(f_name.lower().replace(" ", "_")))


# -*- coding: utf-8 -*-
from collective.revisionmanager.config import PROJECTNAME
from collective.revisionmanager.interfaces import IRevisionSettingsSchema
from collective.revisionmanager.testing import COLLECTIVE_REVISIONMANAGER_INTEGRATION_TESTING  # noqa: E501
from plone import api
from plone.app.testing import logout
from plone.registry.interfaces import IRegistry
from zope.component import getUtility

import unittest

has_get_installer = True

try:
    from Products.CMFPlone.utils import get_installer
except ImportError:  # pragma: no cover
    has_get_installer = False

class ControlPanelTestCase(unittest.TestCase):

    layer = COLLECTIVE_REVISIONMANAGER_INTEGRATION_TESTING

    def setUp(self):
        self.portal = self.layer['portal']
        self.controlpanel = self.portal['portal_controlpanel']

    def test_controlpanel_has_view(self):
        request = self.layer['request']
        view = api.content.get_view(
            u'revisions-controlpanel', self.portal, request)
        self.assertTrue(view())

    def test_controlpanel_view_is_protected(self):
        from AccessControl import Unauthorized
        logout()
        with self.assertRaises(Unauthorized):
            self.portal.restrictedTraverse('@@revisions-controlpanel')

    def test_controlpanel_installed(self):
        actions = [a.getAction(self)['id']
                   for a in self.controlpanel.listActions()]
        self.assertIn('RevisionsControlPanel', actions)

    @unittest.skipIf(api.env.plone_version() < '5.0', 'FIXME')
    def test_controlpanel_removed_on_uninstall(self):
        with api.env.adopt_roles(['Manager']):
            if has_get_installer:
                installer = get_installer(self.portal)
                installer.uninstall_product(PROJECTNAME)
            else:  # pragma: no cover
                installer = api.portal.get_tool('portal_quickinstaller')
                installer.uninstallProducts(products=[PROJECTNAME])

        actions = [a.getAction(self)['id']
                   for a in self.controlpanel.listActions()]
        self.assertNotIn('RevisionsControlPanel', actions)

class RegistryTestCase(unittest.TestCase):

    layer = COLLECTIVE_REVISIONMANAGER_INTEGRATION_TESTING

    def setUp(self):
        self.portal = self.layer['portal']
        self.registry = getUtility(IRegistry)
        self.settings = self.registry.forInterface(IRevisionSettingsSchema)

    def test_number_versions_to_keep_record_in_registry(self):
        self.assertTrue(hasattr(self.settings, 'number_versions_to_keep'))
        self.assertEqual(self.settings.number_versions_to_keep, -1)

    def test_subtransaction_threshold_record_in_registry(self):
        self.assertTrue(hasattr(self.settings, 'subtransaction_threshold'))
        self.assertEqual(self.settings.subtransaction_threshold, 0)

    def test_records_removed_on_uninstall(self):
        with api.env.adopt_roles(['Manager']):
            if has_get_installer:
                installer = get_installer(self.portal)
                installer.uninstall_product(PROJECTNAME)
            else:  # pragma: no cover
                installer = api.portal.get_tool('portal_quickinstaller')
                installer.uninstallProducts(products=[PROJECTNAME])

        records = [
            IRevisionSettingsSchema.__identifier__ + '.number_versions_to_keep',  # noqa: E501
            IRevisionSettingsSchema.__identifier__ + '.subtransaction_threshold',  # noqa: E501
        ]

        for r in records:
            self.assertNotIn(r, self.registry)


import copy
import random
from src import file_log
from src.solution_methods.basic_operators.InsertionOperator import InsertionOperator
import numpy
from src.solution_methods.SolutionMethod import SolutionMethod

class KRegret(SolutionMethod):

    def __init__(self):
        super().__init__("KRegret")

    def initialize_class_attributes(self):
        super().initialize_class_attributes()
        self.non_insertion_cost = None
        self.use_modification = None

        self.k = None

    def get_m_best_routes(self, routes):
        m = self.k
        if (not self.use_modification or m == 1):
            return routes

        routes_costs_arr = numpy.array([
            route.cost()
            for route in routes
        ])

        best_posistions = numpy.argpartition(routes_costs_arr, m)[:m]
        best_routes = []
        for i in best_posistions:
            best_routes.append(routes[i])

        return best_routes

    def get_requests_best_feasible_insertions(self, requests, routes_sol):
        requests_feasible_insertions = {}
        routes = self.get_m_best_routes(routes_sol)
        for request in requests:
            feasible_insertions = []
            for route in routes:
                best_insertion = (
                    InsertionOperator().get_best_insertion_in_route(
                        route,
                        request,
                        self.obj_func,
                        self.constraints
                    )
                )
                if (any(best_insertion)):
                    feasible_insertions.append(best_insertion)
                    continue

                feasible_insertions.append(
                    (None, None, self.non_insertion_cost)
                )

            requests_feasible_insertions[request] = feasible_insertions

        return requests_feasible_insertions

    def get_insertions_and_regret_value(self, requests, feasible_insertions):
        insertions_and_regret_values = {}
        for request in requests:

            request_feasible_insertions = feasible_insertions[request]
            insert_costs_arr = numpy.array(
                [
                    insert_cost
                    for pos, route, insert_cost in request_feasible_insertions
                ]
            )
            if (self.k > len(insert_costs_arr)):
                k_best_insertions_pos = (
                    numpy.argpartition(insert_costs_arr, self.k)[:self.k]
                )

                k_feasible_insertions = [
                    request_feasible_insertions[i]
                    for i in k_best_insertions_pos
                ]

            else:
                k_best_insertions_pos = [i for i in range(self.k)]
                k_feasible_insertions = request_feasible_insertions

            min_insertion_pos = numpy.argmin(insert_costs_arr)

            if (None in request_feasible_insertions[min_insertion_pos]):
                continue

            if (min_insertion_pos not in k_best_insertions_pos):
                i = 0
                found = False
                while (i < len(k_best_insertions_pos) and not found):
                    pos = k_best_insertions_pos[i]
                    if (
                        insert_costs_arr[pos]
                        != insert_costs_arr[min_insertion_pos]
                    ):
                        i += 1
                        continue
                    found = True
                    min_insertion_pos = pos

            regret_value = 0
            pos_min, route_min, insert_cost_min = (
                request_feasible_insertions[min_insertion_pos]
            )
            for i in range(self.k):
                pos_i, route_i, insert_cost_i = k_feasible_insertions[i]

                regret_value += (
                    insert_cost_i - insert_cost_min
                )
            insertions_and_regret_values[request] = (
                request_feasible_insertions[min_insertion_pos],
                regret_value
            )

        return insertions_and_regret_values

    def solve(self, solution, parameters):
        self.k = parameters["k"]
        try:
            only_route_pos = parameters["route"]
        except:
            only_route_pos = None

        requests = copy.deepcopy(parameters["requests_set"])
        new_solution = solution.copy()

        could_insert = True
        i = 0

        while (could_insert and len(requests) > 0):
            if (only_route_pos is not None):
                routes = [new_solution.routes()[only_route_pos]]
            else:
                routes = new_solution.routes()

            feasible_insertions = self.get_requests_best_feasible_insertions(
                requests,
                routes
            )

            insertions_and_regret_values = self.get_insertions_and_regret_value(
                requests,
                feasible_insertions
            )

            if (len(insertions_and_regret_values) == 0):
                could_insert = False
                continue

            request, items = max(
                insertions_and_regret_values.items(),
                key=lambda x : x[1][1]
            )

            insertion, regret_value = insertions_and_regret_values[request]
            position, new_route, insert_cost = insertion
            old_route_identifying = (
                InsertionOperator().get_route_id_value_before_inserted(
                    new_route,
                    request
                )
            )

            old_route_pos = (
                new_solution.find_route_position_by_identifying_value(
                    old_route_identifying
                )
            )

            InsertionOperator().insert_request_in_solution(
                new_solution,
                request,
                position,
                new_route,
                old_route_pos,
                self.obj_func
            )

            requests.discard(request)

        return new_solution

    def get_current_best_solution(self):
        return super().get_current_best_solution()

    def get_attr_relation_reader(self):
        return super().get_attr_relation_reader()


import sensor,image,lcd,time
import KPU as kpu
import _thread#引入多线程模块
import utime
import gc#引入垃圾回收机制
from fpioa_manager import fm
from board import board_info
from Maix import FPIOA,GPIO

WARNING={'cheak':'cheaking','unmask':'please mask','masks':'take off mask and waiting FACE cheak'}
return_meg=['cheak']

# #开始设置驱动boot按键相关的配置
BOUNCE_PROTECTION = 50
start_processing = False
#按键状态设置true函数
def set_key_state(*_):
    global start_processing
    start_processing = True
    utime.sleep_ms(BOUNCE_PROTECTION)

color_R = (255, 0, 0)
color_G = (0, 255, 0)
color_B = (0, 0, 255)

#设置摄像头参数和模式
def step1():
    lcd.init(freq=15000000)
    sensor.reset(dual_buff=False)#应设置为False否则会内存溢出
    sensor.set_pixformat(sensor.RGB565)
    sensor.set_framesize(sensor.QVGA)
    # sensor.set_windowing((224, 224))
    sensor.set_vflip(1)
    sensor.run(1)
    #开始设置驱动boot按键相关的配置
    fm.register(board_info.BOOT_KEY, fm.fpioa.GPIOHS0)
    key_gpio = GPIO(GPIO.GPIOHS0, GPIO.IN)
    #按键中断函数
    key_gpio.irq(set_key_state, GPIO.IRQ_RISING, GPIO.WAKEUP_NOT_SUPPORT)
#挂载口罩模型
def loadmodel():
    global return_meg
    classID = ['unmask','masks']
    status=0
    task = kpu.load("/sd/mask.smodel")
    anchor = (0.1606, 0.3562, 0.4712, 0.9568, 0.9877, 1.9108, 1.8761, 3.5310, 3.4423, 5.6823)
    _ = kpu.init_yolo2(task, 0.5, 0.3, 5, anchor)
    # img_lcd = image.Image()
    while status==0:
        img = sensor.snapshot()
        code = kpu.run_yolo2(task, img)
        status = 1 if code else 0
        if code:
            totalRes = len(code)

            for item in code:
                confidence = float(item.value())
                itemROL = item.rect()
                classID = int(item.classid())

                if confidence < 0.52:
                    _ = img.draw_rectangle(itemROL, color=color_B, tickness=5)
                    continue

                if classID == 1 and confidence > 0.65:
                    _ = img.draw_rectangle(itemROL, color_G, tickness=5)
                    if totalRes == 1:
                        drawConfidenceText(img, (0, 0), 1, confidence)
                        # print("MASK!!!!")
                        return_meg=['masks']
                else:
                    _ = img.draw_rectangle(itemROL, color=color_R, tickness=5)
                    if totalRes == 1:
                        drawConfidenceText(img, (0, 0), 0, confidence)

        else:
            # lcd.display(img)
            lcd.draw_string(50,10,'cheaking', lcd.RED,lcd.WHITE)
        _ = lcd.display(img)
    kpu.deinit(task)
    gc.collect()
#挂载人脸模型
def facemodel():
    # global return_meg
    global BOUNCE_PROTECTION
    global start_processing
    # sensor.set_windowing((224, 224))

    task_fd = kpu.load("/sd/FaceDetection.smodel")
    task_ld = kpu.load("/sd/FaceLandmarkDetection.smodel")
    task_fe = kpu.load("/sd/FeatureExtraction.smodel")

    anchor = (1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658, 5.155437, 6.92275, 6.718375, 9.01025) #anchor for face detect 用于人脸检测的Anchor
    dst_point = [(44,59),(84,59),(64,82),(47,105),(81,105)] #standard face key point position 标准正脸的5关键点坐标 分别为 左眼 右眼 鼻子 左嘴角 右嘴角
    a = kpu.init_yolo2(task_fd, 0.5, 0.3, 5, anchor) #初始化人脸检测模型
    # img_lcd=image.Image() # 设置显示buf
    img_face=image.Image(size=(128,128)) #设置 128 * 128 人脸图片buf
    a=img_face.pix_to_ai() # 将图片转为kpu接受的格式
    record_ftr=[] #空列表 用于存储当前196维特征
    name = ['person_Xu']
    names = ['M1', 'M2', 'M3'] # 人名标签，与上面列表特征值一一对应。
    record_ftrs=[] #空列表 用于存储按键记录下人脸特征， 可以将特征以txt等文件形式保存到sd卡后，读取到此列表，即可实现人脸断电存储。
    person_Xu=[(b'\x15\x13}w\'\xb6\xe3\x0b\xd2O)o\x89\x0f4\xd6\x80\x95\xde0\xcd\x12\xff\x01\xe2\xca\xca\xce#\xd3\x19\'\x02H\xd5\xa9s\xebR\'0\x0e"\x00\xf1\x03\x15\x80\xf6\xf3\x11\xfb\xb9\x1f\x1b\xb9o\xb9\x8ck\x80\xbe#\xd5@\xdb`\x13F\xbc\xf5!\x80\x1b\xd6\xd5\xf3\x11\xe9]\xe5<%@\xc4\r\xb5\x97\x12)\xf5\x06\xa8HD\t\xb5\x1e\xd7\x81\xe9\xf6\xaaL\xb4\x9c)\xd1\xf5/\x01d\xb0\x1b\xb5:\xd6\xf5\xe6/\xac\xd0\xd7\xe63;\x80\x02C\x05\x17\x8c<\xd9i\x1d\x16\x1b\x13\xe3\xbe\xea\r\xd2\x94\xe2\n\xef\x89\xe6BK.Je\x7fp\x17|\xef/d\xae\t\xfb!>\xf2S6\x80\xe5\x9fX\x13\xff\x16N\x07\x11\xc4\xfd\xf1\xde\x803\x11\xe1\x1eL\xe3\xe7\xd0\xa0\xe9\xed')]
    while(1): # 主循环
        img = sensor.snapshot() #从摄像头获取一张图片
        obj = kpu.run_yolo2(task_fd, img) # 运行人脸检测模型，获取人脸坐标位置
        status = 1 if obj else 0
        if obj: # 如果检测到人脸
            for i in obj: # 迭代坐标框
                # Cut face and resize to 128x128
                a = img.draw_rectangle(i.rect(),(138,43,226),thickness=3) # 在屏幕显示人脸方框
                face_cut=img.cut(i.x(),i.y(),i.w(),i.h()) # 裁剪人脸部分图片到 face_cut
                face_cut_128=face_cut.resize(128,128) # 将裁出的人脸图片 缩放到128 * 128像素
                a=face_cut_128.pix_to_ai() # 将猜出图片转换为kpu接受的格式
                #a = img.draw_image(face_cut_128, (0,0))
                # Landmark for face 5 points
                fmap = kpu.forward(task_ld, face_cut_128) # 运行人脸5点关键点检测模型
                plist=fmap[:] # 获取关键点预测结果
                le=(i.x()+int(plist[0]*i.w() - 10), i.y()+int(plist[1]*i.h())) # 计算左眼位置， 这里在w方向-10 用来补偿模型转换带来的精度损失
                re=(i.x()+int(plist[2]*i.w()), i.y()+int(plist[3]*i.h())) # 计算右眼位置
                nose=(i.x()+int(plist[4]*i.w()), i.y()+int(plist[5]*i.h())) #计算鼻子位置
                lm=(i.x()+int(plist[6]*i.w()), i.y()+int(plist[7]*i.h())) #计算左嘴角位置
                rm=(i.x()+int(plist[8]*i.w()), i.y()+int(plist[9]*i.h())) #右嘴角位置
                a = img.draw_circle(le[0], le[1], 4)
                a = img.draw_circle(re[0], re[1], 4)
                a = img.draw_circle(nose[0], nose[1], 4)
                a = img.draw_circle(lm[0], lm[1], 4)
                a = img.draw_circle(rm[0], rm[1], 4) # 在相应位置处画小圆圈
                # align face to standard position
                src_point = [le, re, nose, lm, rm] # 图片中 5 坐标的位置
                T=image.get_affine_transform(src_point, dst_point) # 根据获得的5点坐标与标准正脸坐标获取仿射变换矩阵
                a=image.warp_affine_ai(img, img_face, T) #对原始图片人脸图片进行仿射变换，变换为正脸图像
                a=img_face.ai_to_pix() # 将正脸图像转为kpu格式
                #a = img.draw_image(img_face, (128,0))
                del(face_cut_128) # 释放裁剪人脸部分图片
                # calculate face feature vector
                fmap = kpu.forward(task_fe, img_face) # 计算正脸图片的196维特征值
                feature=kpu.face_encode(fmap[:]) #获取计算结果
                scores = [] # 存储特征比对分数
                mscores = [] #存储我们的特征比对分数
                #识别其他人
                for x in range(len(record_ftrs)): #迭代已存特征值
                    score = kpu.face_compare(record_ftrs[x], feature) #计算当前人脸特征值与已存特征值的分数
                    scores.append(score) #添加分数总表
                max_score = 0
                index = 0
                #识别王昌胜
                for j in range(len(person_Xu)): #迭代已存特征值
                    mscore = kpu.face_compare(person_Xu[j], feature) #计算当前人脸特征值与已存特征值的分数
                    mscores.append(mscore) #添加分数总表
                mmax_score = 0

                for k in range(len(scores)): #迭代所有比对分数，找到最大分数和索引值
                    if max_score < scores[k]:
                        max_score = scores[k]
                        index = k
                if max_score > 75: # 如果最大分数大于85， 可以被认定为同一个人
                    a = img.draw_string(i.x(),i.y(), ("%s :%2.1f" % (names[index], max_score)), color=(0,255,0),scale=3) # 显示人名 与 分数
                for x in range(len(mscores)): #迭代所有比对分数，找到最大分数和索引值
                    if mmax_score < mscores[x]:
                        mmax_score = mscores[x]
                        num = x
                if mmax_score > 75: # 如果最大分数大于85， 可以被认定为同一个人
                        a = img.draw_string(i.y(),i.x(), ("%s :%2.1f" % (name[num], mmax_score)), color=(0,255,0),scale=3) # 显示人名 与 分数
                else:
                    a = img.draw_string(i.h(),i.w(), ("%s Not" % (max_score)), color=(255,0,0),scale=4) #显示未知 与 分数
                if start_processing: #如果检测到按键
                    record_ftr = feature
                    record_ftrs.append(record_ftr) #将当前特征添加到已知特征列表
                    start_processing = False#重置按键状态标志位
                break
        else:
            lcd.display(img)
            lcd.draw_string(50,10,'wait FACE cheak', lcd.RED,lcd.WHITE)
        a = lcd.display(img) #刷屏显示
    kpu.deinit(task_fd)
    kpu.deinit(task_ld)
    kpu.deinit(task_fe)
    gc.collect()
    # time.sleep(2)

#在显示屏上输出字符
def drawConfidenceText(image, rol, classid, value):
    text = ""
    _confidence = int(value * 100)

    if classid == 1:
        text = 'masks: ' + str(_confidence) + '%'
        color_text=color_G
    else:
        text = 'unmask: ' + str(_confidence) + '%'
        color_text=color_R
    image.draw_string(rol[1], rol[0], text, color=color_text, scale=2.5)

if __name__ == "__main__":
    _thread.start_new_thread(step1(),(0,))
    # _thread.start_new_thread(loadmodel(),(1,))
    while True:
        _thread.start_new_thread(loadmodel(),(1,))
        if return_meg[0] == 'masks':
            _thread.start_new_thread(facemodel(),(1,))
            return_meg[0] = 'unmask'
            # time.sleep(2)
        #gc.collect()


import numpy as np
from sklearn.base import clone
from autosklearn.classification import AutoSklearnClassifier
import pandas as pd
from autosklearn.classification import AutoSklearnClassifier

if __name__ == "__main__":

    def fit(model, X, labels):
        models = [clone(model).fit(X,labels[i]) for i in range(0,len(labels))]
        return(models)

    def predict(models, X):
        predictions = [m.predict_proba(X)[:,1] for m in models]
        return(predictions)

    # def evaluate(y, predictions):
    #     # predictions = np.where(np.array(predictions) > 0.5, 1, 0)
    #     predictions = np.array(predictions)
    #     y = np.array(y)
    #      return [roc_auc_score(y[:, i], predictions[i, :]) for i in range(y.shape[1])]

    def save_predictions(predictions, filename):
        df = pd.DataFrame(np.array(predictions).T, columns=['attribute 1', 'attribute 2', 'attribute 3', 'attribute 4', 'attribute 5'])
        df.to_csv(filename, index_label= 'Id')

    model = AutoSklearnClassifier(
      time_left_for_this_task = 45 * 60,
      per_run_time_limit = 125,
      n_jobs = -1
    )

    X_train = np.genfromtxt('protein_features_train.csv', delimiter=',')
    y_train = np.genfromtxt('protein_labels_train.csv', delimiter=',')
    X_test = np.genfromtxt('protein_features_test.csv', delimiter=',')

    labels_train = [np.copy(y_train[:,i]) for i in range(0, y_train.shape[1])]

    models = fit(model, X_train, labels_train)
    predictions = predict(models, X_test)
    save_predictions(predictions, 'predictions.csv')


import numpy as np
import pytest

import sys
import os

cwd = os.getcwd()
sys.path.insert(0, cwd)

from MCSimPython.utils import Rz, Ry, Rx, Rzyx, J, to_positive_angle, rigid_body_transform

class TestKinematicUtils:

    def test_Rz(self):
        # Transformation from body frame to NED frame for rotation about z-axis
        psi = np.deg2rad(90)
        nu = np.array([1, 0, 0])

        # Expected true value
        eta_dot = np.array([0, 1, 0])

        assert np.all(np.isclose(eta_dot, Rz(psi)@nu, rtol=1e-6))

    def test_Rzyx(self):
        psi, theta, phi = np.pi / 2, 0, 0
        nu = np.array([1., 0., 0.])
        eta = np.array([0, 0, 0, phi, theta, psi])

        # Expected true value
        eta_dot = np.array([0., 1., 0.])

        assert np.all(np.isclose(eta_dot, Rzyx(eta)@nu, rtol=1e-6))

    def test_J_dim(self):
        psi, theta, phi = 0, 0, 0
        eta = np.array([0, 0, 0, phi, theta, psi])

        rotmat_6dof = J(eta)

        assert np.all(np.equal((6, 6), rotmat_6dof.shape))

    def test_J(self):
        nu = np.array([1., 0., 0., 0., 0., 0.])
        phi, theta, psi = 0., 0., np.pi/2
        eta = np.array([0, 0, 0, phi, theta, psi])

        eta_dot = np.array([0., 1., 0., 0., 0., 0.])

        assert np.all(np.isclose(eta_dot, J(eta)@nu, rtol=1e-6))

    def test_positive_angle_map(self):
        angle = -np.pi / 2  # corresponding to 270 degrees (3pi/2)
        pos_angle = to_positive_angle(angle)
        true_angle = 3*np.pi / 2
        assert np.equal(pos_angle, true_angle)

    def test_array_positive_angle_map(self):
        angles = np.array([-np.pi, -np.pi/2])
        pos_angles = to_positive_angle(angles)
        true_angles = np.array([np.pi, 3*np.pi/2])
        assert np.all(np.isclose(pos_angles, true_angles, rtol=1e-6))

    def test_rigid_body_transform_translation(self):
        r = np.array([1., 0., -1.]) # Defined in the body-frame
        eta_1 = np.concatenate((np.array([1., 0., 0.]), np.zeros(3)))
        eta_2 = np.concatenate((np.array([0., 1., 0]), np.zeros(3)))
        eta_3 = np.concatenate((np.array([0., 0., 1.0]), np.zeros(3)))

        s_true_1 = np.array([1., 0., 0.])
        s_true_2 = np.array([0., 1., 0.])
        s_true_3 = np.array([0., 0., 1.])

        assert np.all(np.isclose(rigid_body_transform(r, eta_1, in_ned=False), s_true_1, rtol=1e-5))
        assert np.all(np.isclose(rigid_body_transform(r, eta_2, in_ned=False), s_true_2, rtol=1e-5))
        assert np.all(np.isclose(rigid_body_transform(r, eta_3, in_ned=False), s_true_3, rtol=1e-5))

    def test_rigid_body_transform_rotations(self):
        r = np.array([1., 0., -1]) # Define the lever arm in body-frame
        eta13 = np.zeros(3) # No translational motions
        eta36_1 = np.array([np.pi/180*2, 0.0, 0.])  # 2 degree roll
        eta36_2 = np.array([0., 3*np.pi/180, 0.0])  # 3 degree pitch
        eta36_3 = np.array([0., 0., 5*np.pi/180])   # 5 degree yaw

        eta_1 = np.concatenate([eta13, eta36_1])
        eta_2 = np.concatenate([eta13, eta36_2])
        eta_3 = np.concatenate([eta13, eta36_3])

        s_1 = np.array([0.0, 2*np.pi/180, 0.0]) # Only a change in the y-axis
        s_2 = np.array([-1*3*np.pi/180, 0.0, -3*np.pi/180])
        s_3 = np.array([0., 5*np.pi/180, 0.0])

        assert np.allclose(rigid_body_transform(r, eta_1, in_ned=False), s_1, rtol=1e-5)
        assert np.allclose(rigid_body_transform(r, eta_2, in_ned=False), s_2, rtol=1e-5)
        assert np.allclose(rigid_body_transform(r, eta_3, in_ned=False), s_3, rtol=1e-5)

    def test_rigid_transform_ref_frames(self):
        r = np.array([1., 0., 0.])  # Lever arm defined in body-frame

        # Vessel pose in NED-frame
        eta = np.array([
            1.0,
            0.0,
            0.0,
            0.0,
            0.0,
            np.pi/4
        ])

        s_body = np.array([1., np.pi/4, 0.0])    # Lever arm change in body-frame
        s_ned = np.array([np.cos(np.pi/4), -np.sin(np.pi/4) + np.pi/4, 0.]) # Lever arm change in ned-frame

        print(rigid_body_transform(r, eta, in_ned=True))

        assert np.allclose(rigid_body_transform(r, eta, in_ned=False), s_body)
        assert np.allclose(rigid_body_transform(r, eta, in_ned=True), s_ned)


import sfml.network as sf

# python 2.* compatability
try: input = raw_input
except NameError: pass

def run_tcp_server():
    """ Launch a server. The server waits for an incoming connection,
    sends a message and waits for the answer. """

    try:
        # create a server socket to accept new connections
        listener = sf.TcpListener()

        # listen to the given port for incoming connections
        listener.listen(PORT)

        print("Server is listening to port {0}, waiting for connections...".format(PORT))

        # wait for a connection
        socket = listener.accept()
        print("Client connected: {0}".format(socket.remote_address))

        # send a message to the connected client
        message = "Hi, I'm the server"
        socket.send(message.encode('utf-8'))
        print("Message sent to the client: {0}".format(message))

        # recieve a message back from the client
        answer = socket.receive(128).decode('utf-8')
        print("Answer received from the client: {0}".format(answer))

    except sf.SocketException as error:
        print("An error occured!")
        print(error)
        return

def run_tcp_client():
    """ Create a client. The client is connected to a server, displays
    the welcome message and sends an answer. """

    server = input("Type the address or name of the server to connect to: ")
    server = sf.IpAddress.from_string(server)

    # create a socket for communicating with the server
    socket = sf.TcpSocket()

    # connect to the server
    try:
        socket.connect(server, PORT)
        print("Connected to server {0}".format(server))

        # receive a message from the server
        message = socket.receive(128).decode('utf-8')
        print("Message received from the server: {0}".format(message))

        # send an answer to the server
        answer = "Hi, I'm a client"
        socket.send(answer.encode('utf-8'))
        print("Message sent to the server: {0}".format(answer))

    except sf.SocketException as error:
        print("An error occured!")
        print(error)
        return

def run_udp_server():
    """ Launch a server. The server waits for a message then sends an
    answer. """

    # create a socket to receive a message from anyone
    socket = sf.UdpSocket()

    try:
        # listen to messages on the specified port
        socket.bind(PORT)
        print("Server is listening to port {0}, waiting for message...".format(PORT))

        # wait for a message
        message, ip, port = socket.receive(128)
        print("Message received from client {0}: {1}".format(ip, message.decode('utf-8')))

        # send an answer to the client
        answer = "Hi, I'm the server"
        socket.send(answer.encode('utf-8'), ip, port)
        print("Message sent to the client: {0}".format(answer))

    except sf.SocketException as error:
        print("An error occured!")
        print(error)
        return

def run_udp_client():
    """ Send a message to the server, wait for the answer. """

    # ask for the server address
    server = input("Type the address or name of the server to connect to: ")
    server = sf.IpAddress.from_string(server)

    # create a socket for communicating with the server
    socket = sf.UdpSocket()

    try:
        # send a message to the server
        message = "Hi, I'm a client"
        socket.send(message.encode('utf-8'), server, PORT)
        print("Message sent to the server: {0}".format(message))

        # receive an answer from anyone (but most likely from the server)
        answer, ip, port = socket.receive(128)
        print("Message received from {0}: {1}".format(ip, answer.decode('utf-8')))

    except sf.SocketException as error:
        print("An error occured!")
        print(error)
        return

if __name__ == "__main__":
    # choose an arbitrary port for opening sockets
    PORT = 50001

    # TCP or UDP ?
    print("Do you want to use TCP (t) or UDP (u) ?")
    protocol = input()

    # client or server ?
    print("Do you want to be a server (s) or a client (c) ?")
    who = input()

    if protocol == 't':
        if who == 's': run_tcp_server()
        else: run_tcp_client()
    else:
        if who == 's': run_udp_server()
        else: run_udp_client()

    input("Press any key to exit...")


import os
import json
from tgtg import TgtgClient

from make_notify_list_json import save_new_notify_list
from telegram import Telegram

os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

sessionfile = 'tgtg_session.json'
notify_list_file = 'notify_list.json'
telegram_config_file = 'config.json'

def load_tgtg_client() -> TgtgClient:
    if os.path.exists(sessionfile):
        with open(sessionfile) as f:
            credentials = json.load(f)
        client = TgtgClient(
            access_token=credentials['access_token'],
            refresh_token=credentials['refresh_token'],
            user_id=credentials['user_id'],
            cookie=credentials['cookie']
        )
    else:
        client = TgtgClient(email=input('Your email: '))
        with open(sessionfile, 'w') as f:
            json.dump(client.get_credentials(), f, indent=4)
        if not os.path.exists(notify_list_file):
            save_new_notify_list()
    return client

def load_notify_list() -> dict:
    if os.path.exists(notify_list_file):
        with open(notify_list_file, encoding='utf-8') as f:
            notify_list = json.load(f)
    else:
        notify_list = save_new_notify_list()
    return notify_list

def update_notify_list(store_name: str, value: bool) -> dict:
    notify_list = load_notify_list()
    notify_list[store_name] = value
    with open(notify_list_file, 'w', encoding='utf-8') as f:
        json.dump(notify_list, f, indent=4, ensure_ascii=False)
    return notify_list

def load_telegram() -> Telegram:
    if os.path.exists(telegram_config_file):
        with open(telegram_config_file, encoding='utf-8') as f:
            return Telegram(json.load(f))
    else:
        return None


# Test2.py
'''
获得用户输入数字N，计算并输出从N开始的5个质数，单行输出，质数间用逗号,分割。

注意：用户输入的数字N可能是浮点数，都是正数；最后一个输出后不用逗号。
'''
# 请在...补充一行或多行代码

def prime(m):
    if (n < 2):
        return False
    elif ( n == 2):
        return True
    elif (n % 2 ==0):
        return False
    else:
        for i in range(2, n):
            if (n % i ==0):
                return False
        else:
            return True

n = eval(input())
if (isinstance(n, int) == False): # 处理输入
    n = int(n)
if (n <= 0):
    n = 1

count = 0 # 计数
result = [] # 结果
while ( count < 5 ):
#    print('count: {}, n: {}'.format(count, n))
    if prime(n) :
        result.append(n)
        count +=1
    n += 1

for i in result: # 打印
    if ( i == result[len(result)-1] ):
        print(i, end = "")
    else:
        print(i, end = ",")


import os			    # for magick and tesseract commands
import time			  # for epoch time
import calendar 	# for epoch time
from PyPDF2 import PdfFileMerger,PdfFileReader
import pdfplumber

dir_files = [f for f in os.listdir(".") if os.path.isfile(os.path.join(".", f))]
epoch_time = int(calendar.timegm(time.gmtime()))
print(dir_files)

for file in dir_files: # look at every file in the current directory
	if file.endswith('.pdf'): # if it is a PDF, use it
		print('Working on converting: ' + file)
		# setup
		file = file.replace('.pdf', '') # get just the filepath without the extension
		folder = str(int(epoch_time)) + '_' + file # generate a folder name for temporary images
		combined = folder + '/' + file # come up with temporary export path
		# create folder
		if not os.path.exists(folder): # make the temporary folder
			os.makedirs(folder)
		# convert PDF to PNG(s)
		magick = 'convert -density 150 "' + file + '.pdf" "' + combined + '-%04d.png"'
		print(magick)
		os.system(magick)
		# convert PNG(s) to PDF(s) with OCR data
		pngs = [f for f in os.listdir(folder) if os.path.isfile(os.path.join(folder, f))]
		for pic in pngs:
			if pic.endswith('.png'):
				combined_pic = folder + '/' + pic
				print(combined_pic)
				tesseract = 'tesseract "' + combined_pic + '" "' + combined_pic + '-ocr" PDF'
				print(tesseract)
				os.system(tesseract)
		# combine OCR'd PDFs into one
		ocr_pdfs = [f for f in os.listdir(folder) if os.path.isfile(os.path.join(folder, f))]

		merger = PdfFileMerger()
		for pdf in ocr_pdfs:
			if pdf.endswith('.pdf'):
				merger.append(folder + '/' + pdf)

		merger.write(file + '-ocr-combined.pdf')
		merger.close()

dir_files = [f for f in os.listdir(".") if os.path.isfile(os.path.join(".", f))]
for file in dir_files:
	if file.endswith('-combined.pdf'):
		processing = open("processing.txt","w")
		with pdfplumber.open(file) as pdf:
			for page in pdf.pages:
				numpage=page.page_number
				txt=page.extract_text()
				processing.write(txt)
				print(txt)
		processing.close()

		# cut text into paragraph
		txt = open("processing.txt","r")
		read_txt = txt.read()
		txt_split=read_txt.split('\n ')
		txt.close()
		while '' in txt_split:
			txt_split.remove('')
		while ' ' in txt_split:
			txt_split.remove(' ')
		print(txt_split)

		multi_keywords = ['Original','copy','copies']

		output = open("outputText.txt","w")

		# search keywords in paragraph and write result in output file
		for paragraph in  txt_split:
			checker = []
			for word in multi_keywords:
				checker.append(bool(paragraph.count(word)))
			if sum(checker) > 1 :
				output.write(paragraph+'\n')

		output.close()

# remove processing.text
import os
import shutil
if os.path.exists("processing.txt"):
  os.remove("processing.txt")
else:
  print("The file does not exist")

#remove image folder converting
shutil.rmtree(folder)

txt project/convert ocr + finish search.py


import sys
import time
import os
import statistics as st

FILE_NAME = "atk.c"
PAUSE_TIME = 5
REPETITIONS = 10
SECRET = [20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20]
T0_LINE = 13
OFFSET = 0

W = {"name": "WAIT_TIME ", "start": 0, "end": 50, "step": 50}

I = {"name": "I ", "start": 32, "end": 256, "step": 2}
N = {"name": "N ", "start": 128, "end": 180, "step": 20}

It = {"name": "It ", "start": 2, "end": 20000, "step": 2}
Nt = {"name": "Nt ", "start": 128, "end": 50, "step": 10}

def main():

    if (str(sys.argv[1]) is '1'):
        test1()
    elif (str(sys.argv[1]) is '2'):
        test2()
    else:
        print("No test was performed!")

def test1():

    I_name = I["name"]
    N_name = N['name']

    i = N["start"]

    # Modify atk.c with the current N value
    change(FILE_NAME, N_name , i )
    # Register results with N = i
    write_results(1, "N = " + str(i))

    ii = I["start"]
    while (ii < I["end"]):

        # Modify atk.c with the current I value
        change(FILE_NAME , I_name, ii )

        n_half_bytes = []
        rep = 0
        for rep in range(REPETITIONS):

            # Pause to cool CPU
            time.sleep(PAUSE_TIME)
            # Clean, compile, run attack
            os.system("make clean; make; ./atk")
            # Pause to cool CPU
            time.sleep(PAUSE_TIME)
            # run crypto-analysis program
            os.system("python3 crypto.py")

            # get the number of half key bytes discovered by the attack
            dk = read_disc_key_file()
            n_half_bytes.append(get_n_discovered_bits(dk, SECRET))

        # write averaged half key number discovered in results file
        content = str(ii) + "\t" + str(st.mean(n_half_bytes))
        write_results(1, content )

        # Increment cicle variable
        ii *= I["step"]

def test2():

    It_name = It["name"]
    Nt_name = Nt['name']

    i = Nt["start"]

    # Modify atk.c with the current N value
    change(FILE_NAME, Nt_name , i )
    # Register results with N = i
    write_results(2, "N = " + str(i))

    ii = It["start"]
    while (ii < It["end"]):

        # Modify atk.c with the current I value
        change(FILE_NAME , It_name, ii )

        # 1 on correct tbox answer; 0 when not
        capacity = []
        rep = 0
        while(rep < REPETITIONS):
            rep += 1

            # Pause to cool CPU
            time.sleep(PAUSE_TIME)
            # Clean, compile, run attack
            os.system("make clean; make; ./atk")
            # Pause to cool CPU
            time.sleep(PAUSE_TIME)
            # run crypto-analysis program
            os.system("python3 crypto.py")
            # get the number of half key bytes discovered by the attack
            offset, t0 = read_disc_tbox_file()

            if ((t0 == T0_LINE) and (offset == OFFSET)):
                capacity.append(1)
            else:
                capacity.append(0)

        # write averaged half key number discovered in results file
        content = str(ii) + "\t" + str(st.mean(capacity))
        write_results(2, content )

        # Increment cicle variable
        ii *= It["step"]

# Auxiliar Functions

def write_results(test_number, line):

    result_file = "result" + str(test_number) + ".out"

    with open(result_file, 'a') as file:
        file.write( line + "\n")

def performance1():

    l=0
    unused_lines = [6, 31, 52, 58, 59]

    while(True):
        try:
            timings  = read_files(l, "meas")
            l+=1
        except IOError:
            break

        avg = st.mean(timings)
        dev = st.stdev(timings)

        line_score = []
        meas_score = []

        for line in unused_lines:
            if (timings[line] < (avg + 1*dev)):
                line_score.append(timings[line]/avg)
        meas_score.append(st.mean(line_score))

    attack_score = st.mean(meas_score)

    attack_score = float("{0:.4f}".format(attack_score))

    return attack_score

def get_n_discovered_bits(key1, key2):

    n_common_half_keys = 0

    if(len(key1) is not len(key2)):
        print("Key1 has not the same size as key2")

    for i in range(len(key1)):

        if((key1[i] % 16) == (key2[i] % 16)):
            n_common_half_keys += 1
        if((key1[i] >> 4) == (key2[i] >> 4)):
            n_common_half_keys += 1

    return n_common_half_keys

def change(file_name, variable_name, amount ):

    # Read file
    with open(file_name, 'r') as file:
        data = file.readlines()

    # Perform modifications
    for l, line in enumerate(data):
        if variable_name in line:
            data[l] = "#define " + str(variable_name) + str(amount) + "\n"
            break

    # Write in File Modification
    with open(file_name, 'w') as file:
        file.writelines( data )

def read_files(l, file_name):

    meas_file = open("side_channel_info/" + file_name + "#" + str(l) + ".out", "r")
    plaintext_raw = meas_file.readline()
    scores = [int(i) for i in meas_file]
    meas_file.close()

    return scores

def read_disc_key_file():

    table_file = open("discovered_key_.out", "r")
    discovered_key = [int(i) for i in table_file]
    table_file.close()

    return discovered_key

def read_disc_tbox_file():

    tbox_file = open("tbox_discovered_.out", "r")
    values = [int(i) for i in tbox_file]
    tbox_file.close()

    return values[0], values[1]

main()


player = int(input())-1
time = 0
for i in range(int(input())):
    t_quest, response = input().split(' ')

    time+=int(t_quest)
    if(time>=210):
        print(player%8+1)
        break

    if (response=="T"):
        player+=1


# Katrin Erk June 2023
# hypernyms of objects in the Visual Genome

import sys
import os
import json
import zipfile
from collections import defaultdict, Counter
import math
import statistics
import random
from argparse import ArgumentParser

from nltk.corpus import wordnet
from sklearn.linear_model import LogisticRegression

from vgnames import VGOBJECTS, VGATTRIBUTES, VGRELATIONS
import vgiterator
import sentence_util
from vgpaths import VGPaths, get_output_path
from vec_util import VectorInterface
from sds_imagine_util import  ImagineAttr
from hypernymy_util import HypernymHandler

parser = ArgumentParser()
parser.add_argument('--vgdata', help="directory with VG data including frequent items, train/test split, topic model", default = "data/")
parser.add_argument('--trainperc', help = "percentage of object types to use for training PLSR, default 0.8", type = float, default = 0.8)

args = parser.parse_args()

print("reading data")
vgpath_obj = VGPaths(vgdata = args.vgdata)

# most frequent objects, attributes, relations
vgcounts_zipfilename, vgcounts_filename = vgpath_obj.vg_counts_zip_and_filename()
with zipfile.ZipFile(vgcounts_zipfilename) as azip:
    with azip.open(vgcounts_filename) as f:
        vgobjects_attr_rel = json.load(f)

vec_obj = VectorInterface(vgpath_obj)

available_objects = [o for o in vgobjects_attr_rel[VGOBJECTS] if o in vec_obj.object_vec]
missing = len(vgobjects_attr_rel[VGOBJECTS]) - len(available_objects)
if missing > 0:
    print("frequent objects without vectors:", missing, "out of", len(vgobjects_attr_rel[VGOBJECTS]))

# object fmr handling hypernymy
hyper_obj = HypernymHandler(available_objects)

# train/dev/test split
print("splitting objects into train/dev/test, and making classifiers")
hyper_obj.make_hypernym_classifiers(vec_obj, trainpercent = args.trainperc, random_seed = 9386)

###
# for each hypernym: train ridge regression classifier,
# evaluate
all_correct = { "dev" : 0, "test" : 0 }
all_dp = { "dev" : 0, "test" : 0 }
all_nodata = {"dev" : 0, "test" : 0}
detail_accuracy = defaultdict(dict)

for section in ["dev", "test"]:
    for hypernym, predicted, gold in hyper_obj.eval_predict_each(section, vec_obj):
        if predicted is None:
            # no classifier could be fit for this hypernym
            all_nodata[section] += 1
            continue

        # apply to development and test data
        this_accuracy = { }
        correct = sum([int(y == pred) for y, pred in zip(gold, predicted)])
        all_correct[ section ] += correct
        all_dp[ section ] += len(gold)

        detail_accuracy[hypernym][ section ] = correct / len(gold)

for hypernym, acc in detail_accuracy.items():
    print(hypernym, "dev accuracy", round(acc["dev"], 3), "test accuracy", round(acc["test"], 3))

print()
print("Number of hypernyms", len(hyper_obj.hypernym_names))
print(f"Missing training data for {all_nodata['dev']} hypernyms")
print("Number of items: training", len(hyper_obj.training_objectlabels), "dev", len(hyper_obj.dev_objectlabels), "test", len(hyper_obj.test_objectlabels))
print()

print("Overall accuracy, hypernyms with training data: dev", round(all_correct["dev"] / all_dp["dev"], 3),
      "test", round(all_correct["test"] / all_dp["dev"], 3))

if all_nodata["dev"] > 0:
    print("Overall accuracy, including no-data items: dev", round(all_correct["dev"] / all_dp["dev"] + all_nodata["dev"] * len(hyper_obj.dev_objectlabels), 3),
            "test", round(all_correct["test"] / all_dp["test"] + all_nodata["test"] * len(hyper_obj.test_objectlabels), 3))


#Import Libraries
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

#Read and understand data
d2=pd.read_csv('realest.csv')
d2.info()
d2.hist(bins=50,figsize=(20,15))
corr_matrix=d2.corr()
corr_matrix["Price"]

#Clean data
m1 = d2["Space"].median()
d2["Space"].fillna(m1, inplace=True)
m2 = d2["Lot"].median()
d2["Lot"].fillna(m2, inplace=True)
m3 = d2["Tax"].median()
d2["Tax"].fillna(m3, inplace=True)

#Create test set and training set
from sklearn.model_selection import train_test_split
tr,te=train_test_split(d2, test_size=0.2, random_state=42)

#Assign Variables
x1=np.array(tr["Space"])
x2=np.array(tr["Room"])
x3=np.array(tr["Bathroom"])
x4=np.array(tr["Garage"])
y=np.array(tr["Price"])
m=len(x1)

#Feature Normalization
x1_m=np.mean(x1)
x1_s=np.std(x1)
x2_m=np.mean(x2)
x2_s=np.std(x2)
x3_m=np.mean(x3)
x3_s=np.std(x3)
x4_m=np.mean(x4)
x4_s=np.std(x4)
y_m=np.mean(y)
y_s=np.std(y)
x1=(x1-x1_m)/x1_s
x2=(x2-x2_m)/x2_s
x3=(x3-x3_m)/x3_s
x4=(x4-x4_m)/x4_s
y=(y-y_m)/y_s

#Visualize Variables
plt.scatter(x1,y)
plt.xlabel("Space")
plt.show()
plt.scatter(x2,y)
plt.xlabel("Room")
plt.show()
plt.scatter(x3,y)
plt.xlabel("Bathroom")
plt.show()
plt.scatter(x4,y)
plt.xlabel("Garage")
plt.show()

#Apply Gradient Descent and Calculate Cost
x0=np.ones(m)
xt=np.c_[x0,x1,x2,x3,x4]
thetas=np.array([0,0,0,0,0])
h=np.dot(xt,thetas)
thetas=thetas-(0.1/m)*np.dot((h-y),xt)
cost=(np.sum((h-y)**2))/(2*m)
cost1=[]
l=[]
for i in range(15000):
 thetas=thetas-(0.01/m)*np.dot((h-y),xt)
 h = np.dot(xt,thetas)
 cost1.append((np.sum((h-y)**2))/(2*m))
 l.append(i)

#Visualize Result
plt.plot(l,cost1)
plt.show()
plt.scatter(x1,y,marker="o")
plt.scatter(x2,y,marker="o")
plt.plot(x1,h)
plt.plot(x2,h)
plt.show()

yreal=(y*y_s)+y_m
hp=np.dot(xt,thetas)
hreal=(hp*np.std(hp))+np.mean(hp)
cost=(np.sum((hreal-yreal)**2))/(2*m)
realc=np.sqrt(cost)

#using scikit-learn
from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
lin_reg.fit(xt,y)

from sklearn.metrics import mean_squared_error
y_real=(y*y_s)+y_m
h_p = lin_reg.predict(xt)
h_real=(h_p*np.std(h_p))+np.mean(h_p)
lin_mse = mean_squared_error(y_real, h_real)
lin_rmse = np.sqrt(lin_mse)
lin_rmse

Linear Regression/Realestate Price Prediction/Real Estate Price Prediction.py


import copy
import pandas as pd

from cal import cal_centroid

M = 3000

def func1():
    m_nowi = [0.3 * 850, 1.5 * 850, 2.1 * 850, 1.9 * 850, 2.6 * 850, 0.8 * 850]
    cost_ti = pd.read_excel("附件2-问题1数据.xlsx", sheet_name="油箱供油曲线")
    m_ti = []  # 在t时刻下i油箱中油的质量

    for index, row in cost_ti.iterrows():
        cost_nowi = list(row[1:7])
        temp = []
        for k in range(6):
            temp.append(m_nowi[k] - cost_nowi[k])
        m_nowi = copy.deepcopy(temp)
        m_ti.append(copy.deepcopy(temp))

    angle_t = pd.read_excel("附件2-问题1数据.xlsx", sheet_name="飞行器俯仰角")
    angle_t = list(angle_t["飞行器俯仰角(度)"])  # t时刻下飞行器俯仰角
    return m_ti, angle_t

def func2():
    m_ti, angle_t = func1()
    centroid_ti = []  # 在t时刻下i油箱中油的质心位置(x, y, z)
    for now in range(7200):
        m_nowi = m_ti[now]
        angle_now = angle_t[now]
        centroid_nowi = []
        for i in range(6):
            centroid_nowi.append(cal_centroid(i, m_nowi[i] / 850, angle_now))
        centroid_ti.append(copy.deepcopy(centroid_nowi))
    return centroid_ti

def func3():
    m_ti, _ = func1()
    centroid_ti = func2()
    result_centroid_t = []  # 在t时刻下飞行器质心位置[x, y, z]
    for now in range(7200):
        centroid_nowi = centroid_ti[now]
        m_nowi = m_ti[now]

        X_fenzi = 0
        X_fenmu = M
        for i in range(6):
            X_fenzi += centroid_nowi[i][0] * m_nowi[i]
            X_fenmu += m_nowi[i]
        X = X_fenzi / X_fenmu

        Y_fenzi = 0
        Y_fenmu = M
        for i in range(6):
            Y_fenzi += centroid_nowi[i][1] * m_nowi[i]
            Y_fenmu += m_nowi[i]
        Y = Y_fenzi / Y_fenmu

        Z_fenzi = 0
        Z_fenmu = M
        for i in range(6):
            Z_fenzi += centroid_nowi[i][2] * m_nowi[i]
            Z_fenmu += m_nowi[i]
        Z = Z_fenzi / Z_fenmu
        result_centroid_t.append([X, Y, Z])

    return result_centroid_t

def func4():
    """
    将func3的结果写入excel
    :return:
    """
    df = pd.DataFrame(columns=('时间(s)', '质心x坐标', '质心y坐标', '质心z坐标'))
    result_centroid_t = func3()
    for i in range(len(result_centroid_t)):
        result_centroid_t[i].insert(0, i + 1)
        df.loc[i, :] = result_centroid_t[i]
    df.to_excel("测试.xlsx", sheet_name="第一问结果")

if __name__ == '__main__':
    func4()


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def countNodes(self, root: TreeNode) -> int:

        if root == None: return 0
        right, left = root, root
        h_l , h_r = 0, 0

        while left != None:
            h_l +=1
            left = left.left

        while right != None:
            h_r +=1
            right = right.right

        if (h_l == h_r) : return(1 << h_l) -1

        return 1+ self.countNodes(root.left) + self.countNodes(root.right)


import os
import random

import cv2
import numpy as np

root_dir = "../data/kaist/images/"

def calc_stats():
    rgb_images = []
    ir_images = []
    mean = []
    std = []
    set_list = os.listdir(root_dir)
    for s_path in [os.path.join(root_dir, s) for s in set_list]:
        vid_list = os.listdir(s_path)
        for v_path in [os.path.join(s_path, b) for b in vid_list]:
            img_list = os.listdir(os.path.join(v_path, "visible"))
            for img_name in img_list:
                if random.uniform(0, 1) > 0.95:
                    rgb_img = cv2.imread(os.path.join(v_path, "visible", img_name))
                    ir_img = cv2.imread(os.path.join(v_path, "lwir", img_name), cv2.IMREAD_GRAYSCALE)
                    rgb_images.append(rgb_img)
                    ir_images.append(ir_img)
    print(len(rgb_images))

    # calc mean
    total_red = 0
    total_green = 0
    total_blue = 0
    total_intensity = 0
    for index in range(len(rgb_images)):
        img = rgb_images[index]
        ir_img = ir_images[index]

        for i in range(img.shape[0]):
            for j in range(img.shape[1]):
                pixel = img[i, j]
                ir_pixel = ir_img[i, j]

                red = pixel[0]
                total_red += red

                green = pixel[1]
                total_green += green

                blue = pixel[2]
                total_blue += blue

                intensity = ir_pixel
                total_intensity += intensity
    denominator = len(rgb_images) * 511 * 511 * 255

    mean.append(total_red / denominator)
    mean.append(total_green / denominator)
    mean.append(total_blue / denominator)
    mean.append(total_intensity / denominator)
    print("Mean: ", mean)

    std_sum_red = 0
    std_sum_green = 0
    std_sum_blue = 0
    std_sum_ir = 0
    for index in range(len(rgb_images)):
        img = rgb_images[index]
        ir_img = ir_images[index]

        for i in range(img.shape[0]):
            for j in range(img.shape[1]):
                pixel = img[i, j]
                ir_pixel = ir_img[i, j]

                red = pixel[0] / 255
                std_sum_red += (mean[0] - red) ** 2

                green = pixel[1] / 255
                std_sum_green += (mean[1] - green) ** 2

                blue = pixel[2] / 255
                std_sum_blue += (mean[2] - blue) ** 2

                intensity = ir_pixel / 255
                std_sum_ir += (mean[3] - intensity) ** 2
    std_denom = len(rgb_images) * 511 * 511
    std.append(np.sqrt(std_sum_red / std_denom))
    std.append(np.sqrt(std_sum_green / std_denom))
    std.append(np.sqrt(std_sum_blue / std_denom))
    std.append(np.sqrt(std_sum_ir / std_denom))
    print("Std: ", std)

    all_lst = []
    for i in range(len(rgb_images)):
        res = np.reshape(rgb_images[i], (3, 511, 511))
        added = np.append(res, ir_images[i])
        added = np.reshape(added, (4, 511, 511))
        all_lst.append(added)

    # Must has (N x 4 x 511 x 511) ndarray
    print(added)

if __name__ == "__main__":
    calc_stats()


import config
import argparse
import logging
import subprocess
import os

from datetime import datetime
from lib.slackApi import SlackApi
from lib.kubeApi import KubeApi
from lib.helpers import generate_image
from lib.trello import cleanup_trello

logging.basicConfig(
    level=logging.DEBUG, format="[%(asctime)s][%(levelname)s] %(message)s"
)

class Deployorama:
    """
    Perform kubernetes deployment and all that jazz.
    """

    def __init__(self):
        self.tag = config.TAG
        self.migration = config.MIGRATION_LEVEL
        self.check_cronjobs = config.CHECK_CRONJOBS
        self.slacker = SlackApi()
        self.kuber = KubeApi(namespace=config.NAMESPACE)
        self.deployments = {
            tier: self.kuber.get_deployments(
                label_selector="project={}, tier={}".format(config.PROJECT, tier)
            )
            for tier in config.TIERS
        }
        self.cronjobs = self.kuber.get_cronjobs(label_selector="project={}".format(config.PROJECT))
        self.has_down_time = self.migration == 2
        self.has_migration = self.migration > 0
        self.migration_completed = False
        self.deploy_success = True

    def get_new_image(self, image):
        return generate_image(old_image=image, new_tag=self.tag)

    def all_deployments(self):
        return [deploy for sublist in self.deployments.values() for deploy in sublist]

    def send_release_notification(self):
        if not self.deploy_success:
            logging.debug("Skipping release notification due to deployment failure")
            return
        cleanup_trello()

    def deploy(self):
        """
        The master deployment method to process deployment from start to finish.
        """

        if config.DISABLED:
            self.slacker.send_message(text="Automated deployment is currently disabled")
            return

        error_message = None
        error_handling_message = None

        try:
            self.slacker.send_initial_message()
            self.kuber.get_cronjobs(label_selector="project={}".format(config.PROJECT))

            if self.has_down_time:
                self.scale_down_deployments()

            if self.has_migration:
                self.backup_database()
                self.run_migration()

            self.set_images()

            if (self.check_cronjobs):
                self.set_cronjob_images()

            if self.has_down_time:
                self.scale_up_deployments()

        except Exception as e:
            self.deploy_success = False
            error_message = str(e)
            logging.error(error_message)
            error_handling_message = self.handle_deploy_failure()

        self.slacker.send_completion_message(
            error_message=error_message,
            error_handling_message=error_handling_message,
            deployments=self.all_deployments(),
            requires_migration_rollback=self.has_down_time and self.migration_completed,
        )
        self.send_release_notification()

    def handle_deploy_failure(self):
        """
        Handle deployment failure by reverting all modifications.
        """
        step = "Recovering From Deployment Error"
        self.slacker.send_thread_reply(step)

        if self.has_down_time is True and self.migration_completed:
            return "Skipped Automated Recovery: Requires Manual Intervention"

        try:
            self.rollback_images()
            self.scale_up_deployments()
            error_handler_message = "Successfully Rolled Back Deployment"

        except Exception as e:
            error_handler_message = str(e)
            logging.error(error_handler_message)

        return error_handler_message

    def raise_step_error(self, error: Exception, step: str):
        """
        Handle notification for deployment step errors and raise exception with new message.
        """
        error_message = "{}\nFailed: Error={}".format(step, str(error))
        logging.error(error_message)
        self.slacker.send_thread_reply(error_message)
        raise Exception(error_message)

    def scale_down_deployments(self):
        """
        Scale down deployments.
        """
        try:
            for tier in config.TIERS:
                for deployment in self.deployments[tier]:
                    step = "Scaling Down Deployment:\ndeployment={}".format(
                        deployment["name"]
                    )
                    self.slacker.send_thread_reply(step)
                    deployment["scaled_down"] = True
                    self.kuber.set_deployment_replicas(deployment["name"], 0)
                step = "Verifying {} Deployments Scaled Down Successfully".format(tier)
                self.slacker.send_thread_reply(step)
                for deployment in self.deployments[tier]:
                    self.kuber.verify_deployment_update(deployment["name"])
        except Exception as e:
            self.raise_step_error(step=step, error=e)

    def scale_up_deployments(self):
        """
        Scale up all deployments (in reverse order) to original replica counts.
        """
        try:
            for tier in config.TIERS[::-1]:
                for deployment in self.deployments[tier]:
                    if deployment.get("scaled_down", False) is True:
                        step = "Scaling Up Deployment:\ndeployment={}\nreplicas={}".format(
                            deployment["name"], deployment["replicas"]
                        )
                        self.slacker.send_thread_reply(step)
                        self.kuber.set_deployment_replicas(
                            deployment["name"], deployment["replicas"]
                        )
                        deployment["scaled_down"] = False
                step = "Verifying {} Deployments Scaled Up Successfully".format(tier)
                self.slacker.send_thread_reply(step)
                for deployment in self.deployments[tier]:
                    self.kuber.verify_deployment_update(deployment["name"])
        except Exception as e:
            self.raise_step_error(step=step, error=e)

    def backup_database(self):
        """
        Store a cloud sql backup on google storage
        """
        backup_file = "{}-{}.sql".format(
            config.DATABASE_NAME, datetime.today().strftime("%Y-%m-%d--%H%M")
        )
        backup_uri = "{}/{}".format(config.DATABASE_BACKUP_BUCKET, backup_file)
        step = "Backing Up Database:\nbackup={}".format(backup_uri)
        try:
            self.slacker.send_thread_reply(step)
            backup_command = [
                "gcloud",
                "sql",
                "export",
                "sql",
                config.DATABASE_INSTANCE_NAME,
                backup_uri,
                "--database={}".format(config.DATABASE_NAME),
                "--verbosity=debug",
            ]
            subprocess.run(backup_command, check=True)
        except Exception as e:
            self.raise_step_error(step=step, error=e)

    def run_migration(self):
        """
        Perform database migration via k8 app-migrator job.
        """
        step = "Migrating Database"
        try:
            self.slacker.send_thread_reply(step)
            self.kuber.run_migration(tag=self.tag, source=config.APP_MIGRATOR_SOURCE)
            self.migration_completed = True
        except Exception as e:
            self.raise_step_error(step=step, error=e)

    def set_images(self):
        """
        Update images for all deployments.
        """
        try:
            for deployment in self.all_deployments():
                new_image = self.get_new_image(deployment["image"])
                step = "Setting Deployment Image:\ndeployment={}\nold_image={}\nnew_image={}".format(
                    deployment["name"], deployment["image"], new_image
                )
                if deployment["image"] == new_image:
                    self.slacker.send_thread_reply(
                        "Deployment Doesn't Require Image Update: deployment={} image={}".format(
                            deployment["name"], new_image
                        )
                    )
                    continue
                self.slacker.send_thread_reply(step)
                self.kuber.set_deployment_image(deployment["name"], new_image)
                deployment["updated_image"] = True
            step = "Verifying Deployment Updates Completed Successfully"
            self.slacker.send_thread_reply(step)
            for deployment in self.all_deployments():
                self.kuber.verify_deployment_update(deployment["name"])
        except Exception as e:
            self.raise_step_error(step=step, error=e)

    def set_cronjob_images(self):
        """
        Update images for all cronjobs.
        """
        try:
            for cronjob in self.cronjobs:
                new_image = self.get_new_image(cronjob["image"])
                step = "Setting Cronjob Image:\ncronjob={}\nold_image={}\nnew_image={}".format(
                    cronjob["name"], cronjob["image"], new_image
                )
                if (cronjob["image"] == new_image):
                    self.slacker.send_thread_reply(
                        "Cronjob Doesn't Require Image Update: cronjob={} image={}".format(
                            cronjob["name"], new_image
                        )
                    )
                    continue
                self.slacker.send_thread_reply(step)
                self.kuber.set_cronjob_image(cronjob["name"], new_image)
            step = "Cronjob Updates Completed"
            self.slacker.send_thread_reply(step)

        except Exception as e:
            self.raise_step_error(step=step, error=e)

    def rollback_images(self):
        """
        Rollback all deployment images to their original state prior to deployment.
        """
        for deployment in self.all_deployments():
            if deployment.get("updated_image", False) is False:
                continue
            step = "Rolling Back Deployment Image:\ndeployment={}\nattempted_image={}\nrollback_image={}".format(
                deployment["name"],
                self.get_new_image(deployment["image"]),
                deployment["image"],
            )
            try:
                self.slacker.send_thread_reply(step)
                self.kuber.set_deployment_image(
                    deployment["name"], deployment["image"], verify_update=True
                )
                deployment["updated_image"] = False
            except Exception as e:
                self.raise_step_error(step=step, error=e)

if __name__ == "__main__":
    parser = argparse.ArgumentParser("deploy")
    parser.add_argument(
        "-t", "--tag", help="New image tag to be rolled out.", type=str, required=True
    )
    parser.add_argument(
        "-m",
        "--migration",
        help="Migration level: 0=None, 1=Hot, 2=Cold",
        type=int,
        required=True,
        choices=[0, 1, 2]
    )
    parser.add_argument(
        "-cj",
        "--cronjob",
        help=f"Set to True to update cronjobs available for PROJECT:{config.PROJECT}.",
        type=bool,
        default=True,
        required=False,
        choices=[True, False]
    )
    args = parser.parse_args()
    config.TAG = args.tag.strip()
    config.MIGRATION_LEVEL = args.migration
    config.CHECK_CRONJOBS = args.cronjob

    deployer = Deployorama()
    deployer.deploy()
    os._exit(os.EX_OK)