#!/usr/bin/env python
from lib.mailapi import MailAPI
import argparse
import json

def print_result(res):
	for k, v in res.items():
		print("{:>20}: {:<80}".format(k, v))

def api(args):
	return MailAPI(args.server, args.api_username, args.api_password, verify=(not args.insecure))

def create(args):
	name, domain = args.email.split('@')
	res = api(args).createMailAlias(name, domain, args.to)
	print_result(res)

def show(args):
	name, domain = args.email.split('@')
	res = api(args).getMailAlias(name, domain)
	print_result(res)

def list(args):
	res = api(args).listMailAliases(args.domain)
	keys = ['id', 'to',]
	row_format	= "{:>48} {:<80}"
	print(row_format.format(*keys))
	for row in res['results']:
		print(row_format.format(*[row[k] for k in keys]))
	pass

def update(args):
	name, domain = args.email.split('@')
	res = api(args).updateMailAlias(name, domain, args.to)
	print_result(res)

def delete(args):
	name, domain = args.email.split('@')
	res = api(args).deleteMailAlias(name, domain)
	print(res)

def parse_args():
	parser = argparse.ArgumentParser()
	parser.add_argument('--server', '-s', action="store", help='API-Server [http://localhost:8000/]', default='http://localhost:8000/')
	parser.add_argument('--api-username', '-u', action="store", help='API Username [admin]', default='admin')
	parser.add_argument('--api-password', '-p', action="store", help='API Password', default='')
	parser.add_argument('--insecure',     '-k', action="store_true", help='Ignore invalid SSL Certificates [false]', default=False)
	subparsers = parser.add_subparsers(help='commands', dest='cmd')
	subparsers.required = True

	# create
	create_parser = subparsers.add_parser('create', help='Create new Mail Alias')
	create_parser.add_argument('email', action='store', help='Email address')
	create_parser.add_argument('to',    action='store', help='To')
	create_parser.set_defaults(func=create)

	# show
	show_parser = subparsers.add_parser('show', help='Show Mail Alias details')
	show_parser.add_argument('email', action='store', help='Email address')
	show_parser.set_defaults(func=show)

	# list
	list_parser = subparsers.add_parser('list', help='List all count-jobs')
	list_parser.add_argument('--domain', '-d', action='store', help='Domain')
	list_parser.set_defaults(func=list)

	# update
	update_parser = subparsers.add_parser('update', help='Update Alias')
	update_parser.add_argument('email', action='store', help='Email address')
	update_parser.add_argument('to',    action='store', help='to')
	update_parser.set_defaults(func=update)

	# delete
	delete_parser = subparsers.add_parser('delete', help='Delete Mail Alias')
	delete_parser.add_argument('email', action='store', help='Email address')
	delete_parser.set_defaults(func=delete)

	return parser.parse_args()

def main():
	args = parse_args()
	args.func(args)

if __name__ == '__main__':
	main()


import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle

DEFAULT_CIRCLE_RADIUS = 10
DEFAULT_COLOR = 'red'
DEFAULT_ALPHA = 0.5

def overlay_page_clicks(raw_screenshot_path: str, normal_coordinates: np.array, output_path: str, **kwargs):
  radius = kwargs.get('radius') or DEFAULT_CIRCLE_RADIUS
  color = kwargs.get('color') or DEFAULT_COLOR
  alpha = kwargs.get('alpha') or DEFAULT_ALPHA

  img = plt.imread(raw_screenshot_path)
  img_width = img.shape[1]
  img_height = img.shape[0]
  px = 1 / plt.rcParams['figure.dpi']

  fig, ax = plt.subplots(figsize=(img_width * px, img_height * px))
  ax.set_aspect('equal')

  for page_x, page_y in normal_coordinates:
    x = page_x * img_width
    y = page_y * img_height

    circle = Circle((x, y), radius, facecolor=color, alpha=alpha)
    ax.add_patch(circle)

  ax.imshow(img)
  plt.axis('off')
  plt.savefig(output_path, bbox_inches='tight', pad_inches=0)


import os
import os.path as osp
from typing import Optional, Tuple, Union

import numpy as np
import torch as to
from botorch.acquisition import ExpectedImprovement, PosteriorMean, ProbabilityOfImprovement, UpperConfidenceBound
from botorch.fit import fit_gpytorch_model
from botorch.models import SingleTaskGP
from botorch.optim import optimize_acqf
from gpytorch.constraints import GreaterThan
from gpytorch.mlls import ExactMarginalLogLikelihood
from tabulate import tabulate

import pyrado
from pyrado.algorithms.base import Algorithm, InterruptableAlgorithm
from pyrado.algorithms.step_based.actor_critic import ActorCritic
from pyrado.algorithms.stopping_criteria.predefined_criteria import CustomStoppingCriterion
from pyrado.algorithms.utils import until_thold_exceeded
from pyrado.environment_wrappers.base import EnvWrapper
from pyrado.environment_wrappers.domain_randomization import MetaDomainRandWrapper
from pyrado.environment_wrappers.utils import inner_env, typed_env
from pyrado.environments.base import Env
from pyrado.environments.real_base import RealEnv
from pyrado.environments.sim_base import SimEnv
from pyrado.logger.step import StepLogger
from pyrado.policies.base import Policy
from pyrado.sampling.bootstrapping import bootstrap_ci
from pyrado.sampling.parallel_rollout_sampler import ParallelRolloutSampler
from pyrado.sampling.rollout import rollout
from pyrado.spaces import BoxSpace
from pyrado.utils.data_processing import standardize
from pyrado.utils.input_output import print_cbt
from pyrado.utils.math import UnitCubeProjector
from pyrado.utils.ordering import natural_sort

