import pathlib
import sys
from textwrap import dedent
import shutil
import cProfile

from .errors import *

SERIAL = "serial"
MPI_PARALLEL = "mpi"

IN_PROGRESS_PREFIX = "inprogress_"

class PipelineStage:
    """A PipelineStage implements a single calculation step within a wider pipeline.

    Each different type of analysis stge is represented by a subclass of this
    base class.  The base class handles the connection between different pipeline
    stages, and the execution of the stages within a workflow system (parsl),
    potentially in parallel (MPI).

    An instance of one of these classes represents an actual run of the stage,
    with the required inputs, outputs, and configuration specified.

    See documentation pages for more details.

    """

    parallel = True
    config_options = {}
    doc = ""

    def __init__(self, args, comm=None):
        """Construct a pipeline stage, specifying the inputs, outputs, and configuration for it.

        The constructor needs a dict or namespace. It should include:
        - input paths (required)
        - config path (required)
        - output paths (optional but usual)
        - additional configuration (required if not specified elsewhere)

        Input and output paths should map tags to paths.
        Tags are strings, and the first elements in each item in the subclass's
        "inputs" and "output" attributes.
        e.g. for a subclass with:
            inputs = [('eggs', TextFile)]
            outputs = [('spam', TextFile)]
        the args could contain:
            {'eggs': 'inputs/eggs.txt',
             'spam': 'outputs/spam.txt' }
        If spam is not specified it will default to "./spam.txt"

        }

        The config should map "config" to a path where a YAML config file
        is located, e.g. {'config':'/path/to/config.yml'}

        Any config variables that are specified in the class's config attribute
        will be searched for first in args, then in the config file, and then
        by looking at any default value they have been given.
        If they have no default value (and just a type, like int, is listed), then
        it's an error if they are not specified somewhere.

        The execute method can instantiate and run the class together, with added bonuses
        like profiling and debugging tools.

        Parameters
        ----------
        args: dict or namespace
            Specification of input and output paths and any missing config options
        comm: MPI communicator
            (default is None) An MPI comm object to use in preference to COMM_WORLD
        """
        if not isinstance(args, dict):
            args = vars(args)

        # We first check for missing input files, that's a show stopper
        missing_inputs = []
        for x in self.input_tags():
            val = args[x]
            if val is None:
                missing_inputs.append(f"--{x}")
        if missing_inputs:
            missing_inputs = "  ".join(missing_inputs)
            raise ValueError(
                f"""

Missing these names on the command line:
    Input names: {missing_inputs}"""
            )

        self._inputs = {x: args[x] for x in self.input_tags()}
        # We alwys assume the config arg exists, whether it is in input_tags or not
        if args.get("config") is None:
            raise ValueError("The argument --config was missing on the command line.")

        self._inputs["config"] = args["config"]

        # We prefer to receive explicit filenames for the outputs but will
        # tolerate missing output filenames and will default to tag name in
        # current folder (this is for CWL compliance)
        self._outputs = {}
        for i, x in enumerate(self.output_tags()):
            if args[x] is None:
                ftype = self.outputs[i][1]
                self._outputs[x] = ftype.make_name(x)
            else:
                self._outputs[x] = args[x]

        # Finally, we extract configuration information from a combination of
        # command line arguments and optional 'config' file
        self._configs = self.read_config(args)

        use_mpi = args.get("mpi", False)
        if use_mpi:
            try:
                # This isn't a ceci dependency, so give a sensible error message if not installed.
                import mpi4py.MPI
            except ImportError:
                print("ERROR: Using --mpi option requires mpi4py to be installed.")
                raise

        # For scripting and testing we allow an MPI communicator or anything
        # with the same API to be passed in directly, overriding the --mpi
        # flag.
        if comm is not None:
            self._parallel = MPI_PARALLEL
            self._comm = comm
            self._size = self._comm.Get_size()
            self._rank = self._comm.Get_rank()
        elif use_mpi:
            self._parallel = MPI_PARALLEL
            self._comm = mpi4py.MPI.COMM_WORLD
            self._size = self._comm.Get_size()
            self._rank = self._comm.Get_rank()
        else:
            self._parallel = SERIAL
            self._comm = None
            self._size = 1
            self._rank = 0

    pipeline_stages = {}
    incomplete_pipeline_stages = {}

    def __init_subclass__(cls, **kwargs):
        """
        Python 3.6+ provides a facility to automatically
        call a method (this one) whenever a new subclass
        is defined.  In this case we use that feature to keep
        track of all available pipeline stages, each of which is
        defined by a class.

        """
        super().__init_subclass__(**kwargs)

        # This is a hacky way of finding the file
        # where our stage was defined
        filename = sys.modules[cls.__module__].__file__

        stage_is_complete = (
            hasattr(cls, "outputs") and hasattr(cls, "inputs") and hasattr(cls, "run")
        )

        # If there isn't an explicit name already then set it here.
        # by default use the class name.
        if not hasattr(cls, "name"):
            cls.name = cls.__name__

        if stage_is_complete:
            # Deal with duplicated class names
            if cls.name in cls.pipeline_stages:
                other = cls.pipeline_stages[cls.name][1]
                raise DuplicateStageName(
                    "You created two pipeline stages with the"
                    f"name {cls.name}.\nOne was in {filename}\nand the "
                    f"other in {other}\nYou can either change the class "
                    "name or explicitly put a variable 'name' in the top"
                    "level of the class."
                )

            # Check for "config" in the inputs list - this is implicit
            for name, _ in cls.inputs:
                if name == "config":
                    raise ReservedNameError(
                        "An input called 'config' is implicit in each pipeline "
                        "stage and should not be added explicitly.  Please update "
                        f"your pipeline stage called {cls.name} to remove/rename "
                        "the input called 'config'."
                    )

        # Check if user has over-written the config variable.
        # Quite a common error I make myself.
        if not isinstance(cls.config, property):
            raise ReservedNameError(
                "You have a class variable called 'config', which "
                "is reserved in ceci for its own configuration. "
                "You may have meant to specify config_options?"
            )
        # Find the absolute path to the class defining the file
        path = pathlib.Path(filename).resolve()

        # Register the class
        if stage_is_complete:
            cls.pipeline_stages[cls.name] = (cls, path)
        else:
            cls.incomplete_pipeline_stages[cls.__name__] = (cls, path)

    #############################################
    # Life cycle-related methods and properties.
    #############################################

    @classmethod
    def get_stage(cls, name):
        """
        Return the PipelineStage subclass with the given name.

        This is used so that we do not need a new entry point __main__ function
        for each new stage - instead we can just use a single one which can query
        which class it should be using based on the name.

        Returns
        -------
        cls: class
            The corresponding subclass
        """
        stage = cls.pipeline_stages.get(name)

        # If not found, then check for incomplete stages
        if stage is None:
            if name in cls.incomplete_pipeline_stages:
                raise IncompleteStage(
                    f"The stage {name} is not completely written. "
                    "Stages must specify 'inputs', 'outputs' as class variables "
                    f"and a 'run' method.\n{name} might be unfinished, or it might "
                    "be intended as a base for other classes and not to be run."
                )
            else:
                raise StageNotFound(f"Unknown stage '{name}'")
        else:
            return stage[0]

    @classmethod
    def get_module(cls):
        """
        Return the path to the python package containing the current sub-class

        If we have a PipelineStage subclass defined in a module called "bar", in
        a package called "foo" e.g.:
        /path/to/foo/bar.py  <--   contains subclass "Baz"

        Then calling Baz.get_module() will return "foo.bar".

        We use this later to construct command lines like "python -m foo Baz"

        Returns
        -------
        module: str
            The module containing this class.
        """
        return cls.pipeline_stages[cls.name][0].__module__

    @classmethod
    def usage(cls):
        """
        Print a usage message.
        """
        stage_names = "\n- ".join(cls.pipeline_stages.keys())
        try:
            module = cls.get_module().split(".")[0]
        except:
            module = "<module_name>"
        sys.stderr.write(
            f"""
Usage: python -m {module} <stage_name> <stage_arguments>

If no stage_arguments are given then usage information
for the chosen stage will be given.

I currently know about these stages:
- {stage_names}
"""
        )

    @classmethod
    def main(cls):
        """
        Create an instance of this stage and execute it with
        inputs and outputs taken from the command line
        """
        try:
            stage_name = sys.argv[1]
        except IndexError:
            cls.usage()
            return 1
        if stage_name in ["--help", "-h"] and len(sys.argv) == 2:
            cls.usage()
            return 1
        stage = cls.get_stage(stage_name)
        args = stage._parse_command_line()
        stage.execute(args)
        return 0

    @classmethod
    def _parse_command_line(cls):
        cmd = " ".join(sys.argv[:])
        import argparse

        parser = argparse.ArgumentParser(description=f"Run pipeline stage {cls.name}")
        parser.add_argument("stage_name")
        for conf in cls.config_options:
            def_val = cls.config_options[conf]
            opt_type = def_val if type(def_val) == type else type(def_val)

            if opt_type == bool:
                parser.add_argument(f"--{conf}", action="store_const", const=True)
            elif opt_type == list:
                out_type = def_val[0] if type(def_val[0]) == type else type(def_val[0])
                if out_type is str:
                    parser.add_argument(
                        f"--{conf}", type=lambda string: string.split(",")
                    )
                elif out_type is int:
                    parser.add_argument(
                        f"--{conf}",
                        type=lambda string: [int(i) for i in string.split(",")],
                    )
                elif out_type is float:
                    parser.add_argument(
                        f"--{conf}",
                        type=lambda string: [float(i) for i in string.split(",")],
                    )
                else:
                    raise NotImplementedError(
                        "Only handles str, int and float list arguments"
                    )
            else:
                parser.add_argument(f"--{conf}", type=opt_type)
        for inp in cls.input_tags():
            parser.add_argument(f"--{inp}")
        for out in cls.output_tags():
            parser.add_argument(f"--{out}")
        parser.add_argument("--config")

        if cls.parallel:
            parser.add_argument(
                "--mpi", action="store_true", help="Set up MPI parallelism"
            )
        parser.add_argument(
            "--pdb", action="store_true", help="Run under the python debugger"
        )
        parser.add_argument(
            "--cprofile",
            action="store",
            default="",
            type=str,
            help="Profile the stage using the python cProfile tool",
        )
        args = parser.parse_args()
        return args

    @classmethod
    def execute(cls, args):
        """
        Create an instance of this stage and run it
        with the specified inputs and outputs.

        This is calld by the main method.

        Parameters
        ----------
        args: namespace
            The argparse namespace for this subclass.
        """
        import pdb

        stage = cls(args)

        if stage.rank == 0:
            print(f"Executing stage: {cls.name}")

        if args.cprofile:
            profile = cProfile.Profile()
            profile.enable()

        try:
            stage.run()
        except Exception as error:
            if args.pdb:
                print(
                    "There was an exception - starting python debugger because you ran with --pdb"
                )
                print(error)
                pdb.post_mortem()
            else:
                raise
        try:
            stage.finalize()
        except Exception as error:
            if args.pdb:
                print(
                    "There was an exception in the finalization - starting python debugger because you ran with --pdb"
                )
                print(error)
                pdb.post_mortem()
            else:
                raise
        if args.cprofile:
            profile.disable()
            profile.dump_stats(args.cprofile)
            profile.print_stats("cumtime")

        if stage.rank == 0:
            print(f"Stage complete: {cls.name}")

    def finalize(self):
        """Finalize the stage, moving all its outputs to their final locations."""
        # Synchronize files so that everything is closed
        if self.is_mpi():
            self.comm.Barrier()

        # Move files to their final path
        # only the master process moves things
        if self.rank == 0:
            for tag in self.output_tags():
                # find the old and new names
                temp_name = self.get_output(tag)
                final_name = self.get_output(tag, final_name=True)

                # it's not an error here if the path does not exist,
                # because that will be handled later.
                if pathlib.Path(temp_name).exists():
                    # replace directories, rather than nesting more results
                    if pathlib.Path(final_name).is_dir():
                        shutil.rmtree(final_name)
                    shutil.move(temp_name, final_name)
                else:
                    sys.stderr.write(
                        f"NOTE/WARNING: Expected output file {final_name} was not generated.\n"
                    )

    #############################################
    # Parallelism-related methods and properties.
    #############################################

    @property
    def rank(self):
        """The rank of this process under MPI (0 if not running under MPI)"""
        return self._rank

    @property
    def size(self):
        """The number or processes under MPI (1 if not running under MPI)"""
        return self._size

    @property
    def comm(self):
        """The MPI communicator object (None if not running under MPI)"""
        return self._comm

    def is_parallel(self):
        """
        Returns True if the code is being run in parallel.
        Right now is_parallel() will return the same value as is_mpi(),
        but that may change in future if we implement other forms of
        parallelization.
        """
        return self._parallel != SERIAL

    def is_mpi(self):
        """
        Returns True if the stage is being run under MPI.
        """
        return self._parallel == MPI_PARALLEL

    def split_tasks_by_rank(self, tasks):
        """Iterate through a list of items, yielding ones this process is responsible for/

        Tasks are allocated in a round-robin way.

        Parameters
        ----------
        tasks: iterable
            Tasks to split up

        """
        for i, task in enumerate(tasks):
            if i % self.size == self.rank:
                yield task

    def data_ranges_by_rank(self, n_rows, chunk_rows, parallel=True):
        """Split a number of rows by process.

        Given a total number of rows to read and a chunk size, yield
        the ranges within them that this process should handle.

        Parameters
        ----------
        n_rows: int
            Total number of rows to split up

        chunk_rows: int
            Size of each chunk to be read.

        Parallel: bool
            Whether to split data by rank or just give all procs all data.
            Default=True
        """
        n_chunks = n_rows // chunk_rows
        if n_chunks * chunk_rows < n_rows:
            n_chunks += 1
        if parallel:
            it = self.split_tasks_by_rank(range(n_chunks))
        else:
            it = range(n_chunks)
        for i in it:
            start = i * chunk_rows
            end = min((i + 1) * chunk_rows, n_rows)
            yield start, end

    ##################################################
    # Input and output-related methods and properties.
    ##################################################

    def get_input(self, tag):
        """Return the path of an input file with the given tag"""
        return self._inputs[tag]

    def get_output(self, tag, final_name=False):
        """Return the path of an output file with the given tag

        If final_name is False then use a temporary name - file will
        be moved to its final name at the end
        """
        path = self._outputs[tag]

        # If not the final version, add a tag at the start of the filename
        if not final_name:
            p = pathlib.Path(path)
            p = p.parent / (IN_PROGRESS_PREFIX + p.name)
            path = str(p)
        return path

    def open_input(self, tag, wrapper=False, **kwargs):
        """
        Find and open an input file with the given tag, in read-only mode.

        For general files this will simply return a standard
        python file object.

        For specialized file types like FITS or HDF5 it will return
        a more specific object - see the types.py file for more info.

        """
        path = self.get_input(tag)
        input_class = self.get_input_type(tag)
        obj = input_class(path, "r", **kwargs)

        if wrapper:
            return obj
        else:
            return obj.file

    def open_output(self, tag, wrapper=False, final_name=False, **kwargs):
        """
        Find and open an output file with the given tag, in write mode.

        If final_name is True then they will be opened using their final
        target output name.  Otherwise we will prepend "inprogress_" to their
        file name. This means we know that if the final file exists then it
        is completed.

        If wrapper is True this will return an instance of the class
        of the file as specified in the cls.outputs.  Otherwise it will
        return an open file object (standard python one or something more
        specialized).

        Parameters
        ----------

        tag: str
            Tag as listed in self.outputs

        wrapper: bool
            Default=False.  Whether to return a wrapped file

        final_name: bool
            Default=False. Whether to save to

        **kwargs:
            Extra args are passed on to the file's class constructor.

        """
        path = self.get_output(tag, final_name=final_name)
        output_class = self.get_output_type(tag)

        # HDF files can be opened for parallel writing
        # under MPI.  This checks if:
        # - we have been told to open in parallel
        # - we are actually running under MPI
        # and adds the flags required if all these are true
        run_parallel = kwargs.pop("parallel", False) and self.is_mpi()
        if run_parallel:
            kwargs["driver"] = "mpio"
            kwargs["comm"] = self.comm

            # XXX: This is also not a dependency, but it should be.
            #      Or even better would be to make it a dependency of descformats where it
            #      is actually used.
            import h5py

            if not h5py.get_config().mpi:
                print(
                    dedent(
                        """\
                Your h5py installation is not MPI-enabled.
                Options include:
                  1) Set nprocess to 1 for all stages
                  2) Upgrade h5py to use mpi.  See instructions here:
                     http://docs.h5py.org/en/latest/build.html#custom-installation
                Note: If using conda, the most straightforward way is to enable it is
                    conda install -c spectraldns h5py-parallel
                """
                    )
                )
                raise RuntimeError("h5py module is not MPI-enabled.")

        # Return an opened object representing the file
        obj = output_class(path, "w", **kwargs)
        if wrapper:
            return obj
        else:
            return obj.file

    @classmethod
    def output_tags(cls):
        """
        Return the list of output tags required by this stage
        """
        return [tag for tag, _ in cls.outputs]

    @classmethod
    def input_tags(cls):
        """
        Return the list of input tags required by this stage
        """
        return [tag for tag, _ in cls.inputs]

    def get_input_type(self, tag):
        """Return the file type class of an input file with the given tag."""
        for t, dt in self.inputs:
            if t == tag:
                return dt
        raise ValueError(f"Tag {tag} is not a known input")

    def get_output_type(self, tag):
        """Return the file type class of an output file with the given tag."""
        for t, dt in self.outputs:
            if t == tag:
                return dt
        raise ValueError(f"Tag {tag} is not a known output")

    ##################################################
    # Configuration-related methods and properties.
    ##################################################

    @property
    def config(self):
        """
        Returns the configuration dictionary for this stage, aggregating command
        line options and optional configuration file.
        """
        return self._configs

    def read_config(self, args):
        """
        This function looks for the arguments of the pipeline stage using a
        combination of default values, command line options and separate
        configuration file.

        The order for resolving config options is first looking for a default
        value, then looking for a

        In case a mandatory argument (argument with no default) is missing,
        an exception is raised.

        Note that we recognize arguments with no default as the ones where
        self.config_options holds a type instead of a value.
        """
        # Try to load configuration file if provided
        import yaml

        # This is all the config information in the file, including
        # things for other stages
        overall_config = yaml.safe_load(open(self.get_input("config")))

        # The user can define global options that are inherited by
        # all the other sections if not already specified there.
        input_config = overall_config.get("global", {})

        # This is just the config info in the file for this stage.
        # It may be incomplete - there may be things specified on the
        # command line instead, or just using their default values
        stage_config = overall_config.get(self.name, {})
        input_config.update(stage_config)

        # Here we build up the actual configuration we use on this
        # run from all these sources
        my_config = {}

        # Loop over the options of the pipeline stage
        for x in self.config_options:
            opt = None
            opt_type = None

            # First look for a default value,
            # if a type (like int) is provided as the default it indicates that
            # this option doesn't have a default (i.e. is mandatory) and should
            # be explicitly provided with the specified type
            if type(self.config_options[x]) is type:
                opt_type = self.config_options[x]

            elif type(self.config_options[x]) is list:
                v = self.config_options[x][0]
                if type(v) is type:
                    opt_type = v
                else:
                    opt = self.config_options[x]
                    opt_type = type(v)
            else:
                opt = self.config_options[x]
                opt_type = type(opt)

            # Second, look for the option in the configuration file and override
            # default if provided TODO: Check types
            if x in input_config:
                opt = input_config[x]

            # Finally check for command line option that would override the value
            # in the configuration file. Note that the argument parser should
            # already have taken care of type
            if args[x] is not None:
                opt = args[x]

            # Finally, check that we got at least some value for this option
            if opt is None:
                raise ValueError(
                    f"Missing configuration option {x} for stage {self.name}"
                )

            my_config[x] = opt

        # Unspecified parameters can also be copied over.
        # This will be needed for parameters that are more complicated, such
        # as dictionaries or other more structured parameter information.
        for x, val in input_config.items():
            # Omit things we've already dealt with above
            if x in self.config_options:
                continue
            # copy over everything else
            else:
                my_config[x] = val

        return my_config

    def iterate_fits(self, tag, hdunum, cols, chunk_rows, parallel=True):
        """
        Loop through chunks of the input data from a FITS file with the given tag

        TODO: add ceci tests of this functions
        Parameters
        ----------
        tag: str
            The tag from the inputs list to use

        hdunum: int
            The extension number to read

        cols: list
            The columns to read

        chunk_rows: int
            Number of columns to read and return at once

        parallel: bool
            Whether to split up data among processes (parallel=True) or give
            all processes all data (parallel=False).  Default = True.

        Returns
        -------
        it: iterator
            Iterator yielding (int, int, array) tuples of (start, end, data)
            data is a structured array.
        """
        fits = self.open_input(tag)
        ext = fits[hdunum]
        n = ext.get_nrows()
        for start, end in self.data_ranges_by_rank(n, chunk_rows, parallel=True):
            data = ext.read_columns(cols, rows=range(start, end))
            yield start, end, data

    def iterate_hdf(self, tag, group_name, cols, chunk_rows, parallel=True):
        """
        Loop through chunks of the input data from an HDF5 file with the given tag.

        All the selected columns must have the same length.

        Parameters
        ----------
        tag: str
            The tag from the inputs list to use

        group: str
            The group within the HDF5 file to use, looked up as
            file[group]

        cols: list
            The columns to read

        chunk_rows: int
            Number of columns to read and return at once

        parallel: bool
            Whether to split up data among processes (parallel=True) or give
            all processes all data (parallel=False).  Default = True.

        Returns
        -------
        it: iterator
            Iterator yielding (int, int, dict) tuples of (start, end, data)
        """
        import numpy as np

        hdf = self.open_input(tag)
        group = hdf[group_name]

        # Check all the columns are the same length
        N = [len(group[col]) for col in cols]
        n = N[0]
        if not np.equal(N, n).all():
            raise ValueError(
                f"Different columns among {cols} in file {tag}\
            group {group_name} are different sizes - cannot use iterate_hdf"
            )

        # Iterate through the data providing chunks
        for start, end in self.data_ranges_by_rank(n, chunk_rows, parallel=parallel):
            data = {col: group[col][start:end] for col in cols}
            yield start, end, data

    ################################
    # Pipeline-related methods
    ################################

    @classmethod
    def generate_command(cls, inputs, config, outputs):
        """
        Generate a command line that will run the stage
        """
        module = cls.get_module()
        module = module.split(".")[0]

        flags = [cls.name]

        for tag, ftype in cls.inputs:
            try:
                fpath = inputs[tag]
            except KeyError:
                raise ValueError(f"Missing input location {tag}")
            flags.append(f"--{tag}={fpath}")

        flags.append(f"--config={config}")

        for tag, ftype in cls.outputs:
            try:
                fpath = outputs[tag]
            except:
                raise ValueError(f"Missing output location {tag}")
            flags.append(f"--{tag}={fpath}")

        flags = "   ".join(flags)

        # We just return this, instead of wrapping it in a
        # parsl job
        cmd = f"python3 -m {module} {flags}"
        return cmd

    @classmethod
    def generate_cwl(cls, log_dir=None):
        """
        Produces a CWL App object which can then be exported to yaml
        """
        import cwlgen

        module = cls.get_module()
        module = module.split(".")[0]

        # Basic definition of the tool
        cwl_tool = cwlgen.CommandLineTool(
            tool_id=cls.name,
            label=cls.name,
            base_command="python3",
            cwl_version="v1.0",
            doc=cls.__doc__,
        )
        if log_dir is not None:
            cwl_tool.stdout = f"{cls.name}.out"
            cwl_tool.stderr = f"{cls.name}.err"

        # Adds the first input binding with the name of the module and pipeline stage
        input_arg = cwlgen.CommandLineBinding(position=-1, value_from=f"-m{module}")
        cwl_tool.arguments.append(input_arg)
        input_arg = cwlgen.CommandLineBinding(position=0, value_from=f"{cls.name}")
        cwl_tool.arguments.append(input_arg)

        type_dict = {int: "int", float: "float", str: "string", bool: "boolean"}
        # Adds the parameters of the tool
        for opt in cls.config_options:
            def_val = cls.config_options[opt]

            # Handles special case of lists:
            if type(def_val) is list:
                v = def_val[0]
                param_type = {
                    "type": "array",
                    "items": type_dict[v] if type(v) == type else type_dict[type(v)],
                }
                default = def_val if type(v) != type else None
                input_binding = cwlgen.CommandLineBinding(
                    prefix="--{}=".format(opt), item_separator=",", separate=False
                )
            else:
                param_type = (
                    type_dict[def_val]
                    if type(def_val) == type
                    else type_dict[type(def_val)]
                )
                default = def_val if type(def_val) != type else None
                if param_type == "boolean":
                    input_binding = cwlgen.CommandLineBinding(prefix="--{}".format(opt))
                else:
                    input_binding = cwlgen.CommandLineBinding(
                        prefix="--{}=".format(opt), separate=False
                    )

            input_param = cwlgen.CommandInputParameter(
                opt,
                label=opt,
                param_type=param_type,
                input_binding=input_binding,
                default=default,
                doc="Some documentation about this parameter",
            )

            # We are bypassing the cwlgen builtin type check for the special case
            # of arrays until that gets added to the standard
            if type(def_val) is list:
                input_param.type = param_type

            cwl_tool.inputs.append(input_param)

        # Add the inputs of the tool
        for i, inp in enumerate(cls.input_tags()):
            input_binding = cwlgen.CommandLineBinding(prefix="--{}".format(inp))
            input_param = cwlgen.CommandInputParameter(
                inp,
                label=inp,
                param_type="File",
                param_format=cls.inputs[i][1].format,
                input_binding=input_binding,
                doc="Some documentation about the input",
            )
            cwl_tool.inputs.append(input_param)

        # Adds the overall configuration file
        input_binding = cwlgen.CommandLineBinding(prefix="--config")
        input_param = cwlgen.CommandInputParameter(
            "config",
            label="config",
            param_type="File",
            param_format="http://edamontology.org/format_3750",
            input_binding=input_binding,
            doc="Configuration file",
        )
        cwl_tool.inputs.append(input_param)

        # Add the definition of the outputs
        for i, out in enumerate(cls.output_tags()):
            output_name = cls.outputs[i][1].make_name(out)
            output_binding = cwlgen.CommandOutputBinding(glob=output_name)
            output = cwlgen.CommandOutputParameter(
                out,
                label=out,
                param_type="File",
                output_binding=output_binding,
                param_format=cls.outputs[i][1].format,
                doc="Some results produced by the pipeline element",
            )
            cwl_tool.outputs.append(output)

        if log_dir is not None:
            output = cwlgen.CommandOutputParameter(
                f"{cls.name}@stdout",
                label="stdout",
                param_type="stdout",
                doc="Pipeline elements standard output",
            )
            cwl_tool.outputs.append(output)
            error = cwlgen.CommandOutputParameter(
                f"{cls.name}@stderr",
                label="stderr",
                param_type="stderr",
                doc="Pipeline elements standard output",
            )
            cwl_tool.outputs.append(error)

        # Potentially add more metadata
        # This requires a schema however...
        # metadata = {'name': cls.name,
        #         'about': 'Some additional info',
        #         'publication': [{'id': 'one_doi'}, {'id': 'another_doi'}],
        #         'license': ['MIT']}
        # cwl_tool.metadata = cwlgen.Metadata(**metadata)

        return cwl_tool


