import argparse
import copy
import logging
import os
import random
import sys
from dataclasses import dataclass, field
from typing import Optional, Tuple, Union

import datasets
import numpy as np
import torch
import transformers
from datasets import load_dataset, load_metric
from PIL import Image
from pixel import (
    AutoConfig,
    AutoModelForSequenceClassification,
    Modality,
    PangoCairoTextRenderer,
    PIXELForSequenceClassification,
    PIXELTrainer,
    PIXELTrainingArguments,
    PoolingMode,
    PyGameTextRenderer,
    get_attention_mask,
    get_transforms,
    glue_strip_spaces,
    log_sequence_classification_predictions,
    resize_model_embeddings,
)
from transformers import (
    AutoTokenizer,
    DataCollatorWithPadding,
    EarlyStoppingCallback,
    EvalPrediction,
    HfArgumentParser,
    PreTrainedTokenizerFast,
    set_seed,
)
from transformers.trainer_utils import get_last_checkpoint
from transformers.utils import check_min_version
from transformers.utils.versions import require_version

check_min_version("4.17.0")

require_version("datasets>=1.8.0", "To fix: pip install ./datasets")

logger = logging.getLogger(__name__)

@dataclass
class DataTrainingArguments:
    """
    Arguments pertaining to what data we are going to input our model for training and eval.

    Using `HfArgumentParser` we can turn this class
    into argparse arguments to be able to specify them on
    the command line.
    """

    dataset_name: Optional[str] = field(
        default=None, metadata={"help": "The name of the NLI dataset to use (via the datasets library)."}
    )
    dataset_config_name: str = field(
        default=None, metadata={"help": "Subset of the NLI dataset, e.g language ISO code"}
    )
    max_seq_length: Optional[int] = field(
        default=196,
        metadata={
            "help": "The maximum total input sequence length after tokenization. Sequences longer "
            "than this will be truncated, sequences shorter will be padded."
        },
    )
    overwrite_cache: bool = field(
        default=False, metadata={"help": "Overwrite the cached preprocessed datasets or not."}
    )
    pad_to_max_length: bool = field(
        default=True,
        metadata={
            "help": "Whether to pad all samples to `max_seq_length`. "
            "If False, will pad the samples dynamically when batching to the maximum length in the batch."
        },
    )
    max_train_samples: Optional[int] = field(
        default=None,
        metadata={
            "help": "For debugging purposes or quicker training, truncate the number of training examples to this "
            "value if set."
        },
    )
    max_eval_samples: Optional[int] = field(
        default=None,
        metadata={
            "help": "For debugging purposes or quicker training, truncate the number of evaluation examples to this "
            "value if set."
        },
    )
    max_predict_samples: Optional[int] = field(
        default=None,
        metadata={
            "help": "For debugging purposes or quicker training, truncate the number of prediction examples to this "
            "value if set."
        },
    )
    train_file: Optional[str] = field(
        default=None, metadata={"help": "A csv or a json file containing the training data."}
    )
    validation_file: Optional[str] = field(
        default=None, metadata={"help": "A csv or a json file containing the validation data."}
    )
    test_file: Optional[str] = field(default=None, metadata={"help": "A csv or a json file containing the test data."})

    def __post_init__(self):
        if self.dataset_name is not None:
            pass
        elif self.train_file is None or self.validation_file is None:
            raise ValueError("Need either a NLI task, a training/validation file or a dataset name.")
        # else:
        #     train_extension = self.train_file.split(".")[-1]
        #     assert train_extension in ["csv", "json"], "`train_file` should be a csv or a json file."
        #     validation_extension = self.validation_file.split(".")[-1]
        #     assert (
        #         validation_extension == train_extension
        #     ), "`validation_file` should have the same extension (csv or json) as `train_file`."

@dataclass
class ModelArguments:
    """
    Arguments pertaining to which model/config/tokenizer we are going to fine-tune from.
    """

    model_name_or_path: str = field(
        metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"}
    )
    config_name: Optional[str] = field(
        default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"}
    )
    processor_name: Optional[str] = field(
        default=None, metadata={"help": "Pretrained processor name or path if not the same as model_name"}
    )
    rendering_backend: Optional[str] = field(
        default="pangocairo", metadata={
            "help": "Rendering backend to use. Options are 'pygame' or 'pangocairo'. For most applications it is "
                    "recommended to use the default 'pangocairo'."}
    )
    fallback_fonts_dir: Optional[str] = field(
        default=None,
        metadata={"help": "Directory containing fallback font files used by the text renderer for PIXEL. "
                          "PyGame does not support fallback fonts so this argument is ignored when using the "
                          "PyGame backend."},
    )
    render_rgb: bool = field(
        default=False,
        metadata={
            "help": "Whether or not to render images in RGB. RGB rendering can be useful when working with emoji "
            "but it makes rendering a bit slower, so it is recommended to turn on RGB rendering only "
            "when there is need for it. PyGame does not support fallback fonts so this argument is ignored "
            "when using the PyGame backend."
        }
    )
    cache_dir: Optional[str] = field(
        default=None,
        metadata={"help": "Where do you want to store the pretrained models downloaded from huggingface.co"},
    )
    model_revision: str = field(
        default="main",
        metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."},
    )
    use_auth_token: str = field(
        default=None,
        metadata={
            "help": "Will use the token generated when running `transformers-cli login` (necessary to use this script "
            "with private models)."
        },
    )
    pooling_mode: str = field(
        default="mean",
        metadata={
            "help": f"Pooling mode to use in classification head (options are {[e.value for e in PoolingMode]}."
        },
    )
    pooler_add_layer_norm: bool = field(
        default=True,
        metadata={
            "help": "Whether to add layer normalization to the classification head pooler. Note that this flag is"
            "ignored and no layer norm is added when using CLS pooling mode."
        },
    )
    dropout_prob: float = field(
        default=0.1, metadata={"help": "Dropout probability for attention blocks and classification head"}
    )

    def __post_init__(self):
        self.pooling_mode = PoolingMode.from_string(self.pooling_mode)

        if not self.rendering_backend.lower() in ["pygame", "pangocairo"]:
            raise ValueError("Invalid rendering backend. Supported backends are 'pygame' and 'pangocairo'.")
        else:
            self.rendering_backend = self.rendering_backend.lower()

def get_processor(model_args: argparse.Namespace, modality: Modality):
    if modality == Modality.TEXT:
        processor = AutoTokenizer.from_pretrained(
            model_args.processor_name if model_args.processor_name else model_args.model_name_or_path,
            use_fast=True,
            add_prefix_space=True if model_args.model_name_or_path == "roberta-base" else False,
            cache_dir=model_args.cache_dir,
            revision=model_args.model_revision,
            use_auth_token=model_args.use_auth_token if model_args.use_auth_token else None,
        )
    elif modality == Modality.IMAGE:
        renderer_cls = PyGameTextRenderer if model_args.rendering_backend == "pygame" else PangoCairoTextRenderer
        processor = renderer_cls.from_pretrained(
            model_args.processor_name if model_args.processor_name else model_args.model_name_or_path,
            cache_dir=model_args.cache_dir,
            revision=model_args.model_revision,
            use_auth_token=model_args.use_auth_token if model_args.use_auth_token else None,
            fallback_fonts_dir=model_args.fallback_fonts_dir,
            rgb=model_args.render_rgb,
        )
    else:
        raise ValueError("Modality not supported.")
    return processor

def get_model_and_config(model_args: argparse.Namespace, num_labels: int, dataset_name: str):
    config_kwargs = {
        "cache_dir": model_args.cache_dir,
        "revision": model_args.model_revision,
        "use_auth_token": model_args.use_auth_token if model_args.use_auth_token else None,
    }

    config = AutoConfig.from_pretrained(
        model_args.config_name if model_args.config_name else model_args.model_name_or_path,
        num_labels=num_labels,
        finetuning_task=dataset_name,
        attention_probs_dropout_prob=model_args.dropout_prob,
        hidden_dropout_prob=model_args.dropout_prob,
        **config_kwargs,
    )

    logger.info(f"Using dropout with probability {model_args.dropout_prob}")

    if config.model_type in ["bert", "roberta"]:
        model = AutoModelForSequenceClassification.from_pretrained(
            model_args.model_name_or_path,
            config=config,
            **config_kwargs,
        )
    elif config.model_type in ["vit_mae", "pixel"]:
        model = PIXELForSequenceClassification.from_pretrained(
            model_args.model_name_or_path,
            config=config,
            pooling_mode=model_args.pooling_mode,
            add_layer_norm=model_args.pooler_add_layer_norm,
            **config_kwargs,
        )
    else:
        raise ValueError(f"Model type {config.model_type} not supported.")

    return model, config

def get_collator(
    training_args: argparse.Namespace,
    processor: Union[Union[PyGameTextRenderer, PangoCairoTextRenderer], PreTrainedTokenizerFast],
    modality: Modality,
):
    def image_collate_fn(examples):
        pixel_values = torch.stack([example["pixel_values"] for example in examples])
        attention_mask = torch.stack([example["attention_mask"] for example in examples])
        if "label" in examples[0]:
            labels = torch.LongTensor([example["label"] for example in examples])
            return {"pixel_values": pixel_values, "attention_mask": attention_mask, "labels": labels}
        return {"pixel_values": pixel_values, "attention_mask": attention_mask}

    if modality == Modality.IMAGE:
        collator = image_collate_fn
    elif modality == Modality.TEXT:
        collator = DataCollatorWithPadding(processor, pad_to_multiple_of=8) if training_args.fp16 else None
    else:
        raise ValueError(f"Modality {modality} not supported.")

    return collator

def get_preprocess_fn(
    data_args: argparse.Namespace,
    processor: Union[Union[PyGameTextRenderer, PangoCairoTextRenderer], PreTrainedTokenizerFast],
    modality: Modality,
    sentence_keys: Tuple[str, Optional[str]],
):
    sentence1_key, sentence2_key = sentence_keys

    if modality == Modality.IMAGE:

        transforms = get_transforms(
            do_resize=True,
            size=(processor.pixels_per_patch, processor.pixels_per_patch * processor.max_seq_length),
        )
        format_fn = glue_strip_spaces

        def image_preprocess_fn(examples):
            if sentence2_key:
                encodings = [
                    processor(text=(format_fn(a), format_fn(b)))
                    for a, b in zip(examples[sentence1_key], examples[sentence2_key])
                ]
            else:
                encodings = [processor(text=format_fn(a)) for a in examples[sentence1_key]]

            examples["pixel_values"] = [transforms(Image.fromarray(e.pixel_values)) for e in encodings]
            examples["attention_mask"] = [
                get_attention_mask(e.num_text_patches, seq_length=data_args.max_seq_length) for e in encodings
            ]

            if "label" in examples:
                examples["label"] = [l if l != -1 else -100 for l in examples["label"]]

            return examples

        preprocess_fn = image_preprocess_fn

    elif modality == Modality.TEXT:

        def text_preprocess_fn(examples):
            # Tokenize the texts
            args = (
                (examples[sentence1_key],)
                if sentence2_key is None
                else (examples[sentence1_key], examples[sentence2_key])
            )
            result = processor(*args, padding="max_length", max_length=data_args.max_seq_length, truncation=True)

            if "label" in examples:
                result["label"] = [l if l != -1 else -100 for l in examples["label"]]

            return result

        preprocess_fn = text_preprocess_fn
    else:
        raise ValueError(f"Modality {modality} not supported.")

    return preprocess_fn