class BayRn(InterruptableAlgorithm):
    """
    Bayesian Domain Randomization (BayRn)

    .. note::
        A candidate is a set of parameter values for the domain parameter distribution and its value is the
        (estimated) real-world return.

    .. seealso::
        F. Muratore, C. Eilers, M. Gienger, J. Peters, "Bayesian Domain Randomization for Sim-to-Real Transfer",
        arXiv, 2020
    """

    name: str = "bayrn"
    iteration_key: str = "bayrn_iteration"  # logger's iteration key

    def __init__(
        self,
        save_dir: pyrado.PathLike,
        env_sim: MetaDomainRandWrapper,
        env_real: Union[RealEnv, EnvWrapper],
        subrtn: Algorithm,
        ddp_space: BoxSpace,
        max_iter: int,
        acq_fc: str,
        acq_restarts: int,
        acq_samples: int,
        acq_param: dict = None,
        num_init_cand: int = 5,
        mc_estimator: bool = True,
        num_eval_rollouts_real: int = 5,
        num_eval_rollouts_sim: int = 50,
        thold_succ: float = pyrado.inf,
        thold_succ_subrtn: float = -pyrado.inf,
        warmstart: bool = True,
        policy_param_init: Optional[to.Tensor] = None,
        valuefcn_param_init: Optional[to.Tensor] = None,
        subrtn_snapshot_mode: str = "best",
        num_workers: int = 4,
        logger: Optional[StepLogger] = None,
    ):
        """
        Constructor

        .. note::
            If you want to continue an experiment, use the `load_dir` argument for the `train` call. If you want to
            initialize every of the policies with a pre-trained policy parameters use `policy_param_init`.

        :param save_dir: directory to save the snapshots i.e. the results in
        :param env_sim: randomized simulation environment a.k.a. source domain
        :param env_real: real-world environment a.k.a. target domain
        :param subrtn: algorithm which performs the policy / value-function optimization
        :param ddp_space: space holding the boundaries for the domain distribution parameters
        :param max_iter: maximum number of iterations
        :param acq_fc: Acquisition Function
                       'UCB': Upper Confidence Bound (default $\beta = 0.1$)
                       'EI': Expected Improvement
                       'PI': Probability of Improvement
        :param acq_restarts: number of restarts for optimizing the acquisition function
        :param acq_samples: number of initial samples for optimizing the acquisition function
        :param acq_param: hyper-parameter for the acquisition function, e.g. $\beta$ for UCB
        :param num_init_cand: number of initial policies to train, ignored if `init_dir` is provided
        :param mc_estimator: estimate the return with a sample average (`True`) or a lower confidence
                                     bound (`False`) obtained from bootstrapping
        :param num_eval_rollouts_real: number of rollouts in the target domain to estimate the return
        :param num_eval_rollouts_sim: number of rollouts in simulation to estimate the return after training
        :param thold_succ: success threshold on the real system's return for BayRn, stop the algorithm if exceeded
        :param thold_succ_subrtn: success threshold on the simulated system's return for the subroutine, repeat the
                                  subroutine until the threshold is exceeded or the for a given number of iterations
        :param warmstart: initialize the policy (and value function) parameters with the one of the previous iteration.
                          This behavior can also be overruled by passing `init_policy_params` (and
                          `valuefcn_param_init`) explicitly.
        :param policy_param_init: initial policy parameter values for the subroutine, set `None` to be random
        :param valuefcn_param_init: initial value function parameter values for the subroutine, set `None` to be random
        :param subrtn_snapshot_mode: snapshot mode for saving during training of the subroutine
        :param num_workers: number of environments for parallel sampling
        :param logger: logger for every step of the algorithm, if `None` the default logger will be created
        """
        if typed_env(env_sim, MetaDomainRandWrapper) is None:
            raise pyrado.TypeErr(given=env_sim, expected_type=MetaDomainRandWrapper)
        if not isinstance(subrtn, Algorithm):
            raise pyrado.TypeErr(given=subrtn, expected_type=Algorithm)
        if not isinstance(ddp_space, BoxSpace):
            raise pyrado.TypeErr(given=ddp_space, expected_type=BoxSpace)
        if num_init_cand < 1:
            raise pyrado.ValueErr(given=num_init_cand, ge_constraint="1")

        # Call InterruptableAlgorithm's constructor without specifying the policy
        super().__init__(
            num_checkpoints=2,
            init_checkpoint=-2,
            save_dir=save_dir,
            max_iter=max_iter,
            policy=subrtn.policy,
            logger=logger,
        )

        self._env_sim = env_sim
        self._env_real = env_real
        self._subrtn = subrtn
        self._subrtn.save_name = "subrtn"
        self.ddp_space = ddp_space
        self.ddp_projector = UnitCubeProjector(
            to.from_numpy(self.ddp_space.bound_lo).to(dtype=to.get_default_dtype()),
            to.from_numpy(self.ddp_space.bound_up).to(dtype=to.get_default_dtype()),
        )
        self.cands = None  # called x in the context of GPs
        self.cands_values = None  # called y in the context of GPs
        self.argmax_cand = to.Tensor()
        self.acq_fcn_type = acq_fc.upper()
        self.acq_restarts = acq_restarts
        self.acq_samples = acq_samples
        self.acq_param = acq_param
        self.num_init_cand = num_init_cand
        self.mc_estimator = mc_estimator
        self.policy_param_init = policy_param_init
        self.valuefcn_param_init = valuefcn_param_init.detach() if valuefcn_param_init is not None else None
        self.warmstart = warmstart
        self.num_eval_rollouts_real = num_eval_rollouts_real
        self.num_eval_rollouts_sim = num_eval_rollouts_sim
        self.subrtn_snapshot_mode = subrtn_snapshot_mode
        self.thold_succ = to.tensor([thold_succ], dtype=to.get_default_dtype())
        self.thold_succ_subrtn = to.tensor([thold_succ_subrtn], dtype=to.get_default_dtype())
        self.max_subrtn_rep = 3  # number of tries to exceed thold_succ_subrtn during training in simulation
        self.curr_cand_value = -pyrado.inf  # for the stopping criterion
        self.num_workers = int(num_workers)

        if self.policy_param_init is not None:
            if to.is_tensor(self.policy_param_init):
                self.policy_param_init.detach()
            else:
                self.policy_param_init = to.tensor(self.policy_param_init)

        # Save initial environments and the domain distribution parameter space
        self.save_snapshot(meta_info=None)
        pyrado.save(self.ddp_space, "ddp_space.pkl", self.save_dir)

        self.stopping_criterion = self.stopping_criterion | CustomStoppingCriterion(self._custom_stopping_criterion)

    @staticmethod
    def _custom_stopping_criterion(algo: "BayRn") -> bool:
        return algo.curr_cand_value > algo.thold_succ

    @property
    def subroutine(self) -> Algorithm:
        """Get the policy optimization subroutine."""
        return self._subrtn

    @property
    def policy(self) -> Policy:
        return self._subrtn.policy

    @property
    def sample_count(self) -> int:
        return self._cnt_samples + self._subrtn.sample_count

    def train_policy_sim(self, cand: to.Tensor, prefix: str, cnt_rep: int) -> float:
        """
        Train a policy in simulation for given hyper-parameters from the domain randomizer.

        :param cand: hyper-parameters for the domain parameter distribution (need be compatible with the randomizer)
        :param prefix: set a prefix to the saved file name, use "" for no prefix
        :param cnt_rep: current repetition count, coming from the wrapper function
        :return: estimated return of the trained policy in the target domain
        """
        # Save the current candidate
        to.save(cand.view(-1), osp.join(self.save_dir, f"{prefix}_candidate.pt"))

        # Set the domain randomizer
        self._env_sim.adapt_randomizer(cand.detach().cpu().numpy())

        # Reset the subroutine algorithm which includes resetting the exploration
        self._cnt_samples += self._subrtn.sample_count
        self._subrtn.reset()

        # Do a warm start if desired, but randomly reset the policy parameters if training failed once
        self._subrtn.init_modules(
            self.warmstart and cnt_rep == 0,
            policy_param_init=self.policy_param_init,
            valuefcn_param_init=self.valuefcn_param_init,
        )

        # Train a policy in simulation using the subroutine
        self._subrtn.train(snapshot_mode=self.subrtn_snapshot_mode, meta_info=dict(prefix=prefix))
        self._subrtn.save_snapshot(meta_info=None)  # overwrites policy.pt (and vfcn.pt ect)

        # Return the estimated return of the trained policy in simulation
        avg_ret_sim = BayRn.eval_policy(
            None,
            self._env_sim,
            self._subrtn.policy,
            self.mc_estimator,
            prefix,
            self.num_eval_rollouts_sim,
            self.num_workers,
        )
        return float(avg_ret_sim)

    def train_init_policies(self):
        """
        Initialize the algorithm with a number of random distribution parameter sets a.k.a. candidates specified by
        the user. Train a policy for every candidate. Finally, store the policies and candidates.
        """
        cands = to.empty(self.num_init_cand, self.ddp_space.shape[0])
        for i in range(self.num_init_cand):
            print_cbt(
                f"Generating initial domain instance and policy {i + 1} of {self.num_init_cand} ...", "g", bright=True
            )
            # Sample random domain distribution parameters
            cands[i, :] = to.from_numpy(self.ddp_space.sample_uniform())

            # Train a policy for each candidate, repeat if the resulting policy did not exceed the success threshold
            print_cbt(f"Randomly sampled the next candidate: {cands[i].numpy()}", "g")
            wrapped_trn_fcn = until_thold_exceeded(self.thold_succ_subrtn.item(), self.max_subrtn_rep)(
                self.train_policy_sim
            )
            wrapped_trn_fcn(cands[i], prefix=f"init_{i}")

        # Save candidates into a single tensor (policy is saved during training or exists already)
        pyrado.save(cands, "candidates.pt", self.save_dir)
        self.cands = cands

    def eval_init_policies(self):
        """
        Execute the trained initial policies on the target device and store the estimated return per candidate.
        The number of initial policies to evaluate is the number of found policies.
        """
        # Crawl through the experiment's directory
        for root, dirs, files in os.walk(self.save_dir):
            dirs.clear()  # prevents walk() from going into subdirectories
            found_policies = [p for p in files if p.startswith("init_") and p.endswith("_policy.pt")]
            found_cands = [c for c in files if c.startswith("init_") and c.endswith("_candidate.pt")]
        if not len(found_policies) == len(found_cands):
            raise pyrado.ValueErr(msg="Found a different number of initial policies than candidates!")
        elif len(found_policies) == 0:
            raise pyrado.ValueErr(msg="No policies or candidates found!")

        num_init_cand = len(found_cands)
        cands_values = to.empty(num_init_cand)

        # Load all found candidates to save them into a single tensor
        found_cands = natural_sort(found_cands)  # the order is important since it determines the rows of the tensor
        cands = to.stack([to.load(osp.join(self.save_dir, c)) for c in found_cands])

        # Evaluate learned policies from random candidates on the target environment (real-world) system
        for i in range(num_init_cand):
            policy = pyrado.load("policy.pt", self.save_dir, prefix=f"init_{i}", obj=self.policy)
            cands_values[i] = BayRn.eval_policy(
                self.save_dir,
                self._env_real,
                policy,
                self.mc_estimator,
                prefix=f"init_{i}",
                num_rollouts=self.num_eval_rollouts_real,
                num_workers=self.num_workers,
            )

        # Save candidates and their returns into tensors (policy is saved during training or exists already)
        pyrado.save(cands_values, "candidates_values.pt", self.save_dir)
        self.cands, self.cands_values = cands, cands_values

    @staticmethod
    def eval_policy(
        save_dir: Optional[pyrado.PathLike],
        env: [RealEnv, SimEnv, MetaDomainRandWrapper],
        policy: Policy,
        mc_estimator: bool,
        prefix: str,
        num_rollouts: int,
        num_workers: int = 4,
    ) -> to.Tensor:
        """
        Evaluate a policy either in the source or in the target domain.
        This method is static to facilitate evaluation of specific policies in hindsight.

        :param save_dir: directory to save the snapshots i.e. the results in, if `None` nothing is saved
        :param env: target environment for evaluation, in the sim-2-sim case this is another simulation instance
        :param policy: policy to evaluate
        :param mc_estimator: estimate the return with a sample average (`True`) or a lower confidence
                                     bound (`False`) obtained from bootrapping
        :param prefix: to control the saving for the evaluation of an initial policy, `None` to deactivate
        :param num_rollouts: number of rollouts to collect on the target system
        :param prefix: to control the saving for the evaluation of an initial policy, `None` to deactivate
        :param num_workers: number of environments for the parallel sampler (only used for a `SimEnv`)
        :return: estimated return in the target domain
        """
        if save_dir is not None:
            print_cbt(f"Executing {prefix}_policy ...", "c", bright=True)

        rets_real = to.zeros(num_rollouts)
        if isinstance(inner_env(env), RealEnv):
            # Evaluate sequentially when conducting a sim-to-real experiment
            for i in range(num_rollouts):
                rets_real[i] = rollout(env, policy, eval=True).undiscounted_return()
                # If a reward of -1 is given, skip evaluation ahead and set all returns to zero
                if rets_real[i] == -1:
                    print_cbt("Set all returns for this policy to zero.", color="c")
                    rets_real = to.zeros(num_rollouts)
                    break
        elif isinstance(inner_env(env), SimEnv):
            # Create a parallel sampler when conducting a sim-to-sim experiment
            sampler = ParallelRolloutSampler(env, policy, num_workers=num_workers, min_rollouts=num_rollouts)
            ros = sampler.sample()
            for i in range(num_rollouts):
                rets_real[i] = ros[i].undiscounted_return()
        else:
            raise pyrado.TypeErr(given=inner_env(env), expected_type=[RealEnv, SimEnv])

        if save_dir is not None:
            # Save and print the evaluation results
            pyrado.save(rets_real, "returns_real.pt", save_dir, prefix=prefix)
            print_cbt("Target domain performance", bright=True)
            print(
                tabulate(
                    [
                        ["mean return", to.mean(rets_real).item()],
                        ["std return", to.std(rets_real)],
                        ["min return", to.min(rets_real)],
                        ["max return", to.max(rets_real)],
                    ]
                )
            )

        if mc_estimator:
            return to.mean(rets_real)
        else:
            _, ci_lo, _ = bootstrap_ci(
                rets_real.numpy(), np.mean, num_reps=1000, alpha=0.05, ci_sides=1, studentized=False
            )
            return to.from_numpy(ci_lo)

    def step(self, snapshot_mode: str = "latest", meta_info: dict = None):
        # Save snapshot to save the correct iteration count
        self.save_snapshot()

        if self.curr_checkpoint == -2:
            # Train the initial policies in the source domain
            self.train_init_policies()
            self.reached_checkpoint()  # setting counter to -1

        if self.curr_checkpoint == -1:
            # Evaluate the initial policies in the target domain
            self.eval_init_policies()
            self.reached_checkpoint()  # setting counter to 0

        if self.curr_checkpoint == 0:
            # Normalize the input data and standardize the output data
            cands_norm = self.ddp_projector.project_to(self.cands)
            cands_values_stdized = standardize(self.cands_values).unsqueeze(1)

            # Create and fit the GP model
            gp = SingleTaskGP(cands_norm, cands_values_stdized)
            gp.likelihood.noise_covar.register_constraint("raw_noise", GreaterThan(1e-5))
            mll = ExactMarginalLogLikelihood(gp.likelihood, gp)
            fit_gpytorch_model(mll)
            print_cbt("Fitted the GP.", "g")

            # Acquisition functions
            if self.acq_fcn_type == "UCB":
                acq_fcn = UpperConfidenceBound(gp, beta=self.acq_param.get("beta", 0.1), maximize=True)
            elif self.acq_fcn_type == "EI":
                acq_fcn = ExpectedImprovement(gp, best_f=cands_values_stdized.max().item(), maximize=True)
            elif self.acq_fcn_type == "PI":
                acq_fcn = ProbabilityOfImprovement(gp, best_f=cands_values_stdized.max().item(), maximize=True)
            else:
                raise pyrado.ValueErr(given=self.acq_fcn_type, eq_constraint="'UCB', 'EI', 'PI'")

            # Optimize acquisition function and get new candidate point
            cand_norm, _ = optimize_acqf(
                acq_function=acq_fcn,
                bounds=to.stack([to.zeros(self.ddp_space.flat_dim), to.ones(self.ddp_space.flat_dim)]).to(
                    dtype=to.float32
                ),
                q=1,
                num_restarts=self.acq_restarts,
                raw_samples=self.acq_samples,
            )
            cand_norm = cand_norm.to(dtype=to.get_default_dtype())
            next_cand = self.ddp_projector.project_back(cand_norm)
            print_cbt(f"Found the next candidate: {next_cand.numpy()}", "g")
            self.cands = to.cat([self.cands, next_cand], dim=0)
            pyrado.save(self.cands, "candidates.pt", self.save_dir)
            self.reached_checkpoint()  # setting counter to 1

        if self.curr_checkpoint == 1:
            # Train and evaluate a new policy, repeat if the resulting policy did not exceed the success threshold
            wrapped_trn_fcn = until_thold_exceeded(self.thold_succ_subrtn.item(), self.max_subrtn_rep)(
                self.train_policy_sim
            )
            wrapped_trn_fcn(self.cands[-1, :], prefix=f"iter_{self._curr_iter}")
            self.reached_checkpoint()  # setting counter to 2

        if self.curr_checkpoint == 2:
            # Evaluate the current policy in the target domain
            policy = pyrado.load("policy.pt", self.save_dir, prefix=f"iter_{self._curr_iter}", obj=self.policy)
            self.curr_cand_value = BayRn.eval_policy(
                self.save_dir,
                self._env_real,
                policy,
                self.mc_estimator,
                f"iter_{self._curr_iter}",
                self.num_eval_rollouts_real,
                self.num_workers,
            )
            self.cands_values = to.cat([self.cands_values, self.curr_cand_value.view(1)], dim=0)
            pyrado.save(self.cands_values, "candidates_values.pt", self.save_dir)

            # Store the argmax after training and evaluating
            curr_argmax_cand = BayRn.argmax_posterior_mean(
                self.cands, self.cands_values.unsqueeze(1), self.ddp_space, self.acq_restarts, self.acq_samples
            )
            self.argmax_cand = to.cat([self.argmax_cand, curr_argmax_cand], dim=0)
            pyrado.save(self.argmax_cand, "candidates.pt", self.save_dir, suffix="argmax")
            self.reached_checkpoint()  # setting counter to 0

    def save_snapshot(self, meta_info: dict = None):
        super().save_snapshot(meta_info)

        # Policies of every iteration are saved by the subroutine in train_policy_sim()
        if meta_info is None:
            # This algorithm instance is not a subroutine of another algorithm
            pyrado.save(self._env_sim, "env_sim.pkl", self._save_dir)
            pyrado.save(self._env_real, "env_real.pkl", self._save_dir)
        else:
            raise pyrado.ValueErr(msg=f"{self.name} is not supposed be run as a subroutine!")

    def load_snapshot(self, parsed_args) -> Tuple[Env, Policy, dict]:
        ex_dir = self._save_dir or getattr(parsed_args, "dir", None)
        extra = dict()

        # Environment
        env = pyrado.load("env_sim.pkl", ex_dir)
        if hasattr(env, "randomizer"):
            last_cand = to.load(osp.join(ex_dir, "candidates.pt"))[-1, :]
            env.adapt_randomizer(last_cand.numpy())
            print_cbt(f"Loaded the domain randomizer\n{env.randomizer}", "w")
        else:
            print_cbt("Loaded environment has no randomizer, or it is None.", "r")

        # Policy
        policy = pyrado.load(f"{parsed_args.policy_name}.pt", ex_dir, obj=self.policy, verbose=True)

        # Algorithm specific
        if isinstance(self.subroutine, ActorCritic):
            extra["vfcn"] = pyrado.load(
                f"{parsed_args.vfcn_name}.pt", ex_dir, obj=self.subroutine.critic.vfcn, verbose=True
            )

        return env, policy, extra

    @staticmethod
    def argmax_posterior_mean(
        cands: to.Tensor, cands_values: to.Tensor, ddp_space: BoxSpace, num_restarts: int, num_samples: int
    ) -> to.Tensor:
        """
        Compute the GP input with the maximal posterior mean.

        :param cands: candidates a.k.a. x
        :param cands_values: observed values a.k.a. y
        :param ddp_space: space of the domain distribution parameters, indicates the lower and upper bound
        :param num_restarts: number of restarts for the optimization of the acquisition function
        :param num_samples: number of samples for the optimization of the acquisition function
        :return: un-normalized candidate with maximum posterior value a.k.a. x
        """
        if not isinstance(cands, to.Tensor):
            raise pyrado.TypeErr(given=cands, expected_type=to.Tensor)
        if not isinstance(cands_values, to.Tensor):
            raise pyrado.TypeErr(given=cands_values, expected_type=to.Tensor)
        if not isinstance(ddp_space, BoxSpace):
            raise pyrado.TypeErr(given=ddp_space, expected_type=BoxSpace)

        # Normalize the input data and standardize the output data
        uc_projector = UnitCubeProjector(
            to.from_numpy(ddp_space.bound_lo).to(dtype=to.get_default_dtype()),
            to.from_numpy(ddp_space.bound_up).to(dtype=to.get_default_dtype()),
        )
        cands_norm = uc_projector.project_to(cands)
        cands_values_stdized = standardize(cands_values)

        if cands_norm.shape[0] > cands_values.shape[0]:
            print_cbt(
                f"There are {cands.shape[0]} candidates but only {cands_values.shape[0]} evaluations. Ignoring "
                f"the candidates without evaluation for computing the argmax.",
                "y",
            )
            cands_norm = cands_norm[: cands_values.shape[0], :]

        # Create and fit the GP model
        gp = SingleTaskGP(cands_norm, cands_values_stdized)
        gp.likelihood.noise_covar.register_constraint("raw_noise", GreaterThan(1e-5))
        mll = ExactMarginalLogLikelihood(gp.likelihood, gp)
        fit_gpytorch_model(mll)

        # Find position with maximal posterior mean
        cand_norm, _ = optimize_acqf(
            acq_function=PosteriorMean(gp),
            bounds=to.stack([to.zeros(ddp_space.flat_dim), to.ones(ddp_space.flat_dim)]).to(dtype=to.float32),
            q=1,
            num_restarts=num_restarts,
            raw_samples=num_samples,
        )

        cand_norm = cand_norm.to(dtype=to.get_default_dtype())
        cand = uc_projector.project_back(cand_norm.detach())
        print_cbt(f"Converged to argmax of the posterior mean: {cand.numpy()}", "g", bright=True)
        return cand

    @staticmethod
    def train_argmax_policy(
        load_dir: pyrado.PathLike,
        env_sim: MetaDomainRandWrapper,
        subrtn: Algorithm,
        num_restarts: int,
        num_samples: int,
        policy_param_init: to.Tensor = None,
        valuefcn_param_init: to.Tensor = None,
        subrtn_snapshot_mode: str = "best",
    ) -> Policy:
        """
        Train a policy based on the maximizer of the posterior mean.

        :param load_dir: directory to load from
        :param env_sim: simulation environment
        :param subrtn: algorithm which performs the policy / value-function optimization
        :param num_restarts: number of restarts for the optimization of the acquisition function
        :param num_samples: number of samples for the optimization of the acquisition function
        :param policy_param_init: initial policy parameter values for the subroutine, set `None` to be random
        :param valuefcn_param_init: initial value function parameter values for the subroutine, set `None` to be random
        :param subrtn_snapshot_mode: snapshot mode for saving during training of the subroutine
        :return: the final BayRn policy
        """
        # Load the required data
        cands = pyrado.load("candidates.pt", load_dir)
        cands_values = pyrado.load("candidates_values.pt", load_dir).unsqueeze(1)
        ddp_space = pyrado.load("ddp_space.pkl", load_dir)

        if cands.shape[0] > cands_values.shape[0]:
            print_cbt(
                f"There are {cands.shape[0]} candidates but only {cands_values.shape[0]} evaluations. Ignoring the"
                f"candidates without evaluation for computing the argmax.",
                "y",
            )
            cands = cands[: cands_values.shape[0], :]

        # Find the maximizer
        argmax_cand = BayRn.argmax_posterior_mean(cands, cands_values, ddp_space, num_restarts, num_samples)

        # Set the domain randomizer
        env_sim.adapt_randomizer(argmax_cand.numpy())

        # Reset the subroutine algorithm which includes resetting the exploration
        subrtn.reset()

        # Do a warm start
        subrtn.init_modules(
            warmstart=True, policy_param_init=policy_param_init, valuefcn_param_init=valuefcn_param_init
        )

        subrtn.train(snapshot_mode=subrtn_snapshot_mode, meta_info=dict(suffix="argmax"))
        return subrtn.policy


