from torch_common import load_state_dict
from model import get_git_model
from dataset import create_dataset, create_sampler, create_loader, cap_collate_fn
import utils
from torchvision import transforms
from PIL import Image
from transformers import AutoTokenizer
import torch.backends.cudnn as cudnn
import torch
from decord import VideoReader
from pathlib import Path
import random
import numpy as np
import ruamel.yaml as yaml
import os
import argparse
import matplotlib
matplotlib.use('Agg')

def load_images(test_dir, test_transform, config):
    image_files = os.listdir(test_dir)
    image_files = sorted(
        image_files,
        key=lambda x: int(x.split('_')[-1].split('.')[0]))
    image_files = [
        os.path.join(test_dir, each) for each in image_files
    ]
    if len(image_files) != config['num_frm_test']:
        sample_ix = np.linspace(0,
                                len(image_files) - 1,
                                num=config['num_frm_test'],
                                endpoint=True,
                                retstep=False,
                                dtype=int)
        image_files = np.array(image_files)[sample_ix].tolist()
    images = [Image.open(i).convert('RGB') for i in image_files]

    images = [test_transform(i) for i in images]
    images = torch.stack(images)
    return images

def load_video(video_path, height=None, width=None, start_time=None, end_time=None, fps=-1, num_frm=16, test_transform=None):

    if not height or not width:
        vr = VideoReader(video_path)
    else:
        vr = VideoReader(video_path, width=width, height=height)

    vlen = len(vr)

    if start_time or end_time:
        assert fps > 0, 'must provide video fps if specifying start and end time.'

        start_idx = min(int(start_time * fps), vlen)
        end_idx = min(int(end_time * fps), vlen)
    else:
        start_idx, end_idx = 0, vlen

    frame_indices = np.arange(
        start_idx, end_idx, vlen / num_frm, dtype=int)

    raw_sample_frms = vr.get_batch(frame_indices).numpy()
    # raw_sample_frms = raw_sample_frms.permute(0, 3, 1, 2).numpy()

    raw_sample_frms = [Image.fromarray(each) for each in raw_sample_frms]
    images = [test_transform(i) for i in raw_sample_frms]
    images = torch.stack(images)
    return images

@torch.no_grad()
def infer_single(model, tokenizer, device, config):
    model.eval()
    test_file = config['test_file']
    normalize = transforms.Normalize(
        (0.48145466, 0.4578275, 0.40821073), (0.26862954, 0.26130258, 0.27577711))

    test_transform = transforms.Compose([
        transforms.Resize(
            (config['image_res'], config['image_res']), interpolation=transforms.InterpolationMode.BICUBIC),
        transforms.ToTensor(),
        normalize,
    ])
    if os.path.isdir(test_file):
        images = load_images(test_file, test_transform, config)
    else:
        images = load_video(
            test_file, num_frm=config['num_frm_test'], test_transform=test_transform)

    images = images.to(device, non_blocking=True)
    images = images.unsqueeze(0)
    caption = tokenizer([''], padding='longest', truncation=True,
                        max_length=config['max_input_length'], return_tensors="pt").to(device)
    if 'prefix' in config:
        prefix = tokenizer(config['prefix'], padding='longest', truncation=True,
                           max_length=config['max_input_length'], return_tensors="pt").to(device)
        prefix = prefix['input_ids'][:, :-1]

    input_data = {
        'image': images,
        'need_predict': caption['attention_mask'],
        'caption_tokens': caption['input_ids'],
    }
    if 'prefix' in config:
        input_data['prefix'] = prefix

    result = model(input_data)
    # for i in range(result['predictions'].shape[0]):
    cap = tokenizer.decode(
        result['predictions'][0],
        skip_special_tokens=True)
    cap = cap.replace(
        "[CLS]", "").replace("[PAD]", "").strip()
    print(test_file)
    print('===============')
    print(cap)
    return cap

@torch.no_grad()
def infer_batch(model, data_loader, tokenizer, device, config):
    # test;
    model.eval()

    metric_logger = utils.MetricLogger(delimiter="  ")
    header = 'Generate caption test result:'
    print_freq = 50

    ral_val = []

    for n, (image, image_names) in enumerate(metric_logger.log_every(data_loader, print_freq, header)):
        # if n == 5:
        #     break
        image = image.to(device, non_blocking=True)
        caption = ['' for _ in range(image.shape[0])]
        caption = tokenizer('', padding='longest', truncation=True,
                            max_length=config['max_input_length'], return_tensors="pt").to(device)
        if 'prefix' in config:
            prefix = tokenizer(config['prefix'], padding='longest', truncation=True,
                               max_length=config['max_input_length'], return_tensors="pt").to(device)
            prefix = prefix['input_ids'][:, :-1]

        for i in range(len(image_names)):
            input_data = {
                'image': image[i:i+1],
                'need_predict': caption['attention_mask'][i:i+1],
                'caption_tokens': caption['input_ids'][i:i+1],
            }
            if 'prefix' in config:
                input_data['prefix'] = prefix

            result = model(input_data)

            cap = tokenizer.decode(
                result['predictions'][0],
                skip_special_tokens=True)
            cap = cap.replace(
                "[CLS]", "").replace("[PAD]", "").strip()
            ral_val.append({
                "question_id": image_names[i],
                "pred_caption": cap,
            })
    return ral_val

def get_parameter_number(model):
    total_num = sum(p.numel() for p in model.parameters())
    trainable_num = sum(p.numel() for p in model.parameters()
                        if p.requires_grad)
    print("Total: %.2fM, Trainable: %.2fM" %
          (total_num / 1.0e6, trainable_num / 1.0e6))

def main(args, config):
    utils.init_distributed_mode(args)

    device = torch.device(args.device)

    # fix the seed for reproducibility
    seed = args.seed + utils.get_rank()
    torch.manual_seed(seed)
    np.random.seed(seed)
    random.seed(seed)
    cudnn.benchmark = True

    tokenizer = AutoTokenizer.from_pretrained(
        "uer/gpt2-chinese-cluecorpussmall")
    model = get_git_model(tokenizer, {}, config)

    checkpoint = torch.load(args.checkpoint, map_location='cpu')
    # model.load_state_dict(checkpoint)
    load_state_dict(model, checkpoint)

    model.eval()
    model = model.to(device)
    #get_parameter_number(model)
    if '.txt' in config['test_file']:
        dataset = create_dataset(config=config)

        sampler = None
        test_loader = create_loader(dataset, sampler,
                                    batch_size=config['batch_size_test'],
                                    n_worker=32,
                                    collate_fn=cap_collate_fn)

        result = infer_batch(
            model, test_loader, tokenizer, device, config)
        # import pdb; pdb.set_trace()
        save_file_name = os.path.split(
            args.checkpoint)[-1].split('.')[0] + '_' + os.path.split(config['test_file'][0])[-1].split('.')[0]
        if 'prefix' in config:
            save_file_name += config['prefix'].replace(' ', '-')

        with open(os.path.join(args.output_dir, save_file_name + '.txt'), 'w') as f:
            for res in result:
                f.write(f"{res['question_id']}\t{res['pred_caption']}\n")
    else:
        infer_single(model, tokenizer, device, config)
    # result_file = save_result(vqa_result, args.result_dir, 'vqa_result_epoch10')
    # if utils.is_main_process():
    #     result = cal_metric(result_file)

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--config', default='./configs/infer.yaml')
    parser.add_argument('--checkpoint', default='')
    parser.add_argument('--output_dir', default='output')
    parser.add_argument('--evaluate', action='store_true')
    parser.add_argument('--text_encoder', default='bert-base-uncased')
    parser.add_argument('--text_decoder', default='bert-base-uncased')
    parser.add_argument('--device', default='cuda')
    parser.add_argument('--seed', default=42, type=int)
    parser.add_argument('--min_length', default=1, type=int)
    parser.add_argument('--lr', default=2e-5, type=float)
    parser.add_argument('--max_length', default=10, type=int)
    parser.add_argument('--max_input_length', default=25, type=int)
    parser.add_argument('--beam_size', default=5, type=int)
    parser.add_argument('--world_size', default=1, type=int,
                        help='number of distributed processes')
    parser.add_argument('--dist_url', default='env://',
                        help='url used to set up distributed training')
    parser.add_argument('--distributed', default=True, type=bool)
    parser.add_argument('--do_two_optim', action='store_true')
    parser.add_argument('--add_object', action='store_true')
    parser.add_argument('--do_amp', action='store_true')
    parser.add_argument('--no_init_decocde', action='store_true')
    parser.add_argument('--do_accum', action='store_true')
    parser.add_argument('--accum_steps', default=4, type=int)
    parser.add_argument('--to_be_infered', default='', type=str)
    parser.add_argument('--git', action='store_true')
    parser.add_argument('--use_video', action='store_true')
    parser.add_argument('--test_root', default="../demo/frames", type=str)

    args = parser.parse_args()

    config = yaml.load(open(args.config, 'r'), Loader=yaml.Loader)

    args.result_dir = os.path.join(args.output_dir, 'result')

    Path(args.output_dir).mkdir(parents=True, exist_ok=True)
    Path(args.result_dir).mkdir(parents=True, exist_ok=True)
    config['test_file'] = args.to_be_infered
    config['max_input_length'] = args.max_input_length
    config["min_length"] = args.min_length
    config["max_length"] = args.max_length
    config["add_object"] = args.add_object
    config["beam_size"] = args.beam_size
    config['text_encoder'] = args.text_encoder
    config['text_decoder'] = args.text_decoder
    config['test_root'] = args.test_root
    config['use_video'] = False
    if args.git:
        config['gvt'] = False
    if args.use_video:
        config['use_video'] = True

    yaml.dump(config, open(os.path.join(args.output_dir, 'config.yaml'), 'w'))

    main(args, config)


import numpy as np
import pandas as pd
import seaborn as sns
from help_functions import get_meteogalicia_model_4Km, get_meteogalicia_model_1Km, get_table_download_link
import pickle
import streamlit as st
import plotly.express as px
from st_aggrid import AgGrid
import matplotlib.pyplot as plt
import requests
import json
import plotly.express as px
from sklearn.metrics import accuracy_score
from sklearn.metrics import mean_absolute_error

st.set_page_config(page_title="ENM_UDRA",layout="wide")

#score machine learning versus WRF
score_ml = 0
score_wrf = 0

#load algorithm file gust
algo_g_d0 = pickle.load(open("algorithms/gust_UDR_d0.al","rb"))
algo_g_d1 = pickle.load(open("algorithms/gust_UDR_d1.al","rb"))
algo_g_d2 = pickle.load(open("algorithms/gust_UDR_d2.al","rb"))

#load raw meteorological model and get model variables
meteo_model = get_meteogalicia_model_1Km(algo_g_d0["coor"])

#st.write(meteo_model)

#Select meteorological model wind features
w_g0 = meteo_model.wind_gust0*1.94384
dir0 = meteo_model.dir0
mod0 = meteo_model.mod0

#select x _var
model_x_var_g_d0 = meteo_model[:24][algo_g_d0["x_var"]]
model_x_var_g_d1 = meteo_model[24:48][algo_g_d1["x_var"]]
model_x_var_g_d2 = meteo_model[48:72][algo_g_d2["x_var"]]

#forecast machine learning  gust knots
gust_ml_d0 = (algo_g_d0["pipe"].predict(model_x_var_g_d0)*1.94384).round(0)
gust_ml_d1 = (algo_g_d1["pipe"].predict(model_x_var_g_d1)*1.94384).round(0)
gust_ml_d2 = (algo_g_d2["pipe"].predict(model_x_var_g_d2)*1.94384).round(0)

#load algorithm file dir
algo_dir_d0 = pickle.load(open("algorithms/dir_UDR_d0.al","rb"))
algo_dir_d1 = pickle.load(open("algorithms/dir_UDR_d1.al","rb"))
algo_dir_d2 = pickle.load(open("algorithms/dir_UDR_d2.al","rb"))