def main():
    parser = HfArgumentParser((ModelArguments, DataTrainingArguments, PIXELTrainingArguments))
    if len(sys.argv) == 2 and sys.argv[1].endswith(".json"):
        # If we pass only one argument to the script and it's the path to a json file,
        # let's parse it to get our arguments.
        model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1]))
    else:
        model_args, data_args, training_args = parser.parse_args_into_dataclasses()

    # Setup logging
    log_level = logging.INFO
    logging.basicConfig(
        format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
        datefmt="%m/%d/%Y %H:%M:%S",
        handlers=[logging.StreamHandler(sys.stdout)],
        level=log_level,
    )
    logger.setLevel(log_level)
    datasets.utils.logging.set_verbosity(log_level)
    transformers.utils.logging.set_verbosity(log_level)
    transformers.utils.logging.enable_default_handler()
    transformers.utils.logging.enable_explicit_format()

    # Log on each process the small summary:
    logger.warning(
        f"Process rank: {training_args.local_rank}, device: {training_args.device}, n_gpu: {training_args.n_gpu}"
        + f"distributed training: {bool(training_args.local_rank != -1)}, 16-bits training: {training_args.fp16}"
    )
    logger.info(f"Training/evaluation parameters {training_args}")

    # Detecting last checkpoint.
    last_checkpoint = None
    if os.path.isdir(training_args.output_dir) and training_args.do_train and not training_args.overwrite_output_dir:
        last_checkpoint = get_last_checkpoint(training_args.output_dir)
        if last_checkpoint is None and len(os.listdir(training_args.output_dir)) > 0:
            raise ValueError(
                f"Output directory ({training_args.output_dir}) already exists and is not empty. "
                "Use --overwrite_output_dir to overcome."
            )
        elif last_checkpoint is not None and training_args.resume_from_checkpoint is None:
            logger.info(
                f"Checkpoint detected, resuming training at {last_checkpoint}. To avoid this behavior, change "
                "the `--output_dir` or add `--overwrite_output_dir` to train from scratch."
            )

    # Set seed before initializing model.
    set_seed(training_args.seed)

    if training_args.do_train:
        if data_args.train_file:
            # Settings fixed mainly for our robustness experiments
            train_dataset = load_dataset(
                "csv",
                data_files=data_args.train_file,
                delimiter="\t",
                split="train",
                cache_dir=model_args.cache_dir,
                use_auth_token=True if model_args.use_auth_token else None,
            )
            train_dataset = train_dataset.class_encode_column("label")
        else:
            train_dataset = load_dataset(
                data_args.dataset_name,
                data_args.dataset_config_name,
                split="train",
                cache_dir=model_args.cache_dir,
                use_auth_token=True if model_args.use_auth_token else None,
            )
        label_list = train_dataset.features["label"].names

    if training_args.do_eval:
        if data_args.validation_file:
            # Settings fixed mainly for our robustness experiments
            eval_dataset = load_dataset(
                "csv",
                data_files=data_args.validation_file,
                delimiter="\t",
                split="train",
                cache_dir=model_args.cache_dir,
                use_auth_token=True if model_args.use_auth_token else None,
            )
            eval_dataset = eval_dataset.class_encode_column("label")
        else:
            eval_dataset = load_dataset(
                data_args.dataset_name,
                data_args.dataset_config_name,
                split="validation",
                cache_dir=model_args.cache_dir,
                use_auth_token=True if model_args.use_auth_token else None,
            )
        label_list = eval_dataset.features["label"].names

    if training_args.do_predict:
        if data_args.test_file:
            # Settings fixed mainly for our robustness experiments
            predict_dataset = load_dataset(
                "csv",
                data_files=data_args.test_file,
                delimiter="\t",
                split="train",
                cache_dir=model_args.cache_dir,
                use_auth_token=True if model_args.use_auth_token else None,
            )
            predict_dataset = predict_dataset.class_encode_column("label")
        else:
            predict_dataset = load_dataset(
                data_args.dataset_name,
                data_args.dataset_config_name,
                split="test",
                cache_dir=model_args.cache_dir,
                use_auth_token=True if model_args.use_auth_token else None,
            )
        label_list = predict_dataset.features["label"].names

    # Labels
    num_labels = len(label_list)
    label_to_id = {v: i for i, v in enumerate(label_list)}

    # Load pretrained model and config
    model, config = get_model_and_config(model_args, num_labels, data_args.dataset_name)

    model.config.label2id = label_to_id
    model.config.id2label = {id: label for label, id in config.label2id.items()}

    sentence1_key, sentence2_key = ("premise", "hypothesis")

    modality = Modality.TEXT if config.model_type in ["bert", "roberta"] else Modality.IMAGE
    processor = get_processor(model_args, modality)

    if modality == Modality.IMAGE:
        if processor.max_seq_length != data_args.max_seq_length:
            processor.max_seq_length = data_args.max_seq_length

        resize_model_embeddings(model, processor.max_seq_length)

    preprocess_fn = get_preprocess_fn(data_args, processor, modality, (sentence1_key, sentence2_key))

    if training_args.do_train:
        if data_args.max_train_samples is not None:
            train_dataset = train_dataset.select(range(data_args.max_train_samples))
        if modality == Modality.IMAGE:
            train_dataset.features["pixel_values"] = datasets.Image()
        train_dataset.set_transform(preprocess_fn)

    if training_args.do_eval:
        if data_args.max_eval_samples is not None:
            eval_dataset = eval_dataset.select(range(data_args.max_eval_samples))
        if modality == Modality.IMAGE:
            eval_dataset.features["pixel_values"] = datasets.Image()
        eval_examples = copy.deepcopy(eval_dataset)
        eval_dataset.set_transform(preprocess_fn)

    if training_args.do_predict or data_args.test_file is not None:
        if data_args.max_predict_samples is not None:
            predict_dataset = predict_dataset.select(range(data_args.max_predict_samples))
        if modality == Modality.IMAGE:
            predict_dataset.features["pixel_values"] = datasets.Image()
        predict_examples = copy.deepcopy(predict_dataset)
        predict_dataset.set_transform(preprocess_fn)

    # Log a few random samples from the training set:
    if training_args.do_train:
        for index in random.sample(range(len(train_dataset)), 3):
            logger.info(f"Sample {index} of the training set: {train_dataset[index]}.")

    if training_args.do_eval:
        for index in random.sample(range(len(eval_dataset)), 3):
            logger.info(f"Sample {index} of the eval set: {eval_dataset[index]}.")

    # Get the metric function
    metric = load_metric("xnli")

    def compute_metrics(p: EvalPrediction):
        preds = p.predictions[0] if isinstance(p.predictions, tuple) else p.predictions
        preds = np.argmax(preds, axis=1)
        return metric.compute(predictions=preds, references=p.label_ids)

    # Initialize our Trainer
    trainer = PIXELTrainer(
        model=model,
        args=training_args,
        train_dataset=train_dataset if training_args.do_train else None,
        eval_dataset=eval_dataset if training_args.do_eval else None,
        compute_metrics=compute_metrics,
        tokenizer=processor,
        data_collator=get_collator(training_args, processor, modality),
        callbacks=[EarlyStoppingCallback(early_stopping_patience=training_args.early_stopping_patience)]
        if training_args.early_stopping
        else None,
    )

    # Training
    if training_args.do_train:
        checkpoint = None
        if training_args.resume_from_checkpoint is not None:
            checkpoint = training_args.resume_from_checkpoint
        elif last_checkpoint is not None:
            checkpoint = last_checkpoint
        train_result = trainer.train(resume_from_checkpoint=checkpoint)
        metrics = train_result.metrics
        max_train_samples = (
            data_args.max_train_samples if data_args.max_train_samples is not None else len(train_dataset)
        )
        metrics["train_samples"] = min(max_train_samples, len(train_dataset))

        trainer.save_model()

        trainer.log_metrics("train", metrics)
        trainer.save_metrics("train", metrics)
        trainer.save_state()

    # Evaluation
    if training_args.do_eval:
        logger.info("*** Evaluate ***")

        outputs = trainer.predict(test_dataset=eval_dataset, metric_key_prefix="eval")
        metrics = outputs.metrics

        if training_args.log_predictions:
            log_sequence_classification_predictions(
                training_args=training_args,
                features=eval_dataset,
                examples=eval_examples,
                predictions=outputs.predictions,
                sentence1_key=sentence1_key,
                sentence2_key=sentence2_key,
                modality=modality,
                prefix="eval",
            )

        max_eval_samples = data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset)
        metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset))

        trainer.log_metrics("eval", metrics)
        trainer.save_metrics("eval", metrics)

    if training_args.do_predict:
        logger.info("*** Predict ***")

        outputs = trainer.predict(predict_dataset, metric_key_prefix="test")
        metrics = outputs.metrics

        trainer.log_metrics("test", metrics)
        trainer.save_metrics("test", metrics)

        # Log predictions to understand where model goes wrong
        if training_args.log_predictions:
            log_sequence_classification_predictions(
                training_args=training_args,
                features=predict_dataset,
                examples=predict_examples,
                predictions=outputs.predictions,
                sentence1_key=sentence1_key,
                sentence2_key=sentence2_key,
                modality=modality,
                prefix="test",
            )

        max_test_samples = (
            data_args.max_predict_samples if data_args.max_predict_samples is not None else len(predict_dataset)
        )
        metrics["test_samples"] = min(max_test_samples, len(predict_dataset))

    kwargs = {"finetuned_from": model_args.model_name_or_path, "tasks": "text-classification"}
    if data_args.dataset_name is not None:
        kwargs["language"] = data_args.dataset_config_name
        kwargs["dataset_tags"] = data_args.dataset_name
        kwargs["dataset_args"] = data_args.dataset_name
        kwargs["dataset"] = f"{data_args.dataset_name.upper()}"

    if training_args.push_to_hub:
        trainer.push_to_hub(**kwargs)
    else:
        trainer.create_model_card(**kwargs)

def _mp_fn(index):
    # For xla_spawn (TPUs)
    main()

if __name__ == "__main__":
    main()


# Test servo with Maestro

import time
import numpy
import math
from dynamixel_sdk import *                    # Uses Dynamixel SDK library

def map(val, in_min, in_max, out_min, out_max):

    return (val - in_min) * (out_max - out_min) / (in_max - in_min) + out_min

def DeltaINV(x,y,z):

	a = wb - up
	b = sp/2 - (root3/2)*wb
	c = wp - 0.5*wb

	E1 = 2*L*(y + a)
	F1 = 2*z*L
	G1 = x**2 + y**2 + z**2 + a**2 + L**2 + 2*y*a - l**2

	E2 = -L*(root3*(x+b) + y + c)
	F2 = 2*z*L
	G2 = x**2 + y**2 + z**2 + b**2 + c**2 + L**2 + 2*(x*b + y*c) - l**2

	E3 = L*(root3*(x-b) - y - c)
	F3 = 2*z*L
	G3 = x**2 + y**2 + z**2 + b**2 + c**2 + L**2 + 2*(-x*b + y*c) - l**2;

	t1 = [None]*2
	t2 = [None]*2
	t3 = [None]*2

	t1[0] = (-F1 + math.sqrt(E1**2 + F1**2 - G1**2)) / (G1 - E1)
	t1[1] = (-F1 - math.sqrt(E1**2 + F1**2 - G1**2)) / (G1 - E1)
	t2[0] = (-F2 + math.sqrt(E2**2 + F2**2 - G2**2)) / (G2 - E2)
	t2[1] = (-F2 - math.sqrt(E2**2 + F2**2 - G2**2)) / (G2 - E2)
	t3[0] = (-F3 + math.sqrt(E3**2 + F2**2 - G3**2)) / (G3 - E3)
	t3[1] = (-F3 - math.sqrt(E3**2 + F2**2 - G3**2)) / (G3 - E3)

	theta1 = 2*math.atan(t1[1]);
	theta2 = 2*math.atan(t2[1]);
	theta3 = 2*math.atan(t3[1]);

	deg1 = theta1*rad2deg;
	deg2 = theta2*rad2deg;
	deg3 = theta3*rad2deg;

	ServoDeg1 = 90 + deg1
	ServoDeg2 = 90 + deg2
	ServoDeg3 = 90 + deg3

	if isinstance(theta1, complex) or isinstance(theta2, complex) or isinstance(theta3, complex):
		print("Error: Driving angle is complex number")

	return ServoDeg1, ServoDeg2, ServoDeg3