import sys
import pandas as pd
import numpy as np
from sklearn import svm

def csv_conv(filename):
    tf = pd.read_csv(filename, sep = ',')
    x_frame = tf.iloc[0:-1, 0:17]
    y_frame = tf.iloc[0:-1, -1]
    tx = np.asarray(x_frame).astype(float) # Converts the dataframes into workable arrays of values
    ty = np.asarray(y_frame)
    tx = tx.tolist()
    return tx, ty

def main(argv):
    train_x, train_y = csv_conv(argv[0])
    test_x, test_y = csv_conv(argv[1])

    samplesvm = svm.SVC(C = 0.7, max_iter = 1000, kernel='rbf')
    samplesvm.fit(train_x, train_y)
    res = np.asarray(samplesvm.predict(test_x)).tolist()

    datalen = len(res)
    correct = 0
    for el in range(datalen):
        if res[el] == test_y[el]:
            correct += 1
    print(correct/datalen)

if __name__ == "__main__":
    main(sys.argv[1:])


class Solution:
    def sortEvenOdd(self, nums: List[int]) -> List[int]:
        even = []
        odd = []
        for i in range(len(nums)):
            if (i+1)%2==0:
                even.append(nums[i])
            else:
                odd.append(nums[i])
        even = sorted(even, reverse=True)
        odd = sorted(odd)
        numsret = []
        e,o = 0,0
        for i in range(len(nums)):
            if (i+1)%2==0:
                numsret.append(even[e])
                e+=1
            else:
                numsret.append(odd[o])
                o+=1
        return numsret

LeetCode/2164_sort Event and Odd indicessIndependently.py


import re
from base64 import b64decode

from .exceptions.processor_errors import SnippetRuntimeError

class ResultsProcessor:
    """Processes results of code execution"""

    ANSI_ESCAPE_SEQ_RE = r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]'
    ESCAPE_RE = re.compile(ANSI_ESCAPE_SEQ_RE)

    def __init__(self, allow_errors, output_types, processing_manager):
        """Initialization"""
        self.__allow_errors = allow_errors
        self.__output_types = output_types
        self.__processing_manager = processing_manager

        self.__result = ''

    def process_stream(self, text, stream_type):
        """Processes output stream (stdin/stderr)"""
        if self.__output_types.is_enabled(stream_type):
            self.__result += self.__processing_manager.text(text)

    def process_data(self, mime_type, data):
        """Processes text/plain and images"""
        if not self.__output_types.is_enabled(mime_type):
            return

        if mime_type in ['application/pdf', 'image/png', 'image/gif', 'image/jpeg', 'image/tiff']:
            self.__result += self.__processing_manager.image(b64decode(data), mime_type)
            return

        if mime_type == 'text/plain':
            self.__result += self.__processing_manager.text(data + '\n')
            return

        # raise ProcessingError('Not implemented result\'s mime type: %s' % mime_type)

    def process_error(self, name, value, traceback):
        """Processes errors. Raises if errors not allowed in output"""
        result = ''

        for t in traceback:
            result += str.format('\n{0}', ResultsProcessor.ESCAPE_RE.sub('', t))

        if not self.__allow_errors:
            raise SnippetRuntimeError(result)

        self.__result += self.__processing_manager.text(result)

    def get_result(self):
        """Returns processed results"""
        return self.__result


import unittest
import os
from device_registry import app
from tests import add_device, add_room, decode_response