#select x _var
model_x_var_dir_d0 = meteo_model[:24][algo_dir_d0["x_var"]]
model_x_var_dir_d1 = meteo_model[24:48][algo_dir_d1["x_var"]]
model_x_var_dir_d2 = meteo_model[48:72][algo_dir_d2["x_var"]]

#forecast machine learning wind direction degrees
dir_ml_d0 = algo_dir_d0["pipe"].predict(model_x_var_dir_d0)
dir_ml_d1 = algo_dir_d1["pipe"].predict(model_x_var_dir_d1)
dir_ml_d2 = algo_dir_d2["pipe"].predict(model_x_var_dir_d2)

#load algorithm file spd
algo_spdb_d0 = pickle.load(open("algorithms/spd_udr_1km_d0.al","rb"))
algo_spdb_d1 = pickle.load(open("algorithms/spd_udr_1km_d1.al","rb"))
algo_spdb_d2 = pickle.load(open("algorithms/spd_udr_1km_d2.al","rb"))

#select x _var
model_x_var_spdb_d0 = meteo_model[:24][algo_spdb_d0["x_var"]]
model_x_var_spdb_d1 = meteo_model[24:48][algo_spdb_d1["x_var"]]
model_x_var_spdb_d2 = meteo_model[48:72][algo_spdb_d2["x_var"]]

#forecast machine learning wind intensity Beaufort
spdb_ml_d0 = algo_spdb_d0["pipe"].predict(model_x_var_spdb_d0)
spdb_ml_d1 = algo_spdb_d1["pipe"].predict(model_x_var_spdb_d1)
spdb_ml_d2 = algo_spdb_d2["pipe"].predict(model_x_var_spdb_d2)

#Udra wind
r_dir = requests.get("https://servizos.meteogalicia.gal/mgrss/observacion/ultimosHorariosEstacions.action?idEst=10905&idParam=DV_AVG_10m&numHoras=36")
json_data = json.loads(r_dir.content)
time, dir_o = [],[]
for c in json_data["listHorarios"]:
  for c1 in c['listaInstantes']:
    time.append(c1['instanteLecturaUTC'])
    dir_o.append(c1['listaMedidas'][0]["valor"])

r_spd = requests.get("https://servizos.meteogalicia.gal/mgrss/observacion/ultimosHorariosEstacions.action?idEst=10905&idParam=VV_AVG_10m&numHoras=36")
json_data = json.loads(r_spd.content)
spd_o = []
for c in json_data["listHorarios"]:
  for c1 in c['listaInstantes']:
    spd_o.append(c1['listaMedidas'][0]["valor"])

r_gust = requests.get("https://servizos.meteogalicia.gal/mgrss/observacion/ultimosHorariosEstacions.action?idEst=10905&idParam=VV_RACHA_10m&numHoras=36")
json_data = json.loads(r_gust.content)
gust_o = []
for c in json_data["listHorarios"]:
  for c1 in c['listaInstantes']:
    gust_o.append(c1['listaMedidas'][0]["valor"])

df_udr = pd.DataFrame({"Hora UTC":time, "spd_o":spd_o,"dir_o":dir_o,"gust_o":gust_o})
df_udr['Hora UTC'] = pd.to_datetime(df_udr['Hora UTC'])

#Wind directions intervals
interval_d = pd.IntervalIndex.from_tuples([(-0.5,20), (20, 40), (40, 60),
                                           (60,80),(80,100),(100,120),(120,140),(140,160),
                                           (160,180),(180,200),(200,220),(220,240),
                                           (240,260),(260,280),(280,300),(300,320),
                                           (320,340),(340,360)])
labels_d = ['[0, 20]', '(20, 40]', '(40, 60]','(60, 80]', '(80, 100]',
          '(100, 120]', '(120, 140]','(140, 160]', '(160, 180]', '(180, 200]',
          '(200, 220]','(220, 240]', '(240, 260]', '(260, 280]', '(280, 300]',
          '(300, 320]', '(320, 340]', '(340, 360]']
df_udr["dir_o_l"] = pd.cut(df_udr["dir_o"], bins = interval_d,retbins=False,
                        labels = labels_d).map({a:b for a,b in zip(interval_d,labels_d)}).astype(str)

#Wind intensity Beaufort
labels_b = ["F0","F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12"]
interval_b = pd.IntervalIndex.from_tuples([(-1, 0.5), (.5, 1.5), (1.5, 3.3),(3.3,5.5),
                                     (5.5,8),(8,10.7),(10.7,13.8),(13.8,17.1),
                                     (17.1,20.7),(20.7,24.4),(24.4,28.4),(28.4,32.6),(32.6,60)])
df_udr["spd_o_l"] = pd.cut(df_udr["spd_o"], bins=interval_b,retbins=False,
                        labels=labels_b).map({a:b for a,b in zip(interval_b,labels_b)})

#Wind gust to knots
df_udr["gust_o_l"] = round(df_udr.gust_o*1.94384,0)

#st.write(df_udr)

#compare results
df_show=pd.DataFrame({"ML dir": np.concatenate((dir_ml_d0,dir_ml_d1,dir_ml_d2),axis=0),
                      "ML spdb" : np.concatenate((spdb_ml_d0,spdb_ml_d1,spdb_ml_d2),axis=0),
                      "WRF dir": dir0,
                      "WRF spd": mod0,
                      "Hora UTC":meteo_model[:72].index,
                      "ML racha": np.concatenate((gust_ml_d0,gust_ml_d1,gust_ml_d2),axis=0),
                      "WRF racha":w_g0,
                      })

st.write("#### **Pronóstico viento en estación cabo Udra Modelo WRF de Meteogalicia y Machine Learning**")

#label wrf direction
df_show["dir_WRF_l"] = pd.cut(df_show["WRF dir"], bins=interval_d,retbins=False,
                        labels=labels_d).map({a:b for a,b in zip(interval_d,labels_d)}).astype(str)

#label wrf spd to Beaufort scale
df_show["spd_WRF_l"] = pd.cut(df_show["WRF spd"], bins=interval_b,retbins=False,
                        labels=labels_b).map({a:b for a,b in zip(interval_b,labels_b)})

df_show['Hora UTC'] = pd.to_datetime(df_show['Hora UTC'])
#st.write(df_show)

df_rw = pd.concat([df_show.set_index("Hora UTC"),df_udr.set_index("Hora UTC")],axis=1).dropna()
df_rw["Hora UTC"] = df_rw.index
#st.write(df_rw)

#accuracy
acc_ml = round(accuracy_score(df_rw.spd_o_l,df_rw["ML spdb"]),2)
acc_wrf = round(accuracy_score(df_rw.spd_o_l,df_rw["spd_WRF_l"]),2)
if acc_ml>acc_wrf:
  score_ml+=1
if acc_ml<acc_wrf:
  score_wrf+=1

st.write("###### **Intensidad del viento medio hora anterior fuerza Beaufort**")
#show results Beaufort intensity
fig, ax = plt.subplots(figsize=(10,6))
plt.plot(df_rw["Hora UTC"], df_rw['ML spdb'], marker="^", color="b",markersize=8,
         markerfacecolor='w', linestyle='')
plt.plot(df_rw["Hora UTC"], df_rw['spd_o_l'], marker="*", color="g",markersize=8,
         markerfacecolor='w', linestyle='')
plt.plot(df_rw["Hora UTC"], df_rw['spd_WRF_l'], color="r",marker="v", markersize=8,
         markerfacecolor='w', linestyle='');
plt.legend(('Beaufort ml', "Beaufort observada",'Beaufort WRF'),)
plt.grid(True)
plt.title("Precisión actual modelo meteorológico: {:.0%}. Referencia: 37%\nPrecisión actual machine learning: {:.0%}. Referencia: 54%".format(acc_wrf,acc_ml))
st.pyplot(fig)

st.write("###### **Intensidad del viento medio hora anterior fuerza Beaufort pronóstico a 72 horas**")
fig, ax = plt.subplots(figsize=(10,6))
plt.plot(df_show["Hora UTC"], df_show['ML spdb'], marker="^", color="b",markersize=8,
         markerfacecolor='w', linestyle='')
plt.plot(df_show["Hora UTC"], df_show['spd_WRF_l'], color="r",marker="v", markersize=8,
         markerfacecolor='w', linestyle='');
plt.legend(('Beaufort ml','Beaufort WRF'),)
plt.grid(True, which = "both", axis = "both")
st.pyplot(fig)

#probabilistic results
prob = (np.concatenate((algo_spdb_d0["pipe"].predict_proba(model_x_var_spdb_d0),
                        algo_spdb_d1["pipe"].predict_proba(model_x_var_spdb_d1),
                        algo_spdb_d2["pipe"].predict_proba(model_x_var_spdb_d2)),
                       axis =0)).transpose()
df_prob = pd.DataFrame(prob,index = (algo_spdb_d0["pipe"].classes_ )).T

# Find the columns where all values are less than or equal to 5%
cols_to_drop = df_prob.columns[df_prob.apply(lambda x: x <= 0.05).all()]
df_prob.drop(cols_to_drop, axis=1, inplace=True)

#new
df_prob.index = meteo_model[:72].index.strftime('%b %d %H:%M Z')

fig1, ax = plt.subplots()
sns.heatmap(df_prob[:24], annot=True, cmap='coolwarm',
            linewidths=.2, linecolor='black',fmt='.0%')
plt.title('Probabilidades intensidad del viento columnas con más del 5%')
st.pyplot(fig1)

fig2, ax = plt.subplots()
sns.heatmap(df_prob[24:48], annot=True, cmap='coolwarm',
            linewidths=.2, linecolor='black',fmt='.0%')
plt.title('Probabilidades intensidad del viento columnas con más del 5%')
st.pyplot(fig2)

fig3, ax = plt.subplots()
sns.heatmap(df_prob[48:72], annot=True, cmap='coolwarm',
            linewidths=.2, linecolor='black',fmt='.0%')
plt.title('Probabilidades intensidad del viento columnas con más del 5%')
st.pyplot(fig3)

st.write("###### **Dirección viento medio hora anterior (grados)**")

#accuracy
acc_ml = round(accuracy_score(df_rw.dir_o_l,df_rw["ML dir"]),2)
acc_wrf = round(accuracy_score(df_rw.dir_o_l,df_rw["dir_WRF_l"]),2)
if acc_ml>acc_wrf:
  score_ml+=1
if acc_ml<acc_wrf:
  score_wrf+=1

#cat_type = pd.CategoricalDtype(categories=interval_d, ordered=True)
#df_rw['ML dir'] = df_rw['ML dir'].astype(cat_type)

#show results wind direction
fig, ax = plt.subplots(figsize=(10,6))
plt.plot(df_rw["Hora UTC"], df_rw['ML dir'], marker="^", color="b",markersize=8,
         markerfacecolor='w', linestyle='')
plt.plot(df_rw["Hora UTC"], df_rw['dir_o_l'], marker="*", color="g",markersize=8,
         markerfacecolor='w', linestyle='')
plt.plot(df_rw["Hora UTC"], df_rw['dir_WRF_l'], color="r",marker="v", markersize=8,
         markerfacecolor='w', linestyle='');
plt.legend(('dirección ml', "dirección observada", 'dirección WRF'),)
plt.grid(True)
plt.title("Precisión actual modelo meteorológico: {:.0%}. Referencia: 26%\nPrecisión actual machine learning: {:.0%}. Referencia: 46%".format(acc_wrf,acc_ml))
st.pyplot(fig)

st.write("###### **Dirección del viento medio hora anterior intervalos grados pronóstico a 72 horas**")
fig, ax = plt.subplots(figsize=(10,6))
plt.plot(df_show["Hora UTC"], df_show['ML dir'], marker="^", color="b",markersize=8,
         markerfacecolor='w', linestyle='')
plt.plot(df_show["Hora UTC"], df_show['dir_WRF_l'], color="r",marker="v", markersize=8,
         markerfacecolor='w', linestyle='');
plt.legend(('Direccion ml','Dirección WRF'),)
plt.grid(True, which = "both", axis = "both")
st.pyplot(fig)