def RunServo(inputDeg1,inputDeg2,inputDeg3):

	pos1 = inputDeg1
	pos2 = inputDeg2
	pos3 = inputDeg3

	servo_com1 = map(pos1,0.0,360.0,0.0,4095.0)
	servo_com2 = map(pos2,0.0,360.0,0.0,4095.0)
	servo_com3 = map(pos3,0.0,360.0,0.0,4095.0)

	dxl1_goal_position = int(servo_com1)
	dxl2_goal_position = int(servo_com2)
	dxl3_goal_position = int(servo_com3)

	if dxl1_goal_position and dxl2_goal_position and dxl3_goal_position > 568:
		dxl_comm_result1, dxl_error1 = packetHandler.write4ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_GOAL_POSITION, int(dxl1_goal_position))
		dxl_comm_result2, dxl_error2 = packetHandler.write4ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_GOAL_POSITION, int(dxl2_goal_position))
		dxl_comm_result3, dxl_error3 = packetHandler.write4ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_GOAL_POSITION, int(dxl3_goal_position))
	else:
		print("ERROR: servo angle is less than 40deg")

def ReadAngle():
	dxl_present_position1, dxl_comm_result, dxl_error = packetHandler.read4ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_PRESENT_POSITION)
	dxl_present_position2, dxl_comm_result, dxl_error = packetHandler.read4ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_PRESENT_POSITION)
	dxl_present_position3, dxl_comm_result, dxl_error = packetHandler.read4ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_PRESENT_POSITION)

	pre_pos1 = map(dxl_present_position1, 0.0, 4095.0, 0.0, 360.0)
	pre_pos2 = map(dxl_present_position2, 0.0, 4095.0, 0.0, 360.0)
	pre_pos3 = map(dxl_present_position3, 0.0, 4095.0, 0.0, 360.0)

	return pre_pos1,pre_pos2,pre_pos3

def DeltaGoHome():
	pos1 = 90
	pos2 = 90
	pos3 = 90
	################## Go to home position before starting circle ###########################
	servo_ang1 = map(pos1, 0.0, 360.0, 0, 4095)
	servo_ang2 = map(pos2, 0.0, 360.0, 0, 4095)
	servo_ang3 = map(pos3, 0.0, 360.0, 0, 4095)

	dxl1_goal_position = servo_ang1
	dxl2_goal_position = servo_ang2
	dxl3_goal_position = servo_ang3

	dxl_comm_result1, dxl_error1 = packetHandler.write4ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_GOAL_POSITION, int(dxl1_goal_position))
	dxl_comm_result2, dxl_error2 = packetHandler.write4ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_GOAL_POSITION, int(dxl2_goal_position))
	dxl_comm_result3, dxl_error3 = packetHandler.write4ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_GOAL_POSITION, int(dxl3_goal_position))

def IsMoving1():
    Moving1, dxl_comm_result, dxl_error = packetHandler.read1ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_MOVING)

    return Moving1

def IsMoving2():
    Moving2, dxl_comm_result, dxl_error = packetHandler.read1ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_MOVING)
    return Moving2

def IsMoving3():
    Moving3, dxl_comm_result, dxl_error = packetHandler.read1ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_MOVING)
    return Moving3

def MovingStatus1():
    MovingStat1, dxl_comm_result, dxl_error = packetHandler.read1ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_MOVING_STATUS)

    if MovingStat1 > 48:
        print("Motor1 is in Trapezodal Profile")
    elif MovingStat1 < 35 and MovingStat1 > 20:
        print("Motor1 is in Triangular Profile")
    elif MovingStat1 < 20 and MovingStat1 > 3:
        print("Motor1 is in Rectangular Profile")
    elif MovingStat1 < 3:
        print("Motor1 is in Step Mode (No Profile)")
    else:
        print("UNKNOWN Profile...")

    return MovingStat1

def MovingStatus2():
    MovingStat2, dxl_comm_result, dxl_error = packetHandler.read1ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_MOVING_STATUS)

    if MovingStat2 > 48:
        print("Motor2 is in Trapezodal Profile")
    elif MovingStat2 < 35 and MovingStat2 > 20:
        print("Motor2 is in Triangular Profile")
    elif MovingStat2 < 20 and MovingStat2 > 3:
        print("Motor2 is in Rectangular Profile")
    elif MovingStat2 < 3:
        print("Motor2 is in Step Mode (No Profile)")
    else:
        print("UNKNOWN Profile...")

    return MovingStat2

def MovingStatus3():
    MovingStat3, dxl_comm_result, dxl_error = packetHandler.read1ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_MOVING_STATUS)

    if MovingStat3 > 48:
        print("Motor3 is in Trapezodal Profile")
    elif MovingStat3 < 35 and MovingStat3 > 20:
        print("Motor3 is in Triangular Profile")
    elif MovingStat3 < 20 and MovingStat3 > 3:
        print("Motor3 is in Rectangular Profile")
    elif MovingStat3 < 3:
        print("Motor3 is in Step Mode (No Profile)")
    else:
        print("UNKNOWN Profile...")

    return MovingStat3

def DeltaPos(pre_pos,goal_pos):
    pre_pos_pul = map(pre_pos,0.0,360.0,0.0,4095.0)
    pre_pos_pul = int(pre_pos_pul)
    goal_pos_pul = map(goal_pos,0.0,360.0,0.0,4095.0)
    goal_pos_pul = int(goal_pos_pul)

    delta_pos = abs(goal_pos_pul - pre_pos_pul)

    return delta_pos

def SetProfile1(set_V_PRFL,set_A_PRFL):
    ######################### Set Velocity / Acceleration Profile  ##############################
    set_A_Limit = 32767     # 32767 default                [214.577 rev/min^2]
    set_V_Limit = 500       # 350 Default                  [0.229RPM]

    dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_ACCELERATION_LIMIT, set_A_Limit)
    dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_VELOCITY_LIMIT, set_V_Limit)

    dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_PROFILE_ACCELERATION, int(set_A_PRFL))
    dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_PROFILE_VELOCITY, int(set_V_PRFL))

    acceleration_limit, dxl_comm_result, dxl_error = packetHandler.read4ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_ACCELERATION_LIMIT)
    velocity_limit, dxl_comm_result, dxl_error = packetHandler.read4ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_VELOCITY_LIMIT)

    print("V PRFL 1: %f" %set_V_PRFL)
    print("A PRFL 1: %f" %set_A_PRFL)
    print("--------------------------------")

def SetProfile2(set_V_PRFL,set_A_PRFL):
    ######################### Set Velocity / Acceleration Profile  ##############################
    set_A_Limit = 32767     # 32767 default                [214.577 rev/min^2]
    set_V_Limit = 500       # 350 Default                  [0.229RPM]

    #set_A_PRFL = 30      # between 0 ~ set_A_limit      [214.577 rev/min^2]
    #set_V_PRFL = 200      # between 0 ~ set_V_Limit      [0.229RPM]

    dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_ACCELERATION_LIMIT, set_A_Limit)
    dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_VELOCITY_LIMIT, set_V_Limit)

    dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_PROFILE_ACCELERATION, int(set_A_PRFL))
    dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_PROFILE_VELOCITY, int(set_V_PRFL))

    acceleration_limit, dxl_comm_result, dxl_error = packetHandler.read4ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_ACCELERATION_LIMIT)
    velocity_limit, dxl_comm_result, dxl_error = packetHandler.read4ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_VELOCITY_LIMIT)

    print("V PRFL 2: %f" %set_V_PRFL)
    print("A PRFL 2: %f" %set_A_PRFL)
    print("--------------------------------")

def SetProfile3(set_V_PRFL,set_A_PRFL):
    ######################### Set Velocity / Acceleration Profile  ##############################
    set_A_Limit = 32767     # 32767 default                [214.577 rev/min^2]
    set_V_Limit = 500       # 350 Default                  [0.229RPM]

    #set_A_PRFL = 30      # between 0 ~ set_A_limit      [214.577 rev/min^2]
    #set_V_PRFL = 200      # between 0 ~ set_V_Limit      [0.229RPM]

    dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_ACCELERATION_LIMIT, set_A_Limit)
    dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_VELOCITY_LIMIT, set_V_Limit)

    dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_PROFILE_ACCELERATION, int(set_A_PRFL))
    dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_PROFILE_VELOCITY, int(set_V_PRFL))

    acceleration_limit, dxl_comm_result, dxl_error = packetHandler.read4ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_ACCELERATION_LIMIT)
    velocity_limit, dxl_comm_result, dxl_error = packetHandler.read4ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_VELOCITY_LIMIT)

    print("V PRFL 3: %f" %set_V_PRFL)
    print("A PRFL 3: %f" %set_A_PRFL)
    print("--------------------------------")

def TrajectoryGeneration(Vstd,Astd,DelPos1,DelPos2,DelPos3):
    ## Find the shortest moving path ##
    AllDelPos = [DelPos1,DelPos2,DelPos3]
    MIN = min(AllDelPos)
    if DelPos1 == MIN:
        V1 = Vstd
        A1 = Astd
        print("Servo1 is the standard")
        t3_1 = 64*V1/A1 + 64*DelPos1/V1
        t3_2 = t3_1
        t3_3 = t3_1
        t2_1 = 64*DelPos1/V1
        t2_2 = t2_1
        t2_3 = t2_1
        V2 = 64*DelPos2/t2_2
        V3 = 64*DelPos3/t2_3
        A2 = 64*V2 / (t3_2 - 64*DelPos2/V2)
        A3 = 64*V3 / (t3_3 - 64*DelPos3/V3)

    elif DelPos2 == MIN:
        V2 = Vstd
        A2 = Astd
        print("Servo2 is the standard")
        t3_2 = 64*V2/A2 + 64*DelPos2/V2
        t3_1 = t3_2
        t3_3 = t3_2
        t2_2 = 64*DelPos2/V2
        t2_1 = t2_2
        t2_3 = t2_2
        V1 = 64*DelPos1/t2_1
        V3 = 64*DelPos3/t2_3
        A1 = 64*V1 / (t3_1 - 64*DelPos1/V1)
        A3 = 64*V3 / (t3_3 - 64*DelPos3/V3)

    elif DelPos3 == MIN:
        V3 = Vstd
        A3 = Astd
        print("Servo3 is the standard")
        t3_3 = 64*V3/A3 + 64*DelPos3/V3
        t3_1 = t3_3
        t3_2 = t3_3
        t2_3 = 64*DelPos3/V3
        t2_1 = t2_3
        t2_2 = t2_3
        V1 = 64*DelPos1/t2_1
        V2 = 64*DelPos2/t2_2
        A1 = 64*V1 / (t3_1 - 64*DelPos1/V1)
        A2 = 64*V2 / (t3_2 - 64*DelPos2/V2)

    return V1,A1,V2,A2,V3,A3

def TorqueOn():
	dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_ENABLE)
	dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_ENABLE)
	dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_ENABLE)

def TorqueOff():
	dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_DISABLE)
	dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_DISABLE)
	dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_DISABLE)

####################################################### Set Servo Configuration #############################################################
# Control table address
ADDR_PRO_TORQUE_ENABLE      = 64               # Control table address is different in Dynamixel model
ADDR_PRO_GOAL_POSITION      = 116
ADDR_PRO_PRESENT_POSITION   = 132

ADDR_PRO_CURRENT_LIMIT      = 38
ADDR_PRO_GOAL_CURRENT       = 102
ADDR_PRO_PRESENT_CURRENT    = 126

ADDR_PRO_OPERATING_MODE     = 11

ADDR_PRO_GOAL_VELOCITY      = 104