class TestDevice(unittest.TestCase):

    def setUp(self):
        # Create an instance of the test client
        self.app = app.test_client()

        # Use a temporary file as the database file
        app.config['DATABASE'] = '/tmp/test'

    def tearDown(self):
        # Delete the temporary file
        os.unlink(app.config['DATABASE'] + '.db')

    def test_get_invalid_device(self):
        """Test that getting an invalid device's details will return a 404."""

        response = self.app.get('/device/1')
        self.assertEqual(404, response.status_code)

    def test_get_device(self):
        """Test that adding and then getting a device works."""

        add_room('bedroom', "Jake's Bedroom")

        device = {
            'identifier': 'test',
            'name': 'Test',
            'device_type': 'switch',
            'controller_name': 'controller-1',
            'room': {
                'identifier': 'bedroom',
                'name': "Jake's Bedroom",
            },
        }

        # Add the device to the registry
        add_device(device['identifier'],
                        device['name'],
                        device['device_type'],
                        device['controller_name'],
                        device['room']['identifier'])

        # Ask the registry for the device's details
        response = self.app.get('/device/test')

        # Assert that we got an OK response code
        self.assertEqual(200, response.status_code)

        # Decode the json
        decoded_response = decode_response(response)

        self.assertEqual(device, decoded_response)

    def test_delete_device(self):
        """Test that a device is no longer available after deleting it"""

        # Add a device
        add_room('bedroom', "Jake's Bedroom")
        add_device('test-del', 'name', 'type', 'controller', 'bedroom')

        # Try to get the device
        response = self.app.get('/device/test-del')
        self.assertEqual(200, response.status_code)

        # Delete the device
        response = self.app.delete('/device/test-del')
        self.assertEqual(200, response.status_code)

        # Try to get the device again
        response = self.app.get('/device/test-del')
        self.assertEqual(404, response.status_code)

        # Try to delete the device again
        response = self.app.delete('/device/test-del')
        self.assertEqual(404, response.status_code)


import os
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from cartopy import config
import cartopy.crs as ccrs
import xarray as xr
import matplotlib as mp1
import cartopy.feature as cfeature

fig=plt.figure(figsize=[10,10])
#metrics that can be tested:ratio of mod med:obs med ('ratio'),rmse forced through origin ('RMSE'), ODR forced through origin('ODR gradient'),odr not forced through origin (nf ODR gradient).

emission='Ozone'
env_type='Background Urban'
metric_testing='RMSE'

if env_type == 'AURN':
    env_type=' '

metadata_csv='/users/mtj507/scratch/defra_data/defra_site_metadata.csv'
metadata=pd.read_csv(metadata_csv, low_memory=False)
metadata=metadata.loc[metadata['AURN Pollutants Measured'].str.contains(emission)]
metadata=metadata.loc[metadata['Environment Type'].str.contains(env_type)]
metadata=metadata.reset_index(drop=True)
location=metadata['Site Name']

if env_type == ' ':
    env_type='AURN'

metric_csv='/users/mtj507/scratch//obs_vs_forecast/assimilation_scripts/plots/whole_year/o3/ozone_site_metrics_'+env_type+'.csv'
metrics=pd.read_csv(metric_csv,low_memory=False)
metrics.drop(metrics.columns[0],axis=1,inplace=True)
metrics['ratio']=metrics['mod median']/metrics['obs median']

df=pd.merge(metadata,metrics,left_on='Site Name',right_on='site name',how='inner')

nf_csv='/users/mtj507/scratch//obs_vs_forecast/assimilation_scripts/plots/whole_year/o3/ozone_nf_site_metrics_'+env_type+'.csv'
nf=pd.read_csv(nf_csv,low_memory=False)
nf.drop(nf.columns[0],axis=1,inplace=True)

df=pd.merge(df,nf,left_on='Site Name',right_on='site name',how='inner')

ax=fig.add_subplot(1,1,1,projection=ccrs.PlateCarree())
ax.coastlines(resolution='50m')
ax.add_feature(cfeature.LAND.with_scale('50m'))
ax.add_feature(cfeature.OCEAN.with_scale('50m'))

m=plt.cm.ScalarMappable(cmap='cool')
m.set_clim(10,35)
cbar=plt.colorbar(m,orientation='horizontal')

x=df['Longitude']
y=df['Latitude']
plt.scatter(x,y,c=df[metric_testing],cmap='cool',vmin=10,vmax=35)

#norm=mp1.colors.Normalize(vmin=19,vmax=37)
#cbar=plt.colorbar(orientation='horizontal',norm=norm)
#cbar.set_clim(19,37)

if not metric_testing == 'ODR gradient':
    cbar.ax.set_xlabel(metric_testing+r' $\mu g\: m^{-3}$')
if metric_testing == 'ODR gradient' or metric_testing == 'ratio':
    cbar.ax.set_xlabel(metric_testing)
if metric_testing == 'nf RMSE':
    cbar.ax.set_xlabel(r'RMSE $\mu g\: m^{-3}$')

ax.set_title(emission+' '+metric_testing+' - '+env_type)

#plt.show()
path='/users/mtj507/scratch//obs_vs_forecast/assimilation_scripts/plots/whole_year/o3/'
plt.savefig(path+emission+'_'+metric_testing+'_map_'+env_type+'.png')
plt.close()


import pymongo

class Mongo:
    def __init__(self):
        self.client = pymongo.MongoClient("localhost", 27017)
        print(self.client)

    def listDBS(self):
        k = 0
        print("Following Databases are Present")
        for i in self.client.database_names():
            k += 1
            print(k, ".", i)

    def createDB(self):
        self.dbname = input("Enter Database Name: ")
        re = self.client[self.dbname]
        self.client[self.dbname].create_collection("dummy_collection")  # Creating Blank Collection
        print(re)

    def choseDB(self):
        self.listDBS()
        self.dbch = int(input("Chose Database\n"))
        self.rr = self.client.database_names()
        self.mydb = self.rr[self.dbch - 1]
        print("Chosen Database is: ", self.mydb)

    def deleteDB(self):
        self.choseDB()
        cnfm = int(input("Press 1 to Delete 0 to Cancel:\n"))
        if cnfm == 1:
            print("Deleting.. " + self.mydb)
            self.client.drop_database(self.mydb)
            print(self.mydb)
            if self.mydb not in self.client.database_names():
                print("Deleted Successfully")
            else:
                print("Delete Error")
        else:
            pass

    def listCollections(self):
        self.choseDB()
        k = 0
        print("Following Collections are present.")
        for i in self.client[self.mydb].collection_names():
            k += 1
            print(k, '.', i)

    def createCollection(self):
        self.choseDB()
        cname = input("Enter Collection Name:\n")
        r1 = self.client[self.mydb].create_collection(cname)
        print(r1)
        if cname in self.client[self.mydb].collection_names():
            print("Collection " + cname + " Created Successfully")
        else:
            print("Collection creation failed.")

    def deleteCollection(self):
        self.listCollections()
        ch = int(input("\nChoose collection No to Delete: \n"))
        ch -= 1
        self.clist = self.client[self.mydb].collection_names()
        cname = self.clist[ch]
        self.client[self.mydb].drop_collection(cname)
        if cname not in self.client[self.mydb].collection_names():
            print("Collection " + cname + " Deleted Successfully")
        else:
            print("Deletion Error")

    def showData(self, datbase_name, collection_name):
        record = self.client[datbase_name][collection_name].find({}, {'_id': False})  # Filtering
        final_record = list(record)  # Its a cursor and need to translate to list
        print(final_record)
        for i in final_record:
            for k, v in i.items():
                print(k, v)

    def showDocument(self):
        self.listCollections()
        chCol = int(input("Choose Collection:\n"))
        chCol -= 1
        self.clist = self.client[self.mydb].collection_names()
        self.cname = self.clist[chCol]
        print("Chosen Collection is: ", self.cname)
        print("-" * 20, "Cureent Data", "-" * 20)
        self.showData(self.mydb, self.cname)
        print("-" * 55)

    def test(self):
        client = pymongo.MongoClient('mongodb://localhost:27017/')

        db = client.testdb
        rr = client.cars.find()
        cars = db.cars.find()

        for car in cars:
            print('{0} {1}'.format(car['name'],
                                   car['price']))

    def insertDocumentSingle(self):
        self.listCollections()
        chCol = int(input("Choose Collection:\n"))
        chCol -= 1
        self.clist = self.client[self.mydb].collection_names()
        self.cname = self.clist[chCol]
        print("Chosen Collection is: ", self.cname)
        print('1. {"Key1":"Value1}"')
        print('2. {"Key1":"Value1}"')
        new_document = int(input("Chose any Document to Insert:"))
        if new_document == 1:
            new_data = {"Key1": "Value1"}
        else:
            new_data = {"Key2": "Value2"}
        re=self.client[self.mydb][self.cname].insert_one(new_data)
        print(re)

    def insertDocumentMany(self):
        self.listCollections()
        chCol = int(input("Choose Collection:\n"))
        chCol -= 1
        self.clist = self.client[self.mydb].collection_names()
        self.cname = self.clist[chCol]
        print("Chosen Collection is: ", self.cname)
        new_data = [{"name": "Amy", "address": "Apple st 652"}, {"name": "Hannah", "address": "Mountain 21"}]
        re=self.client[self.mydb][self.cname].insert_many(new_data)
        print(re)

    def deleteDocument(self):
        self.listCollections()
        chCol = int(input("Choose Collection:\n"))
        chCol -= 1
        self.clist = self.client[self.mydb].collection_names()
        self.cname = self.clist[chCol]
        print("Chosen Collection is: ", self.cname)
        print("-" * 40)
        record = self.client[self.mydb][self.cname].find({}, {'_id': False})  # Filtering
        final_record = list(record)  # Its a cursor and need to translate to list
        k = 1
        if len(final_record)==0:
            print("No Document Present to Delete.Continuing")
            pass
        else:
            for i in final_record:
                print(k, ".", i)
                k += 1
            ch = int(input("Chose Document to Delete"))
            ch -= 1
            query = final_record[ch]
            re = self.client[self.mydb][self.cname].delete_one(query)
            print("Delete Status", re)

if __name__ == "__main__":
    ob = Mongo()
    while True:
        print("------------------------------")
        print("0  to Exit:")
        print("1  to List Databases:")
        print("2  to Create Database:")
        print("3  to Delete Database:")
        print("4  to List Collection:")
        print("5  to Create Collection:")
        print("6  to Delete Collection")
        print("7  to Show Document")
        print("8  to Insert Document:Single")
        print("9  to Insert Document:Many")
        print("10 to Delete Document")
        print("-------------------------------\n")
        ch = int(input())
        if ch == 0:
            exit()
        elif ch == 1:
            ob.listDBS()
        elif ch == 2:
            ob.createDB()
        elif ch == 3:
            ob.deleteDB()
        elif ch == 4:
            ob.listCollections()
        elif ch == 5:
            ob.createCollection()
        elif ch == 6:
            ob.deleteCollection()
        elif ch == 7:
            ob.showDocument()
        elif ch == 8:
            ob.insertDocumentSingle()
        elif ch == 9:
            ob.insertDocumentMany()
        elif ch == 10:
            ob.deleteDocument()
        else:
            print("Error!")


#!/usr/bin/env python3

# mprof run --interval 0.01 ./prof_conv.py
# mprof plot

import argparse

parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("filename", nargs='?', default="test_dump.h5", help="name of the file to run the profiling on")

clargs = parser.parse_args()

try:
    profile # running via mprof / import breaks plotting (missing timestamps)
except NameError:
    from memory_profiler import profile

import os
import sys

this_dir = os.path.dirname(__file__)
sys.path.insert(0, (os.path.join(this_dir, "../..")))

from sfdata import SFDataFile

def convprof(fname):
    sfd = SFDataFile(fname)

    run_all(
        sfd.to_dataframe,
        sfd.to_dataframe_accumulate,
        sfd.to_dataframe_fill
    )

    run_all(
        sfd.to_xarray,
        sfd.to_xarray_accumulate
    )