#probabilistic results
prob = (np.concatenate((algo_dir_d0["pipe"].predict_proba(model_x_var_dir_d0),
                        algo_dir_d1["pipe"].predict_proba(model_x_var_dir_d1),
                        algo_dir_d2["pipe"].predict_proba(model_x_var_dir_d2)),
                       axis =0)).transpose()
df_prob = pd.DataFrame(prob,index = (algo_dir_d0["pipe"].classes_ )).T
df_prob = df_prob[labels_d]

# Find the columns where all values are less than or equal to 5%
cols_to_drop = df_prob.columns[df_prob.apply(lambda x: x <= 0.05).all()]
df_prob.drop(cols_to_drop, axis=1, inplace=True)

#new
df_prob.index = meteo_model[:72].index.strftime('%b %d %H:%M Z')

fig1, ax = plt.subplots()
sns.heatmap(df_prob[:24], annot=True, cmap='coolwarm',
            linewidths=.2, linecolor='black',fmt='.0%')
plt.title('Probabilidades dirección del viento columnas con más del 5%')
st.pyplot(fig1)

fig2, ax = plt.subplots()
sns.heatmap(df_prob[24:48], annot=True, cmap='coolwarm',
            linewidths=.2, linecolor='black',fmt='.0%')
plt.title('Probabilidades dirección del viento columnas con más del 5%')
st.pyplot(fig2)

fig3, ax = plt.subplots()
sns.heatmap(df_prob[48:72], annot=True, cmap='coolwarm',
            linewidths=.2, linecolor='black',fmt='.0%')
plt.title('Probabilidades dirección del viento columnas con más del 5%')
st.pyplot(fig3)

#show results wind gust
#mae
mae_ml = round(mean_absolute_error(df_rw["gust_o_l"],df_rw["ML racha"]),2)
mae_wrf = round(mean_absolute_error(df_rw["gust_o_l"],df_rw["WRF racha"]),2)
if mae_ml < mae_wrf:
  score_ml+=1
if mae_ml > mae_wrf:
  score_wrf+=1

st.write("###### **Racha máxima hora anterior (nudos)**")
fig, ax = plt.subplots(figsize=(10,6))
df_rw.set_index("Hora UTC")[["ML racha","WRF racha","gust_o_l"]].plot(grid=True, ax=ax, color=["b","r","g"], linestyle='--');
ax.set_title("Error absoluto medio actual con modelo meteorológico: {}. Referencia: 2.1\nError absoluto medio actual con machine learning: {}. Referencia: 1.4".format(mae_wrf,mae_ml))
plt.grid(True, which = "both", axis = "both")
st.pyplot(fig)

st.write("###### **Racha máxima hora anterior (nudos) pronóstico 72 horas**")
fig, ax = plt.subplots(figsize=(10,6))
df_show.set_index("Hora UTC")[["ML racha","WRF racha"]].plot(grid=True, ax=ax, color=["b","r"], linestyle='--')
plt.grid(True, which = "both", axis = "both")
st.pyplot(fig)

#Download excel file
#st.markdown(get_table_download_link(df_show),unsafe_allow_html=True)

st.write("###### **Información complementaria:**")
#map
if st.checkbox("Mapa situación estación meteorológica cabo Udra y puntos modelo WRF (1 Km) Meteogalicia"):
  px.set_mapbox_access_token("pk.eyJ1IjoiZ3JhbmFudHVpbiIsImEiOiJja3B4dGU4OTkwMTFmMm9ycnNhMjJvaGJqIn0.VWzx_PkD9A5cSUVsn_ijCA")
  dist_map=px.scatter_mapbox(algo_g_d0["coor"], hover_data=['distance'],lat='lat', lon='lon',color='distance',
                             color_continuous_scale=px.colors.cyclical.IceFire,)
  st.plotly_chart(dist_map)

#link to actual Udra station data
today_s=pd.to_datetime("today").strftime("%d/%m/%Y)")
st.write("Estación Udra en tiempo real [enlace](https://www.meteogalicia.gal/observacion/meteovisor/indexChartDezHoxe.action?idEstacion=10905&dataSeleccionada="+today_s)

#download quality report
with open("reports/informe_wind.pdf", "rb") as pdf_file:
    PDFbyte = pdf_file.read()
st.download_button(label="Descargar informe del algoritmo de viento",
                    data=PDFbyte,
                    file_name="informe_wind.pdf",
                    mime='application/octet-stream')

#Precipitation
#load algorithm file precipitation marin d0 d1
algo_prec_d0 = pickle.load(open("algorithms/prec_ENM_d0.al","rb"))
algo_prec_d1 = pickle.load(open("algorithms/prec_ENM_d1.al","rb"))
algo_prec_d2 = pickle.load(open("algorithms/prec_ENM_d2.al","rb"))
algo_prec_d3 = pickle.load(open("algorithms/prec_ENM_d3.al","rb"))

#load raw meteorological model and get model variables
meteo_model = get_meteogalicia_model_4Km(algo_prec_d1["coor"])

#select x _var
model_x_var_p0 = meteo_model[:24][algo_prec_d0["x_var"]]
model_x_var_p1 = meteo_model[24:48][algo_prec_d1["x_var"]]
model_x_var_p2 = meteo_model[48:72][algo_prec_d2["x_var"]]
model_x_var_p3 = meteo_model[72:96][algo_prec_d2["x_var"]]

#forecast machine learning precipitation
prec_ml0 = algo_prec_d0["pipe"].predict_proba(model_x_var_p0)
prec_ml1 = algo_prec_d1["pipe"].predict_proba(model_x_var_p1)
prec_ml2 = algo_prec_d2["pipe"].predict_proba(model_x_var_p2)
prec_ml3 = algo_prec_d3["pipe"].predict_proba(model_x_var_p3)

#show results
df_show_pre = pd.DataFrame(np.concatenate((prec_ml0,prec_ml1,prec_ml2,prec_ml3),axis=0),
                         columns=["no p","ML"])
df_show_pre["Hora UTC"] = meteo_model.index[0:96]
df_show_pre["WRF"] = np.around(meteo_model[:96].prec0.values,decimals=1)
df_show_pre = df_show_pre.drop(columns=["no p"])
df_show_pre['ML'] = round(df_show_pre['ML'],2)
df_show_pre['Hora UTC'] = pd.to_datetime(df_show_pre['Hora UTC']).map(lambda t: t.strftime('%d-%m %H'))

#Marin Precipitation and wind
r = requests.get("https://servizos.meteogalicia.gal/mgrss/observacion/ultimosHorariosEstacions.action?idEst=14005&idParam=PP_SUM_1.5m&numHoras=24")

json_data = json.loads(r.content)
time, prec_o = [],[]
for c in json_data["listHorarios"]:
  for c1 in c['listaInstantes']:
    time.append(c1['instanteLecturaUTC'])
    prec_o.append(c1['listaMedidas'][0]["valor"])

df_mar = pd.DataFrame({"time":time,"prec_o":prec_o})
df_mar['time'] = pd.to_datetime(df_mar['time']).map(lambda t: t.strftime('%d-%m %H'))

#rain

df_final = pd.concat([df_mar.set_index("time"),df_show_pre.set_index("Hora UTC")],axis=1)

df_final["prec_o"] = df_final["prec_o"].fillna(0)
df_final[["prec_o","WRF"]].dropna()
#st.write(df_final)

st.write("#### **Pronóstico de precipitación del modelo WRF y precipitación observada**")
fig, ax = plt.subplots(figsize=(10,8))
df_final[["WRF","prec_o"]].dropna()[0:31].plot(ax=ax,ylim =[0, None], grid=True, kind='bar')
st.pyplot(fig)

st.write("#### **Probabilidad de precipitación machine learning**")
fig, ax = plt.subplots(figsize=(10,8))
df_final["ML"] = df_final["ML"].round(1)
df_final["ML"].dropna()[0:31].plot(ax=ax, grid=True,ylim =[0, 1], kind='bar')
st.pyplot(fig)

st.write("#### **Pronóstico de precipitación del modelo WRF**")
fig, ax = plt.subplots(figsize=(10,8))
df_final["WRF"].dropna()[30:].plot(ax=ax, ylim =[0, None],grid=True, kind='bar')
st.pyplot(fig)

st.write("#### **Probabilidad de precipitación machine learning**")
fig, ax = plt.subplots(figsize=(10,8))
df_final["ML"] =df_final["ML"].round(1)
df_final["ML"].dropna()[30:].plot(ax=ax, ylim =[0, 1], grid=True, kind='bar')
st.pyplot(fig)

#download  excel file
#st.markdown(get_table_download_link(df_show_pre),unsafe_allow_html=True)

st.write("###### **Información complementaria:**")
#map
if st.checkbox("Mapa situación ENM y puntos modelo WRF (4 Km) Meteogalicia"):
  px.set_mapbox_access_token("pk.eyJ1IjoiZ3JhbmFudHVpbiIsImEiOiJja3B4dGU4OTkwMTFmMm9ycnNhMjJvaGJqIn0.VWzx_PkD9A5cSUVsn_ijCA")
  dist_map=px.scatter_mapbox(algo_prec_d1["coor"], hover_data=['distance'],
                             lat='lat', lon='lon',color='distance',
                             color_continuous_scale=px.colors.cyclical.IceFire,)
  st.plotly_chart(dist_map)

#link to actual  Marin station data
st.write("Estación Marín en tiempo real [enlace](https://www.meteogalicia.gal/observacion/meteovisor/indexChartDezHoxe.action?idEstacion=14005&dataSeleccionada="+today_s)

#download quality report
with open("reports/informe_prec.pdf", "rb") as pdf_file:
    PDFbyte = pdf_file.read()
st.download_button(label="Descargar informe del algoritmo de precipitación",
                    data=PDFbyte,
                    file_name="informe_prec.pdf",
                    mime='application/octet-stream')

st.write("#### **Resultado global**")
st.write("Mejor modelo meteorológico: {}".format(score_wrf))
st.write("Mejor machine learning: {}".format(score_ml))


import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import hilbert
from scipy import angle, unwrap

from math import pi

x = np.linspace(-5 * pi, 5 * pi, 10000)
s1 = np.sin(x)
s2 = np.sin(x) - 0.5
s3 = np.sin(x) + 2

hs1 = hilbert(s1)
hs2 = hilbert(s2)
hs3 = hilbert(s3)

omega_s1 = unwrap(angle(hs1))  # unwrapped instantaneous phase
omega_s2 = unwrap(angle(hs2))
omega_s3 = unwrap(angle(hs3))

f_inst_s1 = np.diff(omega_s1)  # instantaneous frequency
f_inst_s2 = np.diff(omega_s2)
f_inst_s3 = np.diff(omega_s3)

plt.plot(x[1:], f_inst_s1, "b")
plt.plot(x[1:], f_inst_s2, "g")
plt.plot(x[1:], f_inst_s3, "r")
plt.xlim(-5 * np.pi, 5 * np.pi)
plt.grid()
plt.show()


# Python program to calculate number of days between two dates.

# My solution...

from datetime import date

dateFrom = date(2021, 12, 8)
dateTo = date(2021, 12, 17)
daysBetween = dateTo - dateFrom
print("There are " + str(daysBetween.days) + " days between " + str(dateFrom.strftime("%B ")) + str(dateFrom.day) + " and " + str(dateTo.strftime("%B ")) + str(dateTo.day) + ".")

# It works!

# Example solution...

from datetime import date
f_date = date(2014, 7, 2)
l_date = date(2014, 7, 11)
delta = l_date - f_date
print(delta.days)


import logging

import numpy as np
import pandas as pd
from sortedcontainers import SortedSet, SortedDict

from core.utilities.type_aliases import Float, Vector

"""
The parsers are used for tabular separated files.

The file with the list of transcription factors, must contain the headers
'source' for the name of the transcription factor and 'target' for the name of
the transcription factor on which has influence.

The patient data must be a tabular file with the following headers
["source", "t0", "t1", ..., "tn"]

The time sequence must be a tabular file with the following headers
["t0", "t1", ..., "tn"]

The perturbations files must be a tabular file with the following headers
["<source1>, ..., "<source_n>", "t_start", "t_end"]
"""