ADDR_PRO_ACCELERATION_LIMIT = 40
ADDR_PRO_VELOCITY_LIMIT     = 44
ADDR_PRO_PROFILE_ACCELERATION  = 108
ADDR_PRO_PROFILE_VELOCITY   = 112

ADDR_PRO_POSITION_D_GAIN    = 80
ADDR_PRO_POSITION_I_GAIN    = 82
ADDR_PRO_POSITION_P_GAIN    = 84

ADDR_PRO_MOVING             = 122
ADDR_PRO_MOVING_STATUS       = 123

CURRENT_CONTROL                     = 0
POSITION_CONTROL                    = 3 # Default
CURRENT_BASED_POSITION_CONTROL      = 5

# Protocol version
PROTOCOL_VERSION            = 2.0               # See which protocol version is used in the Dynamixel

# Default setting
DXL1_ID                      = 1                             # Dynamixel ID: 1
DXL2_ID                      = 2                             # Dynamixel ID: 2
DXL3_ID                      = 3                             # Dynamixel ID: 3
BAUDRATE                    = 57600             # Dynamixel default baudrate : 57600
DEVICENAME                  = '/dev/ttyUSB0'    # Check which port is being used on your controller
                                                # ex) Windows: "COM1"   Linux: "/dev/ttyUSB0" Mac: "/dev/tty.usbserial-*"
TORQUE_ENABLE               = 1                 # Value for enabling the torque
TORQUE_DISABLE              = 0                 # Value for disabling the torque

portHandler = PortHandler(DEVICENAME)

# Initialize PacketHandler instance
# Set the protocol version
# Get methods and members of Protocol1PacketHandler or Protocol2PacketHandler
packetHandler = PacketHandler(PROTOCOL_VERSION)

# Open port
if portHandler.openPort():
    print("Succeeded to open the port")
else:
    print("Failed to open the port")
    print("Press any key to terminate...")
    getch()
    quit()

# Set port baudrate
if portHandler.setBaudRate(BAUDRATE):
    print("Succeeded to change the baudrate")
else:
    print("Failed to change the baudrate")
    print("Press any key to terminate...")
    getch()
    quit()
'''
# When need to change mode just remove block comment out
# Disable Dynamixel Torque 1
dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_DISABLE)
if dxl_comm_result != COMM_SUCCESS:
    print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
    print("%s" % packetHandler.getRxPacketError(dxl_error))
else:
    print("Dynamixel 1 has been successfully connected")
# Disable Dynamixel Torque 2
dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_DISABLE)
if dxl_comm_result != COMM_SUCCESS:
    print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
    print("%s" % packetHandler.getRxPacketError(dxl_error))
else:
    print("Dynamixel 2 has been successfully connected")
# Disable Dynamixel Torque 3
dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_DISABLE)
if dxl_comm_result != COMM_SUCCESS:
    print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
    print("%s" % packetHandler.getRxPacketError(dxl_error))
else:
    print("Dynamixel 3 has been successfully connected")

    # Check Operating Mode
dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_OPERATING_MODE, POSITION_CONTROL)
dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_OPERATING_MODE, POSITION_CONTROL)
dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_OPERATING_MODE, POSITION_CONTROL)

present_mode, dxl_comm_result, dxl_error = packetHandler.read1ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_OPERATING_MODE)
if present_mode == 0:
    # Current (Torque) Control Mode
    print("Now Operating Mode is Torque Control")
elif present_mode == 3:
    # Position Control Mode
    print("Now Operating Mode is Position Control")
elif present_mode == 5:
    # Current-based Position Control Mode
    print("Now Operating Mode is Current-based Position Control")
else:
    print("In other Mode that didn't set!")
'''

######################### Set PID Gain Position Loop  ##############################
set_P_Gain = 1000    #800 default
set_I_Gain = 20     #0 default
set_D_Gain = 1000   #4700 default

dxl_comm_result, dxl_error = packetHandler.write2ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_POSITION_P_GAIN, set_P_Gain)
dxl_comm_result, dxl_error = packetHandler.write2ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_POSITION_I_GAIN, set_I_Gain)
dxl_comm_result, dxl_error = packetHandler.write2ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_POSITION_D_GAIN, set_D_Gain)
dxl_comm_result, dxl_error = packetHandler.write2ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_POSITION_P_GAIN, set_P_Gain)
dxl_comm_result, dxl_error = packetHandler.write2ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_POSITION_I_GAIN, set_I_Gain)
dxl_comm_result, dxl_error = packetHandler.write2ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_POSITION_D_GAIN, set_D_Gain)
dxl_comm_result, dxl_error = packetHandler.write2ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_POSITION_P_GAIN, set_P_Gain)
dxl_comm_result, dxl_error = packetHandler.write2ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_POSITION_I_GAIN, set_I_Gain)
dxl_comm_result, dxl_error = packetHandler.write2ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_POSITION_D_GAIN, set_D_Gain)
print("PID's Gain are set")

position_D_gain, dxl_comm_result, dxl_error = packetHandler.read2ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_POSITION_D_GAIN)
position_I_gain, dxl_comm_result, dxl_error = packetHandler.read2ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_POSITION_I_GAIN)
position_P_gain, dxl_comm_result, dxl_error = packetHandler.read2ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_POSITION_P_GAIN)

print("Position D Gain: %d" %position_D_gain)
print("Position I Gain: %d" %position_I_gain)
print("Position P Gain: %d" %position_P_gain)
print("--------------------------------")

################################################################################################################################

rad2deg = 180/math.pi
deg2rad = math.pi/180
########################## parameters ################################
sb = 315.339
sp = 88.335
L = 293         #270
l = 555         #545
h = 70
root3 = math.sqrt(3)
wb = (root3/6)*sb
ub = (root3/3)*sb
wp = (root3/6)*sp
up = (root3/3)*sp
########################### Draw circular path ############################
r = 250.0		# Input the radius of a circle 150 is max.
zeta = [None]*360
X = [None]*360
Y1 = [None]*180
Y2 = [None]*180
Y = [None]*360

for i in range(1,361):
    zeta[i-1]=i*deg2rad
    X[i-1] = r*math.cos(zeta[i-1])

for i in range(1,(len(X)/2)+1):
    Y1[i-1] = math.sqrt(r**2 - X[i-1]**2)

j = 0
for i in range((len(X)/2)+1,len(X)+1):
    Y2[j] = -math.sqrt(r**2 - X[j]**2)
    j = j+1

Y = numpy.concatenate((Y1,Y2))

####################### Run Inverse Kinematics ############################
delaySpeed = 0.05
rest = 3

TorqueOn()
SetProfile1(30,10)
SetProfile2(30,10)
SetProfile3(30,10)
DeltaGoHome()

print("Delta is back home")
time.sleep(3)

i = 0
height = -350
increment = 10

while(i<360):

	xx = X[i]
	yy = Y[i]
	zz = height   # home is -485 but actual length is -460 but the difference

	ServoDEG = DeltaINV(xx,yy,zz)

	ServoANG1 = ServoDEG[0]
	ServoANG2 = ServoDEG[1]
	ServoANG3 = ServoDEG[2]

	RunServo(ServoANG1,ServoANG2,ServoANG3)

	print("i:%d" %i )
	#print("period: %f" %period)
	print('---------------------------')

	if i == 0:
		time.sleep(1)
		# make it delay a bit at first dot

	i = i + increment
	time.sleep(delaySpeed)

################### Finish the full circle #####################
xlast = X[359]
ylast = Y[359]
zlast = height   # home is -485 but actual length is -460 but the difference

ServoDEG = DeltaINV(xlast,ylast,zlast)

ServoANG1 = ServoDEG[0]
ServoANG2 = ServoDEG[1]
ServoANG3 = ServoDEG[2]

RunServo(ServoANG1,ServoANG2,ServoANG3)

time.sleep(1)

DeltaGoHome()


import cv2 as cv
import numpy as np

img = cv.imread("./resources/images/cr7.jpeg")

# 1 - Converting into greyscale
imgGray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) #Greyscale
cv.imshow("Grey Image", imgGray)
cv.waitKey(0)

# # 2 - Adding Blue to Image

imgBlur = cv.GaussianBlur(imgGray, (7,7), 0) # arugments in GaussianBlue are as follows - image, ksize - has to be odd number, sigmaX
cv.imshow("Blur Image", imgBlur)
cv.waitKey(0)

# # 3 - Edge Detection [Detector type = CANNY]

imgCanny = cv.Canny(img, 150,200) # change thresholds to change number of edges
cv.imshow("Edge Detector (CANNY) ", imgCanny)
cv.waitKey(0)

# 4 - Edge Detection [Detector type = CANNY] + Joining Edges usig Dilation [Making Edges thicker]

kernel = np.ones((5,5), np.uint8)
imgDilation = cv.dilate(imgCanny, kernel,iterations = 1)
cv.imshow("canny + dilation", imgDilation)
cv.waitKey(0)

# # 5 - Edge Detection [Detector type = CANNY] + Erosion [Making Edges Thinner]
imgEroded = cv.erode(imgDilation,kernel,iterations = 1)
cv.imshow("Erosion", imgEroded)
cv.waitKey(0)


#!/usr/bin/env python

#Connects to an RTKRCV server stream which outputs an XYZ-ECEF RTK solution.
#This solution message is parsed into its component and transmitted over
#individual ROS topics

import rospy
from std_msgs.msg import String
import socket
from sensor_msgs.msg import Imu, NavSatFix, NavSatStatus
from nav_msgs.msg import Odometry
from geometry_msgs.msg import Quaternion, Point, Pose

def getMsg():

	navsat = NavSatFix()
	navsat.header.stamp = rospy.Time.now()
	#Create a list of ROSTopic names
	topicList = ['dow', 'gpst', 'latitude', 'longitude', 'height', 'check', 'sats',
	'dxx', 'dyy', 'dzz', 'dxy', 'dyz', 'dxz', 'delay', 'ftest']

	#Create an empty array of ROS publishers
	pub = []

	for i in range(len(topicList)):

		#Create a publisher for each topic
		pub.append(rospy.Publisher('/rtklib/' + topicList[i], String, queue_size=30))

	#Initialize the RTKLIB ROS node
	rospy.init_node('rtklib_message', anonymous=True)

	#Define the publishing frequency of the node
	rate = rospy.Rate(10)

	#Create a socket
	sock = socket.socket()

	#Get the address of the local host
	host = socket.gethostname()

	#Connect to the RTKRCV server that is bound to port xxxx
	port = 5801
	sock.connect((host,port))

	while not rospy.is_shutdown():

		#Get the position message from the RTKRCV server
		msgStr = sock.recv(1024)

		#Split the message
		msg = msgStr.split()

		for i in range(len(msg)):

			#Publish over each topic
			pub[i].publish(msg[i])

		rate.sleep()

if __name__ == '__main__':
	try:
		#Run the publisher
		getMsg()
	except rospy.ROSInterruptException:
		pass


"""
.. module:: invoice
   :synopsis: A model for the invoice object.
"""

from .jsondict import JSONDict

class Invoice(JSONDict):
    """This models the Invoice object.

    Required:
        ================ ========== ===============================================
        *Argument*                  *Description*
        --------------------------- -----------------------------------------------
        invoiceNumber    (str):     The invoice number or identifier.
        customerId       (str):     The ID of the customer attached to the invoice.
        invoiceDate      (date):    The date that the invoice was billed on.
        dueDate          (date):    The date that the invoice must be paid by.
        ================ ========== ===============================================

        In addition to the above fields, you will need to add invoiceLineItems.

    Creation:
        Create a Invoice object and create it on the server side with
        with :func:`billdotcom.session.Session.create_invoice`. For example:

            >>> with Session() as s:
            >>>     a = Invoice(
            >>>         customerId= 'abc123',
            >>>         invoiceNumber = 'BC1234',
            >>>         invoiceDate = date(2012,10,1),
            >>>         dueDate = date(2012,11,1),
            >>>     )
            >>>     a['id'] = s.create(a)

    Retrieval:
        Download a list of Invoice objects from the server with the Session.
        For example:

            >>> with Session() as s:
            >>>     print [x['id'] for x in s.list('invoice')]
    """

    def __init__(self, ignore_required=False, **kwargs):
        required = (
            'customerId',
            'invoiceNumber',
            'invoiceDate',
            'dueDate',
        )

        if ignore_required == True:
            required = ()

        super(Invoice, self).__init__('Invoice', required, **kwargs)

        self.nested_map = {
            'invoiceLineItems': InvoiceLineItem
        }
        self.convert_nested()

    def add_line_item(self, line_item):
        self.nested_object.setdefault('invoiceLineItems', [])
        self.nested_object['invoiceLineItems'].append(line_item)

