import collections
import math
import numbers

from simian.public.proto import motion_model_pb2
from simian.public.transforms import proto_util

_Phase = collections.namedtuple("_Phase", "end_time command")

# General support for pre-canned motion commands. Skipping trajectory
# and sequence mode commands for now.
class Sequencer:
    @classmethod
    def FromSpec(cls, motion_command_sequence_proto):
        """Converts a MotionCommandSequence proto to a Sequencer object with specified commands."""
        sequencer = cls()
        for single_command in motion_command_sequence_proto.command_list:
            sequencer._total_duration += single_command.duration
            sequencer._phases.append(_Phase(sequencer._total_duration, single_command.command))
        return sequencer

    def __init__(self):
        self._time = 0.0
        self._total_duration = 0.0
        self._phases = []

    def get_total_duration(self):
        return self._total_duration

    def parse_list_of_dicts(self, specs):
        _dispatch = {
            "velocity_yawrate": self.parse_velocity_yawrate,
            "acceleration_yawrate": self.parse_acceleration_yawrate,
            "normalized_dbw": self.parse_normalized_dbw,
            "velocity_steering": self.parse_velocity_steering,
            "normalized_torque_steering": self.parse_normalized_torque_steering,
            "force_brake_steering": self.parse_force_brake_steering,
            "normalized_dbw_gear": self.parse_normalized_dbw_gear,
            "rover_wheel_command": self.parse_rover_wheel_command,
            "composite_vehicle_command": self.parse_and_append_composite_vehicle_command,
        }
        for spec in specs:
            for key, value in spec.items():
                if key not in _dispatch:
                    raise ValueError('Invalid motion command type "%s".' % key)
                _dispatch[key](value)

    def parse_velocity_yawrate(self, spec):
        for phase in spec:
            self.append_velocity_yawrate(phase["duration"], phase["velocity"], phase["yawrate"])

    def append_velocity_yawrate(self, duration, velocity, yawrate):
        if duration <= 0.0:
            raise ValueError("Invalid duration %f (must be positive)" % duration)
        self._total_duration += duration
        command = motion_model_pb2.Input()
        command.velocity_yawrate.velocity = velocity
        command.velocity_yawrate.yawrate = yawrate
        self._phases.append(_Phase(self._total_duration, command))

    def parse_acceleration_yawrate(self, spec):
        for phase in spec:
            self.append_acceleration_yawrate(
                phase["duration"], phase["acceleration"], phase["yawrate"]
            )

    def append_acceleration_yawrate(self, duration, acceleration, yawrate):
        if duration <= 0.0:
            raise ValueError("Invalid duration %f (must be positive)" % duration)
        self._total_duration += duration
        command = motion_model_pb2.Input()
        command.acceleration_yawrate.acceleration = acceleration
        command.acceleration_yawrate.yawrate = yawrate
        self._phases.append(_Phase(self._total_duration, command))

    def parse_normalized_dbw(self, spec):
        for phase in spec:
            self.append_normalized_dbw(
                phase["duration"], phase["brake"], phase["throttle"], phase["steering"]
            )

    def append_normalized_dbw(self, duration, brake, throttle, steering):
        if duration <= 0.0:
            raise ValueError("Invalid duration %f (must be positive)" % duration)
        if brake < 0.0 or brake > 1.0:
            raise ValueError("Invalid brake %f (must be between 0 and 1)" % brake)
        if throttle < 0.0 or throttle > 1.0:
            raise ValueError("Invalid throttle %f (must be between 0 and 1)" % throttle)
        if abs(steering) > 1.0:
            raise ValueError("Invalid steering %f (must be between -1 and 1)" % steering)
        self._total_duration += duration
        command = motion_model_pb2.Input()
        command.normalized_dbw.brake = brake
        command.normalized_dbw.throttle = throttle
        command.normalized_dbw.steering = steering
        self._phases.append(_Phase(self._total_duration, command))

    def parse_velocity_steering(self, spec):
        for phase in spec:
            self.append_velocity_steering(
                phase["duration"], phase["velocity"], phase["steering_angle"]
            )

    def append_velocity_steering(self, duration, velocity, steering_angle):
        if duration <= 0.0:
            raise ValueError("Invalid duration %f (must be positive)" % duration)
        self._total_duration += duration
        command = motion_model_pb2.Input()
        command.velocity_steering.velocity = velocity
        command.velocity_steering.steering_angle = steering_angle
        self._phases.append(_Phase(self._total_duration, command))

    def parse_normalized_torque_steering(self, spec):
        for phase in spec:
            self.append_normalized_torque_steering(
                phase["duration"], phase["torque"], phase["steering"], phase.get("brake", 0.0)
            )

    def append_normalized_torque_steering(self, duration, torque, steering, brake):
        if duration <= 0.0:
            raise ValueError("Invalid duration %f (must be positive)" % duration)
        if abs(torque) > 1.0:
            raise ValueError("Invalid torque %f (must be between -1 and 1)" % torque)
        if abs(steering) > 1.0:
            raise ValueError("Invalid steering %f (must be between -1 and 1)" % steering)
        self._total_duration += duration
        command = motion_model_pb2.Input()
        command.normalized_torque_steering.torque = torque
        command.normalized_torque_steering.steering = steering
        command.normalized_torque_steering.brake = brake
        self._phases.append(_Phase(self._total_duration, command))

    def parse_force_brake_steering(self, spec):
        for phase in spec:
            self.append_force_brake_steering(
                phase["duration"], phase["motor_force"], phase["brake"], phase["steering"]
            )

    def append_force_brake_steering(self, duration, motor_force, brake, steering):
        if duration <= 0.0:
            raise ValueError("Invalid duration %f (must be positive)" % duration)
        if motor_force < 0.0:
            raise ValueError("Invalid motor_force %f (must be positive)" % motor_force)
        if brake > 1.0 or brake < 0.0:
            raise ValueError("Invalid brake %f (must be between 0 and 1)" % brake)
        if abs(steering) > 1.0:
            raise ValueError("Invalid steering %f (must be between -1 and 1)" % steering)
        self._total_duration += duration
        command = motion_model_pb2.Input()
        command.force_brake_steering.motor_force = motor_force
        command.force_brake_steering.brake = brake
        command.force_brake_steering.steering = steering
        self._phases.append(_Phase(self._total_duration, command))

    def parse_normalized_dbw_gear(self, spec):
        for phase in spec:
            self.append_normalized_dbw_gear(
                phase["duration"],
                phase["brake"],
                phase["throttle"],
                phase["steering"],
                phase["gear"],
            )

    def append_normalized_dbw_gear(self, duration, brake, throttle, steering, gear):
        if duration <= 0.0:
            raise ValueError("Invalid duration %f (must be positive)" % duration)
        if brake < 0.0 or brake > 1.0:
            raise ValueError("Invalid brake %f (must be between 0 and 1)" % brake)
        if throttle < 0.0 or throttle > 1.0:
            raise ValueError("Invalid throttle %f (must be between 0 and 1)" % throttle)
        if abs(steering) > 1.0:
            raise ValueError("Invalid steering %f (must be between -1 and 1)" % steering)
        if gear < 1:
            raise ValueError("Invalid gear %f (must be greater than 0)" % gear)
        self._total_duration += duration
        command = motion_model_pb2.Input()
        command.normalized_dbw_gear.brake = brake
        command.normalized_dbw_gear.throttle = throttle
        command.normalized_dbw_gear.steering = steering
        command.normalized_dbw_gear.gear = int(gear)
        self._phases.append(_Phase(self._total_duration, command))

    def parse_rover_wheel_command(self, spec):
        for phase in spec:
            self.append_rover_wheel_command(
                phase["duration"], phase["fl"], phase["fr"], phase["rl"], phase["rr"]
            )

    def append_rover_wheel_command(self, duration, fl, fr, rl, rr):
        if duration <= 0.0:
            raise ValueError("Invalid duration %f (must be positive)" % duration)
        self._total_duration += duration
        command = motion_model_pb2.Input()

        command.rover_wheel_command.fl.steering = fl["steering"]
        command.rover_wheel_command.fl.ang_vel = fl["ang_vel"]

        command.rover_wheel_command.fr.steering = fr["steering"]
        command.rover_wheel_command.fr.ang_vel = fr["ang_vel"]

        command.rover_wheel_command.rl.steering = rl["steering"]
        command.rover_wheel_command.rl.ang_vel = rl["ang_vel"]

        command.rover_wheel_command.rr.steering = rr["steering"]
        command.rover_wheel_command.rr.ang_vel = rr["ang_vel"]

        self._phases.append(_Phase(self._total_duration, command))

    def parse_and_append_composite_vehicle_command(self, spec):
        for phase in spec:
            command = motion_model_pb2.Input()
            cmd_short = command.composite_vehicle_command

            # Duration
            duration = phase["duration"]
            if duration <= 0.0:
                raise ValueError("Invalid duration %f (must be positive)" % duration)
            self._total_duration += duration

            # Brake input
            if "normalized_brake" in phase:
                cmd_short.brake_input.normalized_brake = phase["normalized_brake"]
            else:
                raise ValueError("Received unexpected or no brake_input.")

            # Powertrain input
            if "normalized_throttle" in phase:
                cmd_short.powertrain_input.normalized_throttle = phase["normalized_throttle"]
            elif "motor_torque" in phase:
                cmd_short.powertrain_input.motor_torque = phase["motor_torque"]
            elif "normalized_motor_torque" in phase:
                cmd_short.powertrain_input.normalized_motor_torque = phase[
                    "normalized_motor_torque"
                ]
            else:
                raise ValueError("Received unexpected or no powertrain_input.")

            # Steering input
            if "angle_rate" in phase:
                cmd_short.steering_input.angle_rate = phase["angle_rate"]
            elif "normalized_angle" in phase:
                cmd_short.steering_input.normalized_angle = phase["normalized_angle"]
            elif "normalized_angle_rate" in phase:
                cmd_short.steering_input.normalized_angle_rate = phase["normalized_angle_rate"]
            else:
                raise ValueError("Received unexpected or no steering_input.")

            self._phases.append(_Phase(self._total_duration, command))

    # Currently a bit of a one-off for when the caller already has a
    # state. As opposed to the others which are geared toward manual
    # text-based specification.
    def append_override_state(self, duration, state2d):
        if duration <= 0.0:
            raise ValueError("Invalid duration %f (must be positive)" % duration)
        self._total_duration += duration
        command = motion_model_pb2.Input()
        command.override_state.MergeFrom(proto_util.state2d_to_proto(state2d))
        self._phases.append(_Phase(self._total_duration, command))

    def is_empty(self):
        return len(self._phases) == 0

    def assert_nonempty(self):
        if not self._phases:
            raise ValueError("Empty motion command sequence.")

    def create_command_relative_time(self, dt):
        return self.create_command_absolute_time(self._time + _to_value(dt))

    # Note this works (fingers crossed) for tt being either a number
    # or a datetime. Under the hood, it is all getting converted to
    # seconds, represented as a floating point for historical
    # reasons. Using a datetime or timedelta could be better here,
    # especially if the create_command_relative_time() method is used,
    # as that can accumulate roundoff errors.
    def create_command_absolute_time(self, tt):
        self.assert_nonempty()
        self._time = math.fmod(_to_value(tt), self._total_duration)
        # Simple linear search suffice for now, we don't expect very
        # long precanned sequences.
        for phase in self._phases:
            if phase.end_time < self._time:
                continue
            return phase.command
        raise Exception("Bug? Fell off the end of the precanned motion command sequence.")