__author__ = "Guido Pio Mariotti"
__copyright__ = "Copyright (C) 2016 Guido Pio Mariotti"
__license__ = "GNU General Public License v3.0"
__version__ = "0.1.0"

def parse_network(filename: str, sep: str = "\t") -> SortedDict:
    # expected headers in a network file
    h_source = "source"
    h_target = "target"

    net_file = pd.read_csv(filename, sep=sep)
    network = SortedDict()
    if not {h_source, h_target}.issubset(net_file.columns):
        logging.getLogger(__name__).error(
            "Missing headers {} and/or {} in {}".format(
                h_source, h_target, filename
            ))
        raise AttributeError("Not valid network headers, check log.")

    for (index, series) in net_file.iterrows():
        target = series[h_target]
        source = series[h_source]
        if source not in network.keys():
            network[source] = SortedSet()
        network[source].add(target)

    return network

def parse_network_data(filename: str, sep: str = "\t",
                       d_type: np.dtype = Float) -> SortedDict:
    # expected headers in a network data file
    h_source = "source"

    data = pd.read_csv(filename, sep=sep)
    if h_source not in data.columns:
        logging.getLogger(__name__).error(
            "Missing header {} in {}".format(h_source, filename)
        )
        raise AttributeError("Not valid data headers, check log.")

    # check that the correct time headers are present
    columns = len(data.columns)
    valid_t_headers = set(["t{}".format(i) for i in range(0, columns - 1)])
    if not valid_t_headers.issubset(data.columns):
        logging.getLogger(__name__).error(
            "Expected headers for time are {}".format(valid_t_headers)
        )
        raise AttributeError("Not valid data headers, check log.")

    data_dictionary = SortedDict(
        {value[h_source]: np.array(value.drop([h_source]).values, dtype=d_type)
         for (i, value) in data.iterrows()
         }
    )

    return data_dictionary

def parse_time_sequence(filename: str, sep: str = "\t",
                        d_type: np.dtype = Float) -> Vector:
    times = pd.read_csv(filename, sep=sep)
    # check validity of headers
    columns = len(times.columns)
    valid_headers = set(["t{}".format(i) for i in range(0, columns)])
    if not valid_headers.issubset(times.columns):
        logging.getLogger(__name__).error(
            "Expected headers for time series are {}".format(valid_headers)
        )
        raise AttributeError("Not valid time series headers, check log.")

    return np.array(times.values, dtype=d_type).flatten()

def parse_perturbations_data(filename: str, sep: str = "\t") -> Vector:
    perturbations = pd.read_csv(filename, sep=sep)

    # check validity of times headers
    h_tstart = "t_start"
    h_tend = "t_end"
    start_idx = len(perturbations.columns) - 2
    # takes the list of the last two headers
    headers = set(perturbations.ix[:, start_idx:].columns)
    valid_headers = {h_tstart, h_tend}
    if headers != valid_headers:
        # they are not the same set
        logging.getLogger(__name__).error(
            "Expected last two headers for perturbations are {}".format(
                valid_headers
            ))
        raise AttributeError("Not valid perturbations headers, check log.")

    return perturbations.values


from menu import *

if __name__ == "__main__":
    greeting()
    player_choice = input("""Type:
     START GAME - type 's' to begin your journey
     CONTINUE GAME - type 'c' to begin your journey """)
    status = True
    while status is True:
        if player_choice == "s":
            player, backpack, player_sack = create_character()
            in_game_menu(player, player_sack, backpack)
            status = False
        elif player_choice == "c":
            print("This feature is not working yet")
        else:
            player_choice = input("""Type 'start game' to begin your journey""")


from collections import Counter

class KarunAI:

    def calculate_best_split(self, investment_size : float,opportunities : list[tuple] = []) -> tuple[dict, float]:
        opportunities = merge_pools(opportunities)
        names = [n for _, _, n in opportunities]
        opportunities = [(p, r) for p, r, _ in opportunities]
        num_opportunities = len(opportunities)

        dp = [[0] * (investment_size + 1) for _ in range(num_opportunities + 1)]
        parent = [[None] * (investment_size + 1) for _ in range(num_opportunities + 1)]

        for i in range(num_opportunities + 1):
            dp[i][0] = 0
            parent[i][0] = 0

        for i in range(investment_size + 1):
            dp[0][i] = 0
            parent[0][i] = 0

        for i in range(1, num_opportunities + 1):
            print(f"Analyzing opportunity {i}/{num_opportunities}")
            for j in range(1, investment_size + 1):
                m, mk = 0, None
                for k in range(0, j+1):
                    cand = dp[i-1][j-k] + returns(*opportunities[i-1], k)
                    if cand > m:
                        m = cand
                        mk = k
                dp[i][j] = m
                parent[i][j] = mk

        i = num_opportunities
        j = investment_size

        allocations = []
        while j >= 0 and i > 0:
            allocations = [parent[i][j]] + allocations
            j -= parent[i][j]
            i -= 1
        allocations = {names[i]: allocations[i] for i in range(len(opportunities))}

        return allocations, dp[-1][-1]

def merge_pools(opps):
        rewards = Counter()
        for ind, (pool, reward, name) in enumerate(opps):
            rewards[(name, pool)] += reward
        return [(p, r, n) for (n, p), r in rewards.items()]

def returns(p : float, r : float, x : float) -> float:
    return x / (p + x) * r


""" Advisory exclusive DAV-style locks for content objects.

When a resource is locked, it is presumed that its SDI UI will display a
warning to users who do not hold the lock.  The locking service can also be
used by add-ons such as DAV implementations.
"""

import datetime
import uuid
import pytz

from zope.interface import implementer

from persistent import Persistent

import colander
import deform.widget

from pyramid.location import lineage
from pyramid.security import has_permission
from pyramid.threadlocal import get_current_registry
from pyramid.traversal import resource_path

from substanced.interfaces import (
    ILock,
    ILockService,
    WriteLock,
    UserToLock,
    )
from substanced.content import (
    content,
    service
    )
from substanced.folder import (
    _AutoNamingFolder,
    Folder,
    )
from substanced.objectmap import (
    reference_target_property,
    reference_targetid_property,
    )
from substanced.property import PropertySheet
from substanced.util import (
    find_objectmap,
    find_service,
    get_oid,
    )
from substanced.schema import Schema
from substanced._compat import INT_TYPES

class LockingError(Exception):
    def __init__(self, lock):
        self.lock = lock

class LockError(LockingError):
    """ Raised when a lock cannot be created due to a conflicting lock.

    Instances of this class have a ``lock`` attribute which is a
    :class:`substanced.locking.Lock` object, representing the conflicting
    lock.
    """

class UnlockError(LockingError):
    """ Raised when a lock cannot be removed

    This may be because the owner suplied in the unlock request does not
    match the owner of the lock, or becaues the lock no longer exists.

    Instances of this class have a ``lock`` attribute which is a
    :class:`substanced.locking.Lock` object, representing the conflicting lock,
    or ``None`` if there was no lock to unlock.
    """

def now():
    return datetime.datetime.utcnow().replace(tzinfo=pytz.UTC)

class LockOwnerSchema(colander.SchemaNode):
    title = 'Owner'
    schema_type = colander.Int

    @property
    def widget(self):
        context = self.bindings['context']
        principals = find_service(context, 'principals')
        if principals is None:
            values = [] # fbo dump/load
        else:
            values = [(get_oid(group), name) for name, group in
                      principals['users'].items()]
        return deform.widget.Select2Widget(values=values)

    def validator(self, node, value):
        context = self.bindings['context']
        objectmap = find_objectmap(context)
        if not value in objectmap.objectid_to_path:
            raise colander.Invalid(node, 'Not a valid userid %r' % value)

class LockResourceSchema(colander.SchemaNode):
    title = 'Resource Path'
    schema_type = colander.String
    widget = deform.widget.TextInputWidget()
    missing = colander.null

    def preparer(self, value):
        context = self.bindings['context']
        request = self.bindings['request']
        objectmap = find_objectmap(context)
        if value is colander.null:
            return colander.null
        try:
            resource = objectmap.object_for(tuple(value.split('/')))
        except ValueError:
            return None
        if not has_permission('sdi.lock', resource, request):
            return False
        return resource

    def validator(self, node, value):
        if value is None:
            raise colander.Invalid(node, 'Resource not found')
        if value is False:
            raise colander.Invalid(
                node,
                'You do not have permission to lock this resource'
                )

class LockSchema(Schema):
    ownerid = LockOwnerSchema()
    timeout = colander.SchemaNode(
        colander.Int(),
        validator=colander.Range(0),
        default=3600,
        title='Timeout (secs)',
        )
    infinite = colander.SchemaNode(
        colander.Boolean(),
        default=False,
        missing=False,
        title='Infinite?',
        description='Locks all descendants',
        )
    last_refresh = colander.SchemaNode(
        colander.DateTime(),
        title='Last Refresh',
        default=now(),
        )
    comment = colander.SchemaNode(
        colander.String(),
        validator=colander.Length(max=255),
        missing=None,
        title='Comment',
        )
    resource = LockResourceSchema()

class LockPropertySheet(PropertySheet):
    schema = LockSchema()

    def get(self):
        result = PropertySheet.get(self)
        resource = result.get('resource')
        if resource is None:
            resource = colander.null
        else:
            resource = resource_path(resource)
        result['resource'] = resource
        return result

    def set(self, appstruct):
        resource = appstruct.get('resource')
        if resource is colander.null:
            appstruct['resource'] = None
        return PropertySheet.set(self, appstruct)

@content(
    'Lock',
    icon='glyphicon glyphicon-lock',
    add_view='add_lock',
    )
@implementer(ILock)
class Lock(Persistent):
    """ A persistent object representing a lock.
    """
    owner = reference_target_property(UserToLock)
    resource = reference_target_property(WriteLock)
    ownerid = reference_targetid_property(UserToLock)
    resourceid = reference_targetid_property(WriteLock)

    def __init__(self,
                 infinite=False,
                 timeout=3600,
                 comment=None,
                 last_refresh=None,
                ):
        self.timeout = timeout
        self.comment=comment
        self.infinite = infinite
        # last_refresh must be a datetime.datetime object with a UTC tzinfo,
        # if provided
        if last_refresh is None:
            last_refresh = now()
        self.last_refresh = last_refresh

    def refresh(self, timeout=None, when=None): # "when" is for testing
        """ Refresh the lock.

        If the timeout is not None, set the timeout for this lock too.
        """
        if timeout is not None:
            self.timeout = timeout
        if when is None: # pragma: no cover
            when = now()
        self.last_refresh = when

    def expires(self):
        """ Return the future datetime at which this lock will expire.

        For invalid locks, the returned value indicates the point in the past
        at which the lock expired.
        """
        if self.timeout is None:
            return None
        return self.last_refresh + datetime.timedelta(seconds=self.timeout)

    def is_valid(self, when=None):
        """ Return True if the lock has not expired and its resource exists.
        """
        objectmap = find_objectmap(self)
        if objectmap is not None:
            # might be None if we're not yet seated
            if self.resourceid is None:
                return False
        if when is None: # pragma: no cover
            when = now()
        expires = self.expires()
        if expires is None:
            return True
        return expires >= when

    @property
    def depth(self):
        return 'infinity' if self.infinite else '0'

    def commit_suicide(self):
        """ Remove this lock from the lock service.
        """
        del self.__parent__[self.__name__]

@service(
    'Lock Service',
    icon='glyphicon glyphicon-briefcase',
    service_name='locks',
    add_view='add_lock_service',
    )