class InvoiceLineItem(JSONDict):
    """This models the InvoiceLineItem object. It allows you to further describe an Invoice,
    assigning amounts among individual line items.

    Required:
        ============= ========== =====================================================
        *Argument*               *Description*
        ------------------------ -----------------------------------------------------
        ============= ========== =====================================================

    Creation:
        InvoiceLineItems are created along with an Invoice. For example

            >>> with Session() as s:
            >>>     a = Invoice(
            >>>         externalId = '123456',
            >>>         customerId = 'abc123',
            >>>         invoiceNumber = 'BC1234',
            >>>         invoiceDate = date(2012,10,1),
            >>>         dueDate = date(2012,11,1),
            >>>         amount = 5.0
            >>>     )
            >>>     a.add_line_item(InvoiceLineItem(amount=2, description="eggs"))
            >>>     a.add_line_item(InvoiceLineItem(amount=3, description="bacon"))
            >>>     a['id'] = s.create(a)

    Retrieval:
        See the :class:`billdotcom.bill.Invoice` class for how you can retrieve invoices.
    """

    def __init__(self, ignore_required=False, **kwargs):
        required = (
            'itemId',
            'quantity'
        )

        if ignore_required == True:
            required = ()

        super(InvoiceLineItem, self).__init__('InvoiceLineItem', required, **kwargs)


import operator
import tempfile
import os
import inspect
import pytest

import pytest
import ast_tools
import fault
from hwtypes import UIntVector

import magma as m
from magma.testing import check_files_equal

Register = m.Register

from ast_tools import SymbolTable

class DualClockRAM(m.Circuit):
    io = m.IO(
        RADDR=m.In(m.Bits[8]),
        WADDR=m.In(m.Bits[8]),
        WDATA=m.In(m.Bits[8]),
        RDATA=m.Out(m.Bits[8]),
        WE=m.In(m.Bit),
        RCLK=m.In(m.Clock),
        WCLK=m.In(m.Clock)
    )

    m.wire(m.bits(0, 8), io.RDATA)

def test_sequential2_basic():
    @m.sequential2()
    class Basic:
        def __init__(self):
            self.x = Register(m.Bits[4])()
            self.y = Register(m.Bits[4])()

        def __call__(self, I: m.Bits[4]) -> m.Bits[4]:
            return self.y(self.x(I))

    m.compile("build/TestSequential2Basic", Basic)
    assert check_files_equal(__file__, f"build/TestSequential2Basic.v",
                             f"gold/TestSequential2Basic.v")

def test_sequential2_assign():
    @m.sequential2()
    class Basic:
        def __init__(self):
            self.x = Register(m.Bits[4])()
            self.y = Register(m.Bits[4])()

        def __call__(self, I: m.Bits[4]) -> m.Bits[4]:
            O = self.y
            self.y = self.x
            self.x = I
            return O

    m.compile("build/TestSequential2Assign", Basic)
    assert check_files_equal(__file__, f"build/TestSequential2Assign.v",
                             f"gold/TestSequential2Assign.v")

    # should be the same as basic
    assert check_files_equal(__file__, f"build/TestSequential2Assign.v",
                             f"gold/TestSequential2Basic.v")

def test_sequential2_hierarchy():
    @m.sequential2()
    class Foo:
        def __init__(self):
            self.x = Register(m.Bits[4])()
            self.y = Register(m.Bits[4])()

        def __call__(self, I: m.Bits[4]) -> m.Bits[4]:
            return self.y(self.x(I))

    @m.sequential2()
    class Bar:
        def __init__(self):
            self.x = Foo()
            self.y = Foo()

        def __call__(self, I: m.Bits[4]) -> m.Bits[4]:
            return self.y(self.x(I))

    m.compile("build/TestSequential2Hierarchy", Bar)
    assert check_files_equal(__file__, f"build/TestSequential2Hierarchy.v",
                             f"gold/TestSequential2Hierarchy.v")

def test_sequential2_pre_unroll(capsys):
    with tempfile.TemporaryDirectory() as tmpdir:
        l0 = inspect.currentframe().f_lineno + 1

        @m.sequential2(pre_passes=[ast_tools.passes.loop_unroll()],
                       post_passes=[
                           ast_tools.passes.debug(dump_source_filename=True,
                                                  dump_source_lines=True)],
                       env=locals().update(y=2),
                       debug=True, path=tmpdir, file_name="foo.py")
        class LoopUnroll:
            def __init__(self):
                self.regs = [[Register(m.Bits[4])() for _ in range(3)] for _ in range(2)]

            def __call__(self, I: m.Bits[4]) -> m.Bits[4]:
                O = self.regs[1][-1]
                for i in ast_tools.macros.unroll(range(y)):
                    for j in ast_tools.macros.unroll(range(2)):
                        self.regs[1 - i][2 - j] = self.regs[1 - i][1 - j]
                    self.regs[1 - i][0] = self.regs[i][-1] if m.Bit(i == 0) else I
                return O

        with open(os.path.join(tmpdir, "foo.py"), "r") as output:
            assert output.read() == """\
def __call__(self, I: m.Bits[4]) -> m.Bits[4]:
    O_0 = self.regs[1][-1]
    self.regs[1 - 0][2 - 0] = self.regs[1 - 0][1 - 0]
    self.regs[1 - 0][2 - 1] = self.regs[1 - 0][1 - 1]
    self.regs[1 - 0][0] = __phi(m.Bit(0 == 0), self.regs[0][-1], I)
    self.regs[1 - 1][2 - 0] = self.regs[1 - 1][1 - 0]
    self.regs[1 - 1][2 - 1] = self.regs[1 - 1][1 - 1]
    self.regs[1 - 1][0] = __phi(m.Bit(1 == 0), self.regs[1][-1], I)
    __0_return_0 = O_0
    return __0_return_0
"""

    assert capsys.readouterr().out == f"""\
BEGIN SOURCE_FILENAME
{os.path.abspath(__file__)}
END SOURCE_FILENAME

BEGIN SOURCE_LINES
{l0+11}:            def __call__(self, I: m.Bits[4]) -> m.Bits[4]:
{l0+12}:                O = self.regs[1][-1]
{l0+13}:                for i in ast_tools.macros.unroll(range(y)):
{l0+14}:                    for j in ast_tools.macros.unroll(range(2)):
{l0+15}:                        self.regs[1 - i][2 - j] = self.regs[1 - i][1 - j]
{l0+16}:                    self.regs[1 - i][0] = self.regs[i][-1] if m.Bit(i == 0) else I
{l0+17}:                return O
END SOURCE_LINES

"""

    m.compile("build/TestSequential2NestedLoopUnroll", LoopUnroll)
    assert check_files_equal(__file__, f"build/TestSequential2NestedLoopUnroll.v",
                             f"gold/TestSequential2NestedLoopUnroll.v")

def test_dual_clock_ram():
    @m.sequential2()
    class DefaultClock:
        def __call__(self) -> m.Bits[8]:
            rdata = DualClockRAM()(
                RADDR=m.bits(0, 8),
                WADDR=m.bits(0, 8),
                WDATA=m.bits(0, 8),
                WE=m.bit(0),
                # Default CLK will be wired up implicitly
                # RCLK=CLK
                # WCLK=CLK
            )
            return rdata

    m.compile("build/TestSequential2DefaultClock", DefaultClock)
    assert check_files_equal(__file__,
                             f"build/TestSequential2DefaultClock.v",
                             f"gold/TestSequential2DefaultClock.v")

    @m.sequential2()
    class ExplicitClock:
        def __call__(self, WCLK: m.Clock, RCLK: m.Clock) -> m.Bits[8]:
            rdata = DualClockRAM()(
                RADDR=m.bits(0, 8),
                WADDR=m.bits(0, 8),
                WDATA=m.bits(0, 8),
                WE=m.bit(0),
                # Wiring clocks explicitly
                RCLK=RCLK,
                WCLK=WCLK
            )
            return rdata

    m.compile("build/TestSequential2ExplicitClock", ExplicitClock)
    assert check_files_equal(__file__,
                             f"build/TestSequential2ExplicitClock.v",
                             f"gold/TestSequential2ExplicitClock.v")

def test_sequential2_return_tuple():
    @m.sequential2()
    class Basic:
        def __init__(self):
            self.x = Register(m.Bits[4])()
            self.y = Register(m.Bits[4])()

        def __call__(self, I: m.Bits[4], S: m.Bit) -> (m.Bits[4], m.Bits[4]):
            self.y = self.x
            self.x = I
            if S:
                return self.x, self.y
            else:
                return self.y, self.x

    m.compile("build/TestSequential2ReturnTuple", Basic, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2ReturnTuple.v",
                             f"gold/TestSequential2ReturnTuple.v")

def test_sequential2_custom_annotations():
    annotations = {"I": m.Bits[4], "S": m.Bit, "return": m.Bits[4]}
    @m.sequential2(annotations=annotations)
    class Basic:
        def __init__(self):
            self.x = Register(m.Bits[4])()
            self.y = Register(m.Bits[4])()

        # Bad annotations to make sure they're overridden
        def __call__(self, I: int, S: str) -> tuple:
            O = self.y
            self.y = self.x
            self.x = I
            return O

    m.compile("build/TestSequential2CustomAnnotations", Basic, inline=True)
    assert check_files_equal(__file__,
                             f"build/TestSequential2CustomAnnotations.v",
                             f"gold/TestSequential2CustomAnnotations.v")

def test_sequential2_counter():
    @m.sequential2()
    class Test2:
        def __init__(self):
            self.count = m.Register(T=m.SInt[16], init=m.sint(0, 16))()

        def __call__(self) -> m.SInt[16]:
            self.count = self.count + 1
            return self.count

    m.compile("build/TestSequential2Counter", Test2, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2Counter.v",
                             f"gold/TestSequential2Counter.v")

def test_sequential2_counter_if():
    @m.sequential2()
    class Test2:
        def __init__(self):
            self.count = m.Register(T=m.SInt[16], init=m.sint(0, 16))()

        def __call__(self, sel: m.Bit) -> m.SInt[16]:
            if sel:
                self.count = self.count + 1
            return self.count

    m.compile("build/TestSequential2CounterIf", Test2, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2CounterIf.v",
                             f"gold/TestSequential2CounterIf.v")

def test_sequential2_product():
    @m.sequential2()
    class Test:
        def __call__(self, sel: m.Bit) -> m.AnonProduct[dict(a=m.Bit)]:
            if sel:
                return m.product(a=m.bit(0))
            else:
                return m.product(a=m.bit(1))

    m.compile("build/TestSequential2Product", Test, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2Product.v",
                             f"gold/TestSequential2Product.v")

def test_sequential2_arr_of_bits():
    T = m.Array[15, m.Bits[7]]
    @m.sequential2()
    class Test2:
        def __init__(self):
            self.reg_arr = m.Register(T=T)()

        def __call__(self, I: T) -> T:
            O = self.reg_arr
            self.reg_arr = I
            return O

    m.compile("build/TestSequential2ArrOfBits", Test2, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2ArrOfBits.v",
                             f"gold/TestSequential2ArrOfBits.v")