# -*- coding: utf-8 -*-
"""
Created on Fri Jun  7 12:07:40 2019

@author: lenovo
"""
'''

Code Challenge
  Name:
    Regular Expression 4
  Filename:
    regex4.py
  Problem Statement:
    You are given email addresses.
    Your task is to print a list containing only valid email addresses in lexicographical order .
    (Take input from User)

    Valid email addresses must follow these rules:

    It must have the username@websitename.extension format type.
    The username can only contain letters, digits, dashes and underscores.
    The website name can only have letters and digits.
    The maximum length of the extension is

  Hint:
    Using Regular Expression
  Input:
    ajeet@forsk.com
    kunal-23@forsk.com
    yogendra_54@forsk.com
  Output:
    ['ajeet@forsk.com', 'kunal-23@forsk.com', 'yogendra_54@forsk.com’]
'''

import re
userinput = input("enter a email = ").split(",")
for i in userinput:
    if (re.match(r'^[a-zA-Z\d\_\-]+@[a-zA-Z\d]+\.[a-z]{2,4}$',i)):
        print (i)
    else:
        print("invalid email")


import re
from src.token_ import Token_

class Validator:
    def __init__(self):
        self.token_types = {
            "<NUMBER>": {"validate": Validator.is_number},
            # "<DIGIT>": {"validate": Validator.is_digit},
            "<OPEN_PARENTHESIS>": {},
            "<CLOSE_PARENTHESIS>": {},
            "<PLUS_SIGN>": {},
            "<MINUS_SIGN>": {},
            "<MULTIPLICATION_SIGN>": {},
            "<DIVISION_SIGN>": {},
            "<EQUALS_SIGN>": {},
            "<MULTI_LINE_COMMENT>": {},
            "<SINGLE_LINE_COMMENT>" "<CHARACTER>": {},
            "<IDENTIFIER>": {"validate": Validator.is_identifier},
            "<COMMAND_END>": {"validate": Validator.is_command_end},
            "<SIMPLE_TYPE>": {"validate": Validator.is_simple_type},
            "<COLON>":{"validate":Validator.is_colon}
        }
        self.validators = [
            Validator.is_number,
            Validator.is_relation,
            # Validator.is_digit,
            Validator.is_identifier,
            Validator.is_plus_sign,
            Validator.is_minus_sign,
            Validator.is_multiplication_sign,
            Validator.is_division_sign,
            Validator.is_open_parenthesis,
            Validator.is_close_parenthesis,
            Validator.is_simple_type,
            Validator.is_keyword,
            Validator.is_command_end,
            Validator.is_comma,
            Validator.is_colon,
            Validator.is_dot,
            Validator.is_equals_sign,
            Validator.is_simple_type,
        ]
        self.token_validators = [
            Validator.is_identifier_list,
            Validator.is_var_declaration,
            Validator.is_simple_type,
            Validator.is_part_var_declaration,
            Validator.is_formal_parameter_section,
            Validator.is_formal_parameters,
            Validator.is_procedure_declaration,
            Validator.is_subroutines_declaration_part,
            Validator.is_program,
            Validator.is_factor,
            Validator.is_therm,
            Validator.is_simple_expression,
            Validator.is_expression,
            Validator.is_expression_list,
            # Validator.is_variable,
        ]

    def validate_lexem(self, lexem: str) -> dict:
        try:
            return list(
                filter(
                    lambda x: x[lexem] != None,
                    [validator(lexem) for validator in self.validators],
                )
            ).pop()

        except Exception as inst:
            # print(inst)
            return {lexem: None}

    def validate_token(self, tk_list: list) -> Token_:
        # print(tk_list)
        try:
            return list(
                filter(
                    lambda x: x.token != None,
                    [validator(tk_list) for validator in self.token_validators],
                )
            ).pop()
        except Exception as inst:
            # print(inst)
            return Token_("", None, None)

    def validate_lexems(self, lexem_list: list) -> list:
        return [self.validate_lexem(lexem) for lexem in lexem_list]

    @classmethod
    def is_number(cls, value: str) -> dict:
        digit_pattern = re.compile("[0-9][0-9]*")
        check = lambda x: {x: "<NUMBER>"} if digit_pattern.fullmatch(x) else {x: None}
        return check(value)

    @classmethod
    def is_plus_sign(cls, value: str) -> dict:
        plus_sign_pattern = re.compile("[+]")
        check = (
            lambda x: {x: "<PLUS_SIGN>"}
            if plus_sign_pattern.fullmatch(x)
            else {x: None}
        )
        return check(value)

    @classmethod
    def is_minus_sign(cls, value: str) -> dict:
        plus_sign_pattern = re.compile("-")
        check = (
            lambda x: {x: "<MINUS_SIGN>"}
            if plus_sign_pattern.fullmatch(x)
            else {x: None}
        )
        return check(value)

    @classmethod
    def is_multiplication_sign(cls, value: str) -> dict:
        multiplication_sign_pattern = re.compile("[*]")
        check = (
            lambda x: {x: "<MULTIPLICATION_SIGN>"}
            if multiplication_sign_pattern.fullmatch(x)
            else {x: None}
        )
        return check(value)

    @classmethod
    def is_division_sign(cls, value: str) -> dict:
        division_sign_pattern = re.compile("div")
        check = (
            lambda x: {x: "<DIVISION_SIGN>"}
            if division_sign_pattern.fullmatch(x)
            else {x: None}
        )
        return check(value)

    @classmethod
    def is_equals_sign(cls, value: str) -> dict:
        equals_sign_pattern = re.compile("\:=")
        check = (
            lambda x: {x: "<EQUALS_SIGN>"}
            if equals_sign_pattern.fullmatch(x)
            else {x: None}
        )
        return check(value)

    @classmethod
    def is_open_parenthesis(cls, value: str) -> dict:
        open_parenthesis_pattern = re.compile("[(]")
        check = (
            lambda x: {x: "<OPEN_PARENTHESIS>"}
            if open_parenthesis_pattern.fullmatch(x)
            else {x: None}
        )
        return check(value)

    @classmethod
    def is_close_parenthesis(cls, value: str) -> dict:
        close_parenthesis_pattern = re.compile("[)]")
        check = (
            lambda x: {x: "<CLOSE_PARENTHESIS>"}
            if close_parenthesis_pattern.fullmatch(x)
            else {x: None}
        )
        return check(value)

    @classmethod
    def is_command_end(cls, value: str) -> dict:
        close_parenthesis_pattern = re.compile("\;")
        check = (
            lambda x: {x: "<COMMAND_END>"}
            if close_parenthesis_pattern.fullmatch(x)
            else {x: None}
        )
        return check(value)

    @classmethod
    def is_comma(cls, value: str) -> dict:
        close_parenthesis_pattern = re.compile("\,")
        check = (
            lambda x: {x: "<COMMA>"}
            if close_parenthesis_pattern.fullmatch(x)
            else {x: None}
        )
        return check(value)

    @classmethod
    def is_colon(cls, value: str) -> dict:
        close_parenthesis_pattern = re.compile("\:")
        check = (
            lambda x: {x: "<COLON>"}
            if close_parenthesis_pattern.fullmatch(x)
            else {x: None}
        )
        return check(value)

    @classmethod
    def is_dot(cls, value: str) -> dict:
        close_parenthesis_pattern = re.compile("\.")
        check = (
            lambda x: {x: "<DOT>"}
            if close_parenthesis_pattern.fullmatch(x)
            else {x: None}
        )
        return check(value)

    @classmethod
    def is_identifier(cls, value: str) -> dict:
        identifier = re.compile("[_|a-z|A-Z]([_|a-z|A-Z]|[0-9])*")
        check = lambda x: {x: "<IDENTIFIER>"} if identifier.fullmatch(x) else {x: None}
        return check(value)

    @classmethod
    def is_simple_type(cls, value: str) -> dict:
        simple_types = ["int", "real", "boolean"]
        check = lambda x: {x: "<SIMPLE_TYPE>"} if value in simple_types else {x: None}
        return check(value)

    @classmethod
    def is_relation(cls, value: str) -> dict:
        relations = ["==", "<>", "<", "<=", ">=", ">"]
        check = lambda x: {x: "<RELATION>"} if value in relations else {x: None}
        return check(value)

    @classmethod
    def is_bool_value(cls, value: str) -> dict:
        booleans = ["true", "false"]
        check = lambda x: {x: "<BOOL_VALUE>"} if value in booleans else {x: None}
        return check(value)

    @classmethod
    def is_keyword(cls, value: str) -> dict:
        keyword = [
            "program",
            "procedure",
            "var",
            "begin",
            "end",
            "if",
            "then",
            "else",
            "while",
            "do",
            "and",
            "or",
            "not",
        ]
        check = (
            lambda x: {x: "<KEYWORD_" + x.upper() + ">"}
            if value in keyword
            else {x: None}
        )
        return check(value)

    @classmethod
    def is_identifier_list(cls, tk_list: list) -> dict:
        checked = False
        i = 0
        while True:
            if i < len(tk_list):
                # print(i, i+1)
                if tk_list[i] == "<IDENTIFIER>":
                    checked = True
                else:
                    break
                if i + 1 < len(tk_list) and tk_list[i + 1] == "<COMMA>":
                    checked = False
                    i += 1
            else:
                break
            i += 1
        if checked:
            return Token_(tk_list, "<IDENTIFIER_LIST>", None)
        else:
            return Token_("", None, None)

    @classmethod
    def is_var_declaration(cls, tk_list: list) -> dict:
        if (
            tk_list[0] == "<SIMPLE_TYPE>"
            and tk_list[-1] == "<COMMAND_END>"
            and cls.is_identifier_list(tk_list[1:-1])
        ):
            return Token_("", "<VAR_DECLARATION>", None)
        return Token_("", None, None)

    @classmethod
    def is_part_var_declaration(cls, tk_list: list) -> dict:
        checked = False
        i = 0
        while True:
            if i < len(tk_list):
                if tk_list[i] == "<VAR_DECLARATION>":
                    checked = True
                else:
                    break
                if i + 1 < len(tk_list) and tk_list[i + 1] == "<COMMAND_END>":
                    checked = False
                    i += 1
            else:
                break
            i += 1
        if checked:
            return Token_(tk_list, "<VAR_DECLARATION_PART>", None)
        else:
            return Token_("", None, None)

    @classmethod
    def is_formal_parameter_section(cls, tk_list: list) -> dict:
        i = 1 if tk_list[0] == "<KEYWORD_VAR>" else 0
        if (
            len(tk_list) > 2
            and tk_list[i] == "<IDENTIFIER_LIST>"
            and tk_list[-2] == "<COLON>"
            and tk_list[-1] == "<SIMPLE_TYPE>"
        ):
            return Token_("", "<FORMAL_PARAMETERS_SECTION>", None)
        return Token_("", None, None)

    @classmethod
    def is_formal_parameters(cls, tk_list: list) -> dict:
        if (
            len(tk_list) > 2
            and tk_list[0] == "<OPEN_PARENTHESIS>"
            and tk_list[-1] == "<CLOSE_PARENTHESIS>"
        ):
            checked = False
            i = 1
            while True:
                if i < len(tk_list) - 1:
                    print(tk_list[i], tk_list[i + 1])
                    if tk_list[i] == "<FORMAL_PARAMETERS_SECTION>":
                        checked = True
                    else:
                        break
                    if i + 1 < len(tk_list) - 1:
                        checked = False
                        if tk_list[i + 1] != "<COMMAND_END>":
                            break
                else:
                    break
                i += 2
            if checked:
                return Token_("", "<FORMAL_PARAMETERS>", None)

        return Token_("", None, None)

    @classmethod
    def is_procedure_declaration(cls, tk_list: list) -> dict:
        if (
            3 < len(tk_list) <= 5
            and tk_list[0] == "<KEYWORD_PROCEDURE>"
            and tk_list[1] == "<IDENTIFIER>"
            and tk_list[-2] == "<COMMAND_END>"
            and tk_list[-1] == "<BLOC>"
        ):
            if len(tk_list) == 5 and tk_list[2] != "<FORMAL_PARAMETERS>":
                return Token_("", None, None)
            return Token_("", "<PROCEDURE_DECLARATION>", None)
        return Token_("", None, None)

    @classmethod
    def is_subroutines_declaration_part(cls, tk_list: list) -> dict:
        i = 0
        checked = True
        while True:
            if i < len(tk_list):
                if (
                    tk_list[i] != "<PROCEDURE_DECLARATION>"
                    or tk_list[i + 1] != "<COMMAND_END>"
                ):
                    checked = False
            else:
                break
            i += 2
        if checked:
            return Token_(tk_list, "<SUBROUTINES_DECLARATION_PART>", None)
        else:
            return Token_("", None, None)

    @classmethod
    def is_program(cls, tk_list: list) -> Token_:
        if (
            len(tk_list) == 5
            and tk_list[0] == "<KEYWORD_PROGRAM>"
            and tk_list[1] == "<IDENTIFIER>"
            and tk_list[2] == "<COMMAND_END>"
            and tk_list[3] == "<BLOC>"
            and tk_list[4] == "<DOT>"
        ):
            return Token_("", "<PROGRAM>", None)
        return Token_("", None, None)

    @classmethod
    def is_factor(cls, tk_list: list) -> Token_:

        if (
            tk_list == ["<VARIABLE>"]
            or tk_list == ["<NUMBER>"]
            or tk_list == ["<OPEN_PARENTHESIS>", "<EXPRESSION>", "<CLOSE_PARENTHESIS>"]
            or tk_list == ["<KEYWORD_NOT>", "<FACTOR>"]
        ):
            return Token_("", "<FACTOR>", None)
        return Token_("", None, None)

    @classmethod
    def is_therm(cls, tk_list: list) -> Token_:
        len_tk_list = len(tk_list)
        if len_tk_list >= 1 and tk_list[0] == "<FACTOR>":
            i = 1
            checked = True
            while True:
                if i < len_tk_list:

                    if not (
                        tk_list[i]
                        in ["<MULTIPLICATION_SIGN>", "<DIVISION_SIGN>", "<KEYWORD_AND>"]
                        and (i + 1 < len_tk_list and tk_list[i + 1] == "<FACTOR>")
                    ):
                        checked = False
                        break
                else:
                    break
                i += 2
            if checked:
                return Token_(tk_list, "<THERM>", None)

        return Token_("", None, None)

    @classmethod
    def is_simple_expression(cls, tk_list: list) -> Token_:
        len_tk_list = len(tk_list)

        if len_tk_list >= 1 and tk_list[0] in [
            "<THERM>",
            "<PLUS_SIGN>",
            "<MINUS_SIGN>",
        ]:
            i = 1
            if tk_list[0] != "<THERM>":
                i += 1
                if tk_list[1] != "<THERM>":
                    return Token_("", None, None)

            checked = True
            while True:
                if i < len_tk_list:

                    if not (
                        tk_list[i] in ["<PLUS_SIGN>", "<MINUS_SIGN>", "<KEYWORD_OR>"]
                        and (i + 1 < len_tk_list and tk_list[i + 1] == "<THERM>")
                    ):
                        checked = False
                        break
                else:
                    break
                i += 2

            if checked:
                return Token_(tk_list, "<SIMPLE_EXPRESSION>", None)

        return Token_("", None, None)

    @classmethod
    def is_expression(cls, tk_list: list) -> Token_:
        len_tk_list = len(tk_list)

        if len_tk_list >= 1 and tk_list[0] == "<SIMPLE_EXPRESSION>":
            i = 1
            checked = True
            while i < len_tk_list:

                if not (
                    tk_list[i] == "<RELATION>"
                    and (
                        i + 1 < len_tk_list and tk_list[i + 1] == "<SIMPLE_EXPRESSION>"
                    )
                ):
                    checked = False
                    break

                i += 2

            if checked:
                return Token_(tk_list, "<SIMPLE_EXPRESSION>", None)

        return Token_("", None, None)

    @classmethod
    def is_expression_list(cls, tk_list: list):
        checked = False
        i = 0
        while True:
            if i < len(tk_list):
                # print(i, i+1)
                if tk_list[i] == "<EXPRESSION>":
                    checked = True
                else:
                    break
                if i + 1 < len(tk_list) and tk_list[i + 1] == "<COMMA>":
                    checked = False
                    i += 1
            else:
                break
            i += 1
        if checked:
            return Token_(tk_list, "<EXPRESSION_LIST>", None)
        else:
            return Token_("", None, None)

    @classmethod
    def is_variable(cls, tk_list: list) -> Token_:
        if tk_list == ["<IDENTIFIER>"] or tk_list == ["<IDENTIFIER>", "<EXPRESSION>"]:
            return Token_(tk_list, "<VARIABLE>", None)
        return Token_(tk_list, None, None)