def _to_value(value):
    if isinstance(value, numbers.Number):
        return value
    # For now assume the only alternative is what we use for sim_time
    # method arg plumbing (as opposed to sim_time in sim data proto
    # which is just a float).
    return 3600 * value.hour + 60 * value.minute + value.second + 1e-6 * value.microsecond


import random
import config

from datasets import AnimeDataset
from pix2pix import UNetGenerator, PatchDiscriminator

import numpy as np
import torch
from torch.utils import data

import torchvision
from torchvision import transforms

from tqdm import tqdm

def main():
    start_epoch = 0
    n_epochs = config.epochs
    weights_folder = config.ckpt_dir

    G, D = UNetGenerator(init_weights=True), PatchDiscriminator(init_weights=True)
    G.to(config.device)
    D.to(config.device)

    optim_G = torch.optim.Adam(G.parameters(), lr=config.lr, betas=(0.5, 0.999))
    optim_D = torch.optim.Adam(D.parameters(), lr=config.lr, betas=(0.5, 0.999))

    bce_loss = torch.nn.BCEWithLogitsLoss()
    l1_loss = torch.nn.L1Loss()

    train_transform = [
        transforms.Resize((256, 256)),
        transforms.ToPILImage(),
        # transforms.ColorJitter(),
        transforms.ToTensor(),
        transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))
    ]
    train_transform = transforms.Compose(train_transform)

    train_data = AnimeDataset(config.train_dir, train_transform)
    train_loader = data.DataLoader(train_data, batch_size=config.batch_size, shuffle=True, num_workers=config.num_workers)

    val_data = AnimeDataset(config.val_dir, train_transform)
    val_loader = data.DataLoader(val_data, batch_size=5)

    for epoch in range(start_epoch, n_epochs):
        train_one_epoch(epoch, G, D, optim_G, optim_D, train_loader, bce_loss, l1_loss)
        torch.save(G.state_dict(), f'{weights_folder}/G-checkpoint-{str(epoch).zfill(3)}epoch.pth')
        torch.save(D.state_dict(), f'{weights_folder}/D-checkpoint-{str(epoch).zfill(3)}epoch.pth')
        test(G, val_loader, epoch)
        # TODO: save里保存epoch信息
        # TODO: 增加tensorboard 或 wandb 配置

def train_one_epoch(epoch, G, D, optim_G, optim_D, train_loader, gan_loss, dist_loss):
    pbar = tqdm(train_loader)
    pbar.set_description(desc=f'Epoch {epoch + 1}/{config.epochs}')

    for i, (x, y) in enumerate(pbar):
        x, y = x.to(config.device), y.to(config.device)

        y_fake = G(x)   # 生成器生成假图
        d_real = D(x, y)    # 判别器对真图进行判别
        d_fake = D(x, y_fake.detach())   # 判别器对假图进行判别

        real = torch.ones_like(d_real)    # 真图全1
        fake = torch.zeros_like(d_real)   # 假图全0

        r_loss = gan_loss(d_real, real)
        f_loss = gan_loss(d_fake, fake)
        D_loss = (r_loss + f_loss) / 2

        # 训练判别器，不需要l1_loss
        D.zero_grad()
        D_loss.backward()
        optim_D.step()

        # 训练生成器
        d_fake = D(x, y_fake)
        G_gan_loss = gan_loss(d_fake, fake)
        l1_loss = dist_loss(y_fake, y)
        G_loss = G_gan_loss + config.l1_lambda * l1_loss
        G.zero_grad()
        G_loss.backward()
        optim_G.step()

        pbar.set_postfix(
            {'D Loss': '{:.5f}'.format(round(D_loss.item(), 4)), 'G Loss': '{:.5f}'.format(round(G_loss.item(), 4))})

def test(gen, val_loader, epoch):
    x, y = next(iter(val_loader))
    x, y = x.to(config.device), y.to(config.device)

    gen.eval()
    with torch.no_grad():
        y_fake = gen(x)
        y_fake = y_fake * 0.5 + 0.5    # 消除正则
        x = x * 0.5 + 0.5
        output = torch.cat((x, y_fake), 3)
        torchvision.utils.save_image(output, config.output_dir + f"/output_{epoch}.png")

    gen.train()

def random_seeds(seed):
    # Python built-in random module
    random.seed(seed)
    # Numpy
    np.random.seed(seed)
    # Torch
    torch.manual_seed(seed)
    if torch.cuda.is_available():
        torch.cuda.manual_seed(seed)
        torch.cuda.manual_seed_all(seed)
    torch.backends.cudnn.benchmark = False
    torch.backends.cudnn.deterministic = True

if __name__ == '__main__':
    random_seeds(42)      # 宇宙的答案 42
    main()


from typing import List

from fastapi import APIRouter, Depends, HTTPException
from odmantic import ObjectId

from ..db.events import add_events, get_event_by_id, get_events, mark_event_processed
from ..models.event import Event, EventFilters, EventInput, EventOutput, EventsOutput
from .custom_routers import DeepLoggerRoute, LightLoggerRoute

deep_logger_router = APIRouter(route_class=DeepLoggerRoute)
light_logger_router = APIRouter(route_class=LightLoggerRoute)

@light_logger_router.get("/events", response_model=EventsOutput)
async def list_events(filters: EventFilters = Depends()) -> EventsOutput:
    return await get_events(filters=filters)

@deep_logger_router.put("/events", response_model=List[EventOutput])
async def add_event(event: EventInput) -> List[Event]:
    if not event.camera_number:
        camera_numbers = []
    else:
        camera_numbers = [event.camera_number]
    return await add_events(
        event.event_type, event.message, camera_numbers=camera_numbers
    )

@deep_logger_router.patch("/events/{id}", response_model=EventOutput)
async def process_event(id: ObjectId) -> Event:
    return await mark_event_processed(id)

@light_logger_router.get("/events/{id}", response_model=EventOutput)
async def get_event(id: ObjectId) -> Event:
    event = await get_event_by_id(id)
    if not event:
        raise HTTPException(404, f"Ивент с id={id} не найден!")

    return event


import logging
import sys

__title__ = 'ebs_snapper'
__version__ = '0.10.6'
__license__ = 'Apache 2.0'
__copyright__ = 'Copyright Rackspace US, Inc. 2015-2017'
__url__ = 'https://github.com/rackerlabs/ebs-snapper-lambda-v2'

LOG = logging.getLogger()
AWS_MOCK_ACCOUNT = '123456789012'

def timeout_check(context, place):
    """Return True if we have less than 1 minute remaining"""

    remaining = context.get_remaining_time_in_millis()
    if remaining < 60000:  # 1 minute
        LOG.warn('Lambda/Less than 1m remaining in function (%sms): %s',
                 str(remaining),
                 place)
        return True

    return False

class EbsSnapperError(Exception):
    """Custom exception for nicer error messages"""
    def __init__(self, msg, other):
        self.traceback = sys.exc_info()
        new_msg = '{}: {}'.format(msg, other.message)
        super(EbsSnapperError, self).__init__(new_msg)


# import libraries
import time
import pandas as pd
from rich import print as rprint
from rich.pretty import pprint
from rich.progress import Progress
import re
from rich.progress import track
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
# ------------------------------------------------------------------
# TODO: functions
# ------------------------------------------------------------------

# This function search each element of the document DOM

def findElementTextBySelector(selector, exception):
    try:
        element = i.find_element(
            By.CSS_SELECTOR, selector).text.strip().upper()
    except:
        element = exception
    return element

def findElementNumberBySelector(selector, exception):
    try:
        element = i.find_element(
            By.CSS_SELECTOR, selector).text.replace('$', '')
        element = "".join([ch for ch in element if ch.isdigit()])
    except:
        element = exception
    return element

# Function Beatiful View

def process_data():
    time.sleep(0.02)

# ----------------------------------------------------------------
# TODO: add support for the WebDriver
# ----------------------------------------------------------------

# Bar progress -> comment
for _ in track(range(100), description='[green]Iniciando Scraping Almacenes EXITO'):
    process_data()
# Initialized by selenium driver
driver = webdriver.Firefox()
driver.maximize_window()
# Categories of brands that should be considered for search results
categories = ['whisky', 'vino', 'cervezas', 'tequilas-y-piscos', 'ron']

# ----------------------------------------------------------------
driver.get("https://www.exito.com/")

time.sleep(10)

# Slect City
open_modal = driver.find_element(
    By.XPATH, "//span[@class='exito-geolocation-3-x-addressResult']")
open_modal.click()
time.sleep(5)

select_geo = driver.find_element(
    By.XPATH, "//div[@class='exito-geolocation-3-x-contentOrderOption flex']//div[1]")
select_geo.click()
time.sleep(2)

select_modal = driver.find_element(
    By.CSS_SELECTOR, ".exito-geolocation-3-x-orderOptionsButton.orderoption-compra-recoge")
select_modal.click()
time.sleep(2)

select_city = driver.find_element(
    By.CSS_SELECTOR, ".exito-geolocation-3-x-cssUnderline.shippingaddress-lista-ciudad.w-100")
select_city.click()
time.sleep(2)

select_city_bog = driver.find_element(
    By.XPATH, "//div[@id='react-select-2-option-0']")
select_city_bog.click()
time.sleep(2)