def run_all(*funcs):
    ref_func = funcs[0]
    ref = create(ref_func)
    for f in funcs:
        run(f, ref)
    del ref

def run(func, ref):
    val = create(func)
    del val # create it twice as consistency check
    val = create(func)
    check(val, ref)

def create(ofunc):
    def func(*args, **kwargs): # SFDataFile is not hashable?
        return ofunc(*args, **kwargs)
    func.__name__ = ofunc.__name__
    func = profile(func)

    def fillna(val, fill_value=-1):
        return val.fillna(fill_value)
    fillna.__name__ = fillna.__name__ + "__" + ofunc.__name__ # assign fillnas to func
    fillna = profile(fillna)

    val = func(show_progress=True)
    val = fillna(val)
    return val

def check(val, ref):
    try:
        assert val.equals(ref)
    except AssertionError:
        print(f"\n{ref}\n{val}\n")

if __name__ == "__main__":
    fname = clargs.filename
    if not os.path.isfile(fname):
        msg = f"File \"{fname}\" does not exist. The script \"create_test_data.py\" may be used to create a default test file \"test_dump.h5\"."
        raise ValueError(msg)
    convprof(fname)


# -*- encoding:utf-8 -*-
"""
  author:lgh
"""

from win32com.client import Dispatch, constants, gencache

def doc2pdf(input, output):
    w = Dispatch('Word.Application')
    try:
        # 打开文件
        doc = w.Documents.Open(input, ReadOnly=1)
        # 转换文件
        doc.ExportAsFixedFormat(output, constants.wdExportFormatPDF,
                                Item=constants.wdExportDocumentWithMarkup,
                                CreateBookmarks=constants.wdExportCreateHeadingBookmarks)
        return True
    except:
        return False
    finally:
        w.Quit(constants.wdDoNotSaveChanges)

def GenerateSupport():
    gencache.EnsureModule('{00020905-0000-0000-C000-000000000046}', 0, 8, 4)

def main():
    input = r'D:\test\LC.docx'
    output = r'D:\test\联创UWB定位系统操作手册.pdf'
    GenerateSupport()
    rc = doc2pdf(input, output)
    if rc:
        print('转换成功')
    else:
        print('转换失败')

if __name__ == '__main__':
    main()


import sys
input = sys.stdin.readline
M = int(input())
S = 0
for _ in range(M):
    lst = input().split()
    op = lst[0]
    num = 0
    if len(lst) > 1:
        num = int(lst[1])
    if op == "add":
        S |= (1 << (num - 1))
    if op == "remove":
        S &= ~(1 << (num - 1))
    if op == "check":
        print(1) if S & 1 <<(num-1) else print(0)
    if op == "toggle":
        S ^= (1 << (num - 1))

    if op == "all":
        S = (1 << 20) - 1

    if op == "empty":
        S = 0


import requests
from lxml import etree
import sys

namespace="{http://uniprot.org/uniprot}"

def get_entry(document):
    return document.findall("./"+namespace+"entry")[0]

entry_ids =[item.strip() for item in open(sys.argv[1])]

xmlroot_string="<uniprot xmlns=\"http://uniprot.org/uniprot\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://uniprot.org/uniprot http://www.uniprot.org/support/docs/uniprot.xsd\"/>"

root=etree.fromstring(xmlroot_string)

url = "https://www.uniprot.org/uniprot/"
for id in entry_ids:

    xml =requests.get(url+id+".xml")
    subroot=etree.fromstring(xml.content)
    root.append(get_entry(subroot))

tree = etree.ElementTree(root)
tree.write(sys.argv[2])


from collections import deque
import sys
input = sys.stdin.readline

N = int(input())
deque = deque()
for _ in range(N):
    cmds = input().split()
    if cmds[0] == "push_front":
        deque.appendleft(cmds[1])
    elif cmds[0] == "push_back":
        deque.append(cmds[1])
    elif cmds[0] == "pop_front":
        if deque: print(deque.popleft())
        else: print(-1)
    elif cmds[0] == "pop_back":
        if deque: print(deque.pop())
        else: print(-1)
    elif cmds[0] == "size":
        print(len(deque))
    elif cmds[0] == "empty":
        if deque: print(0)
        else: print(1)
    elif cmds[0] == "front":
        if deque: print(deque[0])
        else: print(-1)
    elif cmds[0] == "back":
        if deque: print(deque[-1])
        else: print(-1)


#! /usr/bin/env python

import rospy
from midterm_201812275.msg import info
from midterm_201812275.msg import board
import random

pub = rospy.Publisher('get_on', board, queue_size=100)

boarding = 0

def callback(data):
    rospy.loginfo("time : %d, pos : %d", data.time, data.pos)
    # num = random.randint(0, 2)
    if data.time == 50:
        global boarding
        # pass the bus station
        # if num == 1:
            # boarding = 0
            # rospy.loginfo("False!")
        # stop the bus station
        # else:
        boarding = 1
        rospy.loginfo("True!")
    pub.publish(boarding)

while not rospy.is_shutdown():
    rospy.init_node('smartphone')
    sub = rospy.Subscriber('info', info, callback)

    rospy.spin()


# 숫자 문자열과 영단어

def solution(s):
    words = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine']
    x = ''
    result = ''
    for i in s:
        if i.isalpha():
            x += i
            if x in words:
                result += str(words.index(x))
                x = ''
        else:
            result += i

    return int(result)


# -*- coding: utf-8 -*-
"""
Nuke Elbows

This script create right angle 'elbows' with the dot node.

Installation:
Add the following to menu.py

$ import elbows
$ nuke.menu("Nuke").addCommand('Scripts/Elbows', 'elbows.main()', "shift+alt+e")

"""

import nuke

def nodeHasMask(node):
    return node.knobs().has_key('maskChannelMask')

def getMinInputs(node):
    min_inputs = node.minInputs()
    return (min_inputs - 1) if nodeHasMask(node) and min_inputs > 0 else min_inputs

def getPos(node):
    return node.xpos(), node.ypos()

def getSize(node):
    return node.screenWidth() / 2, node.screenHeight() / 2

def checkUnder(src, dst):
    # True if source is within 1/2 the max of both src and dst widths on x axis
    m = getPos(src)[0] + getSize(src)[0]
    d = getPos(dst)[0] + getSize(dst)[0]
    threshold = max(getSize(src)[0], getSize(dst)[0])  # threshold is max of half widths
    return abs(m - d) < threshold

def align(dot, dst, mer):
    # Aligns dots in a parallel way
    size_dot_x, size_dot_y = getSize(dot)
    x = getPos(dst)[0] + getSize(dst)[0] - size_dot_x
    y = getPos(mer)[1] + getSize(mer)[1] - size_dot_y
    dot.setXYpos(x, y)
    return x, y

def align_overhead(dot, dep, node):  # src = dep
    # Create and align dot overhead
    size_dot_x, size_dot_y = getSize(dot)
    x = getPos(node)[0] + getSize(node)[0] - size_dot_x
    y = getPos(dep)[1] + getSize(dep)[1] - size_dot_y
    dot.setXYpos(x, y)
    return x, y

def elbows(node):
    if len(node.dependencies(nuke.INPUTS)) == 1:

        # The node has a single input, so do an overhead elbow

        dep = node.input(0)
        if dep is None:
            return  # It's not connected to anything, exit

        if not checkUnder(node, dep):  # Don't do anything if we're already under it
            if dep.Class() == 'Dot':  # If its a dot, don't make another one
                dot = nuke.nodes.Dot()
                dot.setInput(0, dep)
                align_overhead(dot, dep, node)
                node.setInput(0, dot)
                return [dot]

        else:
            node.setSelected(False)
            dep.setSelected(True)
            dot = nuke.createNode('Dot', inpanel=False)
            dot.setYpos(dot.ypos() + node.screenHeight() * 2)
            dot2 = nuke.nodes.Dot()
            align_overhead(dot2, dot, node)
            dot2.setInput(0, dot)
            node.setInput(0, dot2)
            return [dot, dot2]

    elif len(node.dependencies(nuke.INPUTS)) > 1:

        # The node has multiple inputs, create parallel elbows

        if node.Class() in ('ContactSheet', 'Switch', 'Merge2',
                            'Merge', 'Blend', 'Dissolve', 'Keymix',
                            'Copy', 'AddMix', 'CopyBBox', 'ChannelMerge'):
            dots = []
            try:
                child = node.dependent(nuke.INPUTS)[0]  # check if there is a connected node
            except:
                child = None
            for input in range(node.inputs()):
                if node.Class() not in ('ContactSheet', 'Switch'):
                    if input in [2]:  # input 2 is the mask, skip it
                        continue
                dep = node.input(input)
                if dep is not None:
                    if not checkUnder(node, dep):
                        dep.setSelected(True)
                        dot = nuke.createNode('Dot', inpanel=False)
                        dots.append(dot)
                        dep.setSelected(False)
                        align(dot, dep, node)
                        dot.setSelected(False)
                if child is not None:
                    child.setInput(0, node)
            return dots

def main():
    nodes = nuke.selectedNodes()
    if len(nodes) == 1:
        # A single node selection assumes an elbow joint on non mask inputs.
        elbows(nodes[0])

    elif len(nodes) > 1:
        # If multiple nodes are selected, it assumes we want to add them together.
        # empty lists are false, checking to see if these nodes are not already connected
        if all(not n.dependent(nuke.INPUTS) for n in nodes):
            m = nuke.createNode('Merge2')
            last = nodes[-1]  # get the node that the merge should go under
            m['operation'].setValue('plus')
            m['bbox'].setValue('union')
            m.setYpos(max(n.ypos() for n in nodes) + m.screenHeight() * 3)  # set Ypos under the lowest of selection
            m.setXpos(getPos(last)[0] + getSize(last)[0] - getSize(m)[0])  # set Xpos to the last selected

            for i, node in enumerate(nodes):
                if i >= 2:
                    i += 1
                m.setInput(i, node)
            dots = elbows(m)
            for d in dots:
                d.setSelected(True)
            m.setSelected(True)


import threading
import socket
import time
import crcmod
import random