@implementer(ILockService)
class LockService(Folder, _AutoNamingFolder):
    __sdi_addable__ = ('Lock',)

    def next_name(self, subobject):
        lock_id = str(uuid.uuid4())
        return lock_id

    def _get_ownerid(self, owner_or_ownerid):
        ownerid = get_oid(owner_or_ownerid, None)
        if ownerid is None:
            ownerid = owner_or_ownerid
        if not isinstance(ownerid, INT_TYPES):
            raise ValueError(
                'Bad value for owner_or_ownerid %r' % owner_or_ownerid
                )
        return ownerid

    def borrow_lock(
        self,
        resource,
        owner_or_ownerid,
        locktype=WriteLock,
        ):
        """ Search for an existing, avlid lock on resource.

        If not found, return None.

        If owned by 'owner_or_ownerid', return it.

        Otherwise, raise LockError.
        """
        objectmap = find_objectmap(self)
        ownerid = self._get_ownerid(owner_or_ownerid)
        locks = objectmap.targets(resource, locktype)
        for lock in locks:
            if lock.is_valid():
                if lock.ownerid == ownerid:
                    return lock
                else:
                    raise LockError(lock)
            else:
                lock.commit_suicide()
                break

    def lock(
        self,
        resource,
        owner_or_ownerid,
        timeout=None,
        comment=None,
        locktype=WriteLock,
        infinite=False,
        ):
        # NB: callers should ensure that the user has 'sdi.lock' permission
        # on the resource before calling

        lock = self.borrow_lock(resource, owner_or_ownerid, locktype)
        if lock is not None:
            when = now()
            lock.refresh(timeout, when)
            return lock

        registry = get_current_registry()
        lock = registry.content.create('Lock',
                                       )
        self.add_next(lock) # NB: must add before setting ownerid/resource
        lock.ownerid = self._get_ownerid(owner_or_ownerid)
        lock.resource = resource
        lock.timeout = timeout
        lock.comment = comment
        lock.infinite = infinite
        return lock

    def unlock(
        self,
        resource,
        owner_or_ownerid,
        locktype=WriteLock,
        ):

        # NB: callers should ensure that the user has 'sdi.lock' permission
        # on the resource before calling
        objectmap = find_objectmap(self)
        ownerid = self._get_ownerid(owner_or_ownerid)
        locks = objectmap.targets(resource, locktype)
        lock = None
        for lock in locks:
            if not lock.is_valid():
                lock.commit_suicide()
            elif lock.ownerid == ownerid:
                lock.commit_suicide()
                break
        else: # nobreak
            raise UnlockError(lock)

    def unlock_token(
        self,
        token,
        owner_or_ownerid,
        ):

        # NB: callers should ensure that the user has 'sdi.lock' permission
        # on the resource before calling
        ownerid = self._get_ownerid(owner_or_ownerid)
        lock = self.get(token)
        if lock is None:
            raise UnlockError(None)
        if not lock.is_valid():
            lock.commit_suicide()
            raise UnlockError(None)
        if lock.ownerid != ownerid:
            raise UnlockError(lock)
        lock.commit_suicide()

    def discover(self, resource,
                 include_invalid=False,
                 include_lineage=True,
                 locktype=WriteLock):
        objectmap = find_objectmap(self)
        valid = []
        if include_lineage:
            resources = lineage(resource)
        else:
            resources = [resource]
        for res in resources:
            locks = objectmap.targets(res, locktype)
            for lock in locks:
                if include_invalid or lock.is_valid():
                    valid.append(lock)
        return valid

def _get_lock_service(resource):
    locks = find_service(resource, 'locks')
    if locks is None:
        raise ValueError('No lock service in lineage')
    return locks

def lock_resource(
    resource,
    owner_or_ownerid,
    timeout=None,
    comment=None,
    locktype=WriteLock,
    infinite=False,
    ):
    """ Lock a resource using the lock service.

    If the resource is already locked by the owner supplied as
    owner_or_ownerid, refresh the lock using ``timeout``.

    If the resource is not already locked by another user, create a new lock
    with the given values.

    If the resource is already locked by a different user, raise a
    :class:`substanced.locking.LockError`

    If a Lock Service does not already exist in the lineage, a
    :exc:`ValueError` will be raised.

    .. warning::

       Callers should assert that the owner has the ``sdi.lock`` permission
       against the resource before calling this function to ensure that a user
       can't lock a resource he is not permitted to.

    """
    locks = _get_lock_service(resource)
    return locks.lock(
        resource,
        owner_or_ownerid,
        timeout=timeout,
        comment=comment,
        locktype=locktype,
        infinite=infinite,
        )

def could_lock_resource(
    resource,
    owner_or_ownerid,
    locktype=WriteLock,
    ):
    """ Check that a given owner could lock a resource using the lock service.

    If the resource is already locked by the owner supplied as
    owner_or_ownerid, calling this function will *not* refresh the lock.

    If the resource is not already locked by another user, calling this
    function will *not* create a new lock.

    If the resource is already locked by a different user, raise a
    :class:`substanced.locking.LockError`.

    If a Lock Service does not already exist in the lineage, a
    :exc:`ValueError` will be raised.

    .. warning::

       Callers should assert that the owner has the ``sdi.lock`` permission
       against the resource before calling this function to ensure that a user
       can't lock a resource he is not permitted to.
    """
    locks = _get_lock_service(resource)
    locks.borrow_lock(
        resource,
        owner_or_ownerid,
        locktype=locktype,
        ) # may raise LockError
    return True

def unlock_resource(
    resource,
    owner_or_ownerid,
    locktype=WriteLock,
    ):
    """ Unlock a resource using the lock service.

    If the resource is already locked by a user other than the owner supplied
    as ``owner_or_ownerid`` or the resource isn't already locked with this
    lock type, raise a :class:`substanced.locking.UnlockError` exception.

    Otherwise, remove the lock.

    If a Lock Service does not already exist in the lineage, a
    :exc:`ValueError` will be raised.

        .. warning::

           Callers should assert that the owner has the ``sdi.lock`` permission
           against the resource before calling this function to ensure that a
           user can't lock a resource he is not permitted to.

    """

    locks = _get_lock_service(resource)
    return locks.unlock(
        resource,
        owner_or_ownerid,
        locktype=locktype
        )

def unlock_token(
    resource,
    token,
    owner_or_ownerid,
    ):
    """ Remove a lock from the lock service based on its token.

    If the lock is owned by a user user other than the owner supplied as
    ``owner_or_ownerid`` or ``token`` doesn't identfiy a valid lock,
    raise a :class:`substanced.locking.UnlockError` exception.

    Otherwise remove the lock indicated by ``token``.

    If a Lock Service does not already exist in the lineage, a
    :exc:`ValueError` will be raised.

        .. warning::

           Callers should assert that the owner has the ``sdi.lock`` permission
           against the resource before calling this function to ensure that a
           user can't lock a resource he is not permitted to.

    """

    locks = _get_lock_service(resource)
    return locks.unlock_token(
        token,
        owner_or_ownerid,
        )

def discover_resource_locks(
    resource,
    include_invalid=False,
    include_lineage=True,
    locktype=WriteLock,
    ):
    """ Return locks related to ``resource`` for the given ``locktype``.

    Return a sequence of :class:`substanced.locking.Lock` objects.

    By default, only valid locks are returned.

    Invalid locks for the resource may exist, but they are not
    returned unless ``include_invalid`` is ``True``.

    Under normal circumstances, the length of the sequence returned will be
    either 0 (if there are no locks) or 1 (if there is any lock).

    In some special circumstances, however, when the
    :class:`substanced.locking.lock_resource` API is not used to create locks,
    there may be more than one lock of the same type related to a resource.
    """
    locks = _get_lock_service(resource)
    return locks.discover(
        resource,
        include_invalid=include_invalid,
        include_lineage=include_lineage,
        locktype=locktype
        )

def includeme(config): # pragma: no cover
    config.add_permission('sdi.lock')
    config.add_propertysheet('', LockPropertySheet, ILock)
    config.include('.views')
    config.include('.evolve')


import json

import typer
import jq
import subprocess
import sys
app = typer.Typer()

@app.callback(invoke_without_command=True)
def main(
    value: str = typer.Option(...,"--file", "-f", allow_dash=True, help="File containing jsonln or - for stdin"),
    input: str = typer.Option(..., "--input", "-i", help="jq filter to select input you want to pass to the provided command"),
    output: str = typer.Option(..., "--output", "-o", help="key you would like to inject the command output into"),
    command: str = typer.Option(..., "--command", "-c", help="command you want to execute can contain pipes"),
    replstr: str = typer.Option("{}", "--replstr", "-I", help="Replace string with input data in the command (think xargs -I)"),
    json_command: bool = typer.Option(False, "--jsoncommand", "-j", help="If the command outputs json set this flag"),
    pipe: bool = typer.Option(False, "--pipe", "-p", help="If the input needs to be piped into your command use this flag"),
    array: bool = typer.Option(False, "--array", "-a", help="should the output be split on newlines or as a raw string?"),
):
    if value == "-":
        file = sys.stdin
    else:
        file = open(value, encoding='utf-8')
    for index, line in enumerate(file):
        parsed = json.loads(line)
        input_value = jq.compile(input).input(parsed).first()
        # if array:
        #     typer.echo(f"Good day Ms. {input}.")
        # else:
        if pipe:
            output_value = subprocess.run(command, shell=True, capture_output=True, input=input_value,
                    text=True)
        else:
            final_command = command.replace(replstr, input_value)
            output_value = subprocess.run(final_command, shell=True,text=True, capture_output=True)
        if json_command:
            results = json.loads(output_value.stdout)
        else:
            if array:
                results = output_value.stdout.rstrip("\n").split("\n")
            else:
                results = output_value.stdout
        parsed[output] = results
        typer.echo(json.dumps(parsed))
    file.close()

if __name__ == "__main__":
    app()


#Frequency-based Filtering
import cv2, numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('C:\Lena.png',0).astype(np.float32) / 255