select_address = driver.find_element(
    By.CSS_SELECTOR, ".buycollect-lista-almacen.exito-geolocation-3-x-listaAlmacen")
select_address.click()
time.sleep(2)

select_modal2 = driver.find_element(
    By.XPATH, "//div[@id='react-select-4-option-0']")
select_modal2.click()
time.sleep(2)

select_modal2 = driver.find_element(
    By.XPATH, "//button[normalize-space()='Confirmar']")
select_modal2.click()
time.sleep(10)

# ----------------------------------------------------------------

# PASS

# ----------------------------------------------------------------

select_menu = driver.find_element(
    By.ID, "category-menu")
select_menu.click()
time.sleep(15)

select_mercado = driver.find_element(
    By.ID, "undefined-nivel2-Mercado")
select_mercado.click()
time.sleep(10)

select_menu_whisky = driver.find_element(
    By.XPATH, "//p[@id='Categorías-nivel3-Whisky, ron, brandy y coñac']")
select_menu_whisky.click()

# sleep for a few seconds before loading the page
time.sleep(5)

driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(3)
# class vtex button load more
initial_XPATH = "//div[contains(@class,'vtex-button__label flex items-center justify-center h-100 ph5')]"
# define the max clicks for page
max_click_SHOW_MORE = 20
# count the number of clicks

count = 1
while count <= max_click_SHOW_MORE:
    try:
        WebDriverWait(driver, 30).until(
            EC.visibility_of_element_located((By.XPATH, initial_XPATH))).click()
        time.sleep(2)
        WebDriverWait(driver, 20).until(
            EC.element_to_be_clickable((By.XPATH, initial_XPATH))).click()
        count += 1
        time.sleep(10)
    except TimeoutException:
        break

print("Continue......")

items = driver.find_elements(
    By.CSS_SELECTOR,  ".vtex-product-summary-2-x-element.pointer.pt3.pb4.flex.flex-column.h-100")

data_exito = []

for i in items:
    try:
        name = i.find_element(
            By.CSS_SELECTOR, ".vtex-store-components-3-x-productNameContainer.mv0.t-heading-4").text.strip().upper()
    except:
        name = "SIN DESCRIPCION"
    print(name)

print("Exit......")

# select_menu_whisky = driver.find_element(
#     By.CSS_SELECTOR, ".exito-filters-0-x-filterItem.exito-filters-0-x-filterItem--new-layout-filters.exito-filters-0-x-filterItem--whisky.exito-filters-0-x-filterItem--new-layout-filters--whisky.lh-copy.w-100")
# select_menu_whisky.click()
# time.sleep(2)
# select_cat_lic = driver.find_element(
#     By.XPATH, "//strong[@id='Categorías-nivel2-Licores']")
# select_cat_lic.click()
# time.sleep(5)

# select_b_menu = driver.find_element(
#     By.CSS_SELECTOR, ".exito-filters-0-x-filter__container.exito-filters-0-x-filter__container--new-layout-filters.bb.b--muted-4.exito-filters-0-x-filter__container--category-3")
# select_b_menu.click()
# time.sleep(10)


import pandas as pd
import joblib
import gzip
from sklearn.linear_model import ElasticNetCV, LassoCV, RidgeCV
from sklearn.ensemble import GradientBoostingRegressor, VotingRegressor
from sklearn.model_selection import KFold, train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, OrdinalEncoder
from sklearn.impute import SimpleImputer
from sklearn.compose import ColumnTransformer
from mlxtend.regressor import StackingCVRegressor
from sklearn.metrics import ConfusionMatrixDisplay
from xgboost import XGBRegressor
from lightgbm import LGBMRegressor
import warnings
warnings.filterwarnings('ignore')

# Defineing necesaries variales columns
LotShape = ['IR3', 'IR2', 'IR1', 'Reg']
Utilities = ['ELO', 'NoSeWa', 'NoSewr', 'AllPub']
LandSlope = ['Sev', 'Mod', 'Gtl']
HouseStyle = ['1Story', '1.5Fin', '1.5Unf', '2Story', '2.5Fin', '2.5Unf', 'SFoyer', 'SLvl']
ExterQual = ['Po', 'Fa', 'TA', 'Gd', 'Ex']
ExterCond = ['Po', 'Fa', 'TA', 'Gd', 'Ex']
BsmtQual = ['NA', 'Po', 'Fa', 'TA', 'Gd', 'Ex']
BsmtCond = ['NA', 'Po', 'Fa', 'TA', 'Gd', 'Ex']
BsmtExposure = ['NA', 'No', 'Mn', 'Av', 'Gd']
BsmtFinType1 = ['NA', 'Unf', 'LwQ', 'Rec', 'BLQ', 'ALQ', 'GLQ']
BsmtFinType2 = ['NA', 'Unf', 'LwQ', 'Rec', 'BLQ', 'ALQ', 'GLQ']
HeatingQC = ['Po', 'Fa', 'TA', 'Gd', 'Ex']
CentralAir = ['N', 'Y']
Electrical = ['Mix', 'FuseP', 'FuseF', 'FuseA', 'SBrkr']
KitchenQual = ['Po', 'Fa', 'TA', 'Gd', 'Ex']
Functional = ['Sal', 'Sev', 'Maj2', 'Maj1', 'Mod', 'Min2', 'Min1', 'Typ']
FireplaceQu = ['NA', 'Po', 'Fa', 'TA', 'Gd', 'Ex']
GarageType = ['NA', 'Detchd', 'CarPort', 'BuiltIn', 'Basment', 'Attchd', '2Types']
GarageFinish = ['NA', 'Unf', 'RFn', 'Fin']
GarageQual = ['NA', 'Po', 'Fa', 'TA', 'Gd', 'Ex']
GarageCond = ['NA', 'Po', 'Fa', 'TA', 'Gd', 'Ex']
PavedDrive = ['N', 'P', 'Y']
PoolQC = ['NA', 'Fa', 'TA', 'Gd', 'Ex']
Fence = ['NA', 'MnWw', 'GdWo', 'MnPrv', 'GdPrv']
ord_cols_mf_cat = [Electrical, Functional, Utilities, KitchenQual]
ord_cols_na_cat = [LotShape, LandSlope, HouseStyle, ExterQual, ExterCond, BsmtQual,
                   BsmtCond, BsmtExposure, BsmtFinType1, BsmtFinType2, HeatingQC,
                   CentralAir, FireplaceQu, GarageType, GarageFinish, GarageQual,
                   GarageCond, PavedDrive, PoolQC, Fence]
num_cols_0 = ['MSSubClass', 'LotFrontage', 'LotArea', 'OverallQual', 'OverallCond',
              'YearBuilt', 'YearRemodAdd', 'MasVnrArea', 'BsmtFinSF1', 'BsmtFinSF2',
              'BsmtUnfSF', 'TotalBsmtSF', '1stFlrSF', '2ndFlrSF', 'LowQualFinSF',
              'GrLivArea', 'BsmtFullBath', 'BsmtHalfBath', 'FullBath', 'HalfBath',
              'BedroomAbvGr', 'KitchenAbvGr', 'TotRmsAbvGrd', 'Fireplaces',
              'GarageYrBlt', 'GarageCars', 'GarageArea', 'WoodDeckSF', 'OpenPorchSF',
              'EnclosedPorch', '3SsnPorch', 'ScreenPorch', 'PoolArea', 'MiscVal',
              'MoSold', 'YrSold']
ord_cols_mf = ['Electrical', 'Functional', 'Utilities', 'KitchenQual']
ord_cols_na = ['LotShape', 'LandSlope', 'HouseStyle', 'ExterQual', 'ExterCond',
               'BsmtQual', 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinType2',
               'HeatingQC', 'CentralAir', 'FireplaceQu', 'GarageType', 'GarageFinish',
               'GarageQual', 'GarageCond', 'PavedDrive', 'PoolQC', 'Fence']
oh_cols_na = ['MSZoning', 'Street', 'Alley', 'LandContour', 'LotConfig', 'Neighborhood',
              'Condition1', 'Condition2', 'BldgType', 'RoofStyle', 'RoofMatl',
              'Exterior1st', 'Exterior2nd', 'MasVnrType', 'Foundation', 'Heating',
              'MiscFeature', 'SaleType', 'SaleCondition']

# Importamos datos
df = pd.read_csv('in/train.csv')
y = df['SalePrice']
df.drop('SalePrice', axis=1, inplace=True)
X_train, X_test, y_train, y_test = train_test_split(df, y, test_size=0.15, random_state=7)

# Define Pipelines
pipe_num_0 = Pipeline(steps=[
    ('imp', SimpleImputer(strategy='constant', fill_value=0))
    ])
pipe_ord_mf = Pipeline(steps=[
    ('imp', SimpleImputer(strategy='most_frequent')),
    ('ord', OrdinalEncoder(categories=ord_cols_mf_cat))
    ])
pipe_ord_na = Pipeline(steps=[
    ('imp', SimpleImputer(strategy='constant', fill_value='NA')),
    ('ord', OrdinalEncoder(categories=ord_cols_na_cat))
    ])
pipe_oh_na = Pipeline(steps=[
    ('imp', SimpleImputer(strategy='constant', fill_value='NA')),
    ('ord', OneHotEncoder(handle_unknown='ignore'))
    ])

# Preprocessing all columns
preprocessing = ColumnTransformer(transformers=[('drop_id', 'drop', ['Id']),
                                                ('trans_num_0', pipe_num_0, num_cols_0),
                                                ('trans_ord_mf', pipe_ord_mf, ord_cols_mf),
                                                ('trans_ord_na', pipe_ord_na, ord_cols_na),
                                                ('trans_oh_na', pipe_oh_na, oh_cols_na)
                                                ])

kfolds = KFold(n_splits=10, shuffle=True, random_state=42)

alphas_alt = [14.5, 14.6, 14.7, 14.8, 14.9, 15, 15.1, 15.2, 15.3, 15.4, 15.5]
alphas2 = [5e-05, 0.0001, 0.0002, 0.0003, 0.0004, 0.0005, 0.0006, 0.0007, 0.0008]
e_alphas = [0.0001, 0.0002, 0.0003, 0.0004, 0.0005, 0.0006, 0.0007]
e_l1ratio = [0.8, 0.85, 0.9, 0.95, 0.99, 1]

# declarando models
ridge = RidgeCV(alphas=alphas_alt, cv=kfolds)