def test_sequential2_getitem():
    T = m.Array[8, m.Bits[7]]
    @m.sequential2()
    class Test2:
        def __init__(self):
            self.reg_arr = m.Register(T=T)()
            self.index = m.Register(T=m.Bits[3])()

        def __call__(self, I: T, index: m.Bits[3]) -> m.Array[2, m.Bits[7]]:
            out = m.array([self.reg_arr[index], self.reg_arr[self.index]])
            self.reg_arr = I
            self.index = index
            return out

    m.compile("build/TestSequential2GetItem", Test2, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2GetItem.v",
                             f"gold/TestSequential2GetItem.v")

def test_sequential2_slice():
    @m.sequential2()
    class TestSequential2Slice:
        def __init__(self):
            self.mem = m.Register(T=m.Bits[8 * 8])()

        def __call__(self, write_addr: m.UInt[3], write_data: m.Bits[8],
                     read_addr: m.UInt[3]) -> m.Bits[8]:
            read_data = m.get_slice(self.mem, m.zext(read_addr, 3) * 8, 8)
            self.mem = m.set_slice(self.mem, write_data,
                                   m.zext(write_addr, 3) * 8, 8)
            return read_data

    m.compile("build/TestSequential2Slice", TestSequential2Slice, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2Slice.v",
                             f"gold/TestSequential2Slice.v")

    tester = fault.SynchronousTester(TestSequential2Slice,
                                     TestSequential2Slice.CLK)
    tester.circuit.write_addr = 1
    tester.circuit.write_data = 2
    tester.circuit.read_addr = 1
    tester.advance_cycle()
    tester.circuit.O.expect(2)
    tester.circuit.write_addr = 2
    tester.circuit.write_data = 3
    tester.circuit.read_addr = 2
    tester.advance_cycle()
    tester.circuit.O.expect(3)
    # Check addr 1 wasn't overwriten
    tester.circuit.read_addr = 1
    tester.advance_cycle()
    tester.circuit.O.expect(2)

    build_dir = os.path.join(
        os.path.abspath(os.path.dirname(__file__)),
        "build"
    )
    tester.compile_and_run("verilator", skip_compile=True, directory=build_dir,
                           flags=["-Wno-unused"])

def test_sequential2_prev():
    @m.sequential2()
    class Test2:
        def __init__(self):
            self.cnt = m.Register(T=m.UInt[3])()

        def __call__(self) -> m.UInt[3]:
            self.cnt = self.cnt + 1
            return self.cnt.prev()

    m.compile("build/TestSequential2Prev", Test2, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2Prev.v",
                             f"gold/TestSequential2Prev.v")

def test_sequential2_reset():
    @m.sequential2(reset_type=m.AsyncReset, has_enable=True)
    class Test2:
        def __init__(self):
            # reset_type and has_enable will be set implicitly
            self.cnt = m.Register(T=m.UInt[3])()

        def __call__(self) -> m.UInt[3]:
            self.cnt = self.cnt + 1
            return self.cnt

    m.compile("build/TestSequential2Reset", Test2, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2Reset.v",
                             f"gold/TestSequential2Reset.v")

def test_sequential2_ite_array():
    @m.sequential2()
    class Test:
        def __init__(self):
            self.v = m.Register(T=m.Bit, init=m.bit(0))()

        def __call__(self, sel: m.Bit) -> m.Array[1, m.Bit]:
            self.v = sel
            if sel:
                return m.array([m.bit(0)])
            else:
                return m.array([self.v.prev()])

    m.compile("build/TestSequential2IteArray", Test, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2IteArray.v",
                             f"gold/TestSequential2IteArray.v")

def test_sequential2_ite_array2():
    @m.sequential2()
    class Test:
        def __init__(self):
            self.v = m.Register(T=m.Bit, init=m.bit(0))()

        def __call__(self, sel: m.Bit) -> m.Array[2, m.Bit]:
            self.v = sel
            if sel:
                return m.array([m.bit(0), m.bit(0)])
            else:
                return m.array([self.v.prev(), m.bit(1)])

    m.compile("build/TestSequential2IteArray2", Test, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2IteArray2.v",
                             f"gold/TestSequential2IteArray2.v")

def test_sequential2_ite_array_error():
    with pytest.raises(TypeError,
                       match="Found incompatible types .* in mux inference"):
        @m.sequential2()
        class Test:
            def __init__(self):
                self.v = m.Register(T=m.Bit, init=m.bit(0))()

            def __call__(self, sel: m.Bit) -> m.Array[1, m.Bit]:
                self.v = sel
                if sel:
                    return m.array([m.bit(0), m.bit(0)])
                else:
                    return m.array([self.v.prev()])

def test_sequential2_ite_tuple():
    @m.sequential2()
    class Test:
        def __init__(self):
            self.v = m.Register(T=m.Bit, init=m.bit(0))()

        def __call__(self, sel: m.Bit) -> m.Tuple[m.Bit]:
            self.v = sel
            if sel:
                return m.tuple_(self.v.prev())
            else:
                return m.tuple_(self.v.prev())

    m.compile("build/TestSequential2IteTuple", Test, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2IteTuple.v",
                             f"gold/TestSequential2IteTuple.v")

def test_sequential2_ite_tuple2():
    @m.sequential2()
    class Test:
        def __init__(self):
            self.v = m.Register(T=m.Bit, init=m.bit(0))()

        def __call__(self, sel: m.Bit) -> m.Tuple[m.Bit]:
            self.v = sel
            if sel:
                return m.tuple_(m.bit(0))
            else:
                return m.tuple_(self.v.prev())

    m.compile("build/TestSequential2IteTuple2", Test, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2IteTuple2.v",
                             f"gold/TestSequential2IteTuple2.v")

def test_sequential2_ite_tuple_error_type():
    with pytest.raises(TypeError,
                       match="Found incompatible types .* in mux inference"):
        @m.sequential2()
        class Test:
            def __init__(self):
                self.v = m.Register(T=m.Bit, init=m.bit(0))()

            def __call__(self, sel: m.Bit) -> m.Tuple[m.Bit]:
                self.v = sel
                if sel:
                    return m.tuple_(m.bits(0, 2))
                else:
                    return m.tuple_(self.v.prev())

def test_sequential2_ite_product():
    @m.sequential2()
    class Test:
        def __init__(self):
            self.v = m.Register(T=m.Bit, init=m.bit(0))()

        def __call__(self, sel: m.Bit) -> m.AnonProduct[dict(a=m.Bit)]:
            self.v = sel
            if sel:
                return m.product(a=self.v.prev())
            else:
                return m.product(a=self.v.prev())

    m.compile("build/TestSequential2IteProduct", Test, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2IteProduct.v",
                             f"gold/TestSequential2IteProduct.v")

def test_sequential2_ite_product2():
    @m.sequential2()
    class Test:
        def __init__(self):
            self.v = m.Register(T=m.Bit, init=m.bit(0))()

        def __call__(self, sel: m.Bit) -> m.AnonProduct[dict(a=m.Bit)]:
            self.v = sel
            if sel:
                return m.product(a=m.bit(0))
            else:
                return m.product(a=self.v.prev())

    m.compile("build/TestSequential2IteProduct2", Test, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2IteProduct2.v",
                             f"gold/TestSequential2IteProduct2.v")

def test_sequential2_ite_product_error_type():
    with pytest.raises(TypeError,
                       match="Found incompatible types .* in mux inference"):
        @m.sequential2()
        class Test:
            def __init__(self):
                self.v = m.Register(T=m.Bit, init=m.bit(0))()

            def __call__(self, sel: m.Bit) -> m.AnonProduct[dict(a=m.Bit)]:
                self.v = sel
                if sel:
                    return m.product(a=m.bits(0, 2))
                else:
                    return m.product(a=self.v.prev())

def test_sequential2_ite_product_error_keys():
    with pytest.raises(TypeError,
                       match="Found incompatible types .* in mux inference"):
        @m.sequential2()
        class Test:
            def __init__(self):
                self.v = m.Register(T=m.Bit, init=m.bit(0))()

            def __call__(self, sel: m.Bit) -> m.AnonProduct[dict(a=m.Bit)]:
                self.v = sel
                if sel:
                    return m.product(a=m.bit(0))
                else:
                    return m.product(b=self.v.prev())

def test_sequential2_ite_nested():
    @m.sequential2()
    class Test:
        def __init__(self):
            self.v = m.Register(T=m.Bit, init=m.bit(0))()

        def __call__(self, sel: m.Bit) -> m.AnonProduct[dict(
            a=m.AnonProduct[dict(b=m.Bit)],
            c=m.Tuple[m.Bit])
        ]:
            self.v = sel
            if sel:
                return m.product(a=m.product(b=m.bit(0)),
                                    c=m.tuple_(m.bit(0)))
            else:
                return m.product(a=m.product(b=self.v.prev()),
                                    c=m.tuple_(self.v.prev()))

    m.compile("build/TestSequential2IteNested", Test, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2IteNested.v",
                             f"gold/TestSequential2IteNested.v")

def test_sequential2_ite_bits():
    @m.sequential2()
    class Test:
        def __init__(self):
            self.v = m.Register(T=m.Bits[8], init=m.bits(0, 8))()

        def __call__(self, sel: m.Bit) -> m.AnonProduct[dict(a=m.Bits[8])]:
            self.v = self.v
            if sel:
                return m.product(a=self.v.prev())
            else:
                return m.product(a=self.v.prev())

    m.compile("build/TestSequential2IteBits", Test, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2IteBits.v",
                             f"gold/TestSequential2IteBits.v")

def test_sequential2_ite_bits2():
    @m.sequential2()
    class Test:
        def __init__(self):
            self.v = m.Register(T=m.Bits[8], init=m.bits(0, 8))()

        def __call__(self, sel: m.Bit) -> m.AnonProduct[dict(a=m.Bits[8])]:
            self.v = self.v
            if sel:
                return m.product(a=m.bits(0, 8))
            else:
                return m.product(a=self.v.prev())

    m.compile("build/TestSequential2IteBits2", Test, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2IteBits2.v",
                             f"gold/TestSequential2IteBits2.v")

def test_sequential2_ite_bits3():
    @m.sequential2()
    class Test:
        def __init__(self):
            self.v = m.Register(T=m.Bit, init=m.bit(0))()

        def __call__(self, sel: m.Bit) -> m.AnonProduct[dict(a=m.Bits[8])]:
            self.v = self.v
            if sel:
                return m.product(a=m.concat(m.bits(0, 4),
                                               m.repeat(self.v.prev(), 3),
                                               self.v.prev()))
            else:
                return m.product(a=m.bits(self.v.prev(), 8))

    m.compile("build/TestSequential2IteBits3", Test, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2IteBits3.v",
                             f"gold/TestSequential2IteBits3.v")

def test_sequential2_ite_complex():
    @m.sequential2()
    class Test:
        def __init__(self):
            self.a = m.Register(T=m.Bit, init=m.bit(0))()
            self.b = m.Register(T=m.Bits[2], init=m.bits(0, 2))()

        def __call__(self, sel: m.Bit) -> m.AnonProduct[dict(
                                              a=m.Tuple[m.Bits[2]],
                                              b=m.Array[2, m.Bit],
                                          )]:
            self.a = self.a
            self.b = self.b
            if sel:
                return m.product(
                           a=m.tuple_([self.b.prev()]),
                           b=m.array([self.a.prev(), self.a.prev()]),
                       )
            else:
                return m.product(
                           a=m.tuple_([m.array([self.a.prev(), self.a.prev()])]),
                           b=m.array(self.b.prev()),
                       )

    m.compile("build/TestSequential2IteComplex", Test, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2IteComplex.v",
                             f"gold/TestSequential2IteComplex.v")