fft = cv2.dft(img, flags=cv2.DFT_COMPLEX_OUTPUT)
fft_shift = np.fft.fftshift(fft, axes=[0,1])
sz =  25
mask = np.zeros(fft.shape, np.uint8)
mask[img.shape[0]//2-sz:img.shape[0]//2+sz,
     img.shape[1]//2-sz:img.shape[1]//2+sz, :] = 1
fft_shift *= mask #1-mask
fft = np.fft.ifftshift(fft_shift, axes=[0, 1])

filtered = cv2.idft(fft, flags=cv2.DFT_SCALE | cv2.DFT_REAL_OUTPUT)
mask_new = np.dstack((mask, np.zeros((img.shape[0],img.shape[1]), dtype=np.uint8)))

plt.figure()
plt.subplot(131)
plt.axis('off')
plt.title('original')
plt.imshow(img, cmap='gray')
plt.subplot(132)
plt.axis('off')
plt.title('no high frequencies')
plt.imshow(filtered, cmap='gray')
plt.subplot(133)
plt.axis('off')
plt.title('mask')
plt.imshow(mask_new*255, cmap='gray')

plt.tight_layout(True)
plt.show()


# -*- coding: UTF-8 -*-
import sys

class Validate(object):
    @classmethod
    def parse(cls, argv):
        return cls()

    def process(self, iterable):
        try:
            for collection in iterable:
                errors = []
                previous = None
                i = 0
                total = len(collection['ways'])
                for way in collection['ways']:
                    i += 1
                    if previous == None:
                        previous = way
                    else:
                        # check that the first ref is the same as the last of the previous
                        if way['refs'][0] != previous['refs'][-1]:
                            errors.append('{} of {}. Way {} first refs {} != previous way {} last refs {}'.format(i, total, way['id'], way['refs'][0], previous['id'], previous['refs'][-1]))

                        # check that the first coord is the same as the last of the previous
                        if way['coords'][0] != previous['coords'][-1]:
                            errors.append('{} of {}. Way {} first coord {} != previous way {} last coord {}'.format(i, total, way['id'], way['coords'][0], previous['id'], previous['coords'][-1]))

                        # check that the start of our first segment matches the end of the last way's last segment.
                        if 'segments' in way and way['segments'][0]['start'] != previous['segments'][-1]['end']:
                            errors.append('{} of {}. Way {} first segment start {} != previous way {} last segment end {}'.format(i, total, way['id'], way['segments'][0]['start'], previous['id'], previous['segments'][-1]['end']))

                        # On the the next.
                        previous = way

            if len(errors):
                i = 0
                for way in collection['ways']:
                    i += 1
                    sys.stderr.write("{} of {}, id: {}, first_ref: {}, last_ref: {}\n".format(i, total, way['id'], way['refs'][0], way['refs'][-1]))
                sys.stderr.write("\n")
                for error in errors:
                    sys.stderr.write("Error: {}\n".format(error))
        except:
            e = sys.exc_info()[0]
            errors.append('Exception: {}\nCollection: {}'.format(e, collection))
        yield collection


import os
import pandas as pd
from detect_delimiter import detect
from utils import load_json

def check_dir_files_type(baseaddr):
    all_folder = None

    for f in os.listdir(baseaddr):
        if os.path.isfile(os.path.join(baseaddr, f)):
            if all_folder == True:
                raise Exception('directory can not have both directories and files')
            all_folder = False
        else:
            if all_folder == False:
                raise Exception('directory can not have both directories and files')
            all_folder = True

    if all_folder:
        extension = ''
    else:
        f = os.listdir(baseaddr)[0]
        extension = os.path.splitext(f)[1].lower()

    return extension

def load_data(baseaddr, existing_column_names):
    data = None
    extension = check_dir_files_type(baseaddr)

    if extension == '.txt':
        data = handle_text_data(baseaddr, existing_column_names)
    elif extension == '.json':
        data = handle_json_data(baseaddr, existing_column_names)
    elif extension in ['.csv', '.xlsx']:
        data = handle_excel_data(baseaddr, existing_column_names)
    elif extension == '':
        data = handle_dir_data(baseaddr, existing_column_names)

    return data

def handle_text_data(baseaddr, existing_column_names):
    for filename in os.listdir(baseaddr):
        filename_without_extension = os.path.splitext(filename)[0]
        result = {
            'collection_name': filename_without_extension,
            'rows': []
        }
        if filename_without_extension == 'columns_format':
            continue
        elif filename_without_extension in existing_column_names:
            yield result
            continue

        f = open(os.path.join(baseaddr, filename), 'r', encoding='utf8')
        lines = f.read().strip('\n').split('\n')
        delimiter = detect(lines[0], whitelist=['\t', ',', ' '])

        for line in lines:
            row_list = line.split(delimiter)
            for i in range(len(row_list)):
                if row_list[i] == '':
                    row_list[i] = None
            result['rows'].append(row_list)

        yield result

def handle_json_data(baseaddr, existing_column_names):
    for filename in os.listdir(baseaddr):
        filename_without_extension = os.path.splitext(filename)[0]
        result = {
            'collection_name': filename_without_extension,
            'rows': []
        }
        if filename_without_extension == 'columns_format':
            continue
        elif filename_without_extension in existing_column_names:
            yield result
            continue

        d = load_json(os.path.join(baseaddr, filename))
        for i in range(len(d)):
            for key in d[i]:
                if d[i][key] == '':
                    d[i][key] = None
            result['rows'].append(list(d[i].values()))

        yield result

def handle_excel_data(baseaddr, existing_column_names):
    for filename in os.listdir(baseaddr):
        filename_without_extension = os.path.splitext(filename)[0]
        result = {
            'collection_name': filename_without_extension,
            'rows': []
        }
        if filename_without_extension == 'columns_format':
            continue
        elif filename_without_extension in existing_column_names:
            yield result
            continue

        filename_extension = os.path.splitext(filename)[1]
        if filename_extension == '.xlsx':
            df = pd.read_excel(os.path.join(baseaddr, filename))
        else:
            df = pd.read_csv(os.path.join(baseaddr, filename))
        result['rows'] = df.values.tolist()
        yield result

def handle_dir_data(baseaddr, existing_column_names):
    for collection_name in os.listdir(baseaddr):
        if collection_name == 'columns_format.json':
            continue
        elif collection_name in existing_column_names:
            yield False

        result = {
            'collection_name': collection_name,
            'rows': []
        }
        for filename_id in os.listdir(os.path.join(baseaddr, collection_name)):
            for filename in os.listdir(os.path.join(baseaddr, collection_name, filename_id)):
                if filename == f'{filename_id}.txt':
                    data = handle_text_data(
                        os.path.join(baseaddr, collection_name, filename_id, filename), existing_column_names)
                    row = data['rows'][0]
                    break
                elif filename == f'{filename_id}.json':
                    data = handle_json_data(
                        os.path.join(baseaddr, collection_name, filename_id, filename), existing_column_names)
                    row = data['rows'][0]
                    break
                elif filename in [f'{filename_id}.csv', f'{filename_id}.xlsx']:
                    data = handle_excel_data(
                        os.path.join(baseaddr, collection_name, filename_id, filename), existing_column_names)
                    row = data['rows'][0]
                    break

            result['rows'].append(row)

        yield result


import json
import pandas as pd
import datetime
import os
import requests

client_id = 'CLIENT_ID' # fill this out with your API client_ID
path_to_token_file = '/path/to/token.file'
redirect_uri = 'https://localhost'

print(os.getcwd())

def read_tokens_from_file():
	global refresh_token, refresh_token_expiry
	try:
		with open(path_to_token_file + 'token_file', 'r') as token_file:
			tokens = json.load(token_file)
	except FileNotFoundError:
		print('404')
		print('create token file first')
	print(json.dumps(tokens, indent = 4))
	refresh_token = tokens['refresh_token']
	refresh_token_expiry =\
		pd.to_datetime(tokens['refresh_token_expires_ON'],
						unit = 's')
	return refresh_token, refresh_token_expiry

def both_tokens_by_refresh(refresh_token, client_id):
	resp = requests.post('https://api.tdameritrade.com/v1/oauth2/token',
                         headers={'Content-Type': 'application/x-www-form-urlencoded'},
                         data={'grant_type': 'refresh_token',
                               'refresh_token': refresh_token,
                               'access_type': 'offline',
                               'code': '',
                               'client_id': client_id,
                               'redirect_uri': redirect_uri})
	return (resp.json())

def access_by_refresh(refresh_token, client_id):
	global access_token
	resp = requests.post('https://api.tdameritrade.com/v1/oauth2/token',
                         headers={'Content-Type': 'application/x-www-form-urlencoded'},
                         data={'grant_type': 'refresh_token',
                               'refresh_token': refresh_token,
                               'access_type': '',
                               'code': '',
                               'client_id': client_id,
                               'redirect_uri': redirect_uri})
	access_token = resp.json()['access_token']

def get_today_timestamp():
	today = datetime.date.today()
	today = pd.to_datetime(today).timestamp()
	return int(today)

def update_token_file_by_refresh():
	tokens = both_tokens_by_refresh(refresh_token, client_id)
	if 'access_token' in tokens:
		del tokens['access_token']
		del tokens['expires_in']
	today = get_today_timestamp()
	refresh_token_expires_in = tokens['refresh_token_expires_in']
	refresh_token_expires_ON = int(today + refresh_token_expires_in)
	print(refresh_token_expires_ON)
	tokens['refresh_token_expires_ON'] = refresh_token_expires_ON
	with open(path_to_token_file + 'token_file', 'w') as token_file:
		json.dump(tokens, token_file)

def check_if_still_good():
	today = pd.to_datetime(get_today_timestamp(), unit = 's')
	time_remaining = refresh_token_expiry - today
	if time_remaining.days > 2:
		print('still time')
	else:
		print('get a new refresh_token')
		update_token_file_by_refresh()
		print('updated, try again...')
		quit()

def authenticate():
	read_tokens_from_file()
	check_if_still_good()
	access_by_refresh(refresh_token, client_id)


from SPAlgorithm import SPAlgorithm
import min_heap

class Dijkstra(SPAlgorithm):
    def calc_sp(self, graph, source: int, dest: int) -> float:
        if source == dest:
            return 0

        dist = {}
        queue = min_heap.MinHeap([])
        nodes = list(graph.__adj.keys())

        # Initialize priority queue/heap and distances
        for node in nodes:
            queue.insert(min_heap.Element(node, float("inf")))
            dist[node] = float("inf")
        queue.decrease_key(source, 0)
        dist[source] = 0

        # Meat of the algorithm
        while not queue.is_empty():
            current_element = queue.extract_min()
            current_node = current_element.value
            if current_node == dest:
                break
            for neighbour in graph.__adj[current_node]:
                if dist[current_node] + graph.w(current_node, neighbour) < dist[neighbour]:
                    queue.decrease_key(neighbour, dist[current_node] + graph.w(current_node, neighbour))
                    dist[neighbour] = dist[current_node] + graph.w(current_node, neighbour)
        return dist[dest]


import streamlit as st
import openai
from streamlit_agraph import agraph, Node, Edge, Config
import webbrowser
from urllib.parse import urlencode

def get_job_titles(content):
    openai.api_key = st.secrets["OPENAI_KEY"]

    completion = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[
            {
                "role": "user",
                "content": f"{content}. Only give the specific points in new lines and no other text",
            }
        ],
    )

    chat_response = completion.choices[0].message.content
    print("1" + chat_response)
    job_titles = chat_response.split("\n")
    return job_titles

if (
    "stage" not in st.session_state
    and "job_titles" not in st.session_state
    and "roadmap" not in st.session_state
    and "courses" not in st.session_state
    and "certifications" not in st.session_state
    and "corporate_ladder" not in st.session_state
    and "salary" not in st.session_state
    and "interview_questions" not in st.session_state
    and "JobTitle" not in st.session_state
):
    st.session_state.stage = 0
    st.session_state.job_titles = []
    st.session_state.roadmap = []
    st.session_state.courses = ""
    st.session_state.certifications = ""
    st.session_state.corporate_ladder = ""
    st.session_state.salary = ""
    st.session_state.interview_questions = ""
    st.session_state.JobTitle = ""

def set_stage(stage):
    st.session_state.stage = stage

def set_stage_courses(stage):
    st.session_state.stage = stage
    content = f"Give the names of courses for the role of {st.session_state.JobTitle} with their websites"
    st.session_state.courses = get_job_titles(content)
    st.session_state.courses.insert(0, "")

def set_stage_certifications(stage):
    st.session_state.stage = stage
    content = (
        f"give the names of certifications for the role of {st.session_state.JobTitle}"
    )
    st.session_state.certifications = get_job_titles(content)
    st.session_state.certifications.insert(0, "")

def set_stage_corporate_ladder(stage):
    st.session_state.stage = stage
    content = f"give the corporate ladder job titles for the role of {st.session_state.JobTitle}"
    st.session_state.corporate_ladder = get_job_titles(content)
    st.session_state.corporate_ladder.insert(0, "")

def set_stage_salary(stage):
    st.session_state.stage = stage
    content = f"provide the salary range for the role of {st.session_state.JobTitle}"
    st.session_state.salary = get_job_titles(content)
    st.session_state.salary.insert(0, "")

def set_stage_interview_questions(stage):
    st.session_state.stage = stage
    content = (
        f"provide 10 interview questions for the role of {st.session_state.JobTitle}"
    )
    st.session_state.interview_questions = get_job_titles(content)
    st.session_state.interview_questions.insert(0, "")

def set_stage_Employeed(stage):
    st.session_state.stage = stage
    if (
        "EmpStatus" in st.session_state
        and EmpStatus == "Employed"
        or EmpStatus == "Searching For Jobs"
    ):
        if "Profession" in st.session_state and "Exp" in st.session_state:
            content = f"Recommend suitable job titles for a {st.session_state['Profession'].lower()} with {st.session_state['Exp']} years of experience. "
            st.session_state.job_titles = get_job_titles(content)
            st.session_state.job_titles.insert(0, "")
            # for i in st.session_state.job_titles:
            #    if len(i) < 5:
            #        st.session_state.job_titles.remove(i);

def set_stage_Student(stage):
    st.session_state.stage = stage
    if "EmpStatus" in st.session_state and EmpStatus == "Student":
        if "Discipline" in st.session_state:
            content = f"Recommend suitable job titles for a {st.session_state['Discipline']} {st.session_state['EmpStatus'].lower()}."
            st.session_state.job_titles = get_job_titles(content)
            st.session_state.job_titles.insert(0, "")
            # for i in st.session_state.job_titles:
            #    if len(i) < 5:
            #        st.session_state.job_titles.remove(i);