lasso = LassoCV(max_iter=100, alphas=alphas2,
                random_state=42, cv=kfolds)

elasticnet = ElasticNetCV(max_iter=100, alphas=e_alphas,
                          cv=kfolds, l1_ratio=e_l1ratio)

gbr = GradientBoostingRegressor(n_estimators=3000, learning_rate=0.05,
                                max_depth=4, max_features='sqrt',
                                min_samples_leaf=15, min_samples_split=10,
                                loss='huber', random_state=42)

lightgbm = LGBMRegressor(objective='regression',
                         num_leaves=4,
                         learning_rate=0.01,
                         n_estimators=5000,
                         max_bin=200,
                         bagging_fraction=0.75,
                         bagging_freq=5,
                         bagging_seed=7,
                         feature_fraction=0.2,
                         feature_fraction_seed=7,
                         verbose=-1,
                         # min_data_in_leaf=2,
                         # min_sum_hessian_in_leaf=11
                         )

xgboost = XGBRegressor(learning_rate=0.01, n_estimators=3460,
                       max_depth=3, min_child_weight=0,
                       gamma=0, subsample=0.7,
                       colsample_bytree=0.7,
                       objective='reg:squarederror', nthread=-1,
                       scale_pos_weight=1, seed=27,
                       reg_alpha=0.00006)

# Stack model
stack_gen = StackingCVRegressor(regressors=(ridge, lasso, elasticnet,
                                            gbr, xgboost, lightgbm),
                                meta_regressor=xgboost,
                                use_features_in_secondary=True)

# Voting model
voting = VotingRegressor(estimators=[('ridge',ridge), ('lasso',lasso), ('elasticnet',elasticnet),
                                     ('gbr',gbr), ('lightgbm',lightgbm),
                                     ('xgboost',xgboost),('stack_gen',stack_gen)],
                        weights=[0.1,0.1,0.1,0.1,0.1,0.15,0.25])

# Finaly pipeline
pipe = Pipeline(steps=[('preprocessing', preprocessing),
                       ('models', voting)
                       ])

# Fit pipeline
print('fitting')
pipe.fit(X_train, y_train)

# Test accuracy
print("Accuracy: %s " % str(ridge.score(X_test, y_test)))

# Export model pipeline
joblib.dump(ridge, gzip.open('../models/model_binary.dat.gz', "wb"))


import os
import sys
import time
from enum import Enum

interval_max = 4

vault_path = ''

class activity:

    def __init__(self, duration, state):
        self.duration = 60 * duration
        self.state = state

class Tracking:

    def __init__(self, now, start, duration, state, interval):
        self.now = now
        self.start = start
        self.duration = duration
        self.state = state
        self.interval = interval

    def __str__(self):
        return str(self)

class status(Enum):
    work_state = 1
    short_break_state = 2
    long_break_state = 3

def main(argv):

    global vault_path

    try:
        if len(argv) != 1 or os.path.exists(argv[1]):
            vault_path = argv[1]
        else:
            print("py main.py <vault path>")
            exit()
    except:
        print("py main.py <vault path>")
        exit()

    work = activity(25, status.work_state)

    short_break = activity(5, status.short_break_state)

    long_break = activity(15, status.long_break_state)

    Pomo = Tracking(work.duration, work.duration, work.duration, work.state, 0)

    DisplayTimer(Pomo, 'x')

    PauseManager()

    while True:

        while Pomo.now != 0:

            PauseManager()

            DisplayTimer(Pomo, ' ')

            Pomo.now -= 1

            time.sleep(1)

        if Pomo.state == status.work_state:
            Pomo.interval += 1

        if Pomo.state != status.work_state:
            ConfigNewInterval(work, Pomo)
            DisplayTimer(Pomo, 'x')

        elif Pomo.interval < interval_max and Pomo.state == status.work_state:
            ConfigNewInterval(short_break, Pomo)
            DisplayTimer(Pomo, 'x')

        elif Pomo.interval == interval_max and Pomo.state == status.work_state:

            ConfigNewInterval(long_break, Pomo)
            DisplayTimer(Pomo, 'x')
            Pomo.interval = 0

        while True:
            lines = ReadFileLines()
            if len(lines) == 0 or lines[3] == ' - [ ] -- Start/Pause':
                break

def ConfigNewInterval(activity, Pomo):
    Pomo.state = activity.state

    Pomo.start = activity.duration
    Pomo.now = activity.duration

def GetStateString(state):
    if state == status.work_state:
        return 'Work'
    if state == status.short_break_state:
        return 'Short Break'
    if state == status.long_break_state:
        return 'Long Break'

def SecsToPrettyString(time):
    mins, secs = divmod(time, 60)
    return '{:02d}:{:02d}'.format(mins, secs)

def ReadFileLines():
    while True:
        try:
            file = open(vault_path+"\\Obsidoro.md", 'r', encoding="utf-8")
            break
        except:
            pass

    lines = file.readlines()

    file.close()

    return lines

def WriteFile(data):
    while True:
        try:
            file = open(vault_path+"\\Obsidoro.md", 'w', encoding="utf-8")
            break
        except:
            pass

    file.write(data)

    file.close()

def PauseManager():
    lines = ReadFileLines()

    if len(lines) == 0 or lines[3] == ' - [x] -- Start/Pause':

        while True:

            lines = ReadFileLines()

            if len(lines) == 0 or lines[3] == ' - [ ] -- Start/Pause':
                break

def DisplayTimer(Pomo, tickbox):

    table = '|Status| Total Time| Time Left| Intervals|\n' \
            '|:-:|:-:|:-:|:-:|\n' \
            '|{}|{}|{}|{}|\n'.format(GetStateString(Pomo.state),
                                     SecsToPrettyString(Pomo.start),
                                     SecsToPrettyString(Pomo.now), Pomo.interval)

    start_button = ' - [{}] -- Start/Pause'.format(tickbox)

    new_file_data = table + start_button

    WriteFile(new_file_data)

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


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Oct 13 04:41:16 2018