class Packet_creator:
    def __init__(self):
        self.SEQ_num = 0
        self.prcOfCorrupted = 0.1
        #http://crcmod.sourceforge.net/crcmod.html
        self.crc_func = crcmod.mkCrcFun(0x10211, rev=False, initCrc=0x1d0f, xorOut=0x0000)

    ## funkcia prehľadá súbor 'config.txt' a podľa neho zmení niektoré parametre
    def refresh_configFile(self):
        global showSentPackets, showReceivedPackets, showKeepAlivePackets

        file = open("config.txt", "r")

        print("Aktuálne nastavenie zo súboru 'config.txt':")

        self.timeForPacket = float(file.readline().split(';')[1])
        print(" Maximálny čas čakania na potvrdzujúci paket: " + str(self.timeForPacket) + "s")

        self.timeForKeepAlive = float(file.readline().split(';')[1])
        print(" Interval odosielania KeepAlive: " + str(self.timeForKeepAlive) + "s")

        self.thresholdKA = int(file.readline().split(';')[1])
        print(" Threshold KeepAlive: " + str(self.thresholdKA))

        window = file.readline().split(';')[1]
        sender.set_window(int(window))
        print(" Window: " + window[:-1])

        self.prcOfCorrupted = float(file.readline().split(';')[1])
        print(" Koľko paketov sa má poškodiť pred odoslaním: " + str(round(self.prcOfCorrupted * 100, 2)) + "%")

        value = file.readline().split(';')[1]
        showKeepAlivePackets = value[0] == "1"
        if showKeepAlivePackets:
            print(" Ukázať KeepAlive pakety: Áno")
        else:
            print(" Ukázať KeepAlive pakety: Nie")

        value = file.readline().split(';')[1]
        showReceivedPackets = value[0] == "1"
        if showReceivedPackets:
            print(" Ukázať prichádzajúce pakety: Áno")
        else:
            print(" Ukázať prichádzajúce pakety: Nie")

        value = file.readline().split(';')[1]
        showSentPackets = value[0] == "1"
        if showSentPackets:
            print(" Ukázať odosielajúce pakety: Áno\n")
        else:
            print(" Ukázať odosielajúce pakety: Nie\n")

        file.close()

    def get_timeForPacket(self):
        return self.timeForPacket
    def get_timeForKA(self):
        return self.timeForKeepAlive
    def get_thresholdKA(self):
        return self.thresholdKA

    def get_prcOfCorrupted(self):
        return self.prcOfCorrupted

    def set_prcOfCorrupted(self, value):
        self.prcOfCorrupted = value

    def set_MY_addr(self, IP, port):
        self.MY_IP = IP
        self.MY_PORT = port

    def set_TARGET_addr(self, IP, port):
        self.TARGET_IP = IP
        self.TARGET_PORT = port

    def get_MY_addr(self):
        return (self.MY_IP, self.MY_PORT)

    def get_TARGET_addr(self):
        return (self.TARGET_IP, self.TARGET_PORT)

    ##swich ako sa bude input spracovávať
    def changeInputMode(self, value):
        global inputMode
        inputMode = value

    ##vytvorí crc a vložím ho ako posledné 2 byty
    def generateCRC(self, fragment):
        crc = self.crc_func(fragment)

        fragment += int.to_bytes((crc >> 8) & 0xff, 1, "big")
        fragment += int.to_bytes(crc & 0xff, 1, "big")

        return fragment

    ##vloží fragment do crc funckie a ak výjde 0 tak dáta nie sú poškodené
    def checkCRC(self, fragment):
        if self.crc_func(fragment) == 0:
            return True
        return False

    ##náhodne si vyberie jeden byte z dátovej časti a zmení ho na iný
    def corruptData(self, fragment):
        index = random.randrange(len(fragment)-3) + 3
        return fragment[:index] + int.to_bytes(random.randrange(256), 1, "big") + fragment[index+1:]

    def create_SYN(self):
        body = int.to_bytes(0, 1, "big") #type
        body += int.to_bytes(0, 2, "big") #seq
        return body

    def create_INF(self, SEQ, data):
        body = int.to_bytes(1, 1, "big") #type
        body += int.to_bytes(SEQ, 2, "big") #seq
        body += bytes(data, "utf-8") #data
        return self.generateCRC(body) #vytvorenie CRC kodu

    def create_PSH(self, SEQ, data):
        body = int.to_bytes(2, 1, "big") #type
        body += int.to_bytes(SEQ, 2, "big") #seq
        body += data #data
        return self.generateCRC(body) #vytvorenie CRC kodu

    def create_PSH_F(self, SEQ):
        body = int.to_bytes(3, 1, "big") #type
        body += int.to_bytes(SEQ, 2, "big") #seq
        return body

    def create_MSG(self, SEQ, message):
        body = int.to_bytes(4, 1, "big") #type
        body += int.to_bytes(SEQ, 2, "big") #seq
        body += bytes(message, "utf-8") #data
        return self.generateCRC(body) #vytvorenie CRC kodu

    def create_MSG_F(self, SEQ):
        body = int.to_bytes(5, 1, "big") #type
        body += int.to_bytes(SEQ, 2, "big") #seq
        return body

    def create_ACK(self, SEQ):
        body = int.to_bytes(6, 1, "big") #type
        body += int.to_bytes(SEQ, 2, "big") #seq
        return body

    def create_nACK(self, SEQ):
        body = int.to_bytes(7, 1, "big") #type
        body += int.to_bytes(SEQ, 2, "big") #seq
        return body

    def create_KeepAlive(self, SEQ):
        body = int.to_bytes(8, 1, "big") #type
        body += int.to_bytes(SEQ, 2, "big") #seq
        return body

    def create_KeepAliveACK(self, SEQ):
        body = int.to_bytes(9, 1, "big") #type
        body += int.to_bytes(SEQ, 2, "big") #seq
        return body

    def create_KeepAliveEND(self, SEQ):
        body = int.to_bytes(10, 1, "big") #type
        body += int.to_bytes(SEQ, 2, "big") #seq
        return body

    def create_FIN(self, SEQ):
        body = int.to_bytes(11, 1, "big") #type
        body += int.to_bytes(SEQ, 2, "big") #seq
        return body

    def get_nameOf_type(self, type):
        types = ["SYN", "INF", "PSH", "PSH_F", "MSG", "MSG_F", "ACK", "nACK", "KeepAlive", "KeepAlive_ACK", "KeepAlive_END", "FIN"]
        return types[type]

    def set_enabled_KeepAlive(self, value):
        self.enabled_KA = value

    def enabled_KeepAlive(self):
        return self.enabled_KA

    def get_type(self, body):
        return body[0]

    def get_SEQ(self, body):
        return int.from_bytes(body[1:3], "big")

    def ppSEQ(self):
        self.SEQ_num += 1
        return self.SEQ_num

    def setSEQ_num(self, value):
        self.SEQ_num = value

    def getSEQ_num(self):
        return self.SEQ_num

    ##socket, ktorý sa uloží na oboch uzloch po začatí komunikácie
    def send_socket(self, socket):
        self.sck = socket

    ##odosiela pakety pre prijímača aj vysielača
    def sendPacket(self, body, addr):
        if showSentPackets:
            type = self.get_type(body)
            if type < 13 and (((type == 8 or type == 9) and showKeepAlivePackets) or not (type == 8 or type == 9)): ##filter, či sa ma zobrazovať odosielanie paketu
                print("<- " + self.get_nameOf_type(type) + " - SEQ: " + str(self.get_SEQ(body)))
        self.sck.sendto(body, addr)

    ##prijíma pakety pre prijímača aj vysielača
    def waitForPacket(self):
        return self.sck.recvfrom(1500)