if __name__ == "__main__":
    lexems = [
        "_",
        "_a",
        "a1",
        "1",
        "a111*",
        " ",
        "a_1",
        "#$&",
    ]
    validator = Validator()
    print(validator.validate_lexems(lexems))


'''
Created by auto_sdk on 2015.08.17
'''
from top.api.base import RestApi
class WlbWmsStockPruductProcessingNotifyRequest(RestApi):
	def __init__(self,domain='gw.api.taobao.com',port=80):
		RestApi.__init__(self,domain, port)
		self.extend_fields = None
		self.material_items = None
		self.order_code = None
		self.order_create_time = None
		self.order_type = None
		self.plan_qty = None
		self.plan_work_time = None
		self.product_items = None
		self.remark = None
		self.service_type = None
		self.store_code = None

	def getapiname(self):
		return 'taobao.wlb.wms.stock.pruduct.processing.notify'


#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  wt_tempSensor.py
#
#  Copyright 2017 Francesco Antoniazzi <francesco.antoniazzi@unibo.it>
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#  MA 02110-1301, USA.
#
#

import colorama
from colorama import Fore, Style
import logging
from wot_init import *
from webthing import *
from time import sleep

logging.basicConfig(format=LOGFORMAT,level=LOGLEVEL)

LEGGI_TEMPERATURA = "LeggiTemperatura"
NUOVA_TEMPERATURA = "NuovaTemperatura"