def set_stage_Roadmap(stage):
    st.session_state.stage = stage
    if "JobTitle" in st.session_state:
        content = f"Give steps to become a {st.session_state['JobTitle']}"
        st.session_state.roadmap = get_job_titles(content)
        for i in st.session_state.roadmap:
            if len(i) < 5:
                st.session_state.roadmap.remove(i)

def open_linkedin_job_listings(job_keywords, location):
    base_url = "https://www.linkedin.com/jobs/search/?"
    params = {"keywords": job_keywords, "location": location}
    url = base_url + urlencode(params)

    # Open the URL using the default web browser
    webbrowser.open(url)

def build_roadmap_student_employed(templist):
    nodes = []
    edges = []
    for i in range(len(templist)):
        nodes.append(
            Node(
                id=templist[i], size=25, shape="square", color="#3264a8", label=f"{i+1}"
            )
        )
        if i != len(templist) - 1:
            edges.append(Edge(source=templist[i], label="next", target=templist[i + 1]))
    config = Config(
        width=1500,
        height=1000,
        directed=True,
        physics=False,
        hierarchical=True,
    )

    return_value = agraph(nodes=nodes, edges=edges, config=config)
    set_stage(4)
    if st.session_state.stage > 3:
        st.markdown(
            "
Gain competitive edge by acheiving these certifications
",
            unsafe_allow_html=True,
        )
        st.write(
            "Click the button below to display recommended certifications for your selected job."
        )
        st.button(
            "Display Certifications", on_click=set_stage_certifications, args=(5,)
        )
        temp_courses = "\n".join(st.session_state.certifications)
        st.write(temp_courses)
        set_stage(5)
        if st.session_state.stage > 6:
            st.markdown(
                "
Discover your next level in the corporate ladder
",
                unsafe_allow_html=True,
            )
            st.write(
                "Click the button below to display the corporate ladder for your selected job."
            )
            st.button(
                "Display corporate Ladder",
                on_click=set_stage_corporate_ladder,
                args=(6,),
            )
            temp_courses = "\n".join(st.session_state.corporate_ladder)
            st.write(temp_courses)

def build_roadmap_searching_for_jobs(templist):
    nodes = []
    edges = []
    for i in range(len(templist)):
        nodes.append(
            Node(
                id=templist[i], size=25, shape="square", color="#3264a8", label=f"{i+1}"
            )
        )
        if i != len(templist) - 1:
            edges.append(Edge(source=templist[i], label="next", target=templist[i + 1]))
    config = Config(
        width=1500,
        height=1000,
        directed=True,
        physics=False,
        hierarchical=True,
    )

    return_value = agraph(nodes=nodes, edges=edges, config=config)
    set_stage(4)
    if st.session_state.stage > 3:
        st.markdown(
            "
Crack your next interview with these questions
",
            unsafe_allow_html=True,
        )
        st.write(
            "Click the button below to display possible interview questions for your selected job."
        )
        st.button(
            "Display Interview Question",
            on_click=set_stage_interview_questions,
            args=(5,),
        )
        temp_courses = "\n".join(st.session_state.interview_questions)
        st.write(temp_courses)
        set_stage(5)
        if st.session_state.stage > 4:
            st.markdown(
                "
Find out your next expected salary
",
                unsafe_allow_html=True,
            )
            st.write(
                "Click the button below to display recommended salary for your selected job."
            )
            st.button("Display salary", on_click=set_stage_salary, args=(6,))
            temp_courses = "\n".join(st.session_state.salary)
            st.write(temp_courses)
            set_stage(6)
            if st.session_state.stage > 5:
                st.markdown(
                    "
View available jobs related to your expertise
",
                    unsafe_allow_html=True,
                )
                job_keywords = st.text_input("Enter your job title")
                location = st.text_input("Enter your preferred stay of work")
                if location and job_keywords:
                    open_linkedin_job_listings(job_keywords, location)

def build_roadmap_student(templist):
    nodes = []
    edges = []
    for i in range(len(templist)):
        nodes.append(
            Node(
                id=templist[i], size=25, shape="square", color="#3264a8", label=f"{i+1}"
            )
        )
        if i != len(templist) - 1:
            edges.append(Edge(source=templist[i], label="next", target=templist[i + 1]))
    config = Config(
        width=1500,
        height=1000,
        directed=True,
        physics=False,
        hierarchical=True,
    )

    return_value = agraph(nodes=nodes, edges=edges, config=config)
    set_stage(4)
    if st.session_state.stage > 3:
        st.markdown(
            "
Learn in demand skills through these popular courses
",
            unsafe_allow_html=True,
        )
        st.write(
            "Click the button below to display recommended courses for your selected job."
        )
        st.button("Display Courses", on_click=set_stage_courses, args=(5,))
        temp_courses = "\n".join(st.session_state.courses)
        st.write(temp_courses)

st.set_page_config(page_title="CareerBoost", page_icon="ðŸš€", layout="wide")
st.markdown(
    "
Career Advisor using OpenAI GPT-3
",
    unsafe_allow_html=True,
)
st.sidebar.success("Select a page above.")

EmpStatus = st.radio(
    "What is your current employment status?",
    ("Employed", "Searching For Jobs", "Student"),
    on_change=set_stage,
    args=(1,),
    key="EmpStatus",
)

if st.session_state.stage > 0:
    if EmpStatus == "Employed":
        if st.slider("How many years of experience do you have", 0, 10, key="Exp"):
            st.text_input(
                "Enter your profession",
                key="Profession",
                on_change=set_stage_Employeed,
                args=(2,),
            )
            if st.session_state.stage > 1:
                st.selectbox(
                    "Select a job",
                    st.session_state.job_titles,
                    on_change=set_stage_Roadmap,
                    args=(3,),
                    key="JobTitle",
                )
                if st.session_state.stage > 2:
                    st.markdown(
                        "
Roadmap
",
                        unsafe_allow_html=True,
                    )
                    build_roadmap_student_employed(st.session_state.roadmap)
                st.button("Reset", on_click=set_stage, args=(0,))
    elif EmpStatus == "Searching For Jobs":
        if st.slider("How many years of experience do you have", 0, 10, key="Exp"):
            st.text_input(
                "Enter your profession",
                key="Profession",
                on_change=set_stage_Employeed,
                args=(2,),
            )
            if st.session_state.stage > 1:
                st.selectbox(
                    "Select a job",
                    st.session_state.job_titles,
                    on_change=set_stage_Roadmap,
                    args=(3,),
                    key="JobTitle",
                )
                if st.session_state.stage > 2:
                    st.markdown(
                        "
Roadmap
",
                        unsafe_allow_html=True,
                    )
                    build_roadmap_searching_for_jobs(st.session_state.roadmap)
                st.button("Reset", on_click=set_stage, args=(0,))
    elif EmpStatus == "Student":
        st.selectbox(
            "Which discipline do you study in?",
            ("", "CS", "EEE", "MECH", "BioTech", "Civil"),
            on_change=set_stage_Student,
            args=(2,),
            key="Discipline",
        )
        if st.session_state.stage > 1:
            st.selectbox(
                "Select a job",
                st.session_state.job_titles,
                on_change=set_stage_Roadmap,
                args=(3,),
                key="JobTitle",
            )
            if st.session_state.stage > 2:
                st.markdown(
                    "
Roadmap
", unsafe_allow_html=True
                )
                build_roadmap_student(st.session_state.roadmap)
            st.button("Reset", on_click=set_stage, args=(0,))


import pprint
import random
from splinter import Browser
import time
import json
from selenium.webdriver.remote.errorhandler import UnexpectedAlertPresentException
from typing import List, Any, Tuple
from operator import attrgetter
from datetime import datetime
import os
from pathlib import Path

UNCLICKED = "U"
FLAGGED = "F"
BOMB_DEATH = "BD"
BOMB_REVEALED = "BR"
COMPLETED = "C"
large_size = (29, 15)
med_size = (15, 15)
small_size = (8, 8)
large_url = "https://minesweeperonline.com/#"
medium_url = "https://minesweeperonline.com/#intermediate"
small_url = "https://minesweeperonline.com/#beginner"

cell_class_dict = {
    "square blank": UNCLICKED,
    "square bombdeath": BOMB_DEATH,
    "square bombrevealed": BOMB_REVEALED,
    "square bombflagged": FLAGGED,
    "square bombmisflagged": FLAGGED
}

browser = Browser('firefox')
current_dir = str(Path(".").resolve())
print(os.environ["path"])
if current_dir not in os.environ["path"]:
    os.environ["path"] = os.environ["path"] + str(Path(".").resolve()) + ";"
print(os.environ["path"])

def json_default(value):
    if isinstance(value, datetime):
        time_str = str(value.hour) + ":" + str(value.minute) + ":" + str(value.second)
        return dict(time=time_str)
    else:
        return dict(value.__dict__)

def grid_print(grid):
    n = 0
    for each in grid:
        print("row " + str(n) + ": " + str(each))
        n = n + 1

def right_click_cell(cell):
    cell_id = get_cell_id(cell)
    if read_cell(cell) == UNCLICKED:
        browser.find_by_id(cell_id).right_click()
        print("Right click performed on cell: " + str(cell[0]) + ", " + str(cell[1]))
    else:
        print("Right click was called but cell was already flagged: " + str(cell[0]) + ", " + str(cell[1]))

def left_click_cell(cell):
    cell_id = get_cell_id(cell)
    browser.find_by_id(cell_id).click()

def get_cell_id(cell):
    cell_id = str(cell[1] + 1) + "_" + str(cell[0] + 1)
    return cell_id

def read_cell(cell):
    cell_id = get_cell_id(cell)
    cell_class = browser.find_by_id(cell_id).first["class"]
    if "square open" in cell_class:
        return int(cell_class[-1])
    else:
        return cell_class_dict[cell_class]

def cell_is_int_greater_than_0(cell_value):
    return isinstance(cell_value, int) and cell_value > 0

def read_cells(grid, read_all_cells=False):
    for y in range(0, len(grid)):
        for x in range(0, len(grid[y])):
            if get_grid_cell(x, y, grid) == UNCLICKED:
                if not read_all_cells:
                    adj_flagged_adj_count, adj_unclicked_adjacents, adj_numbered_adjacents \
                        = get_unclicked_adj_and_flagged_adj_count(grid, x, y)
                    if len(adj_numbered_adjacents) > 0:
                        set_grid_cell(x, y, grid, read_cell([x, y]))
                else:
                    set_grid_cell(x, y, grid, read_cell([x, y]))
    print_grid(grid)
    return grid

def print_grid(grid):
    print('\n')
    for grid_row in grid:
        join = "|".join(map(str, grid_row))
        join = join.replace(COMPLETED, "\033[0;32m" + COMPLETED + "\033[00m")
        join = join.replace(FLAGGED, "\033[0;31m" + FLAGGED + "\033[00m")
        join = join.replace(UNCLICKED, "\033[0;37m" + UNCLICKED + "\033[00m")
        join = join.replace('|', "\033[0;30m" + '|' + "\033[00m")
        print(join)
    print('\n')

def read_cell_and_adj_cells(cell: Tuple[int, int], grid):
    adj_spot_list = get_adj_cells(cell[0], cell[1], grid)
    set_grid_cell(cell[0], cell[1], grid, read_cell(cell))
    for spot in adj_spot_list:
        set_grid_cell(spot[0], spot[1], grid, read_cell(spot))

def is_game_over(grid):
    for each in grid:
        if BOMB_DEATH in each or BOMB_REVEALED in each:
            print("Game Lost")
            return True
    return False

def remove_many_agnostic_to_existance(a_list: list, values: list):
    for value in values:
        if value in a_list:
            a_list.remove(value)