@author: rishabh
"""

import os
import json
import numpy as np
#import matplotlib.pyplot as plt

from util import find_analogies

from brown import get_sentences_with_word2idx_limit_vocab as get_brown

class Glove:
    def __init__(self, D, V, context_sz):
        self.D = D
        self.V = V
        self.context_sz =context_sz

    def fit(self, sentences, cc_matrix=None, learning_rate=1e-4, reg=0.1, xmax=100, alpha=0.75, epochs=10, gd=True):
        # build co-occurrence matrix
        # paper calls it X, so we will call it X, instead of calling
        # the training data X
        V = self.V
        D = self.D

        if not os.path.exists(cc_matrix):
            X = np.zeros((V,V))
            N = len(sentences)
            print("Number of sentences to process:",N)
            it = 0
            for sentence in sentences:
                it += 1
                if it % 10000 == 0:
                    print("processed", it, "/", N)
                n = len(sentence)
                for i in range(n):
                    # i just points to which element of the sequence (sentence) we're looking at
                    wi = sentence[i]

                    start = max(0, i - self.context_sz)
                    end = min(n, i+ self.context_sz)

                    if i - self.context_sz < 0:
                        points = 1.0 / (i + 1)
                        X[wi,0] += points
                        X[0,wi] += points
                    if i + self.context_sz > n:
                        points = 1 / (n - i)
                        X[wi,1] += points
                        X[1,wi] += points
                    # left side
                    for j in range(start, i):
                        wj = sentence[j]
                        points = 1 / (i - j)
                        X[wi,wj] += points
                        X[wj,wi] += points

                    # right side
                    for j in range(i + 1, end):
                        wj = sentence[j]
                        points = 1 / (j - i)
                        X[wi,wj] += points
                        X[wj,wi] += points
            np.save(cc_matrix,X)
        else:
            X = np.load(cc_matrix)

        print("max in X:",X.max())

        # Weighting
        fX = np.zeros((V,V))
        fX[X < xmax] = (X[X < xmax] / float(xmax)) ** alpha
        fX[X >= xmax] = 1

        # target
        logX = np.log(X + 1)

        print("max in log(X)",logX.max())

        # initialize weights
        W = np.random.randn(V,D) / np.sqrt(V + D)
        b = np.zeros(V)
        U = np.random.randn(V,D) / np.sqrt(V + D)
        c = np.zeros(V)
        mu = logX.mean()

        costs = []
        sentence_indexes = range(len(sentences))
        for epoch in range(epochs):
            delta = W.dot(U.T) + b.reshape(V,1) + c.reshape(1,V) + mu-logX
            cost = (fX * delta * delta).sum()
            costs.append(cost)
            print("epoch:",epoch,"cost:",cost)

            if gd:
                for i in range(V):
                    W[i] -= learning_rate*(fX[i,:]*delta[i,:]).dot(U)
                W -= learning_rate*reg*W

                for i in range(V):
                    b[i] -= learning_rate*fX[i,:].dot(delta[i,:])

                for j in range(V):
                    U[j] -= learning_rate*(fX[:,j]*delta[:,j]).dot(W)
                U -= learning_rate*reg*U

                for j in range(V):
                    c[j] -= learning_rate*fX[:,j].dot(delta[:,j])
            else:
                # ALS Method
                # update W
                for i in range(V):
                    matrix = reg*np.eye(D) + (fX[i,:] * U.T).dot(U)

                    vector = (fX[i,:] * (logX[i,:] - b[i] - c - mu)).dot(U)
                    W[i] = np.linalg.solve(matrix, vector)

                # update b
                for i in range(V):
                    denominator = fX[i,:].sum()
                    numerator = fX[i,:].dot(logX[i,:] - W[i].dot(U.T) -c -mu)

                    b[i] = numerator / denominator / (1 + reg)

                # update U
                for j in range(V):
                    matrix = reg * np.eye(D) + (fX[:,j]*W.T).dot(W)
                    vector = (fX[:,j]*(logX[:,j] -b -c[j])).dot(W)

                    U[j] = np.linalg.solve(matrix,vector)

                # update c
                for j in range(V):
                    denominator = fX[:,j].sum()
                    numerator = fX[:,j].dot(logX[:,j] - W.dot(U[j]) - b - mu)

                    c[j] = numerator / denominator / (1 + reg)

        self.W = W
        self.U = U

        #plt.plot(costs)
        #plt.show()

    def save(self, fn):
        # function word_analogies expects a (V,D) matrx and a (D,V) matrix
        arrays = [self.W, self.U.T]
        np.savez(fn, *arrays)

def main(we_file, w2_ifile):

    cc_matrix = "cc_matrix_brown.npy"

    if os.path.exists(cc_matrix):
        with open(w2_ifile) as f:
            word2idx = json.load(f)
        sentences  = []
    else:
        keep_words = set([
        'king', 'man', 'woman',
        'france', 'paris', 'london', 'rome', 'italy', 'britain', 'england',
        'french', 'english', 'japan', 'japanese', 'chinese', 'italian',
        'australia', 'australian', 'december', 'november', 'june',
        'january', 'february', 'march', 'april', 'may', 'july', 'august',
        'september', 'october',
        ])
        sentences, word2idx = get_brown(n_vocab=5000, keep_words=keep_words)
        with open(w2_ifile,'w') as f:
            json.dump(word2idx, f)

    V = len(word2idx)
    model = Glove(200, V, 10)

    model.fit(sentences, cc_matrix=cc_matrix, epochs=20)
    model.save(we_file)

if __name__ == '__main__':
    we = 'glove_model_50.npz'
    w2i = 'glove_word2idx_50.json'

    main(we, w2i)
    npz = np.load(we)
    W1 = npz['arr_0']
    W2 = npz['arr_1']

    with open(w2i) as f:
        word2idx = json.load(f)
        idx2word = {i:w for w,i in word2idx.items()}

    for concat in (True,False):
        print("** concat:", concat)

        if concat:
            We = np.hstack([W1, W2.T])
        else:
            We = (W1 + W2.T) / 2

        find_analogies('king', 'man', 'woman', We, word2idx, idx2word)
        find_analogies('france', 'paris', 'london', We, word2idx, idx2word)
        find_analogies('france', 'paris', 'rome', We, word2idx, idx2word)
        find_analogies('paris', 'france', 'italy', We, word2idx, idx2word)
        find_analogies('france', 'french', 'english', We, word2idx, idx2word)
        find_analogies('japan', 'japanese', 'chinese', We, word2idx, idx2word)
        find_analogies('japan', 'japanese', 'italian', We, word2idx, idx2word)
        find_analogies('japan', 'japanese', 'australian', We, word2idx, idx2word)
        find_analogies('december', 'november', 'june', We, word2idx, idx2word)


from datetime import datetime
from decimal import Decimal
from unittest import TestCase
from uuid import uuid4

from chalicelib.models import (
    Account,
    Transaction,
    TransactionSummary,
    TransactionSummaryByMonth,
)

class TestTransaction(TestCase):
    @classmethod
    def setUpClass(cls):
        cls.transactions = [
            Transaction(id=0, date=datetime(2023, 7, 15), amount=Decimal("60.5")),
            Transaction(id=1, date=datetime(2023, 7, 28), amount=Decimal("-10.3")),
            Transaction(id=2, date=datetime(2023, 8, 2), amount=Decimal("-20.46")),
            Transaction(id=3, date=datetime(2023, 8, 13), amount=Decimal("10")),
        ]
        cls.account = Account(id=uuid4(), transactions=cls.transactions)

    def test_summary(self):
        summary_expected = TransactionSummary(
            total=4,
            balance=Decimal("39.74"),
            average_credit=Decimal("35.25"),
            average_debit=Decimal("-15.38"),
        )
        self.assertEqual(self.account.get_summary(), summary_expected)

    def test_summary_by_month(self):
        summary_expected = TransactionSummaryByMonth(
            total=2,
            balance=Decimal("50.2"),
            average_credit=Decimal("60.50"),
            average_debit=Decimal("-10.30"),
            month=7,
        )
        self.assertEqual(self.account.get_summary_by_month(7), summary_expected)


import pandas as pd
import math
from operator import itemgetter
import random
import matplotlib.pyplot as plt
import numpy as np

# Read in data
data = pd.read_csv('house_votes_84.csv')

# Shuffles the rows of the normalized data and returns a tuple with a training set and a test set in that order
def train_test_split():
    data_sample = data.sample(frac=1)
    return (data_sample.iloc[:348], data_sample.iloc[348:])

# Given a subset of the data, calculate the entropy
def calculate_entropy(subset):

    num_Democrats = 0
    num_Republicans = 0

    # Case where a size-1 dataframe is automatically converted to a list
    if type(subset) == list:
        for instance in subset:
            if instance == 0:
                num_Democrats += 1
            else:
                num_Republicans += 1
    else:
        for instance in subset['target']:
            if instance == 0:
                num_Democrats += 1
            else:
                num_Republicans += 1

    # Cases for if either class has 0 entries in the subset to avoid log domain error
    if num_Democrats == 0 and num_Republicans == 0:
        return 0
    elif num_Democrats == 0:
        return - (num_Republicans/len(subset) * math.log2(num_Republicans/len(subset)))
    elif num_Republicans == 0:
        return - (num_Democrats/len(subset) * math.log2(num_Democrats/len(subset)))

    return -(num_Democrats/len(subset) * math.log2(num_Democrats/len(subset))) - (num_Republicans/len(subset) * math.log2(num_Republicans/len(subset)))

# Given a subset of data and the partitions made by splitting on an attribute, return the information gain of that split
# This is used to find the best attribute to split the decision tree on
def calculate_information_gain(subset, partitions):

    partitions_size = sum(len(p) for p in partitions)
    entropies = []
    information = 0

    for partition in partitions:
        entropies.append(calculate_entropy(partition))

    for i in range(len(entropies)):
        information += entropies[i] * (len(partitions[i])/partitions_size)

    return calculate_entropy(subset) - information

# This node class is used during training to split on attributes and create the tree
class tree_node():

    def __init__(self):
        self.label = ''
        self.split_attribute = ''
        self.partitions = []
        self.children = [] # Array of tuples, the first value being the child node itself, and the second being the attribute value that leads to the node
        self.is_leaf = False
        self.attr_branch = 9
        self.parent = ''

    # Finds the best attribute to split on during a step in training
    def find_best_split(self, subset, attribute_list):

        criterion_vals = []

        for attr in attribute_list:
            yea_list = []
            nay_list = []
            no_vote_list = []
            for instance in subset.iterrows():
                if instance[1][attr] == 0:
                    no_vote_list.append(instance[1]['target'])
                if instance[1][attr] == 1:
                    nay_list.append(instance[1]['target'])
                if instance[1][attr] == 2:
                    yea_list.append(instance[1]['target'])

            criterion_vals.append( ( attr, calculate_information_gain(subset, [no_vote_list, nay_list, yea_list]) ) )
            self.split_attribute = max(criterion_vals, key=itemgetter(1))[0]

        return self.split_attribute

# Given a new tree node, train the tree to be used for predictions
def train_tree(dataset, root):

    attribute_list = data.columns.to_list()[:16]

    # The recursive call of the function must be separated to reset the attribute list every time train_tree is used
    def train_tree_recur(dataset, root, attr_list):

        # Find the majority class in dataset for use in creating leaf nodes
        majority_class = ''
        num_Democrats = 0
        num_Republicans = 0
        for instance in dataset['target']:
            if instance == 0:
                num_Democrats += 1
            else:
                num_Republicans += 1
            if num_Democrats > num_Republicans:
                majority_class = 0
            elif num_Republicans > num_Democrats:
                majority_class = 1
            else:
                tie_breaker = random.randint(0, 1)
                if tie_breaker == 0:
                    majority_class = 0
                else:
                    majority_class = 1

        # Stopping Criteria

        # Stop if 75% or more of the current partition belongs to one class, and set the label as that class
        if num_Democrats > .75 * len(dataset.index):
            root.label = 0
            root.is_leaf = True
            return root
        elif num_Republicans > .75 * len(dataset.index):
            root.label = 1
            root.is_leaf = True
            return root

        # Stop if there are no more attributes left to test, and set the label as the current majority class
        if len(attr_list) == 0:
            root.label = majority_class
            root.is_leaf = True
            return root

        # Select best attribute to split and remove it from the list
        best_attr = root.find_best_split(dataset, attr_list)
        attr_list.remove(best_attr)

        # Create the partitions based on the best split attribute
        yea_partition = []
        nay_partition = []
        no_vote_partition = []

        for i in range(dataset[best_attr].size):
            if dataset[best_attr].values[i] == 0:
                no_vote_partition.append(dataset.iloc[i])
            elif dataset[best_attr].values[i] == 1:
                nay_partition.append(dataset.iloc[i])
            else:
                yea_partition.append(dataset.iloc[i])

        # Convert partition lists to dataframes for further operations
        yea_partition = pd.DataFrame(yea_partition)
        nay_partition = pd.DataFrame(nay_partition)
        no_vote_partition = pd.DataFrame(no_vote_partition)

        # Create leaf nodes and subtrees based on above partitions
        if len(yea_partition) == 0:
            yea_leaf = tree_node()
            yea_leaf.label = majority_class
            yea_leaf.is_leaf = True
            yea_leaf.attr_branch = 2
            root.children.append(yea_leaf)
        else:
            yea_child = train_tree_recur(yea_partition, tree_node(), attr_list)
            yea_child.attr_branch = 2
            root.children.append(yea_child)

        if len(nay_partition) == 0:
            nay_leaf = tree_node()
            nay_leaf.label = majority_class
            nay_leaf.is_leaf = True
            nay_leaf.attr_branch = 1
            root.children.append(nay_leaf)
        else:
            nay_child = train_tree_recur(nay_partition, tree_node(), attr_list)
            nay_child.attr_branch = 1
            root.children.append(nay_child)

        if len(no_vote_partition) == 0:
            no_vote_leaf = tree_node()
            no_vote_leaf.label = majority_class
            no_vote_leaf.is_leaf = True
            no_vote_leaf.attr_branch = 0
            root.children.append(no_vote_leaf)
        else:
            no_vote_child = train_tree_recur(no_vote_partition, tree_node(), attr_list)
            no_vote_child.attr_branch = 0
            root.children.append(no_vote_child)

        return root

    return train_tree_recur(dataset, root, attribute_list)

# Trains a tree with training data and uses it to classify test data
def make_predictions(training_set, test_set):

    predicted_classes = [] # Stores the final predictions of each instance as a tuple containing the indices and the predicted classes
    cur_node = train_tree(training_set, tree_node())

    for instance in test_set.iterrows():
        while True:
            if cur_node.is_leaf:
                predicted_classes.append((instance[0], cur_node.label))
                while cur_node.parent != '':
                    cur_node = cur_node.parent
                break
            else:
                # Go down the tree based on the best attribute
                attr_val = instance[1][cur_node.split_attribute] # The value of the attribut to split on
                for child in cur_node.children:
                    if child.attr_branch == attr_val:
                        child.parent = cur_node
                        cur_node = child

    assert(len(predicted_classes) == len(test_set.index)) # Check that the number of predictions made is equal to the number of rows in the test set

    return predicted_classes

# Computes how accurate the prediction algorithm is by training it on the training_set and testing it on the test_set
def compute_accuracy(training_set, test_set):
    number_correct = 0
    predictions = make_predictions(training_set, test_set)

    for i in range(len(predictions)):
        if test_set.iloc[i][16] == predictions[i][1]:
            number_correct += 1

    return number_correct / len(predictions)

# Creates 50 train-test splits, trains the data using the training data, and tests it on the test data
# The accuracies of each of these 50 trials are graphed and stored
def get_results():
    accuracies = []

    for i in range(50):
        train, test = train_test_split()
        accuracies.append(compute_accuracy(train, test))

    plt.plot(range(1, 51), accuracies)
    plt.xlabel("Trial Run Number")
    plt.ylabel("Accuracy")
    plt.title("Accuracies for 50 Trial Runs")
    plt.savefig("Plots/test_run_accuracies")
    plt.clf()

get_results()


"""
Assumes screen resolution of 1366x 768,
using chrome browser without bookmarks tool bar enabled.
At top of screen, press down arrow 4 times to center game view.
"""
import pyscreenshot as ImageGrab
import os
import time

#---------------------------
#Global vars
#---------------------------
x_pad = 200
y_pad = 119

def screenGrab():
    #box = (x_pad+1, y_pad+1, x_pad+641, y_pad+481)
    im = ImageGrab.grab()
    im.save(os.getcwd() + '/full_snap__' + str(int(time.time())) + '.png', 'PNG')

def main():
    screenGrab()

if __name__ == '__main__':
    main()


import os
import pathlib
import tensorflow as tf
from keras.layers import *

AUTOTUNE = tf.data.experimental.AUTOTUNE

def data_handle(path):
    root_dir = os.getcwd() + os.sep + path
    root_dir_path = pathlib.Path(root_dir)

    all_image_filename = [str(jpg_path) for jpg_path in root_dir_path.glob('**/*.jpg')]
    all_image_label = [pathlib.Path(image_file).parent.name for image_file in all_image_filename]
    all_image_unique_labelname = list(set(all_image_label))

    name_index = dict((name, index) for index, name in enumerate(all_image_unique_labelname))
    image_lable_code = [name_index[pathlib.Path(path).parent.name] for path in all_image_filename]

    return all_image_filename, image_lable_code

# 2. 生成 dataset
# 借助文件名获取执行的图片，还有同时给出对应的标签信息
# 因为图片大小为256的数据跑得太慢，所以把图片缩放到32
def get_image_by_filename(filename, label):
    # 借助 tf 读入文件
    image_data = tf.io.read_file(filename)
    image_jpg = tf.image.decode_jpeg(image_data)
    image_resized = tf.image.resize(image_jpg, [32, 32])
    image_scale = image_resized / 255.0
    return image_scale, label

def only_get_image_by_filename(filename):
    # 借助 tf 读入文件
    image_info = []
    for f in filename:
        image_data = tf.io.read_file(f)
        image_jpg = tf.image.decode_jpeg(image_data)
        image_resized = tf.image.resize(image_jpg, [32, 32])
        image_scale = image_resized / 255.0
        image_info.append(image_scale)
    return image_info

# 3. 生成cnn网络，完成训练
class Model:
    def __init__(self):
        self.num_epochs = 10
        self.learning_rate = 0.001
        self.model = tf.keras.Sequential()

class LeNet5(Model):
    def __init__(self):
        super().__init__()

    def setModel(self):
        self.model.add(Conv2D(6, (5, 5), activation='relu', input_shape=(32, 32, 1)))
        self.model.add(MaxPooling2D(2, 2))
        self.model.add(Conv2D(16, (5, 5), activation='relu'))
        self.model.add(MaxPooling2D(2, 2))
        self.model.add(Flatten())
        self.model.add(Dense(120, activation='relu'))
        self.model.add(Dense(84, activation='relu'))
        self.model.add(Dense(65, activation='softmax'))

    def trainModel(self, train_data, tf_test_fea, tf_test_lab):
        self.model.summary()

        self.model.compile(
            optimizer=tf.keras.optimizers.Adam(learning_rate=self.learning_rate),
            loss=tf.keras.losses.sparse_categorical_crossentropy,
            metrics=['accuracy']
        )

        self.model.fit(train_data, epochs=self.num_epochs, validation_data=(tf_test_fea, tf_test_lab))

if __name__ == '__main__':
    # 1. 获取指定目录(子目录)下的所有的文件的名称、该文件所对应的标签名称（该文件的父目录的名称）==>> 编码 == list
    # 我把中英文的训练都放在了train_data文件夹下，同理中英文的测试都放在test_data文件夹下
    train_path = 'train_data'
    test_path = 'test_data'

    all_image_filename, train_image_lable_code = data_handle(train_path)
    all_test_image_filename, test_image_lable_code = data_handle(test_path)

    tf_train_feature_filenames = tf.constant(all_image_filename)
    tf_train_labels = tf.constant(train_image_lable_code)
    train_dataset = tf.data.Dataset.from_tensor_slices((tf_train_feature_filenames, tf_train_labels))

    tf_test_feature = tf.convert_to_tensor(only_get_image_by_filename(all_test_image_filename))
    tf_test_labels = tf.constant(test_image_lable_code)

    # map
    train_dataset = train_dataset.map(map_func=get_image_by_filename, num_parallel_calls=AUTOTUNE)

    train_dataset = train_dataset.shuffle(buffer_size=200000)
    train_dataset = train_dataset.batch(batch_size=32)
    train_dataset = train_dataset.prefetch(AUTOTUNE)

    lenet = LeNet5()
    lenet.setModel()
    lenet.trainModel(train_dataset, tf_test_feature, tf_test_labels)


import os
from collections import defaultdict

from leapp import reporting
from leapp.libraries.stdlib import api
from leapp.models import TargetInitramfsTasks, UpgradeInitramfsTasks

DRACUT_MOD_DIR = '/usr/lib/dracut/modules.d/'
SUMMARY_DRACUT_FMT = (
    'The requested dracut modules for the initramfs are in conflict.'
    ' At least one dracut module is specified to be installed from'
    ' multiple paths. The list of conflicting dracut module names'
    ' with paths is listed below: {}'
)

def _printable_modules(conflicts):
    list_separator_fmt = '\n    - '
    for name, paths in conflicts.items():
        paths = sorted([str(i) for i in paths])
        output = ['{}{}: {}'.format(list_separator_fmt, name, paths)]
    return ''.join(output)

def _treat_path(dmodule):
    """
    In case the path is not set, set the expected path of the dracut module.
    """
    if not dmodule.module_path:
        return os.path.join(DRACUT_MOD_DIR, dmodule.name)
    return dmodule.module_path

def _detect_dracut_modules_conflicts(msgtype):
    """
    Return dict of modules with conflicting tasks

    In this case when a dracut module should be applied but different
    sources are specified. E.g.:
       include dracut modules X where,
         msg A)  X
         msg B)  X from custom path
    """
    dracut_modules = defaultdict(set)
    for msg in api.consume(msgtype):
        for dmodule in msg.include_dracut_modules:
            dracut_modules[dmodule.name].add(_treat_path(dmodule))
    return {key: val for key, val in dracut_modules.items() if len(val) > 1}

def process():
    conflicts = _detect_dracut_modules_conflicts(UpgradeInitramfsTasks)
    if conflicts:
        report = [
            reporting.Title('Conflicting requirements of dracut modules for the upgrade initramfs'),
            reporting.Summary(SUMMARY_DRACUT_FMT.format(_printable_modules(conflicts))),
            reporting.Severity(reporting.Severity.HIGH),
            reporting.Groups([reporting.Groups.SANITY]),
            reporting.Groups([reporting.Groups.INHIBITOR]),
        ]
        reporting.create_report(report)

    conflicts = _detect_dracut_modules_conflicts(TargetInitramfsTasks)
    if conflicts:
        report = [
            reporting.Title('Conflicting requirements of dracut modules for the target initramfs'),
            reporting.Summary(SUMMARY_DRACUT_FMT.format(_printable_modules(conflicts))),
            reporting.Severity(reporting.Severity.HIGH),
            reporting.Groups([reporting.Groups.SANITY]),
            reporting.Groups([reporting.Groups.INHIBITOR]),
        ]
        reporting.create_report(report)


from django import template
from django.urls import reverse

register = template.Library()

@register.simple_tag
def add_active(request, name, by_path=False):
    """ Return the string 'active' current request.path is same as name
        Keyword aruguments:
        request -- Django request object
        name -- name of the url or the actual path
        by_path -- True if name contains a url instead of url name"""

    if by_path:
        path = name
    else:
        path = reverse(name)

    if request.path == path:
        return ' active '

    return ''


import whois
import random
import string

def random_string_generator(str_size, allowed_chars):
    return ''.join(random.choice(allowed_chars) for x in range(str_size))

class color:
    GREEN = '\033[92m'
    STOP = '\033[0m'
    RED='\033[31m'
    BLUE='\033[94m'
    BOLD = '\033[93m'

def whois_query():
    hostname = input(color.BOLD + "WHOIS Domain or Query: " + color.STOP)
    report = False
    rep = input(color.BOLD + "Generate Report? (Y/n): " + color.STOP)
    if rep == 'y' or rep == 'Y':
        report = True
    if isRegistered(hostname) == False:
        print(color.RED + "[-] Domain is not registered." + color.STOP)
        return None

    domain = whois.whois(hostname)
    print(color.GREEN + "[+] Registrar Name: " + color.STOP, domain.registrar)
    print(color.GREEN + "[+] Organisation: " + color.STOP, domain.org)
    print(color.GREEN + "[+] City: " + color.STOP, domain.city)
    print(color.GREEN + "[+] State: " + color.STOP, domain.state)
    print(color.GREEN + "[+] Country: " + color.STOP, domain.country)
    print(color.GREEN + "[+] ZipCode: " + color.STOP, domain.zipcode)
    print(color.GREEN + "[+] Name Servers: " + color.STOP)
    for i in domain.name_servers:
        print("\t", i)
    print(color.GREEN + "[+] Whois Server: " + color.STOP, domain.whois_server)

    if report and isRegistered(hostname):
        try:
            url = random_string_generator(12, string.ascii_letters)
            with open("Report/whois_info_" + str(url) + ".txt", 'w') as file:
                file.write("Registrar Name: " + str(domain.registrar) + "\n")
                file.write("Organisation: " + str(domain.org) + "\n")
                file.write("City: " + str(domain.city) + "\n")
                file.write("State: " + str(domain.state) + "\n")
                file.write("Country: " + str(domain.country) + "\n")
                file.write("ZipCode: " + str(domain.zipcode) + "\n")
                file.write("Name Servers: ")
                file.write("\n")
                for i in domain.name_servers:
                    file.write(str(i) + "\t")
                file.write("\n")
                file.write("Whois Server: " + str(domain.whois_server))
                file.write("\n")
            print(color.BLUE + "[+]Report generated Successfully at Report/whois_info_" + str(url) + ".txt ." + color.STOP)
        except:
            print(color.RED + "[-]Unable to Generate Report." + color.STOP)
    #print(domain)
    return "PASS"

def isRegistered(domain_name):
    try:
        w = whois.whois(domain_name)
    except:
        return False
    else:
        return bool(w.domain_name)

#whois_query()


from chess.helpers import inverse

def create_empty_field():
    return {
        1: {
            'A': '♜',
            'B': '♞',
            'C': '♝',
            'D': '♛',
            'E': '♚',
            'F': '♝',
            'G': '♞',
            'H': '♜',
        },
        2: {
            'A': '♟',
            'B': '♟',
            'C': '♟',
            'D': '♟',
            'E': '♟',
            'F': '♟',
            'G': '♟',
            'H': '♟',
        },
        7: {
            'A': '♙',
            'B': '♙',
            'C': '♙',
            'D': '♙',
            'E': '♙',
            'F': '♙',
            'G': '♙',
            'H': '♙',
        },
        8: {
            'A': '♖',
            'B': '♘',
            'C': '♗',
            'D': '♕',
            'E': '♔',
            'F': '♗',
            'G': '♘',
            'H': '♖',
        }
    }

def find_in_field(i, j, field):
    try:
        return field[i][j]
    except:
        return ' '

def render(field, fallen):
    l = '  '
    for c in 'ABCDEFGH':
        l += '  ' + c + '  '

    print(l)

    white_fallen = len(fallen.get('white'))
    black_fallen = len(fallen.get('black'))

    for i in list(range(1, 9))[-1::-1]:
        divider = '  ' + '-----' * 8 + '-'

        if i == 3 or i == 5:
            divider += '-----------------'

        if i == 2:
            divider += ' Fallen whites ↓'
        if i == 6:
            divider += ' Fallen blacks ↑'

        print(divider)

        l = str(i) + ' '
        for j in 'ABCDEFGH':
            content = find_in_field(i, j, field)
            l += '| ' + content + '  '
        l += '|'

        if i >= 7 and fallen.get('black'):
            if black_fallen >= 0:
                t = 0
                while t < 3 and t < black_fallen:
                    l += ' ' + fallen.get('black')[t]
                    black_fallen -= 1
                    t += 1

        if i <= 2 and fallen.get('white'):
            if white_fallen >= 0:
                t = 0
                while t < 3 and t < white_fallen:
                    l += ' ' + fallen.get('white')[t]
                    white_fallen -= 1
                    t += 1

        print(l)

    print('  ' + '-----' * 8 + '-')

    return field

class Game:
    def __init__(self, field, moves):
        self.field = field
        self.moves = moves
        self.fallen = {
            'white': [],
            'black': []
        }
        self.queue = 'white'
        self.turn = 0
        self.turns = []

    def move(self, _from, _to):
        try:
            self.field = self._move_to(_from, _to)
            self.queue = inverse(self.queue)
            self.turn += 1
            self.turns.append([_from, _to])
            render(self.field, self.fallen)
        except Exception as err:
            print(err)
        return self

    def get_color(self, s):
        return 'black' if s in '♜♞♝♛♚♝♞♜♟' else 'white'

    def _move_to(self, _from, _to):
        [from_i, from_j] = _from
        [to_i, to_j] = _to

        print(f"Movig from {from_i}{from_j} to {to_i}{to_j}\n")

        figure = self.find(from_i, from_j)
        if figure == ' ':
            raise Exception('No figure')

        color = self.get_color(figure)
        if  color != self.queue:
            raise Exception(f'It\'s {self.queue}s turn')

        move_fn = self.moves[figure]

        move_result = move_fn(self, from_i, to_i, from_j, to_j)

        if move_result:
            del self.field[from_i][from_j]
            if self.field.get(to_i):
                if self.field[to_i].get(to_j):
                    self.field[to_i][to_j] = figure
                else:
                    self.field[to_i] = self.field.get(to_i, {})
                    self.field[to_i][to_j] = figure
            else:
                self.field[to_i] = {to_j: figure}

            if isinstance(move_result, dict):
                self.fallen[move_result['color']].append(move_result['figure'])
        else:
            raise Exception('This move is not allowed')

        return self.field

    def find(self, i, j):
        return find_in_field(i, j, self.field)

def start(moves):
    field = create_empty_field()
    game = Game(field, moves)
    render(game.field, game.fallen)
    print('Game is started')
    return game


import os
from smbus2 import SMBus
import time

#bus = SMBus(1)

def measure_int_temp():
	temp = os.popen("vcgencmd measure_temp").readline()
	temp = temp.replace("temp=", "")
	temp = temp.replace("'C", "")
	temp = temp.replace("\n", "")
	return float(temp)

def measure_ext_temp():
	with SMBus(1) as bus:
		temp = bus.read_i2c_block_data(0x40, 0xE3,2)
	time.sleep(0.1)
	cTemp = ((temp[0] * 256 + temp[1]) * 175.72 / 65536.0) - 46.85
	return round(cTemp, 1)

def measure_ext_humid():
	with SMBus(1) as bus:
		rh = bus.read_i2c_block_data(0x40, 0xE5, 2)
	time.sleep(0.1)
	humidity = ((rh[0] * 256 + rh[1]) * 125 / 65536.0) - 6
	return round(humidity, 1)

if __name__ == "__main__":
	print("Internal Temp:     " + str(measure_int_temp()))
	print("External Temp:     " + str(measure_ext_temp()))
	print("External Humidity: " + str(measure_ext_humid()))

Demos/Simple Rasperry Pi Data Collection/datamonitorplus.py


# Helpful functions for the discord bot

from typing import Any

import discord
import requests
from discord.ext.commands import context

import src.DiscordBot.discordBot
from src.SQLServer.gameManager import get_log_channel_id
from src.SQLServer.modelManager import is_model_logged, log_model

# Checks if a guild exists
async def does_guild_exist(guild_id: str, discord_client: discord.Client) -> bool:
    try:
        await discord_client.fetch_guild(int(guild_id))
    except discord.errors.Forbidden:
        return False

    return True

# Used by handle_prompt, ensures a sent message is a proper response to the prompt sent
def prompt_check(message_data: dict[str, Any], ctx: context) -> bool:
    return ctx.author.id == message_data["author"].id and ctx.channel == message_data["channel"]

# Returns the appropriate channel(s) for a given place
def get_logging_channels(guild_id: str) -> tuple[bool, str]:
    retrieve_success, log_id = get_log_channel_id(guild_id, True, False)

    if retrieve_success:
        return True, log_id

    return False, ""

# Takes a specified list of questions and prompts them to the user, returns the user's answers to the questions
async def handle_prompt(prompts: list[str], message_data: dict[str, Any]) -> list[str]:
    responses = []

    for prompt in prompts:
        await message_data["send message"](prompt)
        response_message_object = await message_data["discord_client"].wait_for("message",
                                                                                check=lambda ctx: prompt_check(
                                                                                message_data, ctx))
        responses.append(response_message_object.content)

    return responses

# Adds a game log message to the queue
def queue_game_logging_message(channel_id: str, place_details: dict[str, Any], job_id: str) -> bool:
    embed_success, message_dictionary = generate_place_logging_dictionary(place_details, job_id)

    if embed_success:
        # channels = get_logging_channels(channel_id)

        src.DiscordBot.discordBot.message_queue.put([channel_id, message_dictionary])

        return True
    else:
        print(f"Failed generating log embeds for {place_details['name']}")

    return False

# Adds a game log message to the queue
def queue_spam_logging_message(channel_id: str, client_address: str, job_id: str) -> bool:
    embed_success, message_dictionary = generate_spam_logging_dictionary(client_address, job_id)

    if embed_success:
        # channels = get_logging_channels(channel_id)

        src.DiscordBot.discordBot.message_queue.put([channel_id, message_dictionary])

        return True
    else:
        print(f"Failed generating spam embeds")

    return False

# Adds a model log message to the queue
def queue_model_logging_message(guild_id: str, model_info: dict) -> bool:
    channel_id = get_logging_channels(guild_id)

    download_response = requests.get(f"https://assetdelivery.roblox.com/v1/assetId/{model_info['id']}")
    download_json = download_response.json()

    if "location" not in download_json.keys():
        return False

    download_link = download_json["location"]
    embed_success, message_dictionary = generate_model_logging_dictionary(model_info, download_link)

    if embed_success and not is_model_logged(model_info["id"]):
        log_model(model_info["id"], model_info["name"])

        src.DiscordBot.discordBot.message_queue.put([channel_id, message_dictionary])
        return True

    return False

# Adds a script log message to the queue
def queue_script_logging_message(guild_id: str, place_details: dict[str, Any], job_id: str, script_source: str,
                                 roblox_user_id: int, roblox_username: str) -> bool:
    channel_id = get_logging_channels(guild_id)
    embed_success, message_dictionary = generate_script_logging_dictionary(place_details, job_id, script_source,
                                                                           roblox_user_id, roblox_username)

    if embed_success:
        src.DiscordBot.discordBot.message_queue.put([channel_id, message_dictionary])
        return True
    else:
        print(f"Failed generating script log embeds for {place_details['name']}")

    return False

# Creates and returns the embeds for a place log message
def generate_place_logging_dictionary(game_data: dict[str, Any], job_id: str) -> tuple[bool, Any]:
    try:
        embed = discord.Embed(title=game_data["name"], colour=discord.Colour(0xdf5dff),
                              url=f"https://www.roblox.com/games/{str(game_data['rootPlaceId'])}/")

        embed.set_image(
            url=f"https://www.roblox.com/asset-thumbnail/image?assetId={str(game_data['rootPlaceId'])}"
                f"&width=768&height=432&format=png")
        embed.set_author(name="Renos - HTTP")
        embed.set_footer(text="made by yours truly")

        embed.add_field(name="Players", value="{:,}".format(game_data["playing"]), inline=True)
        embed.add_field(name="Visits", value="{:,}".format(game_data["visits"]), inline=True)
        embed.add_field(name="Max Players", value=game_data["maxPlayers"], inline=True)
        embed.add_field(name="Place ID", value=game_data["rootPlaceId"], inline=True)
        embed.add_field(name="Game URL", value=f"https://www.roblox.com/games/{str(game_data['rootPlaceId'])}/",
                        inline=True)
        embed.add_field(name="Job ID", value=job_id, inline=True)

        return True, {"embed": embed}
    except (discord.errors.HTTPException, KeyError):
        print(f"oh no! {game_data['name']} had an error!")
        return False, []

# Creates and returns the embeds for a spam log message
def generate_spam_logging_dictionary(client_address: str, job_id: str) -> tuple[bool, Any]:
    try:
        embed = discord.Embed(title="Spam Request Hijacked", colour=discord.Colour(0xdf5dff))

        embed.set_author(name="Renos - Spam")
        embed.set_footer(text="made by yours truly")

        embed.add_field(name="Client Address", value=client_address, inline=True)
        embed.add_field(name="Job ID", value=job_id, inline=True)

        return True, {"embed": embed}
    except (discord.errors.HTTPException, KeyError):
        return False, []

# Creates and returns the embeds for a model log message
def generate_model_logging_dictionary(model_info: dict, download_link: str) -> tuple[bool, dict]:
    embed = discord.Embed(title="Typhoon Model Logger", colour=discord.Colour(0xffe485))

    embed.set_thumbnail(url=model_info["thumbnail_url"])

    embed.add_field(name="Name", value=model_info["name"], inline=False)
    embed.add_field(name="Description",
                    value=model_info["description"][:100] if model_info["description"] != "" else "None", inline=False)
    embed.add_field(name="Creator", value=f"[{model_info['creator_name']}]({model_info['creator_url']})")
    embed.add_field(name="Download Link", value=download_link, inline=False)
    embed.add_field(name="Asset Link", value=model_info["asset_url"], inline=False)

    return True, {"embed": embed}

# Creates and returns the embeds for a script log message
def generate_script_logging_dictionary(game_data: dict[str, Any], job_id: str, script_source: str, roblox_user_id: int,
                                       roblox_username: str) -> tuple[bool, Any]:
    # The threshold for whether or not the script source is included in the embed or a separate file is 500
    requires_file_for_script = len(script_source) >= 500

    try:
        embed = discord.Embed(title="typhon", colour=discord.Colour(0x9013fe), description="script logged!\n\n** **")

        embed.set_image(
            url=f"https://www.roblox.com/asset-thumbnail/image?assetId={str(game_data['rootPlaceId'])}"
                f"&width=768&height=432&format=png")
        embed.set_footer(text="typhon script logger")

        embed.add_field(name="game", value=f"https://www.roblox.com/games/{str(game_data['rootPlaceId'])}/",
                        inline=True)
        embed.add_field(name="executor name", value=roblox_username, inline=True)
        embed.add_field(name="executor id", value=str(roblox_user_id), inline=True)
        if not requires_file_for_script:
            embed.add_field(name="script source", value=f"```lua\n{script_source}\n```", inline=True)
        else:
            embed.add_field(name="script source", value="see attached file", inline=True)
            with open(r"source.lua", "w") as script_file:
                script_file.write(f"--Script generated courtesy of Renos Webhook Security\n\n {script_source}")

        embed.add_field(name="job id", value=job_id, inline=True)

        if not requires_file_for_script:
            dictionary = {"embed": embed}
        else:
            dictionary = {"embed": embed, "file": discord.File("source.lua")}

        return True, dictionary
    except (discord.errors.HTTPException, KeyError):
        print(f"oh no! {game_data['name']} had an error!")
        return False, []


#%%i
import csv
import gzip
from pathlib import Path

def itero(filas, select, types, has_headers):
    if has_headers:
        encabezados = next(filas)
        if select:
            indices = [encabezados.index(nombre_columna) for nombre_columna in
                       select]
            encabezados = select
        else:
            indices = []
        registros = []
        for fila in filas:
            if not fila:
                continue
            if indices:
                fila = [fila[index] for index in indices]
            if types:
                fila = [func(val) for func, val in zip(types, fila)]
            registro = dict(zip(encabezados, fila))
            registros.append(registro)

    if not has_headers:
        registros = []
        for fila in filas:
            if not fila:
                continue
            if types:
                fila = [func(val) for func, val in zip(types, fila)]
            registro = tuple(fila)
            registros.append(registro)
    return registros

def itero_iterables(filas, select, types, has_headers):
    if has_headers:
        headers = filas[0]
        if select:
            indices = [headers.index(nom_col) for nom_col in select]
            headers = select
        else:
            indices = []
        registros = []
        for fila in filas[1:]:
            if not fila:
                continue
            if indices:
                fila = [fila[index] for index in indices]
            if types:
                fila = [func(val) for func, val in zip(types, fila)]
            registro = dict(zip(headers, fila))
            registros.append(registro)

    if not has_headers:
        registros = []
        for fila in filas:
            if not fila:
                continue
            if types:
                fila = [func(val) for func, val in zip(types, fila)]
            registro = tuple(fila)
            registros.append(registro)
    return registros

def parse_csv(filas, select=None, types=[str, int, float],
              has_headers=True):
    if type(filas) in [list, tuple]:
        registros = itero_iterables(filas, select, types, has_headers)
    else:
        suffix = (Path(filas).suffix)
        if suffix == '.csv':
            with open(filas) as f:
                filas = csv.reader(f)
                registros = itero(filas, select, types, has_headers)
        if suffix == '.gz':
            with gzip.open(filas, 'rt') as f:
                filas = csv.reader(f)
                registros = itero(filas, select, types, has_headers)
    return registros

print('que bueno que esta esto')


from adb_shell.adb_device import AdbDeviceTcp
from adb_shell.auth.sign_pythonrsa import PythonRSASigner
from pathlib import Path
import os
import re
import sys
import copy
import threading

class UploadThread (threading.Thread):

    def __init__(self, f, filenames, remote_dir):
        threading.Thread.__init__(self)
        # self.thread_id = thread_id
        self.push_function = f
        self.filenames = copy.deepcopy(filenames)
        self.remote_dir = remote_dir

    def run(self):
        print(self.filenames)
        for filename in self.filenames:
            self.push_function(filename, Path(os.path.join(self.remote_dir, filename.split('/')[-1])).as_posix())
            print('Upload ', filename, 'Done')

class DownloadThread (threading.Thread):

    def __init__(self, f, filename, local_dir):
        threading.Thread.__init__(self)
        # self.thread_id = thread_id
        self.pull_function = f
        self.filename = filename
        self.local_dir = local_dir

    def run(self):
        self.pull_function(self.filename, Path(os.path.join(self.local_dir, self.filename.split('/')[-1])).as_posix())
        print('Download ', self.filename, 'Done')

# arp -a -> show ip & device
class AdbConnect:

    def __init__(self, ip):
        self.ip = ip
        self.device = None
        self.user_root = '/storage/emulated/0/'
        self.current_dir = None
        self.dirs = []
        self.files = []
        if sys.platform.startswith('win'):
            import winreg
            key = winreg.OpenKey(
                winreg.HKEY_CURRENT_USER, r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders')
            self.default_download_dir = Path(winreg.QueryValueEx(key, "Desktop")[0]).as_posix()
        else:
            self.default_download_dir = os.path.expanduser('~')
        self.current_down_dir = self.default_download_dir

    def set_ip(self, ip):
        self.ip = ip

    def connect(self):
        with open(os.path.join(os.path.expanduser('~'), '.android/adbkey')) as f:
            p = f.read()
        signer = PythonRSASigner('', p)
        self.device = AdbDeviceTcp(self.ip, 5555, default_timeout_s=9.)
        self.device.connect(rsa_keys=[signer], auth_timeout_s=0.1)
        # ls -l
        self.ls()
        print('connect')

    def disconnect(self):
        if self.device is not None:
            self.device.close()
        print('close')

    def check_dir_or_file(self, names):
        detailed_names = re.split('\n', names)[1:-1]
        # print(detailed_names)
        # 7 -> support space in filename
        self.dirs, self.files = [], []
        for e in detailed_names:
            if e.startswith('d'):
                self.dirs.append(re.split('\s+', e, maxsplit=7)[-1])
            else:
                self.files.append(re.split('\s+', e, maxsplit=7)[-1])

    def ls(self, dir_name=None):
        if dir_name is None:
            self.current_dir = self.user_root
        else:
            self.current_dir = dir_name
        dir_file_names = self.device.shell('ls -la "' + self.current_dir + '"')
        self.check_dir_or_file(dir_file_names)
        # print('dirs', self.dirs, 'files', self.files, sep='\n')

    def change_directory(self, dir_name):
        if dir_name == '.':
            # do nothing
            pass
        elif dir_name == '..':
            self.current_dir = Path(self.current_dir).parent.as_posix()
        else:
            self.current_dir = Path(os.path.join(self.current_dir, dir_name)).as_posix()
        self.ls(self.current_dir)
        # print(self.current_dir, 'dirs', self.dirs, 'files', self.files, sep='\n')

    def pull_file(self, filename):
        download_dir = self.current_down_dir
        d_thread = DownloadThread(f=self.device.pull, filename=Path(os.path.join(self.current_dir, filename)).as_posix(), local_dir=download_dir)
        d_thread.start()
        # self.device.pull(
        #     Path(os.path.join(self.current_dir, filename)).as_posix(),
        #     os.path.join(download_dir, filename)
        # )

    def thread_upload(self, local_files):
        # remote_dir -> current dir
        u_thread = UploadThread(f=self.device.push, filenames=local_files, remote_dir=self.current_dir)
        u_thread.start()
        # for e in local_files:
        #     self.device.push(e, Path(os.path.join(self.current_dir,e.split('/')[-1])).as_posix())