wt = WebThing(JSAP,JPAR,name="Termometro",uri="wot:Thermometer")
temperatura = Property(wt,"Temperatura",uri="wot:Temperatura",dataschema="float",writable=False,value="15.0")
leggi = Action(wt,name="LeggiTemperatura",uri="wot:LeggiTemperatura")
comunica = Event(wt,name="3sTemperatura",uri="wot:3sTemperatura",out_dataschema="float")

class ActionRequestHandler:
	def __init__(self):
		pass
	def handle(self, added, removed):
		for item in added:
			print(item)

def get_actual_value():
	# in questa funzione ci dovrebbe essere la comunicazione fisica con
	# il sensore per ricavare la temperatura
	return temperatura.value

if __name__ == '__main__':
	import sys

	wt.add_property(temperatura)
	wt.add_action(leggi)
	wt.add_event(comunica)
	wt.add_forProperty(leggi,temperatura)
	wt.add_forProperty(comunica,temperatura)

	wt.post()

	wt.listenForActionRequests(ActionRequestHandler())

	colorama.init()
	print(Fore.RED + "Waiting for action requests..." + Style.RESET_ALL)

	while True:
		try:
			sleep(5)
			comunica.throwNewEvent(output_value=get_actual_value())
		except KeyboardInterrupt:
			print("CTRL-C pressed! Bye!")
			sys.exit(0)