class Receiver:
    def __init__(self, port):
        self.message = []
        self.path = []
        self.file = []

        hostname = socket.gethostname()
        self.MY_IP = socket.gethostbyname(hostname)

        ##self.MY_IP = "127.0.0.1" # pre localhost komunikáciu
        self.MY_PORT = port

        self.writeInfo()

        packet_creator.set_enabled_KeepAlive(False)

        self.sock = socket.socket(socket.AF_INET,  # Internet
                             socket.SOCK_DGRAM)  # UDP
        self.sock.bind((self.MY_IP, self.MY_PORT))

        self.receiverInput = True
        self.activeClass = True
        self.arrived_SEQ = 0
        self.synchronized = False

    def writeInfo(self):
        print("\n\n\nIP adresa zariadenia: " + self.MY_IP)
        print("Port, na ktorom sa očakáva komunikácia: " + str(self.MY_PORT) + "\n\n")

    ##získa dátovu a časť a (ak je to potrebné) dekóduje ju
    def getDataFromPacket(self, body, decode):
        if decode:
            return body[3:-2].decode("utf-8")
        return body[3:-2]

    def getReceiverInput(self):
        return self.receiverInput

    def setReceiverInput(self, value):
        self.receiverInput = value

    def setActiveClass(self, value):
        self.activeClass = value

    def insertData(self, arr, data):
        ## pakety môžu vďaka ARQ prichádzať v rôznom poradí, preto v tejto funkcií vďaka poradiu paketu (SEQ)
        ## sa paket uloží do zoznamu na príslušné miesto
        for i, one_data in enumerate(arr):
            if packet_creator.get_SEQ(data) < packet_creator.get_SEQ(one_data):
                arr.insert(i, data)
                return arr
        arr.append(data)
        return arr

    ## funkcia uloží súbor a vyhodnotí prenos
    def saveData(self, folderPath):
        path = ""
        file = b""

        for part in self.path:
            path += self.getDataFromPacket(part, True)
        for part in self.file:
            file += self.getDataFromPacket(part, False)

        if folderPath[-1] != '/':
            folderPath += "/"

        f = open(folderPath + path, "w+b")
        f.write(file)
        f.close()
        print("Súbor bol úspešne prijatý.")
        print("Veľkosť súboru: " + str(len(file)) + "B")
        print("Počet fragmentov: " + str(len(self.path) + len(self.file)))
        print("Počet dát v jednom fragmente: " + str(len(self.file[0]) - 5))
        print("Čas prenosu súboru: " + str(round(self.end_time_recvFile - self.start_time_recvFile, 4)) + "s")
        print("Cesta k súboru: '" + folderPath + path + "'")

        self.path = []
        self.file = []

    def send_packet(self, body, addr):
        packet_creator.sendPacket(body, addr)

    ##funkcia sa volá pri tom ako uzol sa stane vysielačom, kde pošle paket sám na seba (aby zrušil while) a znoza ju zavola
    ##to preto aby sa pakety neočakávali na porte, ktorý je určený na začiatku používateľom ale na tom, z ktorého sa poslal paket
    def restart_listening(self):
        self.cancel_waiting(1)
        self.synchronized = True
        self.waiting_for_packet()

    ##fukncia pošle paket sám na seba (aby ukončil while cyklus a program)
    def stop_waiting(self):
        self.activeClass = False
        packet_creator.sendPacket(int.to_bytes(255, 1, "big"), packet_creator.get_MY_addr())

    ## funkcia pošle paket sám na seba (aby ukončil while cyklus)
    def cancel_waiting(self, type):
        self.activeClass = False
        if type == 0:
            packet_creator.sendPacket(int.to_bytes(253, 1, "big"), packet_creator.get_MY_addr())
        if type == 1:
            self.sock.sendto(int.to_bytes(253, 1, "big"), (self.MY_IP, self.MY_PORT))

    def cancel_keepAlive_waiting(self):
        print("\nKomunikácia prerušená! - po " + str(packet_creator.get_thresholdKA()) + " neprijatých KeepAlive paketoch\n")
        self.stop_waiting()

    ## thread čakajúci na keepAlive pakety
    def exceeded_waiting_for_keepAlive(self, SEQ):
        ## po n * m sekundách skontroluje či sa zväčšilo arrived_SEQ číslo (n - čas čakania na keepalive; m - threshold)
        time.sleep((packet_creator.get_timeForKA() + 0.1) * packet_creator.get_thresholdKA())

        if SEQ >= self.arrived_SEQ and packet_creator.enabled_KeepAlive():
            self.cancel_keepAlive_waiting()

    ## thread čakajúci na INF/PSH/MSG pakety
    def exceeded_waiting_for_packet(self, SEQ):
        ## po n * m sekundách skontroluje či sa zväčšilo arrived_SEQ číslo (n - čas čakania na paket; m - threshold)
        SEQ += 1
        time.sleep(packet_creator.get_timeForPacket() * packet_creator.get_thresholdKA())

        if SEQ >= self.arrived_SEQ:
            print("Spojenie prerušené v dôsledku " + str(packet_creator.get_thresholdKA()) + "x neprijatia paketu.")
            self.stop_waiting()
            exit()

    ##v tejto funkcii sa prijíma väčšina paketov (aj vysielača aj prijímača)
    def waiting_for_packet(self):
        self.activeClass = True
        while self.activeClass:
            if self.synchronized:
                ## čakanie na porte uloženom v packet_creator
                ## vysielač - ten z ktorého odosiela
                ## prijímač - ten, ktorý zadal na začiatku používateľ
                data, addr = packet_creator.waitForPacket()
            else:
                data, addr = self.sock.recvfrom(1500)  #čakanie na porte zadanom od používateľa

            type = packet_creator.get_type(data)

            SEQ = packet_creator.get_SEQ(data)

            packet_creator.setSEQ_num(SEQ)

            ##filter či sa má ukazovať prijímanie paketu
            if showReceivedPackets and type < 13 and (((type == 8 or type == 9) and showKeepAlivePackets) or not (type == 8 or type == 9)):
                print("-> " + packet_creator.get_nameOf_type(type), " - SEQ: " + str(SEQ))

            if type == 0: #SYN
                self.synchronized = True

                packet_creator.send_socket(self.sock)

                self.receiverInput = False
                ack_P = packet_creator.create_ACK(packet_creator.get_type(data))

                self.send_packet(ack_P, addr)

                #uložím si adresu
                packet_creator.set_TARGET_addr(addr[0], addr[1])
                packet_creator.set_MY_addr(self.MY_IP, self.MY_PORT)

                print("\n\nKomunikácia nadviazaná!")
                print("IP adresa odosielateľa: " + addr[0])
                print("Port odosielateľa: " + str(addr[1]) + "\n\n")

                print("Ako si prajete pokračovať:\n 'm' - Poslať správu\n 'f' - Poslať súbor\n 'e' - Ukončiť komunikáciu\n")

                packet_creator.changeInputMode(1) #poslanie suboru

                self.keepAlive_arrived = False
                threading.Thread(target=self.exceeded_waiting_for_keepAlive, args=(0, )).start()

            if type == 1 or type == 2 or type == 4: #INF/PSH/MSG

                threading.Thread(target=self.exceeded_waiting_for_packet, args=(self.arrived_SEQ,)).start() #thread čakania na ďalší paket

                if packet_creator.checkCRC(data): #ak je paket nepoškodený
                    ack_P = packet_creator.create_ACK(SEQ)
                    self.send_packet(ack_P, addr) #odošle ack

                    if type == 1:  # INF
                        if len(self.path) == 0: #pridanie prvého údaju do poľa path
                            self.arrived_SEQ = SEQ
                            self.start_time_recvFile = time.time()
                            self.path.append(data)
                        else:
                            self.path = self.insertData(self.path, data)
                            self.arrived_SEQ += 1

                    elif type == 2:  # PSH
                        if len(self.file) == 0:
                            self.file.append(data)  #pridanie prvého údaju do poľa file
                        else:
                            self.file = self.insertData(self.file, data)
                        self.arrived_SEQ += 1

                    elif type == 4:  # sprava
                        if len(self.message) == 0:
                            self.arrived_SEQ = SEQ
                            self.message.append(data) #pridanie prvého údaju do poľa message
                        else:
                            self.message = self.insertData(self.message, data)
                            self.arrived_SEQ += 1

                else: #paket je poškodený - odšlem nACK
                    self.arrived_SEQ += 1
                    nack_p = packet_creator.create_nACK(SEQ)
                    self.send_packet(nack_p, addr)

            elif type == 3: #PSH_F
                self.arrived_SEQ += 10 #fix aby to určite nepadlo
                self.end_time_recvFile = time.time()
                time.sleep(0.5)
                print("Zadajte absolútnu cestu k priečinku, do ktorého sa má súbor uložiť: ", end="")
                packet_creator.changeInputMode(4)

            elif type == 5: #MSG_F
                self.arrived_SEQ += 10 #fix aby to určite nepadlo
                print(">> ", end="")
                for part in self.message:
                    print(self.getDataFromPacket(part, True), end="")
                print()
                print("\nAko si prajete pokračovať:\n 'm' - Poslať správu\n 'f' - Poslať súbor\n 'e' - Ukončiť komunikáciu\n")

                self.message = []

            elif type == 6: #ACK
                ##freeze aby sa odoslali na začiatku všetky pakety z okna
                if not sender.sentFirtsPackets:
                    time.sleep(0.1)
                sender.pp_arrived_SEQ()
                sender.move_window()

            elif type == 7: #nACK
                ##freeze aby sa odoslali na začiatku všetky pakety z okna
                if not sender.sentFirtsPackets:
                    time.sleep(0.1)
                sender.pp_arrived_SEQ()
                sender.send_again_packet(SEQ)

            elif type == 8: #KeepAlive
                ##odošlem naspať KeepAliveACK a zavolám thread, ktorý kontroluje či dôjde ďalší keepalive
                packet_creator.set_enabled_KeepAlive(True)

                self.arrived_SEQ = SEQ

                self.keepAlive_arrived = True

                ack_P = packet_creator.create_KeepAliveACK(SEQ)
                self.send_packet(ack_P, addr)

                threading.Thread(target=self.exceeded_waiting_for_keepAlive, args=(SEQ, )).start()

            elif type == 9: #keepAlive ACK
                ##v objekte sender zväčším arrived_SEQ, pre potreby zistenia či došiel keepAliveACK
                sender.pp_arrived_SEQ()

            elif type == 10: #keepAlive stop
                packet_creator.set_enabled_KeepAlive(False)

            elif type == 11: #FIN
                print("Komunikácia úspešne ukončená")
                print("Pre ukončenia aplikácie zadajte 'e'")
                break

            elif type == 253: #prerušenie čakania (ukončenie while cyklu)
                break

            elif type == 255: #stopnutie komunikácie
                time.sleep(0.5)
                print("\n\nKomunikácia ukončená!\n")
                print("Prajete si znova začať komunikáciu ? (y/n) ", end="")
                packet_creator.changeInputMode(0)
                break