def click_if_flags_are_greater_than_spot_num(x, y, grid):
    spot_number = get_grid_cell(x, y, grid)
    flagged_adj_count, unclicked_adjacents, numbered_adjacents \
        = get_unclicked_adj_and_flagged_adj_count(grid, x, y)
    if len(unclicked_adjacents) == 0:
        print("Marking cell complete without an action")
        set_grid_cell(x, y, grid, COMPLETED)
        return True
    if int(spot_number) > flagged_adj_count and int(spot_number) == len(unclicked_adjacents) + flagged_adj_count:
        print("Right clicking unclicked adjacents of cell: {x}, {y}".format(**{"x": x, "y": y}))
        for cell in unclicked_adjacents:
            right_click_cell(cell)
        set_grid_cell(x, y, grid, COMPLETED)
        return True
    elif flagged_adj_count == spot_number and len(unclicked_adjacents) > 0:
        for cell in unclicked_adjacents:
            left_click_cell(cell)
        set_grid_cell(x, y, grid, COMPLETED)
        return True
    elif spot_number == flagged_adj_count + 1 and len(unclicked_adjacents) == 2:
        #print("2 reference case first parameter met for cell: " + str([x, y]))
        #print("numbered_adjacents: " + str(numbered_adjacents))
        for numbered_adj_cell in numbered_adjacents:
            adj_flagged_adj_count, adj_unclicked_adjacents, adj_numbered_adjacents \
                = get_unclicked_adj_and_flagged_adj_count(grid, numbered_adj_cell[0], numbered_adj_cell[1])
            if 1 == get_grid_cell(numbered_adj_cell[0], numbered_adj_cell[1], grid) - adj_flagged_adj_count:
                #print("checking for numbered_adj_cell: " + str(numbered_adj_cell))
                if len(adj_unclicked_adjacents) == 3:
                    differences = []
                    #print("unclicked_adjacents: " + str(unclicked_adjacents))
                    #print("adj_unclicked_adjacents: " + str(adj_unclicked_adjacents))
                    for a_list in adj_unclicked_adjacents:
                        if a_list not in unclicked_adjacents:
                            differences.append(a_list)
                    #print("differences: " + str(differences))
                    if len(differences) == 1:
                        print("Left clicking difference: " + str(differences))
                        for cell in differences:
                            left_click_cell(cell)
                elif len(unclicked_adjacents) == 2:
                    #print("Checking t bone scenario")
                    go_ahead = True
                    for a_list in unclicked_adjacents:
                        if a_list not in adj_unclicked_adjacents:
                            go_ahead = False
                    if go_ahead:
                        differences = []
                        for a_list in adj_unclicked_adjacents:
                            if a_list not in unclicked_adjacents:
                                differences.append(a_list)
                        for cell in differences:
                            print("Left clicking on t bone cells: " + str(differences))
                            left_click_cell(cell)
            elif 2 == get_grid_cell(numbered_adj_cell[0], numbered_adj_cell[1], grid) - adj_flagged_adj_count:
                if len(adj_unclicked_adjacents) == 3:
                    differences = []
                    #print("unclicked_adjacents: " + str(unclicked_adjacents))
                    #print("adj_unclicked_adjacents: " + str(adj_unclicked_adjacents))
                    for a_list in adj_unclicked_adjacents:
                        if a_list not in unclicked_adjacents:
                            differences.append(a_list)
                    #print("differences: " + str(differences))
                    if len(differences) == 1:
                        print("Right clicking difference: " + str(differences))
                        for cell in differences:
                            right_click_cell(cell)
    else:
        return False

def get_adj_cells(x, y, grid):
    adj_spot_list = []
    adj_spots_vectors = [
        (-1, -1), (0, -1), (1, -1),
        (-1, 0), (1, 0),
        (-1, 1), (0, 1), (1, 1)
    ]
    if x == 0:
        remove_many_agnostic_to_existance(adj_spots_vectors, [(-1, -1), (-1, 0), (-1, 1)])
    if x == len(grid[0]) - 1:
        remove_many_agnostic_to_existance(adj_spots_vectors, [(1, -1), (1, 0), (1, 1)])
    if y == 0:
        remove_many_agnostic_to_existance(adj_spots_vectors, [(-1, -1), (0, -1), (1, -1)])
    if y == len(grid) - 1:
        remove_many_agnostic_to_existance(adj_spots_vectors, [(-1, 1), (0, 1), (1, 1)])
    for spot in adj_spots_vectors:
        spot_to_check = [x + spot[0], y + spot[1]]
        adj_spot_list.append(spot_to_check)
    return adj_spot_list

def get_unclicked_adj_and_flagged_adj_count(grid, x, y):
    flagged_adj_count = 0
    unclicked_adjacents = []
    numbered_adjacents = []
    adj_spot_list = get_adj_cells(x, y, grid)
    for spot_to_check in adj_spot_list:
        grid_content_at_spot_to_check = get_grid_cell(spot_to_check[0], spot_to_check[1], grid)
        if grid_content_at_spot_to_check == FLAGGED:
            flagged_adj_count = flagged_adj_count + 1
        elif grid_content_at_spot_to_check == UNCLICKED:
            unclicked_adjacents.append(spot_to_check)
        elif cell_is_int_greater_than_0(grid_content_at_spot_to_check):
            numbered_adjacents.append(spot_to_check)
            #print("numbered_adjacents: " + str(numbered_adjacents))
    return flagged_adj_count, unclicked_adjacents, numbered_adjacents

class GuessObj(object):
    def __init__(self, x: int, y: int):
        self.cell = (x, y)
    cell: Tuple[int, int]
    bomb_probability: float

def guess(grid: List[List[Any]]):
    bombs_left = read_bombs_counter("mines_hundreds", 100) + read_bombs_counter("mines_tens", 10) + read_bombs_counter("mines_ones", 1)
    guess_list: List[GuessObj] = []
    for y in range(0, len(grid)):
        for x in range(0, len(grid[y])):
            if get_grid_cell(x, y, grid) == UNCLICKED:
                guess_list.append(GuessObj(x, y))

    for guess_obj in guess_list:
        x = guess_obj.cell[0]
        y = guess_obj.cell[1]
        flagged_adj_count, unclicked_adjacents, numbered_adjacents = \
            get_unclicked_adj_and_flagged_adj_count(grid, x, y)
        if len(numbered_adjacents) > 0:
            numbered_adjacents_ps = []
            for num_adj in numbered_adjacents:
                num_adj_flagged_adj_count, num_adj_unclicked_adjacents, num_adj_numbered_adjacents = \
                    get_unclicked_adj_and_flagged_adj_count(grid, num_adj[0], num_adj[1])
                adj_p = (int(get_grid_cell(num_adj[0], num_adj[1], grid)) - num_adj_flagged_adj_count) \
                        / len(num_adj_unclicked_adjacents)
                numbered_adjacents_ps.append(adj_p)
            guess_obj.bomb_probability = max(numbered_adjacents_ps)
        else:
            guess_obj.bomb_probability = bombs_left / len(guess_list)
    #print("Guess List: " + json.dumps(guess_list, default=json_default, sort_keys=True, indent=4))
    min_guess = min(guess_list, key=attrgetter('bomb_probability'))
    print("Making a guess click on: " + json.dumps(min_guess, default=json_default, sort_keys=True, indent=4))
    left_click_cell(min_guess.cell)
    read_cell_and_adj_cells(min_guess.cell, grid)
    return True

def read_bombs_counter(div_id: str, multiplier: int):
    return int(browser.find_by_id(div_id)["class"][-1]) * multiplier

def get_grid_cell(x: int, y: int, grid: List[List[Any]]):
    try:
        return grid[y][x]
    except IndexError as e:
        print("Index error on get grid for cell: " + str([x, y]))
        raise e

def set_grid_cell(x, y, grid, new_value):
    try:
        grid[y][x] = new_value
    except IndexError as e:
        print("Index error on set grid for cell: " + str([x, y]))
        raise e

def cycle_through_number_cells(grid):
    for y in range(0, len(grid)):
        for x in range(0, len(grid[0])):
            if cell_is_int_greater_than_0(get_grid_cell(x, y, grid)):
                if click_if_flags_are_greater_than_spot_num(x, y, grid):
                    return True
    print("Cycled through every cell without making a move")
    #time.sleep(1)
    return False

def play_new_game(autoplay):
    if not autoplay:
        continue_yes = 'n'
        while continue_yes.upper() != 'Y':
            continue_yes = input("Press 'y' + enter to continue...")

def open_minesweeper_webpage():
    while True:
        size_input = input("Want to play a small, medium, large, or custom game? (s, m, l, c): ")
        if size_input.upper() == "L":
            url = large_url
            size = large_size
            break
        elif size_input.upper() == "M":
            url = medium_url
            size = med_size
            break
        elif size_input.upper() == "S":
            url = small_url
            size = small_size
            break
        elif size_input.upper() == "C":
            url = large_url
            custom_size_input_x = int(input("Please enter the board width: "))
            custom_size_input_y = input("Please enter the board height: ")
            custom_size_input_bombs = input("Please enter the number of mines: ")
            size = (int(custom_size_input_x) - 1, int(custom_size_input_y) - 1)
            break
        else:
            print("Sorry, please input s, m, or l")
    co_op = input("Co-Op? y/n: ")
    if co_op.upper() == "Y":
        autoplay = False
    else:
        autoplay = True
    browser.visit(url)
    if size_input.upper() == "C":
        browser.find_by_id("options-link").first.click()
        browser.find_by_id("custom").first.click()
        browser.find_by_id("custom_height").fill(str(custom_size_input_y))
        browser.find_by_id("custom_width").fill(str(custom_size_input_x))
        browser.find_by_id("custom_mines").fill(str(custom_size_input_bombs))
        time.sleep(2)
        browser.find_by_value("New Game").first.click()
    while True:
        try:
            browser.find_by_id("face").first.click()
            starting_click = (random.randint(1, size[0] - 1), random.randint(1, size[1] - 1))
            print("starting_click: " + str(starting_click))
            left_click_cell(starting_click)
            print("starting bot while loop")
            game_over = False
            grid = [[UNCLICKED] * (size[0] + 1) for _ in range((size[1] + 1))]
            print("Instantiated grid of size: " + str((len(grid[0]), len(grid))))
            read_cell_and_adj_cells(starting_click, grid)
            read_all_cells = False
            tries = 0
            while not game_over:
                grid = read_cells(grid, read_all_cells=read_all_cells)
                read_all_cells = False
                if not cycle_through_number_cells(grid):
                    print("Failed to find moves, reading all cells just to be sure")
                    tries = tries + 1
                    read_all_cells = True
                    if tries > 2:
                        guess(grid)
                        tries = 0
                    #read_all_cells = True
                if browser.find_by_id("face")["class"] == "facewin":
                    print("Game won")
                    game_over = True
                else:
                    game_over = is_game_over(grid)
            play_new_game(autoplay)
        except UnexpectedAlertPresentException as e:
            print("Score alert pop up found")
            play_new_game(autoplay)

if __name__ == '__main__':
    open_minesweeper_webpage()


with open("2021/Day 2/input.txt") as f:
    instructions = f.read().splitlines()
instructions = list(map(lambda s: s.split(), instructions))

total = [0, 0]
for line in instructions:
    if line[0] == "forward":
        total[0] += int(line[1])
    elif line[0] == "down":
        total[1] += int(line[1])
    elif line[0] == "up":
        total[1] -= int(line[1])

print(total[0]*total[1])

aim = 0
total = [0, 0]
for line in instructions:
    if line[0] == "forward":
        total[0] += int(line[1])
        total[1] += aim*int(line[1])
    if line[0] == "down":
        aim += int(line[1])
    if line[0] == "up":
        aim -= int(line[1])
print(total[0]*total[1])


import sqlite3
import numpy as np

def dict_factory(cursor, row):
    d = {}
    for idx, col in enumerate(cursor.description):
        d[col[0]] = row[idx]
    return d

conn = sqlite3.connect('mux.db')
conn.row_factory = dict_factory
    #sqlite3.Row

cur = conn.cursor()
cur.execute('select out from mux WHERE out=40')
pinout=cur.fetchone()

cur.execute('select A0, A1, A2, A3, A4, CS1, CS2, CS3 from mux ')
row = cur.fetchone()

print(pinout)
print(row)
print

# cur.execute("select 1 as A")
# print(cur.fetchone()['A'])