#!/usr/bin/python3
from random import choice
print ("Love calculator")

nameone=str(input("Enter the first name: "))
nametwo=str(input("Enter the second name: "))
bad=str(" You're shit outta luck fam")
good=str(" Impregnate each other")
percent=(choice(range(1,101)))
symbol=("%")

if percent < 49:
    percent=str(percent)
    print (percent + symbol + bad)
else:
    percent=str(percent)
    print (percent + symbol + good)


import numpy as np
import os

# Constants for printing graphs to terminal
CREDBG    = '\33[41m'
CBLUEBG   = '\33[44m'
CEND  = '\033[0m'

# Ensure that a grid location is in bounds
def check_bounds(val, N):
    return val > -1 and val < N

# Returns number of units in component -- used to check district connectivity
def count_component_size(grid, stack, component_id):
    N = len(grid)
    marks = np.zeros(grid.shape, dtype=np.int32)
    elems = 0
    while len(stack) > 0:
        v = stack.pop()
        x = v[0]
        y = v[1]
        marks[x, y] = 1
        elems +=+ 1
        for increment in (-1, 1):
            if check_bounds(x+increment, N) and marks[x+increment, y] == 0 and grid[x+increment, y] == component_id:
                stack.append((x+increment, y))
                marks[x+increment, y] = 1
            if check_bounds(y+increment, N) and marks[x, y+increment] == 0  and grid[x, y+increment] == component_id:
                stack.append((x, y+increment))
                marks[x, y+increment] = 1
    return elems

# Further experiment: modify to locate an element on the boundary for faster feasible proposals
def locate_random_element(grid, component_id, rng):
    N = len(grid)
    loc = rng.integers(N, size=2)
    while(grid[loc[0], loc[1]] != component_id):
        loc = rng.integers(N, size=2)
    return loc

# Give proposed sources for the DFS so that we can stop unproductive searches early.
def check_connectivity(grid, rng, loc_zero, loc_one):
    N = len(grid)
    return count_component_size(grid, [loc_zero], 0) == N * N / 2 and count_component_size(grid, [loc_one], 1) == N * N / 2

def propose_flip(grid, rng):
    proposal = [[-1, -1], [-1, -1]]
    while(proposal[0][0] == -1):
        loc_zero = locate_random_element(grid, 0, rng)
        loc_one = locate_random_element(grid, 1, rng)
        grid[loc_zero[0], loc_zero[1]] = 1
        grid[loc_one[0], loc_one[1]] = 0
        if(check_connectivity(grid, rng, loc_one, loc_zero)):
            proposal = [loc_zero, loc_one]
        grid[loc_zero[0], loc_zero[1]] = 0
        grid[loc_one[0], loc_one[1]] = 1
    return proposal

def is_on_boundary(grid, location):
    N = len(grid)
    x = location[0]
    y = location[1]
    component_id = grid[x, y]
    for increment in (-1, 1):
        if check_bounds(x+increment, N) and grid[x+increment, y] != component_id:
            return 1
        if check_bounds(y+increment, N) and grid[x, y+increment] != component_id:
            return 1
    return 0

def count_boundary_edges(grid, location):
    N = len(grid)
    x = location[0]
    y = location[1]
    component_id = grid[x, y]
    edges = 0
    for increment in (-1, 1):
        if check_bounds(x+increment, N) and grid[x+increment, y] != component_id:
            edges += 1
        if check_bounds(y+increment, N) and grid[x, y+increment] != component_id:
            edges += 1
    return edges

# Change in number of boundary edges
def calc_change_boundary(grid, proposed_flip):
    N = len(grid)
    loc_zero = proposed_flip[0]
    loc_one = proposed_flip[1]

    delta_boundary_districts = 0
    delta_boundary_edges = 0
    for loc in (loc_zero, loc_one):
        delta_boundary_edges -= count_boundary_edges(grid, loc)
        x = loc[0]
        y = loc[1]
        for increment in (-1, 1):
            if check_bounds(x+increment, N):
                delta_boundary_districts -= is_on_boundary(grid, [x+increment, y])
            if check_bounds(y+increment, N):
                delta_boundary_districts -= is_on_boundary(grid, [x, y+increment])
        delta_boundary_districts -= is_on_boundary(grid, [x, y])

    grid[loc_zero[0], loc_zero[1]] = 1
    grid[loc_one[0], loc_one[1]] = 0

    for loc in (loc_zero, loc_one):
        delta_boundary_edges += count_boundary_edges(grid, loc)
        x = loc[0]
        y = loc[1]
        for increment in (-1, 1):
            if check_bounds(x+increment, N):
                delta_boundary_districts += is_on_boundary(grid, [x+increment, y])
            if check_bounds(y+increment, N):
                delta_boundary_districts += is_on_boundary(grid, [x, y+increment])
        delta_boundary_districts += is_on_boundary(grid, [x, y])

    grid[loc_zero[0], loc_zero[1]] = 0
    grid[loc_one[0], loc_one[1]] = 1

    # Normalize so that these are on roughly similar scales.  Constant found through experimentation
    return delta_boundary_edges / 4 + delta_boundary_districts

def perform_flip(grid, lam, rng):
    proposal = propose_flip(grid, rng)
    change_boundary = calc_change_boundary(grid, proposal)
    if change_boundary <= 0 or rng.random() < lam ** change_boundary:
        loc_zero = proposal[0]
        loc_one = proposal[1]
        grid[loc_zero[0], loc_zero[1]] = 1
        grid[loc_one[0], loc_one[1]] = 0
        return True
    return False

def anneal(grid, temp_fun, goal_fun, rng, max_iters):
    successful = False
    for i in range(max_iters):
        if i % 1000 == 0:
            print("Progress Check! i =", i)
            pretty_print_grid(grid)
        temp = temp_fun(i)
        res = perform_flip(grid, temp, rng)
        # Don't check when temp = 1, you will never be meeting the goal in the pure mixing phase
        # Don't check when not accepted, as this will never achieve the goal
        if(res and temp < 1 and goal_fun(grid)):
            print("Objective Achieved!")
            pretty_print_grid(grid)
            successful = True
            break
    if not successful:
        print("Annealing was Unsuccessful.  Printing grid now")
        pretty_print_grid(grid)
    return successful