def test_sequential2_ite_complex_register():
    class T(m.Product):
        a = m.Array[1, m.Bits[2]]
        b = m.Tuple[m.AnonProduct[dict(c=m.Array[2, m.Bit])]]

    @m.sequential2()
    class Test:
        def __init__(self):
            self.a = m.Register(
                T=T,
                init=m.product(
                    a=m.array([m.bits(0, 2)]),
                    b=m.tuple_([m.product(c=m.array([m.bit(0), m.bit(0)]))]),
                ),
            )()

        def __call__(self, sel: m.Bit) -> T:
            self.a = self.a
            if sel:
                return self.a
            else:
                return self.a

    m.compile("build/TestSequential2IteComplexRegister", Test, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2IteComplexRegister.v",
                             f"gold/TestSequential2IteComplexRegister.v")

def test_sequential2_ite_complex_register2():
    class T(m.Product):
        a = m.Array[1, m.Bits[2]]
        b = m.Tuple[m.AnonProduct[dict(c=m.Array[2, m.Bit])]]

    @m.sequential2()
    class Test:
        def __init__(self):
            self.a = m.Register(
                T=T,
                init=m.product(
                    a=m.array([m.bits(0, 2)]),
                    b=m.tuple_([m.product(c=m.array([m.bit(0), m.bit(0)]))]),
                ),
            )()

        def __call__(self, sel: m.Bit) -> T:
            self.a = self.a
            if sel:
                return m.product(
                    a=m.array([self.a.b[0].c]),
                    b=m.tuple_([m.product(
                        c=m.array([m.bit(0), m.bit(self.a.a[0][1:2])]))]
                    ),
                )
            else:
                return self.a

    m.compile("build/TestSequential2IteComplexRegister2", Test, inline=True)
    assert check_files_equal(__file__, f"build/TestSequential2IteComplexRegister2.v",
                             f"gold/TestSequential2IteComplexRegister2.v")

def test_gcd():
    @m.sequential2()
    class GCD:
        def __init__(self):
            self.x = m.Register(m.UInt[16])()
            self.y = m.Register(m.UInt[16])()

        def __call__(self, a: m.In(m.UInt[16]), b: m.In(m.UInt[16]),
                     load: m.In(m.Bit)) -> (m.Out(m.UInt[16]), m.Out(m.Bit)):
            if load:
                self.x = a
                self.y = b
            elif self.y != 0:
                if self.x > self.y:
                    self.x = self.x - self.y
                else:
                    self.y = self.y - self.x
            return self.x.prev(), self.y.prev() == 0

    m.compile("build/GCD", GCD, inline=True)
    tester = fault.SynchronousTester(GCD, clock=GCD.CLK)
    tester.circuit.a = 32
    tester.circuit.b = 16
    tester.circuit.load = 1
    tester.advance_cycle()
    tester.circuit.load = 0
    tester.advance_cycle()
    tester.wait_on(tester.circuit.O1 == 1)
    tester.circuit.O0.expect(16)
    dir_ = os.path.join(os.path.dirname(__file__), "build")
    tester.compile_and_run("verilator", skip_compile=True, directory=dir_,
                           flags=["-Wno-unused"])

@pytest.mark.parametrize('op', [operator.add, operator.sub, operator.mul,
                                operator.floordiv, operator.truediv,
                                operator.mod, operator.lshift, operator.rshift,
                                operator.and_, operator.xor, operator.or_])
def test_r_ops(op):
    @m.sequential2()
    class Test:
        def __init__(self):
            self.x = m.Register(m.UInt[16])()
            self.y = m.Register(m.UInt[16])()

        def __call__(self, a: m.In(m.UInt[16]), b: m.In(m.UInt[16]),
                     load: m.In(m.Bit)) -> (m.Out(m.UInt[16]),
                                            m.Out(m.UInt[16])):
            if load:
                self.x = a
                self.y = b
            else:
                self.x = op(self.x, self.y)
                self.y = op(self.y, self.x)
            return self.x.prev(), self.y.prev()

    type(Test).rename(Test, f"TestRop{op.__name__}")
    m.compile(f"build/TestRop{op.__name__}", Test, inline=True)
    if op in {operator.mod, operator.truediv}:
        # coreir doesn't support urem primitive
        # hwtypes BV doesn't support truediv
        # but we still test these right hand op implementation for coverage and
        # to make sure they compile without error
        return
    tester = fault.SynchronousTester(Test, clock=Test.CLK)
    tester.circuit.a = a = 32
    tester.circuit.b = b = 3
    tester.circuit.load = 1
    tester.advance_cycle()
    tester.circuit.load = 0
    tester.advance_cycle()
    O0 = op(a, b)
    tester.circuit.O0.expect(O0)
    tester.circuit.O1.expect(op(b, O0))
    dir_ = os.path.join(os.path.dirname(__file__), "build")
    tester.compile_and_run("verilator", flags=['-Wno-unused'],
                           skip_compile=True, directory=dir_)

@pytest.mark.parametrize('op', [operator.invert, operator.neg])
def test_u_ops(op):
    @m.sequential2()
    class Test:
        def __init__(self):
            self.x = m.Register(m.SInt[16])()

        def __call__(self, a: m.In(m.SInt[16]),
                     load: m.In(m.Bit)) -> m.Out(m.SInt[16]):
            if load:
                self.x = a
            else:
                self.x = op(self.x)
            return self.x.prev()

    type(Test).rename(Test, f"TestUop{op.__name__}")
    m.compile(f"build/TestUop{op.__name__}", Test, inline=True)
    tester = fault.SynchronousTester(Test, clock=Test.CLK)
    tester.circuit.a = a = 32
    tester.circuit.load = 1
    tester.advance_cycle()
    tester.circuit.load = 0
    tester.advance_cycle()
    O = op(a)
    tester.circuit.O.expect(O)
    dir_ = os.path.join(os.path.dirname(__file__), "build")
    tester.compile_and_run("verilator", flags=['-Wno-unused'],
                           skip_compile=True, directory=dir_)

def test_reset_no_init():
    Data = m.UInt[8]

    @m.sequential2(reset_type=m.AsyncReset)
    class Inc:
        def __call__(self, i: Data) -> Data:
            return i + 1

def test_magma_not_in_env():

    Data = m.UInt[8]
    env = SymbolTable({}, {'Data': Data})

    @m.sequential2(env=env, reset_type=m.AsyncReset)
    class Inc:
        def __init__(self):
            pass

        def __call__(self, i: Data) -> Data:
            return i + 1

def test_named_outputs():
    Data = m.UInt[8]
    @m.sequential2(output_port_names=['s','c_out'])
    class Adder:
        def __call__(self, a: Data, b: Data, c_in: m.Bit) -> (Data, m.Bit):
            return a.adc(b, c_in)

    assert Adder.interface.ports.keys() == {'a', 'b', 'c_in', 's', 'c_out', 'CLK'}

def test_special_attr():
    def _is_dunder(name: str) -> bool:
        return (len(name) > 4
                and name[:2] == name[-2:] == '__'
                and name[2] != '_' and name[-3] != '_')

    # a sentinel
    _null = object()

    # This is basically the PEak base class
    class PeakPokeBase:
        # enable a descriptor like protocol on instance attributes
        def __getattribute__(self, attr):
            val = super().__getattribute__(attr)

            if _is_dunder(attr):
                return val

            try:
                getter = val._peak_
            except AttributeError:
                return val

            return getter()

        def __setattr__(self, attr, value):
            if _is_dunder(attr):
                return super().__setattr__(attr, value)

            try:
                current = super().__getattribute__(attr)
            except AttributeError:
                return super().__setattr__(attr, value)

            setter = getattr(current, '_poke_', _null)

            if setter is _null:
                return super().__setattr__(attr, value)
            else:
                return setter(value)

    class PeakPokeRegister:
        def __init__(self, T, init):
            self.reg = m.Register(T, init,
                has_enable=False,
                reset_type=m.AsyncReset
                )()

        def _peak_(self):
            return self.reg.O

        def _poke_(self, value):
            self.reg.I @= value

    Data = m.UInt[8]
    @m.sequential2()
    class Counter(PeakPokeBase):
        def __init__(self):
            self.reg = PeakPokeRegister(Data, 0)

        def __call__(self, en: m.Bit) -> Data:
            val = self.reg
            if en & (val < 7):
                self.reg = val + 1
            elif en:
                self.reg = 0
            else:
                self.reg = val
            return val


from typing import Optional

from .updater import BLACKLIST_FILE_PATH, BlacklistUpdater

SetOrNone = Optional[set]

# Start an optional update on module load
blacklist_updater = BlacklistUpdater()
blacklist_updater.process(force=False)

class DomainListValidator(object):
    'Check the provided email against domain lists.'
    domain_whitelist = set()
    domain_blacklist = set('localhost')

    def __init__(
            self, whitelist: SetOrNone = None, blacklist: SetOrNone = None):
        if whitelist:
            self.domain_whitelist = set(x.lower() for x in whitelist)
        if blacklist:
            self.domain_blacklist = set(x.lower() for x in blacklist)
        else:
            self._load_builtin_blacklist()

    def _load_builtin_blacklist(self):
        'Load our built-in blacklist.'
        try:
            with open(BLACKLIST_FILE_PATH) as fd:
                lines = fd.readlines()
        except FileNotFoundError:
            return
        self.domain_blacklist.update(
            x.strip().lower() for x in lines if x.strip())

    def __call__(self, user_part: str, domain_part: str) -> bool:
        'Do the checking here.'
        if domain_part in self.domain_whitelist:
            return True
        if domain_part in self.domain_blacklist:
            return False
        return True

domainlist_check = DomainListValidator()


import random
import matplotlib.pyplot as plt

# Markedsparametre

# Alpha: hvor meget forbrugere vil efterspørge, hvis prisen er nul
alpha = 10.5

# Beta: hældning på demand-kurve, hvor stor effekt prisen på varen har på efterspørgslen
beta = 1.75

# Theta: afgører hvilken indflydelse det har at prisen afviger fra markedsgennemsnittet
theta = 1.45833

def demand(price, market_price):
    return alpha - beta * price + theta * market_price

class Producer:
    def __init__(self, initial_price, initial_production):
        # Initielle værdier
        self.price = initial_price
        self.market_price_forecast = self.price + random.gauss(0, 5)
        self.quantity = initial_production
        self.excess_supply = 0

        # Normalfordelte konstanter (det står ikke i paperet hvordan de er sat)
        self.epsilon = random.gauss(0, 1)
        self.u = random.gauss(0, 1)
        self.eta = random.gauss(0, 1)

        # Koefficienter for agenten (pt. samme for alle agenter)
        # Disse er fra paperet, deltager 9, gruppe 4
        # beregnet via first-order heuristics

        # Koefficienter til estimering af markedspris
        self.w0 = 0.817 # vægtning af sidste obseverede markedspris
        self.w1 = 0.238 # vægtning af vores egen sidste forudsigelse

        # Koefficienter til beslutning af pris
        self.coeff_p = 0.832    # vægtning af sidste pris
        self.coeff_pe = 0.199   # vægtning af forventede markedspris
        self.coeff_S = -0.127  # straf for overskydende varer, der ikke bliver solgt

        # Koefficienter til beregning af produktion
        self.alpha = 11.812
        self.beta = 1.412
        self.theta = 1.058

    def set_price(self, market_price):
        # Forudsig fremtidig markedspris
        self.market_price_forecast = (self.w0 * market_price
                                      + self.w1 * self.market_price_forecast
                                      + self.epsilon)

        # Sæt vores pris denne periode
        self.price = (self.coeff_p * self.price
                      + self.coeff_pe * self.market_price_forecast
                      + self.coeff_S * self.excess_supply
                      + self.u)

    def set_production_level(self):
        # Forudsig efterspørgsel
        demand = (self.alpha
                  - self.beta * self.price
                  + self.theta * self.market_price_forecast
                  + self.eta)

        # Producer den mængde der efterspørges
        self.quantity = max(demand, 0)

    def observe_demand(self, demand):
        # Opdater overskud i varer (hvor meget blev ikke solgt)
        self.excess_supply = max(self.quantity - demand, 0)