class Sender:
    def __init__(self):
        self.sock = socket.socket(socket.AF_INET,  # Internet
                             socket.SOCK_DGRAM)  # UDP

        self.local_path = ""
        self.target_path = ""
        self.file = ""

        ##bindnutie portu a by sa zistilo, z ktorého portu bude vysielač odosielať (pre neskoršie použitie, keď potrebujem poslať paket sám na seba)
        self.sock.bind(('', 0))
        addr = self.sock.getsockname()
        MY_PORT = addr[1]
        hostname = socket.gethostname()
        MY_IP = socket.gethostbyname(hostname)
        packet_creator.set_MY_addr(MY_IP, MY_PORT)

        self.window = 10

        self.packetsToSend = []

    def set_window(self, value):
        self.window = value

    def set_local_path(self, path):
        self.local_path = path

    def set_target_path(self, path):
        self.target_path = path

    def set_TARGET_ADDR(self, addr):
        self.TARGET_IP = addr[0]
        self.TARGET_PORT = addr[1]

    def send_packet(self, body):
        packet_creator.sendPacket(body, packet_creator.get_TARGET_addr())

    ##funkcia zistí či dané SEQ číslo je v poli SEQ čísel, ktoré sa majú poškodiť, ak áno tak sa paket poškodí a odošle
    def send_and_corrupt_packet(self, body):
        if len(self.corrupted) != 0 and self.corrupted[0] == packet_creator.get_SEQ(body):
            self.send_packet(packet_creator.corruptData(body))
            self.corrupted.pop(0)
        else:
            self.send_packet(body)

    ##thread čakajúci na ACK podľa SEQ - arrived_SEQ
    def exceeded_waiting_for_ACK(self, SEQ):
        time.sleep(packet_creator.get_timeForPacket())
        ##po n sekunách kontroluje či došiel ACK (zväčšené arrived_SEQ)

        if SEQ >= self.arrived_SEQ: ##nedošiel packet
            l = len(self.thresholdForPackets)
            m = packet_creator.get_thresholdKA()

            ##funkcia pridáva do poľa SEQ čísla paketov, ktoré nedorazili (veľkosť poľa je maximálne 3 - vtedy sa posledný vypustí)
            if l == m or l == m - 1:
                if l == m:
                    self.thresholdForPackets.pop(0)
                self.thresholdForPackets.append(SEQ)

                equal = True
                for i in range(1, m):
                    if self.thresholdForPackets[i - 1] != self.thresholdForPackets[1]:
                        equal = False
                        break
                ##ak tieto tri SEQ čísla v poli sú rovnaké (3-krát neprišiel jeden paket) - komunikácia sa ukončí
                if equal:
                    self.thresholdForPackets = []
                    print("Spojenie prerušené v dôsledku " + str(packet_creator.get_thresholdKA()) + "x neprijatia paketu do " + str(packet_creator.get_timeForPacket()) + "s")
                    receiver.stop_waiting()

                else:
                    self.send_again_packet(SEQ)

            else:
                self.thresholdForPackets.append(SEQ)
                self.send_again_packet(SEQ)

    def send_again_packet(self, SEQ):
        #zistím ktorý paket treba znova poslať podľa SEQ
        for packet in self.packetsToSend:
            if SEQ == packet_creator.get_SEQ(packet):
                self.send_and_corrupt_packet(packet)
                threading.Thread(target=self.exceeded_waiting_for_ACK, args=(self.arrived_SEQ,)).start()
                break

    ##po príchode ack sa volá táto funkcia, ktorá posunie okno o jeden paket
    def move_window(self):
        ##podmienka zisťuje či je okno na konci poľa paketov na odoslanie (nemá sa kde ďalej posunúť)
        if self.lastIndexInWindow != len(self.packetsToSend) - 1:
            ##nie je na konci - pridáme doň ďalší paket a pošleme ho
            self.lastIndexInWindow += 1
            self.packetsInWindow.append(self.packetsToSend[self.lastIndexInWindow])

            self.send_and_corrupt_packet(self.packetsInWindow[-1])
            threading.Thread(target=self.exceeded_waiting_for_ACK, args=(self.arrived_SEQ,)).start()

        ##odstraníme z okna posledný paket
        self.packetsInWindow.pop(0)

        if len(self.packetsInWindow) == 0: ##všetky pakety odoslané

            if packet_creator.get_type(self.packetsToSend[-1]) == 2: #PSH_F
                ##odošlem final paket, ktorý informuje uzol o ukončení odosielania súboru
                psh_f = packet_creator.create_PSH_F(packet_creator.ppSEQ())
                self.send_packet(psh_f)

                end_time_sendFile = time.time()
                print("Súbor úspešne odoslaný")
                print("Čas odoslania: " + str(round(end_time_sendFile - self.start_time_sendFile, 4)) + "s")

            else:
                ##odošlem final paket, ktorý informuje uzol o ukončení odosielania správy
                msg_f = packet_creator.create_MSG_F(packet_creator.ppSEQ())
                self.send_packet(msg_f)

                print("Správa úspešne odoslaná")

            ##znova spustím keepalive a switchnem do modu na odosielanie
            packet_creator.changeInputMode(-1)
            self.packetsToSend = []
            time.sleep(packet_creator.get_timeForKA()) ##zmrazenie ak sa náhodou správa poslala tak rýchlo, že sa ešte ani nestihol ukončiť keepalive
            print("\nAko si prajete ďalej pokračovať:\n 'm' - Poslať správu\n 'f' - Poslať súbor\n 'e' - Ukončiť komunikáciu\n")
            packet_creator.changeInputMode(1)
            self.start_keepAlive()

    ##funkcia odošle pripravené pakety
    def send_prepared_packets(self):

        self.thresholdForPackets = [] ##pole, v ktorom sa ukladajú SEQ čísla paketov, ktorých potvrdzovacie pakety nedorazili

        ##corrupt data
        ##vytvorí za pole SEQ čísel, u ktorých sa pri odosielaní poškodia dáta
        numOfPackets = len(self.packetsToSend)
        numForCorrupt = int(packet_creator.get_prcOfCorrupted() * numOfPackets)
        self.corrupted = []
        for i in range(numForCorrupt):
            self.corrupted.append(packet_creator.get_SEQ(self.packetsToSend[random.randrange(numOfPackets)]))
        self.corrupted.sort()

        ##zmenšenie okna, ak počet paketov na odoslanie je menej ako veľkosť okna
        if len(self.packetsToSend) < self.window:
            win = len(self.packetsToSend)
        else:
            win = self.window

        self.arrived_SEQ = packet_creator.get_SEQ(self.packetsToSend[0]) + (win - 1) #arrived_SEQ začne o posunutie okna (keďže ACK SEQ budú posunuté)

        self.packetsInWindow = []

        #vložia sa pakety do poľa podľa veľskoti okna
        for i in range(win):
            self.packetsInWindow.append(self.packetsToSend[i])

        self.lastIndexInWindow = win - 1

        self.sentFirtsPackets = False #premenná slúži na jemné zmrazenie prichádzajúcich ACK paketov (aby sa stihli poslať všetky pakety)

        #pošlem všetky pakety z okna
        for i, protocol in enumerate(self.packetsInWindow):
            if i % 32 == 0: #pri odosielaní väčšieho počtu paketov to prestane posielať - sleep fix
                time.sleep(0.2)
            self.send_and_corrupt_packet(protocol)
            threading.Thread(target=self.exceeded_waiting_for_ACK, args=(self.arrived_SEQ,)).start()

        self.sentFirtsPackets = True #začiatočné pakety sa odoslali, zmrazenie už nie je potrebné

    ##funkcia žiada input od použivateľa, podľa ktorého sa rozdelia data do skupín podľa veľkosti (inputu)
    def ask_for_size(self):
        while True:
            size = int(input("Zadajte počet bajtov pre dáta jedného fragmentu (1-1467): "))
            if size >= 1 and size <= 1467:
                break
        return size

    ##rozdelenie dát do skupín
    def split_data(self, data, size):
        array_of_data = []
        j = 0
        l = len(data)
        for i in range(size, l+size, size):
            array_of_data.append(data[j:i])
            j = i

        return array_of_data

    ##funkcia odošle správu
    def send_message(self, message):
        self.stop_keepAlive()

        size = self.ask_for_size()

        array_of_data = self.split_data(message, size)

        ##vytvorenie paketov z fragmentov
        for one_data in array_of_data:
            self.packetsToSend.append(packet_creator.create_MSG(packet_creator.ppSEQ(), one_data))

        print("Odošle sa " + str(len(array_of_data)) + " paketov.")

        self.send_prepared_packets()

        packet_creator.changeInputMode(-1) #pri switchnuti -1 input z klávesnice nič nespraví

    ##funkcia pridá k ceste na uloženie súboru názov súboru
    def get_filename(self):
        ##cyklus získa reversnutý názov súboru
        filename = ''
        for c in self.local_path[::-1]:
            if c == '/' or c == '\\':
                break
            filename += c

        ##prevráti názov
        return filename[::-1]

    ##odosielanie súboru
    def send_file(self):
        self.stop_keepAlive()

        size = self.ask_for_size()

        ## prečítanie súboru
        file = open(self.local_path, "r+b")
        read = file.read()
        file.close()

        ## príprava cesty
        array_of_data = self.split_data(self.get_filename(), size)
        for one_data in array_of_data:
            self.packetsToSend.append(packet_creator.create_INF(packet_creator.ppSEQ(), one_data))

        ## príprava súboru
        array_of_data = self.split_data(read, size)
        for one_data in array_of_data:
            self.packetsToSend.append(packet_creator.create_PSH(packet_creator.ppSEQ(), one_data))

        print("Odošle sa " + str(len(self.packetsToSend)) + " paketov o veľkosti " + str(len(read)) + "B. ")
        self.start_time_sendFile = time.time() #odmeranie času odosielania
        self.send_prepared_packets()

        packet_creator.changeInputMode(-1) #pri switchnuti -1 input z klávesnice nič nespraví

    ##funkcia stopne keepalive, stopne čakanie na paket a pošle ukončovací paket (oznámenie druhému uzlu)
    def end_com(self):
        self.stop_keepAlive()
        receiver.cancel_waiting(0)
        fin_p = packet_creator.create_FIN(packet_creator.ppSEQ())
        packet_creator.sendPacket(fin_p, packet_creator.get_TARGET_addr())

    ##funkcia oznamí druhému uzlu koniec keepalive a ukončí keepalive
    def stop_keepAlive(self):
        keepAliveStop_p = packet_creator.create_KeepAliveEND(packet_creator.ppSEQ())
        packet_creator.set_enabled_KeepAlive(False)
        #self.enabled_keepAlive = False
        self.send_packet(keepAliveStop_p)

    ##funkcia pripraví premenné na posielanie keepalive a zavolá tento thread
    def start_keepAlive(self):
        self.arrived_SEQ = packet_creator.getSEQ_num()
        packet_creator.set_enabled_KeepAlive(True)
        threading.Thread(target=self.thread_keepAlive, name="t1").start()

    def exceeded_waiting_for_keepAlive(self, ex_SEQ):
        ##funkcia každý n sekúnd inkrementuje lokálnu premennú, ktorú porovnáva s arrived_SEQ (to sa zväčšuje pri prijatí paketu), ak lokálna premenná
        ##"predbehne" arrived_SEQ -> niekoľko potvrdzujúcich paketov neprišlo
        ex_SEQ -= packet_creator.get_thresholdKA() - 1 #aby komunikacia nespadla po prvom neprijatom pakete
        while packet_creator.enabled_KeepAlive():
            time.sleep(packet_creator.get_timeForKA() + 0.1)

            if ex_SEQ >= self.arrived_SEQ and packet_creator.enabled_KeepAlive():
                self.keepAlive_arrived = False
                break

            ex_SEQ += 1

    ##funkcia inkrementuje premennú arrived_SEQ, ktorú používam pri kontrole keepalive_ack alebo ack paketov
    def pp_arrived_SEQ(self):
        self.arrived_SEQ += 1

    ##funkcia každých n sekúnd odosiela keepalive paket, pričom na začiatku po pol sekunde zavolá thread, ktorý kontroluje, či prišli keepalive_ack pakety
    def thread_keepAlive(self):
        packet_creator.set_enabled_KeepAlive(True)
        self.keepAlive_arrived = True
        threading.Timer(0.5, self.exceeded_waiting_for_keepAlive, args=(self.arrived_SEQ, )).start()
        while packet_creator.enabled_KeepAlive():
            time.sleep(packet_creator.get_timeForKA())
            if packet_creator.enabled_KeepAlive():
                self.send_packet(packet_creator.create_KeepAlive(packet_creator.ppSEQ()))

            if not self.keepAlive_arrived and packet_creator.enabled_KeepAlive():
                print("\nKomunikácia prerušená! - po " + str(packet_creator.get_thresholdKA()) + " neprijatých KeepAlive paketoch\n")
                receiver.stop_waiting()
                break

    def exceeded_waiting_for_SYN_packet(self):
        ## ak žiaden paket nebol prijatý, inputMode ostal nezmenený - 0
        if inputMode == 0:
            ## nACK paket na seba
            nACK_p = packet_creator.create_nACK(0)
            self.sock.sendto(nACK_p, packet_creator.get_MY_addr())

    def waiting_for_SYN_packet(self):
        ##po nejakom čase sa zavolá thread, ktorý zistí, že či bol prijatý paket
        threading.Timer(packet_creator.get_timeForPacket(), self.exceeded_waiting_for_SYN_packet).start()

        data, addr = packet_creator.waitForPacket()

        type = packet_creator.get_type(data)

        if type == 6: #ACK - paket prišiel
            print("\n\nKomunikácia nadviazaná!")
            print("IP adresa prijímateľa: " + addr[0])
            print("Port prijímateľa: " + str(addr[1]) + "\n\n")

            print("Ako si prajete pokračovať:\n 'm' - Poslať správu\n 'f' - Poslať súbor\n 'e' - Ukončiť komunikáciu\n")

            packet_creator.changeInputMode(1) #switch na mód inputu - "odosielanie"

            self.start_keepAlive() #začne odosielať keepalive
            return True #vráti true - komunikácia nadviazaná
        elif type == 7: #nACK - paket neprišiel, bol odoslaný týmto uzlom, funkciou exceeded_waiting_for_SYN_packet()
            print("\n\nKomunikáciu sa nepodarilo nadviazať!\n\nPrajete si znova začať komunikáciu ? (y/n) ", end="")
            return False #vráti false - komunikáciu sa nepodarilo nadviazať

    ##funkcia začne komunikáciu - vracia True hodnotu ak sa nadviaže komunikácia
    def establish_com(self):
        syn_P = packet_creator.create_SYN()

        self.TARGET_IP = input("Zadajte IP adresu prijímateľa: ")
        self.TARGET_PORT = int(input("Zadajte port prijímateľa: "))

        packet_creator.send_socket(self.sock)
        packet_creator.set_TARGET_addr(self.TARGET_IP, self.TARGET_PORT)

        self.sock.sendto(syn_P, (self.TARGET_IP, self.TARGET_PORT))

        return self.waiting_for_SYN_packet()

def thread_waiting_for_input():
    global inputMode
    while True:
        s = input()

        if inputMode == 0: #zacat komunikaciu
            if s == "y":
                if sender.establish_com():
                    threading.Thread(target=receiver.restart_listening).start()
            elif s == "n":
                ##ukončenie komunikácie - vypnutie očakávania paketu aby sa vypol program
                receiver.cancel_waiting(1)
                exit()

        elif inputMode == 1: #odosielanie

            if s == "m": #sprava
                print("Zadajte správu: ", end="")
                inputMode = 2

            if s == "f": #subor
                print("Zadajte absolútnu cestu k súboru: ", end="")
                inputMode = 3

            if s == "e": #konec
                sender.end_com()
                print("Komunikácia úspešne ukončená")
                break

        elif inputMode == 2: #sprava
            sender.send_message(s)

        elif inputMode == 3: #cesta k suboru
            sender.set_local_path(s)
            sender.send_file()
            inputMode = 1

        elif inputMode == 4: #kde sa ma súbor uložiť
            receiver.saveData(s)
            print("\nAko si prajete pokračovať:\n 'm' - Poslať správu\n 'f' - Poslať súbor\n 'e' - Ukončiť komunikáciu\n")
            #sender.set_target_path(s)
            inputMode = 1
            #sender.send_file()

showKeepAlivePackets = False
showSentPackets = True
showReceivedPackets = True

MY_PORT = int(input("Zadajte port, na ktorom očakávate komunikáciu: "))

packet_creator = Packet_creator() #objekt, v ktorom sú funkcie a premenné o paketoch
receiver = Receiver(MY_PORT) #objekt, ktorý obsahuje funkcionalitu vysielača
sender = Sender() #objekt, ktorý obsahuje funkcionalitu prijímača
packet_creator.refresh_configFile() #načítanie nastavení z 'config.txt'

inputMode = 0 #prepínač na input - začiatok komunikácie

t_input = threading.Thread(target=thread_waiting_for_input)

print("Prajete si začať komunikáciu ? (y/n) ", end="")
t_input.start()

receiver.waiting_for_packet()