# If the middle row is totally correct then we must have a horizontal split
# In practice it's infeasible to expect exactly this.
def is_horizontal_split(grid):
    N = len(grid)
    x = 0
    y = N // 2 - 1
    component_id = grid[y, x]
    while(grid[y, x] == component_id):
        x = x + 1
        if x == N:
            return True
    return False

# Generates linear-type temperature functions, with short periods of pure mixing and pure hill-climb at the beginning and end
def linear_temp_generator(period):
    return lambda t: 1 if t % period < period / 10 else 0 if t % period > 9 * period / 10 else 1 - (t % period - period / 10) / (4 * period / 5)

def steep_linear_temp_generator(period):
    return lambda t: 1 if t % period < period / 5 else 0 if t % period > 4 * period / 5 else 1 - (t % period - period / 5) / (3 * period / 5)

def all_or_nothing_linear_temp_generator(period):
    return lambda t: 1 if t < period / 4 else 0

def pretty_print_grid(grid):
    N = len(grid)
    for i in range(N):
        for j in range(N):
            print((CREDBG if grid[i, j] == 1 else CBLUEBG) + "  " + CEND, end="")
        print("")

# Was able to achieve this flip around 4000 iterations
def six_flip_run():
    rng = np.random.default_rng(0)
    N = 6
    row = np.hstack((np.ones(N//2, dtype=np.int32), np.zeros(N//2, dtype=np.int32)))
    grid = np.tile(row, (N, 1))
    anneal(grid, linear_temp_generator(10000), is_horizontal_split, rng, 100000)

# Was able to achieve this flip around 13000 iterations
def ten_flip_run():
    rng = np.random.default_rng(3)
    N = 10
    row = np.hstack((np.ones(N//2, dtype=np.int32), np.zeros(N//2, dtype=np.int32)))
    grid = np.tile(row, (N, 1))
    anneal(grid, linear_temp_generator(20000), is_horizontal_split, rng, 100000)

# Was able to achieve this flip around 16000 iterations
def sixteen_flip_run():
    rng = np.random.default_rng(3)
    N = 16
    row = np.hstack((np.ones(N//2, dtype=np.int32), np.zeros(N//2, dtype=np.int32)))
    grid = np.tile(row, (N, 1))
    anneal(grid, all_or_nothing_linear_temp_generator(40000), is_horizontal_split, rng, 50000)

# Was able to achieve this flip around 35000 iterations
def twenty_flip_run():
    rng = np.random.default_rng(4)
    N = 20
    row = np.hstack((np.ones(N//2, dtype=np.int32), np.zeros(N//2, dtype=np.int32)))
    grid = np.tile(row, (N, 1))
    anneal(grid, steep_linear_temp_generator(40000), is_horizontal_split, rng, 40000)

# Flip achieved around 390,000 iterations
def thirty_flip_run():
    rng = np.random.default_rng(3)
    N = 30
    row = np.hstack((np.ones(N//2, dtype=np.int32), np.zeros(N//2, dtype=np.int32)))
    grid = np.tile(row, (N, 1))
    anneal(grid, steep_linear_temp_generator(400000), is_horizontal_split, rng, 400000)

# Flip achieved around 877,000 iterations (not perfect but about the best we can hope for)
def forty_flip_run():
    rng = np.random.default_rng(0)
    N = 40
    row = np.hstack((np.ones(N//2, dtype=np.int32), np.zeros(N//2, dtype=np.int32)))
    grid = np.tile(row, (N, 1))
    anneal(grid, steep_linear_temp_generator(1000000), is_horizontal_split, rng, 1000000)

def main():
    os.system("")
    # six_flip_run()
    # ten_flip_run()
    sixteen_flip_run()
    # twenty_flip_run()
    # thirty_flip_run()
    # forty_flip_run()

if __name__ == "__main__":
    main()


"""
Let d(n) be defined as the sum of proper divisors of n
(numbers less than n which divide evenly into n).
If d(a) = b and d(b) = a, where a ≠ b, then a and b are
an amicable pair and each of a and b are called amicable numbers.

For example, the proper divisors of 220 are
1, 2, 4, 5, 10, 11, 20, 22, 44, 55 and 110;
therefore d(220) = 284.
The proper divisors of 284 are 1, 2, 4, 71 and 142; so d(284) = 220.

Evaluate the sum of all the amicable numbers under 10000.
"""

def sum_of_divisors(n):
    sum = 0
    for i in range(1, n//2 + 1):
        if n%i == 0:
            sum += i
    return sum

sums = {}
n = 300

for i in range(1, n+1):
    sums[i] = sum_of_divisors(i)

amicable = []

#print(sums)

for key in sums.keys():
    if sums[key] in sums.keys() and sums[key] == sums[sums[key]]:
        print(key)
        print(sums[key])
        print(sums[sums[key]])

        amicable.append(sums[key])
        print(amicable)

print(amicable)
#print(sums.keys())


from datetime import datetime

from sqlalchemy import *

metadata = MetaData('sqlite:///tutorial.sqlite')

user_table = Table(
    'tf_user', metadata,
    Column('id', Integer, primary_key=True),
    Column('user_name', Unicode(16), unique=True, nullable=False),
    Column('password', Unicode(40), nullable=False),
    Column('display_name', Unicode(255), default=''),
    Column('created', DateTime, default=datetime.now))

group_table = Table(
    'tf_group', metadata,
    Column('id', Integer, primary_key=True),
    Column('group_name', Unicode(16), unique=True, nullable=False))

permission_table = Table(
    'tf_permission', metadata,
    Column('id', Integer, primary_key=True),
    Column('permission_name', Unicode(16), unique=True, nullable=False))

user_group_table = Table(
    'tf_user_group', metadata,
    Column('user_id', None, ForeignKey('tf_user.id'), primary_key=True),
    Column('group_id', None, ForeignKey('tf_group.id'), primary_key=True))

group_permission_table = Table(
    'tf_group_permission', metadata,
    Column('permission_id', None, ForeignKey('tf_permission.id'), primary_key=True),
    Column('group_id', None, ForeignKey('tf_group.id'), primary_key=True))

metadata.create_all()


# coding=utf-8

import requests
import os

from django.core.mail import EmailMessage
from django.http import JsonResponse, HttpResponse
from django.utils.encoding import smart_str
from django.views.decorators.csrf import csrf_exempt

from SMTP_Project import settings

# Create your views here.

@csrf_exempt
def download_file(request):
    user_data = dict(
        cf_field_1=request.POST.get('cf_field_1'),
        cf_field_2=request.POST.get('cf_field_2'),
        ip=request.POST.get('ip'),
        tests=request.POST.get('cf_field_3')
    )
    data = dict(
        cw_attach=user_data['cf_field_1'],
        cf_field_2=user_data['cf_field_2'],
        cf_field_3=user_data['tests']
    )
    headers = dict(
        http_proxy_address=user_data['ip']
    )

    file_name = user_data['cf_field_1'] + '_' + user_data['cf_field_2'] + '_' + user_data['ip'] + '.pdf'
    path_to_file = os.path.join(settings.MEDIA_ROOT, file_name)
    r = requests.post('http://resmedlab.siroca.com:8084/Zakazresults.aspx', data=data, headers=headers)
    f = open(path_to_file, 'wb')
    f.write(r.content)
    f.close()

    with open(path_to_file, 'rb') as fh:
        response = HttpResponse(fh.read(), content_type="application/pdf")
        response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(file_name)

    os.remove(path_to_file)
    return response

@csrf_exempt
def send_to_mail(request):
    user_data = dict(
        cf_field_1=request.POST.get('cf_field_1'),
        cf_field_2=request.POST.get('cf_field_2'),
        ip=request.POST.get('ip'),
        tests=request.POST.get('cf_field_3')
    )
    print(user_data)
    data = dict(
        cw_attach=user_data['cf_field_1'],
        cf_field_2=user_data['cf_field_2'],
        cf_field_3=user_data['tests']
    )
    headers = dict(
        http_proxy_address=user_data['ip']
    )

    file_name = user_data['cf_field_1'] + '_' + user_data['cf_field_2'] + '_' + user_data['ip'] + '.pdf'
    path_to_file = os.path.join(settings.MEDIA_ROOT, file_name)
    r = requests.post('http://resmedlab.siroca.com:8084/Zakazresults.aspx', data=data, headers=headers)
    f = open(path_to_file, 'wb')
    f.write(r.content)
    f.close()

    kwargs = dict(
        to=[request.POST.get('email')],
        title='Получение результатов анализа',
        body=''
    )

    file = dict(
        path=path_to_file,
        name=file_name
    )
    send_file(kwargs, file)
    os.remove(file['path'])
    return JsonResponse(dict(status='SENT'))

def send_file(kwargs, file):
    title = kwargs.pop('title')
    mail = EmailMessage(title, **kwargs)
    mail.content_subtype = 'html'
    with open(file['path'], 'rb') as f:
        mail.attach(file['name'], f.read(), 'application/pdf')
        mail.send()
        f.close()


from math import sqrt
from random import randint, uniform
from time import sleep
import numpy as np
import pygame, sys

from display import *
from Animal import Animal, Rabbit, Fox, Plant

def check_collisions(objects):
    foxes = []
    rabbits = []
    plants = []

    # Sort the objects following their class
    for o in objects:
        if isinstance(o, Fox):
            foxes.append(o)
        elif isinstance(o, Rabbit):
            rabbits.append(o)
        elif isinstance(o, Plant):
            plants.append(o)

    # Resolve the foxes
    for f in foxes:
        for r in rabbits:
            if f.dist(r) < f.size:
                f.eat(r)
                rabbits.remove(r)
                objects.remove(r)
                print("MIAM")
                break

    for i, r in enumerate(rabbits):
        for b in rabbits[i+1:]:
            if r.dist(b) < r.size:
                r.mate_with(b, objects)
                print("We mate !")
                break
        for p in plants:
            if r.dist(p) < r.size:
                r.eat(p)
                plants.remove(p)
                objects.remove(p)
                print("MIAM la plante")
                break

if __name__ == "__main__":
    # Prepare the screen
    pygame.init()
    size = width, height = 1000, 1000
    screen = pygame.display.set_mode(size)

    animals = [Rabbit(randint(0, width),randint(0, height)) for r in range(50)]
    animals += [Fox(randint(0, width),randint(0, height)) for r in range(5)]
    animals += [Plant(randint(0, width),randint(0, height)) for r in range(30)]
    screen.fill(Color.GREEN.value)
    draw(screen, animals)

    while True:
        for a in animals:
            target = a.find_direction(animals)
            pygame.draw.line(screen, Color.BLACK.value, (a.x, a.y), (a.x+target[0], a.y+target[1]), 1)
            a.move(target)

        check_collisions(animals)
        animals += [Plant(randint(0, width),randint(0, height)) for r in range(5)]

        for a in animals:
            a.get_old(animals)

        pygame.display.update()
        sleep(0.3)
        screen.fill(Color.GREEN.value)
        draw(screen, animals)


'''
Created on Feb 3, 2015

@author: arpeetkale1
'''
import nltk
from nltk.stem.porter import *
from gensim.utils import simple_preprocess
from gensim.parsing.preprocessing import STOPWORDS

def remove_tags(text):
    cleanr = re.compile('<.*?>')
    cleanText = re.sub(cleanr, '', text)
    cleanedText = re.sub('[^A-Za-z]+', ' ', cleanText)
    return cleanedText

def processLanguage(contentArray, length, stem, posTag):
    processedArray = []
    tokens = []
    stemmedTagged = []
    onlyTagged = []
    stemmed = []
    _str = ''
    COUNT = 0
    try:
        stemmer = PorterStemmer()

        if stem == True and posTag == True:

            for item in contentArray:
                tokenized = nltk.word_tokenize(remove_tags(item))
                tagged = nltk.pos_tag(tokenized)
                print(str(COUNT) + ' ')
                COUNT += 1
                for tag in tagged:
                    if 'NN' in tag or 'NNS' in tag or 'JJ' in tag or 'RB' in tag:
                        _str = _str + ' ' + stemmer.stem(tag[0])

                stemmedTagged.append(_str)
                _str = ''
            processedArray = stemmedTagged

        elif stem == False and posTag == True:

            for item in contentArray:
                tokenized = nltk.word_tokenize(remove_tags(item))
                tagged = nltk.pos_tag(tokenized)
                print(str(COUNT) + ' ')
                COUNT += 1
                for tag in tagged:
                    if 'NN' in tag or 'NNS' in tag or 'JJ' in tag or 'RB' in tag:
                        _str = _str + ' ' + tag[0]

                stemmedTagged.append(_str)
                _str = ''
            processedArray = stemmedTagged

        elif stem == True and posTag == False:

            for item in contentArray:
                tokenized = nltk.word_tokenize(remove_tags(item))
                tagged = tokenized  #nltk.pos_tag(tokenized)
                print(str(COUNT) + ' ')
                COUNT += 1
                for tag in tagged:
                    _str = _str + ' ' + stemmer.stem(tag)

                stemmedTagged.append(_str)
                _str = ''
            processedArray = stemmedTagged

        return processedArray

    except Exception as e:
        print(_str(e))

def tokenize(text):
    return [token for token in simple_preprocess(text) if token not in STOPWORDS]


import pygame
import xml.etree.ElementTree as ET

from Active_MVC.Model import SmartAgent
from Active_MVC.Model.Game import Game
from Active_MVC.Model.IObserver import IObserver
from Active_MVC.Model.Move import Move

class GameController:
    def __init__(self, view, gameModel):
        self.gameView = view
        self.gameState = gameModel

    def getGameState(self):
        languageXmlTree = ET.parse('../Config/languages.xml')
        languagesRoot = languageXmlTree.getroot()
        validMoves = self.gameState.getValidMoves()
        moveMade = False
        selectedSquare = ()
        playerClicks = []  # initial piece position, legal move location
        running = True
        gameOver = True

        while running:
            humanTurn = (self.gameState.whiteToMove and not self.gameState.whiteAIControl) or (not self.gameState.whiteToMove and not self.gameState.blackAIControl)
            for currentEvent in pygame.event.get():
                if currentEvent.type == pygame.QUIT:
                    running = False
                if currentEvent.type == pygame.MOUSEBUTTONDOWN:
                    if not gameOver and humanTurn:
                        columnClickLocation, rowClickLocation = self.gameView.getClickLocation()
                        if selectedSquare == (rowClickLocation, columnClickLocation):  # deselect and restart move if the same location is clicked
                            selectedSquare = ()
                            playerClicks = []
                        else:
                            selectedSquare = (rowClickLocation, columnClickLocation)
                            playerClicks.append(selectedSquare)
                        if len(playerClicks) == 2:
                            move = Move(playerClicks[0], playerClicks[1], self.gameState.board)
                            if move in validMoves:
                                print(rowClickLocation, columnClickLocation)
                                self.gameState.makeMove(move)
                                moveMade = True
                                selectedSquare = ()
                                playerClicks = []
                            else:
                                playerClicks = [selectedSquare]

                    # Side button handlers
                    if self.gameView.startGameButton.rect.collidepoint(currentEvent.pos):
                        print("test start")
                        gameOver = False
                        self.gameState = Game(self.gameState)
                        validMoves = self.gameState.getValidMoves()
                        selectedSquare = ()
                        playerClicks = []
                        moveMade = False
                    elif self.gameView.restartGameButton.rect.collidepoint(currentEvent.pos):
                        print("test restart")
                        self.gameState = Game(self.gameState)
                        validMoves = []
                        selectedSquare = ()
                        playerClicks = []
                        moveMade = False
                        self.requestUpdate(validMoves, selectedSquare)
                        #self.gameState.notify(self.gameView, self.gameView.screen, self.gameState, validMoves, selectedSquare)
                        # self.drawGameState(self.gameView.screen, self.gameState, self.gameState.getValidMoves(), selectedSquare)
                    elif self.gameView.pvpButton.rect.collidepoint(currentEvent.pos):
                        print("test pvp")
                        self.gameState.whiteAIControl = False
                        self.gameState.blackAIControl = False
                    elif self.gameView.pvAIButton.rect.collidepoint(currentEvent.pos):
                        print("test pve")
                        self.gameState.whiteAIControl = False
                        self.gameState.blackAIControl = True
                    elif self.gameView.AIvAIButton.rect.collidepoint(currentEvent.pos):
                        print("test ai")
                        self.gameState.whiteAIControl = True
                        self.gameState.blackAIControl = True
                    elif self.gameView.lang_ro.rect.collidepoint(currentEvent.pos):
                        print("test ro")
                        romanian = None
                        for language in languagesRoot.findall("language"):
                            if language.get('name') == "romanian":
                                romanian = language
                                break
                        self.gameView.startGameButton.set_text(romanian.find('start').text)
                        self.gameView.restartGameButton.set_text(romanian.find('restart').text)
                        self.gameView.pvpButton.set_text(romanian.find('pvp').text)
                        self.gameView.pvAIButton.set_text(romanian.find('pvai').text)
                        self.gameView.AIvAIButton.set_text(romanian.find('aivai').text)
                    elif self.gameView.lang_en.rect.collidepoint(currentEvent.pos):
                        print("test en")
                        english = None
                        for language in languagesRoot.findall("language"):
                            if language.get('name') == "english":
                                english = language
                                break
                        self.gameView.startGameButton.set_text(english.find('start').text)
                        self.gameView.restartGameButton.set_text(english.find('restart').text)
                        self.gameView.pvpButton.set_text(english.find('pvp').text)
                        self.gameView.pvAIButton.set_text(english.find('pvai').text)
                        self.gameView.AIvAIButton.set_text(english.find('aivai').text)
                    elif self.gameView.lang_fr.rect.collidepoint(currentEvent.pos):
                        print("test fr")
                        french = None
                        for language in languagesRoot.findall("language"):
                            if language.get('name') == "french":
                                french = language
                                break
                        self.gameView.startGameButton.set_text(french.find('start').text)
                        self.gameView.restartGameButton.set_text(french.find('restart').text)
                        self.gameView.pvpButton.set_text(french.find('pvp').text)
                        self.gameView.pvAIButton.set_text(french.find('pvai').text)
                        self.gameView.AIvAIButton.set_text(french.find('aivai').text)
                    elif self.gameView.lang_ch.rect.collidepoint(currentEvent.pos):
                        print("test ch")
                        chinese = None
                        for language in languagesRoot.findall("language"):
                            if language.get('name') == "chinese":
                                chinese = language
                                break
                        self.gameView.startGameButton.set_text(chinese.find('start').text)
                        self.gameView.restartGameButton.set_text(chinese.find('restart').text)
                        self.gameView.pvpButton.set_text(chinese.find('pvp').text)
                        self.gameView.pvAIButton.set_text(chinese.find('pvai').text)
                        self.gameView.AIvAIButton.set_text(chinese.find('aivai').text)
                    self.gameView.manager.process_events(currentEvent)

            if not gameOver and not humanTurn:
                agentMove = SmartAgent.findBestMoveMinMax(self.gameState, validMoves)
                if agentMove is None:
                    agentMove = SmartAgent.findRandomMove(validMoves)
                self.gameState.makeMove(agentMove)
                moveMade = True

            if moveMade:
                self.animateMove(self.gameState.moveLog[-1], self.gameView.screen, self.gameState.board)
                validMoves = self.gameState.getValidMoves()
                moveMade = False

            # self.gameState.notify(self.gameView, self.gameView.screen, self.gameState, validMoves, selectedSquare)
            # self.drawGameState(self.gameView.screen, self.gameState, validMoves, selectedSquare)
            self.requestUpdate(validMoves, selectedSquare)

            if self.gameState.checkMate:
                gameOver = True
                if self.gameState.whiteToMove:
                    self.gameView.drawText(self.gameView.screen, "Black wins")
                else:
                    self.gameView.drawText(self.gameView.screen, "White wins")
            elif self.gameState.staleMate:
                gameOver = True
                self.gameView.drawText(self.gameView.screen, "Stalemate")

            self.gameView.clock.tick(self.gameView.MAX_FPS)
            pygame.display.flip()

    def handleDrawText(self, text):
        font = pygame.font.SysFont("Helvetica", 50, True, False)
        textObject = font.render(text, False, pygame.Color("Black"))
        textLocation = pygame.Rect(0, 0, self.gameView.WINDOW_WIDTH, self.gameView.WINDOW_HEIGHT).move(
            self.gameView.WINDOW_WIDTH / 2 - textObject.get_width() / 2, self.gameView.WINDOW_HEIGHT / 2 - textObject.get_height() / 2)
        self.gameView.drawText(self.gameView.screen, textObject, textLocation)

    def drawPieces(self, screen, board):
        for row in range(self.gameView.DIMENSION):
            for column in range(self.gameView.DIMENSION):
                piece = board[row][column]
                if piece != "--":
                    screen.blit(self.gameView.PIECES_IMAGES[self.gameView.parsePieceToKey(piece)],
                                pygame.Rect(column * self.gameView.SQUARE_SIZE, row * self.gameView.SQUARE_SIZE, self.gameView.SQUARE_SIZE / 2,
                                            self.gameView.SQUARE_SIZE / 2))

    def drawGameState(self, screen, gameState, validMoves, selectedSquare):
        time_delta = self.gameView.clock.tick(60)/1000.0
        self.gameView.manager.update(time_delta)
        self.gameView.screen.blit(self.gameView.background, (0, 0))
        self.gameView.drawBoard(screen)
        self.gameView.highlightSquares(screen, gameState, validMoves, selectedSquare)
        self.drawPieces(screen, gameState.board)
        self.gameView.manager.draw_ui(screen)

    def animateMove(self, move, screen, board):
        global colors
        colors = [pygame.Color("white"), pygame.Color("gray")]
        coords = []
        dRow = move.endRow - move.startRow
        dCol = move.endCol - move.startCol
        framePerSquare = 10
        frameCount = (abs(dRow) + abs(dCol)) * framePerSquare
        for frame in range(frameCount + 1):
            row, column = (move.startRow + dRow * frame / frameCount, move.startCol + dCol * frame / frameCount)
            self.gameView.drawBoard(screen)
            self.drawPieces(screen, board)
            color = colors[(move.endRow + move.endCol) % 2]
            endSquare = pygame.Rect(move.endCol * self.gameView.SQUARE_SIZE, move.endRow * self.gameView.SQUARE_SIZE, self.gameView.SQUARE_SIZE,
                                    self.gameView.SQUARE_SIZE)
            pygame.draw.rect(screen, color, endSquare)
            if move.takenPiece != "--":
                screen.blit(self.gameView.PIECES_IMAGES[self.gameView.parsePieceToKey(move.takenPiece)], endSquare)
            screen.blit(self.gameView.PIECES_IMAGES[self.gameView.parsePieceToKey(move.movedPiece)],
                        pygame.Rect(column * self.gameView.SQUARE_SIZE, row * self.gameView.SQUARE_SIZE, self.gameView.SQUARE_SIZE,
                                    self.gameView.SQUARE_SIZE))
            pygame.display.flip()
            self.gameView.clock.tick(60)

    def requestUpdate(self, validMoves, selectedSquare):
        self.gameState.notify(self.gameView, self.gameView.screen, self.gameState, validMoves, selectedSquare)
        self.drawPieces(self.gameView.screen, self.gameState.board)
        self.gameView.manager.draw_ui(self.gameView.screen)


import ctypes
import requests
import time
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
def changetext():
    response = requests.get("https://api.kanye.rest/text")
    data = response.json()
    img = Image.open("D:\projects\kanyepaper\Background.png")
    draw = ImageDraw.Draw(img)
    # font = ImageFont.truetype(<font-file>, <font-size>)
    font = ImageFont.truetype("arial.ttf",16)
    print(type(data))
    print(data)
    text = '"' +  data["quote"]+'"'
    # draw.text((x, y),"Sample Text",(r,g,b))
    draw.text((500, 450),data["quote"],(255,255,255),font=font)
    draw.text((540, 470),"~Kanye West",(255,255,255),font=font)
    img.save('D:\projects\kanyepaper\sample-out.png')
    ctypes.windll.user32.SystemParametersInfoW(20, 0, "D:\projects\kanyepaper\sample-out.png" , 0)

#while(1):
changetext()
time.sleep(60)


from szurubooru import api, db

def test_info_api(
        tmpdir, config_injector, context_factory, post_factory, fake_datetime):
    directory = tmpdir.mkdir('data')
    directory.join('test.txt').write('abc')
    config_injector({'data_dir': str(directory)})
    db.session.add_all([post_factory(), post_factory()])
    info_api = api.InfoApi()
    with fake_datetime('13:00'):
        assert info_api.get(context_factory()) == {
            'postCount': 2,
            'diskUsage': 3,
            'featuredPost': None,
        }
    directory.join('test2.txt').write('abc')
    with fake_datetime('13:59'):
        assert info_api.get(context_factory()) == {
            'postCount': 2,
            'diskUsage': 3, # still 3 - it's cached
            'featuredPost': None,
        }
    with fake_datetime('14:01'):
        assert info_api.get(context_factory()) == {
            'postCount': 2,
            'diskUsage': 6, # cache expired
            'featuredPost': None,
        }


import datetime
import os
from decimal import Decimal

from boto3.dynamodb.conditions import Attr, Key

from aws_utils.utils import random_id

class DynamoDb:
    def __init__(self, session):
        self.client = session.client('dynamodb')
        self.resource = session.resource('dynamodb')

    @staticmethod
    def convert_types(item):
        for k in dict(item):
            if isinstance(item[k], datetime.datetime):
                item[k] = item[k].isoformat()
            elif isinstance(item[k], float):
                item[k] = Decimal(str(item[k]))
            elif isinstance(item[k], dict):
                item[k] = DynamoDb.convert_types(item[k])
        return item

    @staticmethod
    def projection_string(kwargs):
        if 'ProjectionExpression' in kwargs:
            names = {}
            counter = 1
            attributes = kwargs['ProjectionExpression'].split(',')
            for a_index, attribute in enumerate(attributes):
                sub_attributes = attribute.split('.')
                for sa_index, sub_attribute in enumerate(sub_attributes):
                    place_holder = '#attr' + str(counter)
                    names[place_holder] = sub_attribute
                    sub_attributes[sa_index] = place_holder
                    counter += 1
                attribute = '.'.join(sub_attributes)
                attributes[a_index] = attribute
            kwargs['ProjectionExpression'] = ','.join(attributes)
            kwargs['ExpressionAttributeNames'] = names
        return kwargs

    def post_item(self, table, key, item, **kwargs):
        item['created_on'] = datetime.datetime.utcnow().isoformat()
        item.update(key)
        item = DynamoDb.convert_types(item)
        table = self.resource.Table(os.environ[table])
        response = table.put_item(Item=item, ReturnValues='ALL_OLD', **kwargs)
        response['Key'] = key
        return response

    def get_item(self, table, key, **kwargs):
        kwargs = DynamoDb.projection_string(kwargs)
        table = self.resource.Table(os.environ[table])
        response = table.get_item(Key=key, **kwargs)
        if 'Item' in response and response['Item']:
            return response['Item']
        return {}

    def delete_item(self, table, key, **kwargs):
        table = self.resource.Table(os.environ[table])
        response = table.delete_item(Key=key, ReturnValues='ALL_OLD', **kwargs)
        response['Key'] = key
        return response

    def query(self, table, partition_key, sort_key=None, **kwargs):
        kwargs = DynamoDb.projection_string(kwargs)
        key1, val1 = partition_key.popitem()
        key_exp = Key(key1).eq(val1)
        if sort_key:
            key_exp = key_exp & sort_key
        table = self.resource.Table(os.environ[table])
        response = table.query(KeyConditionExpression=key_exp, **kwargs)
        if 'Items' in response and response['Items']:
            return {k: v for k, v in response.items() if k in ['Items', 'Count', 'ScannedCount', 'LastEvaluatedKey']}
        return {}

    def update_item(self, table, key, updates=None, deletes=None, adds=None, appends=None,**kwargs):
        exp = ''
        names = {}
        values = {}
        updates = updates or {}
        deletes = deletes or []
        updates = DynamoDb.convert_types(updates)
        updates['updated_on'] = datetime.datetime.utcnow().isoformat()

        def add_attribute(attribute):
            if '.' not in attribute:
                attr_placeholder = '#attr' + random_id()
                names[attr_placeholder] = attribute
                return attr_placeholder
            attributes = attribute.split('.')
            for _idx, _val in enumerate(attributes):
                attr_placeholder = '#attr' + random_id()
                attributes[_idx] = attr_placeholder
                names[attr_placeholder] = _val
            return '.'.join(attributes)

        def add_value(value):
            val_placeholder = ':val' + random_id()
            values[val_placeholder] = value
            return val_placeholder
        if appends:
            for k1, v1 in dict(appends).items():
                appends[add_attribute(k1)] = add_value(v1)
                del appends[k1]
            exp += 'SET '
            exp += ', '.join('{0}=list_append({0},{1})'.format(k2, v2) for (k2, v2) in appends.items())
            exp += ' '
        if updates:
            for k1, v1 in dict(updates).items():
                updates[add_attribute(k1)] = add_value(v1)
                del updates[k1]
            exp += 'SET '
            exp += ', '.join('{}={}'.format(k2, v2) for (k2, v2) in updates.items())
            exp += ' '
        if deletes:
            for k3, v3 in enumerate(deletes):
                deletes[k3] = add_attribute(v3)
            exp += 'REMOVE '
            exp += ', '.join(deletes)
            exp += ' '
        if adds:
            for k4, v4 in dict(adds).items():
                adds[add_attribute(k4)] = add_value(v4)
                del adds[k4]
            exp += 'ADD '
            exp += ', '.join('{} {}'.format(k5, v5) for (k5, v5) in adds.items())
            exp += ' '
        table = self.resource.Table(os.environ[table])

        # ensure key exist or reject
        key_exist_conditions = None
        for k, v in key.items():
            key_exist_conditions = key_exist_conditions & Attr(k).eq(v) if key_exist_conditions else Attr(k).eq(v)

        if 'ConditionExpression' in kwargs:
            kwargs['ConditionExpression'] = kwargs['ConditionExpression'] & key_exist_conditions
        else:
            kwargs['ConditionExpression'] = key_exist_conditions

        response = table.update_item(
            Key=key, UpdateExpression=exp,
            ExpressionAttributeNames=names,
            ExpressionAttributeValues=values, **kwargs
        )
        response['Key'] = key
        return response


import camToTimeLapse
from datetime import datetime, timedelta

import argparse

from Sun import Sun

if __name__ == "__main__":
    print('---------------')

    parser=argparse.ArgumentParser()
    parser.add_argument('startDate',type=camToTimeLapse.mkdate)
    parser.add_argument('dirIn', type=str)
    args=parser.parse_args()
    print(args.dirIn)

    #Longitude of Szklarska Poreba: 15.5261478
    #Latitude of Szklarska Poreba: 50.8274316
    coords = {'longitude' : 15.5261478, 'latitude' : 50.8274316 }
    sun = Sun(args.startDate)

    file_ext = '.mp4'
    numOfFramesToSkip = 0

    startDate = args.startDate + timedelta(hours = sun.getSunriseTime( coords )['hr']-1, minutes = sun.getSunriseTime( coords )['min'])
    endDate =   args.startDate + timedelta(hours =  sun.getSunsetTime( coords )['hr']+1, minutes =  sun.getSunsetTime( coords )['min'])
    camToTimeLapse.setTimeMarkers(startDate, endDate)
    print('--list files')
    files = camToTimeLapse.list_files(args.dirIn, file_ext, numOfFramesToSkip)
#    print('--filter files')
#    files = camToTimeLapse.filter_files(files)
#    print('--convert mp4 to pic')
#    camToTimeLapse.convert_mp4_to_pic(files)
#    print('--convert pics to movie')
    camToTimeLapse.convert_jpg_to_blend(files, 'dayBlend')