# Et par hjælpefunktioner
def average(prices):
    return sum(prices)/len(prices)

def prices(agents):
    prices = []
    for agent in agents:
        prices.append(agent.price)
    return prices

def quantities(agents):
    quantities = []
    for agent in agents:
        quantities.append(agent.quantity)
    return quantities

# Parametre for simulationen
num_agents = 2000 # Antal agenter
iterations = 200 # Antal iterationer
initial_production_quantity = 20 # Alle agenter producerer lige meget

# Opret agenterne
agents = []
for i in range(num_agents):
    initial_price = random.gauss(15, 2)
    agent = Producer(initial_price, initial_production_quantity)
    agents.append(agent)

# Initiel markedspris
market_price = average(prices(agents))

# Gem markedspriser og produktions gennemsnit over tid (til plot)
market_price_list = [market_price]
production_averages = [initial_production_quantity]

# Kør simulationen
for t in range(iterations):
    # Lad agenterne sætte pris og produktionsniveau
    for agent in agents:
        agent.set_price(market_price)
        agent.set_production_level()

    # Beregn markedspris og gennemsnitlig produktion
    market_price = average(prices(agents))
    production_average = average(quantities(agents))

    # Lad agenter observere faktisk efterspørgsel
    for agent in agents:
        d = demand(agent.price, market_price)
        agent.observe_demand(d)

    # Gem markedspris og gns. produktion til plot
    market_price_list.append(market_price)
    production_averages.append(production_average)

# Print resultater
for t in range(iterations):
    print(t, market_price_list[t], production_averages[t])

# Plot markedspris
plt.title('markedspris vs. tid')
plt.xlabel('t')
plt.ylabel('markedspris')
plt.plot(range(iterations+1), market_price_list, 'm.')
plt.show()

# Plot produktion
plt.title('Gennemsnitlig produktion vs. tid')
plt.xlabel('t')
plt.ylabel('produktion')
plt.plot(range(iterations+1), production_averages, 'm.')
plt.show()


import os

basedir = os.path.abspath(os.path.dirname(__file__))

CACHE_PATH = os.path.join(basedir, ".cache")
STATIC_FILES_PATH = os.path.join(basedir, ".static")

# chromedriver
CHROMEDRIVER_PATH = "/home/vnatschke/.local/bin/chromedriver"

# providers settings
ANIMEFLV_BASE_URL = os.getenv("ANIMEFLV_BASE_URL", "https://www3.animeflv.net")


# Prerequisit: selenium and chromedriver
# On Mac:
# Pip3 install -U selenium
# brew  install chromedriver

import time
from sys import exit
import os

try:
	from selenium import webdriver
	from selenium.webdriver.common.by import By
	from selenium.common.exceptions import NoSuchElementException, WebDriverException
except ImportError as e:
	print("Please install selenium")
	exit(1)

chromedriver_location='/usr/local/bin/chromedriver'
initial_url='https://www.cvs.com/immunizations/covid-19-vaccine?icid=cvs-home-hero1-banner-1-link2-coronavirus-vaccine#'

state='California'

chromeOptions = webdriver.ChromeOptions()
chromeOptions.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2})
chromeOptions.add_argument("--headless")
chromeOptions.add_argument("--no-sandbox")
chromeOptions.add_argument("--disable-setuid-sandbox")

chromeOptions.add_argument("--remote-debugging-port=0")

chromeOptions.add_argument("--disable-dev-shm-using")
chromeOptions.add_argument("--disable-extensions")
chromeOptions.add_argument("--disable-gpu")
chromeOptions.add_argument("start-maximized")
chromeOptions.add_argument("disable-infobars")
chromeOptions.add_argument(r"user-data-dir=.\cookies\\test")

try:
	driver = webdriver.Chrome(chromedriver_location, options=chromeOptions)
except WebDriverException:
	print("Chromedriver not found. Install chromedriver and set chromedriver_location")
	exit(1)

driver.get(initial_url);
time.sleep(3)

try:
	CA=driver.find_element(By.XPATH,'/html/body/div[3]/div/div[1]/a');
	CA.click();
	time.sleep(5);
except NoSuchElementException:
	pass

try:
	CA=driver.find_element_by_link_text(state);
	CA.click();
except NoSuchElementException:
	driver.quit();

time.sleep(2)

CA_text=driver.find_element(By.XPATH,'/html/body/div[2]/div/div[13]/div/div/div/div/div/div[1]/div[2]/div/div/div[2]/div/div[6]/div/div')
print(CA_text.text)

driver.quit()


#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# guio-ping.py
#
# 17 de nov. 2022  <adria@molevol-OptiPlex-9020>

"""
1. Envia una ordre de 'mtr' al sistema amb el mòdul 'os'.
2. Recull el resultat (en format csv?) amb pandas dins un dataframe.
3. Elimina i afegeix info per ajustar a les necessitats.
4. Append a un file.csv per guardar les anàlisis.
"""

import sys
import os
import pandas as pd

# Recull la data de les anàlisis de ping...
import datetime

# Funció per fer Sleep...
import time

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

def data(f):
    """
    Retorna la data d'ara amb el format indicat. Les opcions son:
    + f = 'd'; '11-Sep-2022'
    + f = 'h'; '10:56'
    """
    # Imprimeix-la segons el format que indica als documents...
    # <https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior>

    ara = datetime.datetime.now()
    if f=='d':
        # Prén la data 'avui'.
        return ara.strftime('%d-%b-%Y')
    elif f=='h':
        # Prén la hora 'ara'.
        return ara.strftime('%H:%M')

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# Si es crida com a script:
if __name__ == '__main__':

    ### PARSE ARGUMENTS ###
    import argparse

    parser = argparse.ArgumentParser(
        description='Analyse the network via `mtr` for a period of time (by default, a day)')
    # file-name: positional arg.
    parser.add_argument('hostnames', type=str,
    help='Path to hostnames file (each row should correspond to a singular hostname)'
                        )
    # file-name: optional required argument.
    parser.add_argument('-o', '--outfile', type=str,
        help='Path and filename where output should be written (will append to the end)')
    # integer: not required.
    parser.add_argument('-n', '--numb',
            type=int, default=int(24), required=False,
            help="Amount of packets sent while performing the analyses")

    args = parser.parse_args()
    # call a value: args.operacio or args.filename.

    # init the dataframe to store all hostnames' traceroutes:
    df = pd.DataFrame(columns=[
        'Start_Time',
        'Status',
        'Host',
        'Hop',
        'Ip',
        'Loss%',
        'Best',
        'Avg',
        'Wrst',
        'StDev',
    ])

    with open(args.hostnames) as hfile:
        for hname in hfile:
            hname = hname.strip()
            print(f'-- Pinging to `{hname}`')
            # Make sure `mtr` is installed in the command-line.
            # Creates a tmp file (traceroute.tmp.csv) with the analysis results.
            command = f"mtr -c {args.numb} --csv -o 'LBAWV' {hname} > traceroute.tmp.csv"

            # -c 10 should send {args.numb} packets.
            # --csv: output in csv format.
            # -o 'lBAWV': output these fields only.

            os.system(command)
            # Concatena el dataframe `df` amb el resultat de la comanda
            # anterior.
            # elimina la primera i última columna (.iloc[:,1:-1])
            # la primera te la versió del soft. i la última és buida.
            df = pd.concat([df,
                    pd.read_csv('traceroute.tmp.csv').iloc[:,1:-1].assign(Hora=data('h'))])

    print(f'-- Writing pd.DataFrame() to `{args.outfile}`')
    # Imprimeix el header si el fitxer no existeix.
    # mode 'append' to already existing file.
    df.to_csv(args.outfile, mode='a', header=not os.path.exists(args.outfile))

    # Imprimeix els resultats finals en pantalla.
    print('-- Final dataframe:'); print()
    print(df.info())
    # remove tmp file
    os.system('rm --force traceroute.tmp.csv')
    print (f'-- temp. file traceroute.tmp.csv has been removed')


todos = [[],[]]
contador = 0
x = []
for p in range(1,8):
    x.append(int(input(f'Digite o {p} valor')))
    if x[contador] % 2 == 0:
        todos[0].append(x[contador])
    else:
        todos[1].append(x[contador])
    contador += 1
todos[0].sort()
todos[1].sort()
print(f'Voce digitou {p} numeros')
print(f'Os numeros pares foram {todos[0]}')
print(f'Os numeros impares foram {todos[1]}')


import numpy as np
import pandas as pd
import yfinance as yf
import xlsxwriter
import math
import time

# Scrape the list of S&P500 companies from Wikipedia
table = pd.read_html('https://en.wikipedia.org/wiki/List_of_S%26P_500_companies')
stocks = table[0]
print(stocks)

#Wiki gives us a lot of crap, we just need the symbol
stocks = stocks[['Symbol']]
stocks.columns = ['Ticker']

#yfinance requires secondary assets such as BRK.B to be listed as BRK-B
stocks['Ticker'] = stocks['Ticker'].str.replace('.', '-')

my_columns = ['Ticker', 'Price','Market Capitalization', 'Number Of Shares to Buy']
final_dataframe = pd.DataFrame(columns = my_columns)

for symbol in stocks['Ticker']:
    print(f"Fetching data for {symbol}")
    tickerData = yf.Ticker(symbol)
    retries = 5  # adjustable retry total
    for i in range(retries):
        try:
            temp_df = pd.DataFrame([
                {
                    'Ticker': symbol,
                    'Price': tickerData.info['previousClose'],
                    'Market Capitalization': tickerData.info['marketCap'],
                    'Number Of Shares to Buy': 'N/A'
                }
            ])
            final_dataframe = pd.concat([final_dataframe, temp_df], ignore_index=True)
            print(f"Data fetched for {symbol}")
            break
        except KeyError:
            print(f'Data not found for {symbol}, retrying ({i+1}/{retries})...')
            time.sleep(1)  # adjustable delay
    else:
        print(f'Failed to fetch data for {symbol} after {retries} retries, skipping.')

portfolio_size = input("Enter the value of your portfolio:")

try:
    val = float(portfolio_size)
except ValueError:
    print("That's not a number! \n Try again:")
    portfolio_size = input("Enter the value of your portfolio:")

position_size = float(portfolio_size) / len(final_dataframe.index)
for i in range(0, len(final_dataframe['Ticker'])-1):
    final_dataframe.loc[i, 'Number Of Shares to Buy'] = math.floor(position_size / final_dataframe['Price'][i])

writer = pd.ExcelWriter('recommended_trades.xlsx', engine='xlsxwriter')
final_dataframe.to_excel(writer, sheet_name='Recommended Trades', index = False)

background_color = '#0a0a23'
font_color = '#ffffff'

string_format = writer.book.add_format(
        {
            'font_color': font_color,
            'bg_color': background_color,
            'border': 1
        }
    )

dollar_format = writer.book.add_format(
        {
            'num_format':'$0.00',
            'font_color': font_color,
            'bg_color': background_color,
            'border': 1
        }
    )

integer_format = writer.book.add_format(
        {
            'num_format':'0',
            'font_color': font_color,
            'bg_color': background_color,
            'border': 1
        }
    )

column_formats = {
                    'A': ['Ticker', string_format],
                    'B': ['Price', dollar_format],
                    'C': ['Market Capitalization', dollar_format],
                    'D': ['Number of Shares to Buy', integer_format]
                    }

for column in column_formats.keys():
    writer.sheets['Recommended Trades'].set_column(f'{column}:{column}', 18, column_formats[column][1])
    writer.sheets['Recommended Trades'].write(f'{column}1', column_formats[column][0], column_formats[column][1])

writer.close()