from datetime import datetime, timedelta
import functools
import inspect
import os
import shutil
import sys
import tempfile
import re
from errno import ENOENT
from collections.abc import Iterator
from contextlib import contextmanager
from importlib import import_module
from numbers import Integral, Number
from threading import Lock
from typing import Iterable, Optional
import uuid
from weakref import WeakValueDictionary
from functools import lru_cache
from _thread import RLock

from .core import get_deps

system_encoding = sys.getdefaultencoding()
if system_encoding == "ascii":
    system_encoding = "utf-8"

def apply(func, args, kwargs=None):
    if kwargs:
        return func(*args, **kwargs)
    else:
        return func(*args)

def deepmap(func, *seqs):
    """Apply function inside nested lists

    >>> inc = lambda x: x + 1
    >>> deepmap(inc, [[1, 2], [3, 4]])
    [[2, 3], [4, 5]]

    >>> add = lambda x, y: x + y
    >>> deepmap(add, [[1, 2], [3, 4]], [[10, 20], [30, 40]])
    [[11, 22], [33, 44]]
    """
    if isinstance(seqs[0], (list, Iterator)):
        return [deepmap(func, *items) for items in zip(*seqs)]
    else:
        return func(*seqs)

def homogeneous_deepmap(func, seq):
    if not seq:
        return seq
    n = 0
    tmp = seq
    while isinstance(tmp, list):
        n += 1
        tmp = tmp[0]

    return ndeepmap(n, func, seq)

def ndeepmap(n, func, seq):
    """Call a function on every element within a nested container

    >>> def inc(x):
    ...     return x + 1
    >>> L = [[1, 2], [3, 4, 5]]
    >>> ndeepmap(2, inc, L)
    [[2, 3], [4, 5, 6]]
    """
    if n == 1:
        return [func(item) for item in seq]
    elif n > 1:
        return [ndeepmap(n - 1, func, item) for item in seq]
    elif isinstance(seq, list):
        return func(seq[0])
    else:
        return func(seq)

@contextmanager
def ignoring(*exceptions):
    try:
        yield
    except exceptions:
        pass

def import_required(mod_name, error_msg):
    """Attempt to import a required dependency.

    Raises a RuntimeError if the requested module is not available.
    """
    try:
        return import_module(mod_name)
    except ImportError as e:
        raise RuntimeError(error_msg) from e

@contextmanager
def tmpfile(extension="", dir=None):
    extension = "." + extension.lstrip(".")
    handle, filename = tempfile.mkstemp(extension, dir=dir)
    os.close(handle)
    os.remove(filename)

    try:
        yield filename
    finally:
        if os.path.exists(filename):
            if os.path.isdir(filename):
                shutil.rmtree(filename)
            else:
                with ignoring(OSError):
                    os.remove(filename)

@contextmanager
def tmpdir(dir=None):
    dirname = tempfile.mkdtemp(dir=dir)

    try:
        yield dirname
    finally:
        if os.path.exists(dirname):
            if os.path.isdir(dirname):
                with ignoring(OSError):
                    shutil.rmtree(dirname)
            else:
                with ignoring(OSError):
                    os.remove(dirname)

@contextmanager
def filetext(text, extension="", open=open, mode="w"):
    with tmpfile(extension=extension) as filename:
        f = open(filename, mode=mode)
        try:
            f.write(text)
        finally:
            try:
                f.close()
            except AttributeError:
                pass

        yield filename

@contextmanager
def changed_cwd(new_cwd):
    old_cwd = os.getcwd()
    os.chdir(new_cwd)
    try:
        yield
    finally:
        os.chdir(old_cwd)

@contextmanager
def tmp_cwd(dir=None):
    with tmpdir(dir) as dirname:
        with changed_cwd(dirname):
            yield dirname

@contextmanager
def noop_context():
    yield

class IndexCallable(object):
    """Provide getitem syntax for functions

    >>> def inc(x):
    ...     return x + 1

    >>> I = IndexCallable(inc)
    >>> I[3]
    4
    """

    __slots__ = ("fn",)

    def __init__(self, fn):
        self.fn = fn

    def __getitem__(self, key):
        return self.fn(key)

@contextmanager
def filetexts(d, open=open, mode="t", use_tmpdir=True):
    """Dumps a number of textfiles to disk

    Parameters
    ----------
    d : dict
        a mapping from filename to text like {'a.csv': '1,1\n2,2'}

    Since this is meant for use in tests, this context manager will
    automatically switch to a temporary current directory, to avoid
    race conditions when running tests in parallel.
    """
    with (tmp_cwd() if use_tmpdir else noop_context()):
        for filename, text in d.items():
            try:
                os.makedirs(os.path.dirname(filename))
            except OSError:
                pass
            f = open(filename, "w" + mode)
            try:
                f.write(text)
            finally:
                try:
                    f.close()
                except AttributeError:
                    pass

        yield list(d)

        for filename in d:
            if os.path.exists(filename):
                with ignoring(OSError):
                    os.remove(filename)

def concrete(seq):
    """Make nested iterators concrete lists

    >>> data = [[1, 2], [3, 4]]
    >>> seq = iter(map(iter, data))
    >>> concrete(seq)
    [[1, 2], [3, 4]]
    """
    if isinstance(seq, Iterator):
        seq = list(seq)
    if isinstance(seq, (tuple, list)):
        seq = list(map(concrete, seq))
    return seq

def pseudorandom(n, p, random_state=None):
    """Pseudorandom array of integer indexes

    >>> pseudorandom(5, [0.5, 0.5], random_state=123)
    array([1, 0, 0, 1, 1], dtype=int8)

    >>> pseudorandom(10, [0.5, 0.2, 0.2, 0.1], random_state=5)
    array([0, 2, 0, 3, 0, 1, 2, 1, 0, 0], dtype=int8)
    """
    import numpy as np

    p = list(p)
    cp = np.cumsum([0] + p)
    assert np.allclose(1, cp[-1])
    assert len(p) < 256

    if not isinstance(random_state, np.random.RandomState):
        random_state = np.random.RandomState(random_state)

    x = random_state.random_sample(n)
    out = np.empty(n, dtype="i1")

    for i, (low, high) in enumerate(zip(cp[:-1], cp[1:])):
        out[(x >= low) & (x < high)] = i
    return out

def random_state_data(n, random_state=None):
    """Return a list of arrays that can initialize
    ``np.random.RandomState``.

    Parameters
    ----------
    n : int
        Number of arrays to return.
    random_state : int or np.random.RandomState, optional
        If an int, is used to seed a new ``RandomState``.
    """
    import numpy as np

    if not all(
        hasattr(random_state, attr) for attr in ["normal", "beta", "bytes", "uniform"]
    ):
        random_state = np.random.RandomState(random_state)

    random_data = random_state.bytes(624 * n * 4)  # `n * 624` 32-bit integers
    l = list(np.frombuffer(random_data, dtype=np.uint32).reshape((n, -1)))
    assert len(l) == n
    return l

def is_integer(i):
    """
    >>> is_integer(6)
    True
    >>> is_integer(42.0)
    True
    >>> is_integer('abc')
    False
    """
    return isinstance(i, Integral) or (isinstance(i, float) and i.is_integer())

ONE_ARITY_BUILTINS = set(
    [
        abs,
        all,
        any,
        ascii,
        bool,
        bytearray,
        bytes,
        callable,
        chr,
        classmethod,
        complex,
        dict,
        dir,
        enumerate,
        eval,
        float,
        format,
        frozenset,
        hash,
        hex,
        id,
        int,
        iter,
        len,
        list,
        max,
        min,
        next,
        oct,
        open,
        ord,
        range,
        repr,
        reversed,
        round,
        set,
        slice,
        sorted,
        staticmethod,
        str,
        sum,
        tuple,
        type,
        vars,
        zip,
        memoryview,
    ]
)
MULTI_ARITY_BUILTINS = set(
    [
        compile,
        delattr,
        divmod,
        filter,
        getattr,
        hasattr,
        isinstance,
        issubclass,
        map,
        pow,
        setattr,
    ]
)

def getargspec(func):
    """Version of inspect.getargspec that works with partial and warps."""
    if isinstance(func, functools.partial):
        return getargspec(func.func)

    func = getattr(func, "__wrapped__", func)
    if isinstance(func, type):
        return inspect.getfullargspec(func.__init__)
    else:
        return inspect.getfullargspec(func)

def takes_multiple_arguments(func, varargs=True):
    """Does this function take multiple arguments?

    >>> def f(x, y): pass
    >>> takes_multiple_arguments(f)
    True

    >>> def f(x): pass
    >>> takes_multiple_arguments(f)
    False

    >>> def f(x, y=None): pass
    >>> takes_multiple_arguments(f)
    False

    >>> def f(*args): pass
    >>> takes_multiple_arguments(f)
    True

    >>> class Thing(object):
    ...     def __init__(self, a): pass
    >>> takes_multiple_arguments(Thing)
    False

    """
    if func in ONE_ARITY_BUILTINS:
        return False
    elif func in MULTI_ARITY_BUILTINS:
        return True

    try:
        spec = getargspec(func)
    except Exception:
        return False

    try:
        is_constructor = spec.args[0] == "self" and isinstance(func, type)
    except Exception:
        is_constructor = False

    if varargs and spec.varargs:
        return True

    ndefaults = 0 if spec.defaults is None else len(spec.defaults)
    return len(spec.args) - ndefaults - is_constructor > 1

def get_named_args(func):
    """Get all non ``*args/**kwargs`` arguments for a function"""
    s = inspect.signature(func)
    return [
        n
        for n, p in s.parameters.items()
        if p.kind in [p.POSITIONAL_OR_KEYWORD, p.POSITIONAL_ONLY, p.KEYWORD_ONLY]
    ]

class Dispatch(object):
    """Simple single dispatch."""

    def __init__(self, name=None):
        self._lookup = {}
        self._lazy = {}
        if name:
            self.__name__ = name

    def register(self, type, func=None):
        """Register dispatch of `func` on arguments of type `type`"""

        def wrapper(func):
            if isinstance(type, tuple):
                for t in type:
                    self.register(t, func)
            else:
                self._lookup[type] = func
            return func

        return wrapper(func) if func is not None else wrapper

    def register_lazy(self, toplevel, func=None):
        """
        Register a registration function which will be called if the
        *toplevel* module (e.g. 'pandas') is ever loaded.
        """

        def wrapper(func):
            self._lazy[toplevel] = func
            return func

        return wrapper(func) if func is not None else wrapper

    def dispatch(self, cls):
        """Return the function implementation for the given ``cls``"""
        # Fast path with direct lookup on cls
        lk = self._lookup
        try:
            impl = lk[cls]
        except KeyError:
            pass
        else:
            return impl
        # Is a lazy registration function present?
        toplevel, _, _ = cls.__module__.partition(".")
        try:
            register = self._lazy.pop(toplevel)
        except KeyError:
            pass
        else:
            register()
            return self.dispatch(cls)  # recurse
        # Walk the MRO and cache the lookup result
        for cls2 in inspect.getmro(cls)[1:]:
            if cls2 in lk:
                lk[cls] = lk[cls2]
                return lk[cls2]
        raise TypeError("No dispatch for {0}".format(cls))

    def __call__(self, arg, *args, **kwargs):
        """
        Call the corresponding method based on type of argument.
        """
        meth = self.dispatch(type(arg))
        return meth(arg, *args, **kwargs)

    @property
    def __doc__(self):
        try:
            func = self.dispatch(object)
            return func.__doc__
        except TypeError:
            return "Single Dispatch for %s" % self.__name__

def ensure_not_exists(filename):
    """
    Ensure that a file does not exist.
    """
    try:
        os.unlink(filename)
    except OSError as e:
        if e.errno != ENOENT:
            raise

def _skip_doctest(line):
    # NumPy docstring contains cursor and comment only example
    stripped = line.strip()
    if stripped == ">>>" or stripped.startswith(">>> #"):
        return line
    elif ">>>" in stripped and "+SKIP" not in stripped:
        if "# doctest:" in line:
            return line + ", +SKIP"
        else:
            return line + "  # doctest: +SKIP"
    else:
        return line

def skip_doctest(doc):
    if doc is None:
        return ""
    return "\n".join([_skip_doctest(line) for line in doc.split("\n")])

def extra_titles(doc):
    lines = doc.split("\n")
    titles = {
        i: lines[i].strip()
        for i in range(len(lines) - 1)
        if lines[i + 1].strip() and all(c == "-" for c in lines[i + 1].strip())
    }

    seen = set()
    for i, title in sorted(titles.items()):
        if title in seen:
            new_title = "Extra " + title
            lines[i] = lines[i].replace(title, new_title)
            lines[i + 1] = lines[i + 1].replace("-" * len(title), "-" * len(new_title))
        else:
            seen.add(title)

    return "\n".join(lines)

def ignore_warning(doc, cls, name, extra="", skipblocks=0):
    """Expand docstring by adding disclaimer and extra text"""
    import inspect

    if inspect.isclass(cls):
        l1 = "This docstring was copied from %s.%s.%s.\n\n" % (
            cls.__module__,
            cls.__name__,
            name,
        )
    else:
        l1 = "This docstring was copied from %s.%s.\n\n" % (cls.__name__, name)
    l2 = "Some inconsistencies with the Dask version may exist."

    i = doc.find("\n\n")
    if i != -1:
        # Insert our warning
        head = doc[: i + 2]
        tail = doc[i + 2 :]
        while skipblocks > 0:
            i = tail.find("\n\n")
            head = tail[: i + 2]
            tail = tail[i + 2 :]
            skipblocks -= 1
        # Indentation of next line
        indent = re.match(r"\s*", tail).group(0)
        # Insert the warning, indented, with a blank line before and after
        if extra:
            more = [indent, extra.rstrip("\n") + "\n\n"]
        else:
            more = []
        bits = [head, indent, l1, indent, l2, "\n\n"] + more + [tail]
        doc = "".join(bits)

    return doc

def unsupported_arguments(doc, args):
    """ Mark unsupported arguments with a disclaimer """
    lines = doc.split("\n")
    for arg in args:
        subset = [
            (i, line)
            for i, line in enumerate(lines)
            if re.match(r"^\s*" + arg + " ?:", line)
        ]
        if len(subset) == 1:
            [(i, line)] = subset
            lines[i] = line + "  (Not supported in Dask)"
    return "\n".join(lines)

def _derived_from(cls, method, ua_args=[], extra="", skipblocks=0):
    """ Helper function for derived_from to ease testing """
    # do not use wraps here, as it hides keyword arguments displayed
    # in the doc
    original_method = getattr(cls, method.__name__)

    if isinstance(original_method, property):
        # some things like SeriesGroupBy.unique are generated.
        original_method = original_method.fget

    doc = original_method.__doc__
    if doc is None:
        doc = ""

    # Insert disclaimer that this is a copied docstring
    if doc:
        doc = ignore_warning(
            doc, cls, method.__name__, extra=extra, skipblocks=skipblocks
        )
    elif extra:
        doc += extra.rstrip("\n") + "\n\n"

    # Mark unsupported arguments
    try:
        method_args = get_named_args(method)
        original_args = get_named_args(original_method)
        not_supported = [m for m in original_args if m not in method_args]
    except ValueError:
        not_supported = []
    if len(ua_args) > 0:
        not_supported.extend(ua_args)
    if len(not_supported) > 0:
        doc = unsupported_arguments(doc, not_supported)

    doc = skip_doctest(doc)
    doc = extra_titles(doc)

    return doc

def derived_from(original_klass, version=None, ua_args=[], skipblocks=0):
    """Decorator to attach original class's docstring to the wrapped method.

    The output structure will be: top line of docstring, disclaimer about this
    being auto-derived, any extra text associated with the method being patched,
    the body of the docstring and finally, the list of keywords that exist in
    the original method but not in the dask version.

    Parameters
    ----------
    original_klass: type
        Original class which the method is derived from
    version : str
        Original package version which supports the wrapped method
    ua_args : list
        List of keywords which Dask doesn't support. Keywords existing in
        original but not in Dask will automatically be added.
    skipblocks : int
        How many text blocks (paragraphs) to skip from the start of the
        docstring. Useful for cases where the target has extra front-matter.
    """

    def wrapper(method):
        try:
            extra = getattr(method, "__doc__", None) or ""
            method.__doc__ = _derived_from(
                original_klass,
                method,
                ua_args=ua_args,
                extra=extra,
                skipblocks=skipblocks,
            )
            return method

        except AttributeError:
            module_name = original_klass.__module__.split(".")[0]

            @functools.wraps(method)
            def wrapped(*args, **kwargs):
                msg = "Base package doesn't support '{0}'.".format(method.__name__)
                if version is not None:
                    msg2 = " Use {0} {1} or later to use this method."
                    msg += msg2.format(module_name, version)
                raise NotImplementedError(msg)

            return wrapped

    return wrapper

def funcname(func):
    """Get the name of a function."""
    # functools.partial
    if isinstance(func, functools.partial):
        return funcname(func.func)
    # methodcaller
    if isinstance(func, methodcaller):
        return func.method[:50]

    module_name = getattr(func, "__module__", None) or ""
    type_name = getattr(type(func), "__name__", None) or ""

    # toolz.curry
    if "toolz" in module_name and "curry" == type_name:
        return func.func_name[:50]
    # multipledispatch objects
    if "multipledispatch" in module_name and "Dispatcher" == type_name:
        return func.name[:50]
    # numpy.vectorize objects
    if "numpy" in module_name and "vectorize" == type_name:
        return ("vectorize_" + funcname(func.pyfunc))[:50]

    # All other callables
    try:
        name = func.__name__
        if name == "<lambda>":
            return "lambda"
        return name[:50]
    except AttributeError:
        return str(func)[:50]

def typename(typ):
    """
    Return the name of a type

    Examples
    --------
    >>> typename(int)
    'int'

    >>> from dask.core import literal
    >>> typename(literal)
    'dask.core.literal'
    """
    if not typ.__module__ or typ.__module__ == "builtins":
        return typ.__name__
    else:
        return typ.__module__ + "." + typ.__name__

def ensure_bytes(s):
    """Turn string or bytes to bytes

    >>> ensure_bytes('123')
    b'123'
    >>> ensure_bytes('123')
    b'123'
    >>> ensure_bytes(b'123')
    b'123'
    """
    if isinstance(s, bytes):
        return s
    if hasattr(s, "encode"):
        return s.encode()
    msg = "Object %s is neither a bytes object nor has an encode method"
    raise TypeError(msg % s)

def ensure_unicode(s):
    """Turn string or bytes to bytes

    >>> ensure_unicode('123')
    '123'
    >>> ensure_unicode('123')
    '123'
    >>> ensure_unicode(b'123')
    '123'
    """
    if isinstance(s, str):
        return s
    if hasattr(s, "decode"):
        return s.decode()
    msg = "Object %s is neither a bytes object nor has an encode method"
    raise TypeError(msg % s)

def digit(n, k, base):
    """

    >>> digit(1234, 0, 10)
    4
    >>> digit(1234, 1, 10)
    3
    >>> digit(1234, 2, 10)
    2
    >>> digit(1234, 3, 10)
    1
    """
    return n // base ** k % base

def insert(tup, loc, val):
    """

    >>> insert(('a', 'b', 'c'), 0, 'x')
    ('x', 'b', 'c')
    """
    L = list(tup)
    L[loc] = val
    return tuple(L)

def dependency_depth(dsk):
    deps, _ = get_deps(dsk)

    @lru_cache(maxsize=None)
    def max_depth_by_deps(key):
        if not deps[key]:
            return 1

        d = 1 + max(max_depth_by_deps(dep_key) for dep_key in deps[key])
        return d

    return max(max_depth_by_deps(dep_key) for dep_key in deps.keys())

def memory_repr(num):
    for x in ["bytes", "KB", "MB", "GB", "TB"]:
        if num < 1024.0:
            return "%3.1f %s" % (num, x)
        num /= 1024.0

def asciitable(columns, rows):
    """Formats an ascii table for given columns and rows.

    Parameters
    ----------
    columns : list
        The column names
    rows : list of tuples
        The rows in the table. Each tuple must be the same length as
        ``columns``.
    """
    rows = [tuple(str(i) for i in r) for r in rows]
    columns = tuple(str(i) for i in columns)
    widths = tuple(max(max(map(len, x)), len(c)) for x, c in zip(zip(*rows), columns))
    row_template = ("|" + (" %%-%ds |" * len(columns))) % widths
    header = row_template % tuple(columns)
    bar = "+%s+" % "+".join("-" * (w + 2) for w in widths)
    data = "\n".join(row_template % r for r in rows)
    return "\n".join([bar, header, bar, data, bar])

def put_lines(buf, lines):
    if any(not isinstance(x, str) for x in lines):
        lines = [str(x) for x in lines]
    buf.write("\n".join(lines))

_method_cache = {}

class methodcaller(object):
    """
    Return a callable object that calls the given method on its operand.

    Unlike the builtin `operator.methodcaller`, instances of this class are
    serializable
    """

    __slots__ = ("method",)
    func = property(lambda self: self.method)  # For `funcname` to work

    def __new__(cls, method):
        if method in _method_cache:
            return _method_cache[method]
        self = object.__new__(cls)
        self.method = method
        _method_cache[method] = self
        return self

    def __call__(self, obj, *args, **kwargs):
        return getattr(obj, self.method)(*args, **kwargs)

    def __reduce__(self):
        return (methodcaller, (self.method,))

    def __str__(self):
        return "<%s: %s>" % (self.__class__.__name__, self.method)

    __repr__ = __str__

class itemgetter(object):
    """
    Return a callable object that gets an item from the operand

    Unlike the builtin `operator.itemgetter`, instances of this class are
    serializable
    """

    __slots__ = ("index",)

    def __init__(self, index):
        self.index = index

    def __call__(self, x):
        return x[self.index]

    def __reduce__(self):
        return (itemgetter, (self.index,))

    def __eq__(self, other):
        return type(self) is type(other) and self.index == other.index

class MethodCache(object):
    """Attribute access on this object returns a methodcaller for that
    attribute.

    Examples
    --------
    >>> a = [1, 3, 3]
    >>> M.count(a, 3) == a.count(3)
    True
    """

    __getattr__ = staticmethod(methodcaller)
    __dir__ = lambda self: list(_method_cache)

M = MethodCache()

class SerializableLock(object):
    _locks = WeakValueDictionary()
    """ A Serializable per-process Lock

    This wraps a normal ``threading.Lock`` object and satisfies the same
    interface.  However, this lock can also be serialized and sent to different
    processes.  It will not block concurrent operations between processes (for
    this you should look at ``multiprocessing.Lock`` or ``locket.lock_file``
    but will consistently deserialize into the same lock.

    So if we make a lock in one process::

        lock = SerializableLock()

    And then send it over to another process multiple times::

        bytes = pickle.dumps(lock)
        a = pickle.loads(bytes)
        b = pickle.loads(bytes)

    Then the deserialized objects will operate as though they were the same
    lock, and collide as appropriate.

    This is useful for consistently protecting resources on a per-process
    level.

    The creation of locks is itself not threadsafe.
    """

    def __init__(self, token=None):
        self.token = token or str(uuid.uuid4())
        if self.token in SerializableLock._locks:
            self.lock = SerializableLock._locks[self.token]
        else:
            self.lock = Lock()
            SerializableLock._locks[self.token] = self.lock

    def acquire(self, *args, **kwargs):
        return self.lock.acquire(*args, **kwargs)

    def release(self, *args, **kwargs):
        return self.lock.release(*args, **kwargs)

    def __enter__(self):
        self.lock.__enter__()

    def __exit__(self, *args):
        self.lock.__exit__(*args)

    def locked(self):
        return self.lock.locked()

    def __getstate__(self):
        return self.token

    def __setstate__(self, token):
        self.__init__(token)

    def __str__(self):
        return "<%s: %s>" % (self.__class__.__name__, self.token)

    __repr__ = __str__

def get_scheduler_lock(collection=None, scheduler=None):
    """Get an instance of the appropriate lock for a certain situation based on
    scheduler used."""
    from . import multiprocessing
    from .base import get_scheduler

    actual_get = get_scheduler(collections=[collection], scheduler=scheduler)

    if actual_get == multiprocessing.get:
        return multiprocessing.get_context().Manager().Lock()

    return SerializableLock()

def ensure_dict(d):
    if type(d) is dict:
        return d
    elif hasattr(d, "dicts"):
        result = {}
        seen = set()
        for dd in d.dicts.values():
            dd_id = id(dd)
            if dd_id not in seen:
                result.update(dd)
                seen.add(dd_id)
        return result
    return dict(d)

class OperatorMethodMixin(object):
    """A mixin for dynamically implementing operators"""

    @classmethod
    def _bind_operator(cls, op):
        """ bind operator to this class """
        name = op.__name__

        if name.endswith("_"):
            # for and_ and or_
            name = name[:-1]
        elif name == "inv":
            name = "invert"

        meth = "__{0}__".format(name)

        if name in ("abs", "invert", "neg", "pos"):
            setattr(cls, meth, cls._get_unary_operator(op))
        else:
            setattr(cls, meth, cls._get_binary_operator(op))

            if name in ("eq", "gt", "ge", "lt", "le", "ne", "getitem"):
                return

            rmeth = "__r{0}__".format(name)
            setattr(cls, rmeth, cls._get_binary_operator(op, inv=True))

    @classmethod
    def _get_unary_operator(cls, op):
        """ Must return a method used by unary operator """
        raise NotImplementedError

    @classmethod
    def _get_binary_operator(cls, op, inv=False):
        """ Must return a method used by binary operator """
        raise NotImplementedError

def partial_by_order(*args, **kwargs):
    """

    >>> from operator import add
    >>> partial_by_order(5, function=add, other=[(1, 10)])
    15
    """
    function = kwargs.pop("function")
    other = kwargs.pop("other")
    args2 = list(args)
    for i, arg in other:
        args2.insert(i, arg)
    return function(*args2, **kwargs)

def is_arraylike(x):
    """Is this object a numpy array or something similar?

    Examples
    --------
    >>> import numpy as np
    >>> is_arraylike(np.ones(5))
    True
    >>> is_arraylike(np.ones(()))
    True
    >>> is_arraylike(5)
    False
    >>> is_arraylike('cat')
    False
    """
    from .base import is_dask_collection

    return bool(
        hasattr(x, "shape")
        and isinstance(x.shape, tuple)
        and hasattr(x, "dtype")
        and not any(is_dask_collection(n) for n in x.shape)
    )

def is_dataframe_like(df):
    """ Looks like a Pandas DataFrame """
    typ = type(df)
    return (
        all(hasattr(typ, name) for name in ("groupby", "head", "merge", "mean"))
        and all(hasattr(df, name) for name in ("dtypes", "columns"))
        and not any(hasattr(typ, name) for name in ("name", "dtype"))
    )

def is_series_like(s):
    """ Looks like a Pandas Series """
    typ = type(s)
    return (
        all(hasattr(typ, name) for name in ("groupby", "head", "mean"))
        and all(hasattr(s, name) for name in ("dtype", "name"))
        and "index" not in typ.__name__.lower()
    )

def is_index_like(s):
    """ Looks like a Pandas Index """
    typ = type(s)
    return (
        all(hasattr(s, name) for name in ("name", "dtype"))
        and "index" in typ.__name__.lower()
    )

def natural_sort_key(s):
    """
    Sorting `key` function for performing a natural sort on a collection of
    strings

    See https://en.wikipedia.org/wiki/Natural_sort_order

    Parameters
    ----------
    s : str
        A string that is an element of the collection being sorted

    Returns
    -------
    tuple[str or int]
        Tuple of the parts of the input string where each part is either a
        string or an integer

    Examples
    --------
    >>> a = ['f0', 'f1', 'f2', 'f8', 'f9', 'f10', 'f11', 'f19', 'f20', 'f21']
    >>> sorted(a)
    ['f0', 'f1', 'f10', 'f11', 'f19', 'f2', 'f20', 'f21', 'f8', 'f9']
    >>> sorted(a, key=natural_sort_key)
    ['f0', 'f1', 'f2', 'f8', 'f9', 'f10', 'f11', 'f19', 'f20', 'f21']
    """
    return [int(part) if part.isdigit() else part for part in re.split(r"(\d+)", s)]

def factors(n):
    """Return the factors of an integer

    https://stackoverflow.com/a/6800214/616616
    """
    seq = ([i, n // i] for i in range(1, int(pow(n, 0.5) + 1)) if n % i == 0)
    return set(functools.reduce(list.__add__, seq))

def parse_bytes(s):
    """Parse byte string to numbers

    >>> from dask.utils import parse_bytes
    >>> parse_bytes('100')
    100
    >>> parse_bytes('100 MB')
    100000000
    >>> parse_bytes('100M')
    100000000
    >>> parse_bytes('5kB')
    5000
    >>> parse_bytes('5.4 kB')
    5400
    >>> parse_bytes('1kiB')
    1024
    >>> parse_bytes('1e6')
    1000000
    >>> parse_bytes('1e6 kB')
    1000000000
    >>> parse_bytes('MB')
    1000000
    >>> parse_bytes(123)
    123
    >>> parse_bytes('5 foos')  # doctest: +SKIP
    ValueError: Could not interpret 'foos' as a byte unit
    """
    if isinstance(s, (int, float)):
        return int(s)
    s = s.replace(" ", "")
    if not any(char.isdigit() for char in s):
        s = "1" + s

    for i in range(len(s) - 1, -1, -1):
        if not s[i].isalpha():
            break
    index = i + 1

    prefix = s[:index]
    suffix = s[index:]

    try:
        n = float(prefix)
    except ValueError as e:
        raise ValueError("Could not interpret '%s' as a number" % prefix) from e

    try:
        multiplier = byte_sizes[suffix.lower()]
    except KeyError as e:
        raise ValueError("Could not interpret '%s' as a byte unit" % suffix) from e

    result = n * multiplier
    return int(result)

byte_sizes = {
    "kB": 10 ** 3,
    "MB": 10 ** 6,
    "GB": 10 ** 9,
    "TB": 10 ** 12,
    "PB": 10 ** 15,
    "KiB": 2 ** 10,
    "MiB": 2 ** 20,
    "GiB": 2 ** 30,
    "TiB": 2 ** 40,
    "PiB": 2 ** 50,
    "B": 1,
    "": 1,
}
byte_sizes = {k.lower(): v for k, v in byte_sizes.items()}
byte_sizes.update({k[0]: v for k, v in byte_sizes.items() if k and "i" not in k})
byte_sizes.update({k[:-1]: v for k, v in byte_sizes.items() if k and "i" in k})

def format_time(n):
    """format integers as time

    >>> from dask.utils import format_time
    >>> format_time(1)
    '1.00 s'
    >>> format_time(0.001234)
    '1.23 ms'
    >>> format_time(0.00012345)
    '123.45 us'
    >>> format_time(123.456)
    '123.46 s'
    """
    if n >= 1:
        return "%.2f s" % n
    if n >= 1e-3:
        return "%.2f ms" % (n * 1e3)
    return "%.2f us" % (n * 1e6)

def format_time_ago(n: datetime) -> str:
    """Calculate a '3 hours ago' type string from a Python datetime.

    Examples
    --------
    >>> from datetime import datetime, timedelta

    >>> now = datetime.now()
    >>> format_time_ago(now)
    'Just now'

    >>> past = datetime.now() - timedelta(minutes=1)
    >>> format_time_ago(past)
    '1 minute ago'

    >>> past = datetime.now() - timedelta(minutes=2)
    >>> format_time_ago(past)
    '2 minutes ago'

    >>> past = datetime.now() - timedelta(hours=1)
    >>> format_time_ago(past)
    '1 hour ago'

    >>> past = datetime.now() - timedelta(hours=6)
    >>> format_time_ago(past)
    '6 hours ago'

    >>> past = datetime.now() - timedelta(days=1)
    >>> format_time_ago(past)
    '1 day ago'

    >>> past = datetime.now() - timedelta(days=5)
    >>> format_time_ago(past)
    '5 days ago'

    >>> past = datetime.now() - timedelta(days=8)
    >>> format_time_ago(past)
    '1 week ago'

    >>> past = datetime.now() - timedelta(days=16)
    >>> format_time_ago(past)
    '2 weeks ago'

    >>> past = datetime.now() - timedelta(days=190)
    >>> format_time_ago(past)
    '6 months ago'

    >>> past = datetime.now() - timedelta(days=800)
    >>> format_time_ago(past)
    '2 years ago'

    """
    units = {
        "years": lambda diff: diff.days / 365,
        "months": lambda diff: diff.days / 30.436875,  # Average days per month
        "weeks": lambda diff: diff.days / 7,
        "days": lambda diff: diff.days,
        "hours": lambda diff: diff.seconds / 3600,
        "minutes": lambda diff: diff.seconds % 3600 / 60,
    }
    diff = datetime.now() - n
    for unit in units:
        dur = int(units[unit](diff))
        if dur > 0:
            if dur == 1:  # De-pluralize
                unit = unit[:-1]
            return "%s %s ago" % (dur, unit)
    return "Just now"

def format_bytes(n):
    """Format bytes as text

    >>> from dask.utils import format_bytes
    >>> format_bytes(1)
    '1 B'
    >>> format_bytes(1234)
    '1.23 kB'
    >>> format_bytes(12345678)
    '12.35 MB'
    >>> format_bytes(1234567890)
    '1.23 GB'
    >>> format_bytes(1234567890000)
    '1.23 TB'
    >>> format_bytes(1234567890000000)
    '1.23 PB'
    """
    if n > 1e15:
        return "%0.2f PB" % (n / 1e15)
    if n > 1e12:
        return "%0.2f TB" % (n / 1e12)
    if n > 1e9:
        return "%0.2f GB" % (n / 1e9)
    if n > 1e6:
        return "%0.2f MB" % (n / 1e6)
    if n > 1e3:
        return "%0.2f kB" % (n / 1000)
    return "%d B" % n

timedelta_sizes = {
    "s": 1,
    "ms": 1e-3,
    "us": 1e-6,
    "ns": 1e-9,
    "m": 60,
    "h": 3600,
    "d": 3600 * 24,
}

tds2 = {
    "second": 1,
    "minute": 60,
    "hour": 60 * 60,
    "day": 60 * 60 * 24,
    "millisecond": 1e-3,
    "microsecond": 1e-6,
    "nanosecond": 1e-9,
}
tds2.update({k + "s": v for k, v in tds2.items()})
timedelta_sizes.update(tds2)
timedelta_sizes.update({k.upper(): v for k, v in timedelta_sizes.items()})

def parse_timedelta(s, default="seconds"):
    """Parse timedelta string to number of seconds

    Examples
    --------
    >>> from datetime import timedelta
    >>> from dask.utils import parse_timedelta
    >>> parse_timedelta('3s')
    3
    >>> parse_timedelta('3.5 seconds')
    3.5
    >>> parse_timedelta('300ms')
    0.3
    >>> parse_timedelta(timedelta(seconds=3))  # also supports timedeltas
    3
    """
    if s is None:
        return None
    if isinstance(s, timedelta):
        s = s.total_seconds()
        return int(s) if int(s) == s else s
    if isinstance(s, Number):
        s = str(s)
    s = s.replace(" ", "")
    if not s[0].isdigit():
        s = "1" + s

    for i in range(len(s) - 1, -1, -1):
        if not s[i].isalpha():
            break
    index = i + 1

    prefix = s[:index]
    suffix = s[index:] or default

    n = float(prefix)

    multiplier = timedelta_sizes[suffix.lower()]

    result = n * multiplier
    if int(result) == result:
        result = int(result)
    return result

def has_keyword(func, keyword):
    try:
        return keyword in inspect.signature(func).parameters
    except Exception:
        return False

def ndimlist(seq):
    if not isinstance(seq, (list, tuple)):
        return 0
    elif not seq:
        return 1
    else:
        return 1 + ndimlist(seq[0])

def iter_chunks(sizes, max_size):
    """Split sizes into chunks of total max_size each

    Parameters
    ----------
    sizes : iterable of numbers
        The sizes to be chunked
    max_size : number
        Maximum total size per chunk.
        It must be greater or equal than each size in sizes
    """
    chunk, chunk_sum = [], 0
    iter_sizes = iter(sizes)
    size = next(iter_sizes, None)
    while size is not None:
        assert size <= max_size
        if chunk_sum + size <= max_size:
            chunk.append(size)
            chunk_sum += size
            size = next(iter_sizes, None)
        else:
            assert chunk
            yield chunk
            chunk, chunk_sum = [], 0
    if chunk:
        yield chunk

hex_pattern = re.compile("[a-f]+")

def key_split(s):
    """
    >>> key_split('x')
    'x'
    >>> key_split('x-1')
    'x'
    >>> key_split('x-1-2-3')
    'x'
    >>> key_split(('x-2', 1))
    'x'
    >>> key_split("('x-2', 1)")
    'x'
    >>> key_split('hello-world-1')
    'hello-world'
    >>> key_split(b'hello-world-1')
    'hello-world'
    >>> key_split('ae05086432ca935f6eba409a8ecd4896')
    'data'
    >>> key_split('<module.submodule.myclass object at 0xdaf372')
    'myclass'
    >>> key_split(None)
    'Other'
    >>> key_split('x-abcdefab')  # ignores hex
    'x'
    >>> key_split('_(x)')  # strips unpleasant characters
    'x'
    """
    if type(s) is bytes:
        s = s.decode()
    if type(s) is tuple:
        s = s[0]
    try:
        words = s.split("-")
        if not words[0][0].isalpha():
            result = words[0].strip("_'()\"")
        else:
            result = words[0]
        for word in words[1:]:
            if word.isalpha() and not (
                len(word) == 8 and hex_pattern.match(word) is not None
            ):
                result += "-" + word
            else:
                break
        if len(result) == 32 and re.match(r"[a-f0-9]{32}", result):
            return "data"
        else:
            if result[0] == "<":
                result = result.strip("<>").split()[0].split(".")[-1]
            return result
    except Exception:
        return "Other"

def stringify(obj, exclusive: Optional[Iterable] = None):
    """Convert an object to a string

    If ``exclusive`` is specified, search through `obj` and convert
    values that are in ``exclusive``.

    Note that when searching through dictionaries, only values are
    converted, not the keys.

    Parameters
    ----------
    obj : Any
        Object (or values within) to convert to string
    exclusive: Iterable, optional
        Set of values to search for when converting values to strings

    Returns
    -------
    result : type(obj)
        Stringified copy of ``obj`` or ``obj`` itself if it is already a
        string or bytes.

    Examples
    --------
    >>> stringify(b'x')
    b'x'
    >>> stringify('x')
    'x'
    >>> stringify({('a',0):('a',0), ('a',1): ('a',1)})
    "{('a', 0): ('a', 0), ('a', 1): ('a', 1)}"
    >>> stringify({('a',0):('a',0), ('a',1): ('a',1)}, exclusive={('a',0)})
    {('a', 0): "('a', 0)", ('a', 1): ('a', 1)}
    """

    typ = type(obj)
    if typ is str or typ is bytes:
        return obj
    elif exclusive is None:
        return str(obj)

    if typ is tuple and obj:
        from .optimization import SubgraphCallable

        obj0 = obj[0]
        if type(obj0) is SubgraphCallable:
            obj0 = obj0
            return (
                SubgraphCallable(
                    stringify(obj0.dsk, exclusive),
                    obj0.outkey,
                    stringify(obj0.inkeys, exclusive),
                    obj0.name,
                ),
            ) + tuple(stringify(x, exclusive) for x in obj[1:])
        elif callable(obj0):
            return (obj0,) + tuple(stringify(x, exclusive) for x in obj[1:])

    if typ is list:
        return [stringify(v, exclusive) for v in obj]
    if typ is dict:
        return {k: stringify(v, exclusive) for k, v in obj.items()}
    try:
        if obj in exclusive:
            return stringify(obj)
    except TypeError:  # `obj` not hashable
        pass
    if typ is tuple:  # If the tuple itself isn't a key, check its elements
        return tuple(stringify(v, exclusive) for v in obj)
    return obj

def stringify_collection_keys(obj):
    """Convert all collection keys in ``obj`` to strings.

    This is a specialized version of ``stringify()`` that only converts keys
    of the form: ``("a string", ...)``
    """

    typ = type(obj)
    if typ is tuple and obj:
        obj0 = obj[0]
        if type(obj0) is str or type(obj0) is bytes:
            return stringify(obj)
        if callable(obj0):
            return (obj0,) + tuple(stringify_collection_keys(x) for x in obj[1:])
    if typ is list:
        return [stringify_collection_keys(v) for v in obj]
    if typ is dict:
        return {k: stringify_collection_keys(v) for k, v in obj.items()}
    if typ is tuple:  # If the tuple itself isn't a key, check its elements
        return tuple(stringify_collection_keys(v) for v in obj)
    return obj

_NOT_FOUND = object()

# TODO: Copied from functools.cached_property in python 3.8:
class cached_property:
    def __init__(self, func):
        self.func = func
        self.attrname = None
        self.__doc__ = func.__doc__
        self.lock = RLock()

    def __set_name__(self, owner, name):
        if self.attrname is None:
            self.attrname = name
        elif name != self.attrname:
            raise TypeError(
                "Cannot assign the same cached_property to two different names "
                f"({self.attrname!r} and {name!r})."
            )

    def __get__(self, instance, owner=None):
        if instance is None:
            return self
        if self.attrname is None:
            raise TypeError(
                "Cannot use cached_property instance without calling __set_name__ on it."
            )
        try:
            cache = instance.__dict__
        except AttributeError:  # not all objects have __dict__ (e.g. class defines slots)
            msg = (
                f"No '__dict__' attribute on {type(instance).__name__!r} "
                f"instance to cache {self.attrname!r} property."
            )
            raise TypeError(msg) from None
        val = cache.get(self.attrname, _NOT_FOUND)
        if val is _NOT_FOUND:
            with self.lock:
                # check if another thread filled cache while we awaited lock
                val = cache.get(self.attrname, _NOT_FOUND)
                if val is _NOT_FOUND:
                    val = self.func(instance)
                    try:
                        cache[self.attrname] = val
                    except TypeError:
                        msg = (
                            f"The '__dict__' attribute on {type(instance).__name__!r} instance "
                            f"does not support item assignment for caching {self.attrname!r} property."
                        )
                        raise TypeError(msg) from None
        return val


__sets = {}

import numpy as np

from .pascal_voc import pascal_voc
from .imagenet3d import imagenet3d
from .kitti import kitti
from .kitti_tracking import kitti_tracking
from .nthu import nthu
from .coco import coco
from .kittivoc import kittivoc

def _selective_search_IJCV_top_k(split, year, top_k):
    """Return an imdb that uses the top k proposals from the selective search
    IJCV code.
    """
    imdb = pascal_voc(split, year)
    imdb.roidb_handler = imdb.selective_search_IJCV_roidb
    imdb.config['top_k'] = top_k
    return imdb

# Set up voc_<year>_<split> using selective search "fast" mode
for year in ['2007', '2012', '0712']:
    for split in ['train', 'val', 'trainval', 'test']:
        name = 'voc_{}_{}'.format(year, split)
        __sets[name] = (lambda split=split, year=year:
                        pascal_voc(split, year))

    # Set up kittivoc
    for split in ['train', 'val', 'trainval', 'test']:
        name = 'kittivoc_{}'.format(split)
        # print name
        __sets[name] = (lambda split=split: kittivoc(split))

# # KITTI dataset
for split in ['train', 'val', 'trainval', 'test']:
    name = 'kitti_{}'.format(split)
    # print name
    __sets[name] = (lambda split=split: kitti(split))

# Set up coco_2014_<split>
for year in ['2014']:
    for split in ['train', 'val', 'minival', 'valminusminival']:
        name = 'coco_{}_{}'.format(year, split)
        __sets[name] = (lambda split=split, year=year: coco(split, year))

# Set up coco_2015_<split>
for year in ['2015']:
    for split in ['test', 'test-dev']:
        name = 'coco_{}_{}'.format(year, split)
        __sets[name] = (lambda split=split, year=year: coco(split, year))

# NTHU dataset
for split in ['71', '370']:
    name = 'nthu_{}'.format(split)
    # print name
    __sets[name] = (lambda split=split: nthu(split))

def get_imdb(name):
    """Get an imdb (image database) by name."""
    if not __sets.has_key(name):
        # print (list_imdbs())
        raise KeyError('Unknown dataset: {}'.format(name))
    return __sets[name]()

def list_imdbs():
    """List all registered imdbs."""
    return __sets.keys()


import wx
from listing11_01 import BlockWindow

class TestFrame(wx.Frame):
    def __init__(self, lables, col_sizes, row_sizes):
        wx.Frame.__init__(self, None, -1, "Resizing Flex Grid Sizer")
        sizer = wx.FlexGridSizer(rows=3, cols=3)#, hgap=5, vgap=5)

        for label in labels:
            bw = BlockWindow(self, label=label)
            if label == "five": bw.SetMinSize((150,50))
            sizer.Add(bw, 0,
                      flag=wx.GROW | wx.ALL,
                      border = 5)

        for col, size in zip(range(len(col_sizes)), col_sizes):
            sizer.AddGrowableCol(col, size)

        for row, size in zip(range(len(row_sizes)), row_sizes):
            sizer.AddGrowableRow(row, size)

        self.SetSizer(sizer)
        self.Fit()

app = wx.PySimpleApp()

labels = "one two three four five six seven eight nine".split()
col_sizes = [1,2,1] # re-size proportions
row_sizes = [1,5,1]
TestFrame(labels, col_sizes, row_sizes).Show()
app.MainLoop()


import sys
sys.setrecursionlimit(10**8)
dx = [1, 0, -1, 0]
dy = [0, 1, 0, -1]

def DFS(y, x, visited):
    global shark_x, Y
    for d in range(4):
        newy = y + dy[d]
        newx = x + dx[x]
        if 0 <= newy < Y and 0 <= newx < X and (newy, newx) not in visited and (cheese[newy][newx] == 0 or cheese[newy][newx] == -1):
            DFS(newy,newx,visited)
        cheese[y][x] = -1

def melted(y, x, visited):
    visited.add((y, x))

    check = False
    for d in range(4):
        newy = y + dy[d]
        newx = x + dx[x]
        if cheese[newy][newx] == -1:
            check = True
            break

    for d in range(4):
        newy = y + dy[d]
        newx = x + dx[x]
        if 0 < newy < Y and 0 < newx < shark_x and (newy, newx) not in visited and cheese[newy][newx] == 1:
            melted(newy, newx, visited)
    if check:
        cheese[y][x] = -1
    return visited

Y, shark_x = map(int, input().split())
cheese = [list(map(int, input().split()))for _ in range(Y)]

melt = False
time = 0
while not melt:
    DFS(0, 0, set())
    visited = set()

    for y in range(Y):
        for x in range(shark_x):
            if cheese[y][x] == 1 and (y, x) not in visited:
                visited = melted(y, x, set())
    time += 1

    melt = True
    for y in range(Y):
        for x in range(shark_x):
            if cheese[y][x] == 1:
                melt = False
print(time)
print(len(visited))


import time
import pyperclip
import pyautogui
import keyboard
from bs4 import BeautifulSoup

def get_page_source(url):
    # Espera 3 segundos antes de comenzar
    time.sleep(1.5)

    # Copia la URL al portapapeles
    pyperclip.copy(url)

    # Emula el atajo de teclado Ctrl+L para seleccionar la barra de direcciones
    pyautogui.hotkey('ctrl', 'l')

    # Espera 0.2 segundos para que se seleccione la barra de direcciones
    time.sleep(0.2)

    # Emula el atajo de teclado Ctrl+V para pegar la dirección de la página
    pyautogui.hotkey('ctrl', 'v')

    # Espera 0.2 segundos para que se pegue la dirección
    time.sleep(0.2)

    # Emula la tecla Enter para abrir la página
    pyautogui.press('enter')

    # Espera 1 segundo para que se cargue la página
    time.sleep(2.5)

    # Emula el atajo de teclado Ctrl+U para abrir el código fuente de la página
    pyautogui.hotkey('ctrl', 'u')

    # Espera 1 segundo para que se abra el código fuente
    time.sleep(3)

    # Emula el atajo de teclado Ctrl+A para seleccionar todo el contenido
    pyautogui.hotkey('ctrl', 'a')

    # Espera 1 segundo para que se realice la selección
    time.sleep(1.5)

    # Emula el atajo de teclado Ctrl+C para copiar el contenido al portapapeles
    pyautogui.hotkey('ctrl', 'c')

    # Espera 1 segundo para que se copie al portapapeles
    time.sleep(1)

    pyautogui.hotkey('ctrl', 'w')
    time.sleep(0.5)

    # Obtiene el contenido del portapapeles
    page_source = pyperclip.paste()

    # Parsea el código fuente con BeautifulSoup
    soup = BeautifulSoup(page_source, 'html.parser')

    # Encuentra todos los elementos <article>
    articles = soup.find_all('article')

    # Abre el archivo "pagesource.txt" en modo append
    with open('pagesource.txt', 'a', encoding='utf-8') as file:
        for article in articles:
            file.write(str(article))
            file.write('\n\n')

    print(f"El contenido de los elementos <article> de {url} se ha agregado a 'pagesource.txt'")

def process_page_source():
    # Leer el archivo "pagesource.txt"
    with open('pagesource.txt', 'r', encoding='utf-8') as file:
        page_source = file.read()

    # Realizar el procesamiento adicional con la variable "page_source"
    # ...

    # Imprimir el resultado
    print("Procesamiento adicional completado.")

def stop_program():
    print("Programa detenido")
    exit()

if __name__ == '__main__':
    with open('urls.txt', 'r') as file:
        urls = file.read().splitlines()

    print("Presiona 'esc' en cualquier momento para detener el programa.")
    print("El programa iniciará en 2 segundos.")
    time.sleep(1.5)

    # Activa la ventana del navegador utilizando Alt+Tab
    pyautogui.keyDown('alt')
    pyautogui.press('tab')
    pyautogui.keyUp('alt')

    keyboard.on_press_key('esc', stop_program)

    for url in urls:
        get_page_source(url)
        print("----------------------------------")

        # Llamar a la función para procesar el contenido del archivo "pagesource.txt"
        process_page_source()
        print("----------------------------------")


#start programa
print("*** Online kasino ***")
import numpy as np
import time, sys

#kasino gratis novac ulaz
baza = 5
ime=input("Kako se zoves?: ")
print ("Zdravo " + ime+".")
time.sleep(2)

#provjera likvidnosti
dodaj=input ("Poklanjamo ti 5KM. Koliko ti para imas " + ime+"? ")
cijena = baza + float(dodaj)
if cijena>=20:
    print ("Dobrodosao " +ime+ " idemo se igrati.")
    time.sleep(2)
    print ("***Kasino lutrija ti poklanja... ***")
    time.sleep(2)

    #kasino poklanja
    x= np.random.randint(1,1000,1)
    print (str(x))
    if x<500:
        time.sleep(2)
        print("Samo "+str(x)+" Premalo si dobio, zajebaše te.")

    elif x>=500:
        time.sleep(2)
        print("Uhh "+str(x)+" maraka."+" Eto para majstore.")

    #provjera stanja
    stanje=cijena+x
    print ("Na računu imaš "+str(stanje)+"KM")
    time.sleep(2)

    #ulog novca
    kocka=input("** "+ime+" koliko želiš da uložiš? ** ")
    time.sleep(1)

    if int(kocka)>stanje:
            print (ime+" nemaš toliko para na računu.")
            #kocka=input("** "+ime+" koliko želiš da uložiš? ** ")

    if int(kocka)<=stanje:
            print (ime+" uložio si "+kocka+"KM.")

    #novo stanje novca
    time.sleep(2)
    stanje_novo=cijena+x-int(kocka)
    print ("*** Na računu imaš još "+str(stanje_novo)+"KM ***")

elif cijena<20:
    print ("Minimalan ulaz je sa 20KM. Kokuz si brate, nemas dovoljno para. Doviđenja " + ime+".")
    #kraj programa


# Necessary imports
from flask import Blueprint, request
from flask_login import current_user, login_required
from sqlalchemy.orm import joinedload

from ..models import db, PlanetComment
from ..forms import PlanetCommentForm

planet_comment_routes = Blueprint('planet_comments', __name__)

# Get all comments route
@planet_comment_routes.route('/')
def get_all_planet_comments():
    all_comments = PlanetComment.query.all()
    return [comment.to_dict() for comment in all_comments]

# Get all comments for one planet route
@planet_comment_routes.route('/planet/<int:id>')
def get_one_planet_all_comments(id):
    all_planet_comments = PlanetComment.query.filter(PlanetComment.planet_id == id).all()
    return [comment.to_dict() for comment in all_planet_comments]

# Get one comment details route
@planet_comment_routes.route('/<int:id>')
def get_one_comment(id):
    one_comment = PlanetComment.query.get(id)
    if one_comment:
        return one_comment.to_dict()
    return {"message": "planet comment not found"}

# Update a planet comment route
@planet_comment_routes.route('<int:id>', methods=["PATCH", "PUT"])
def update_planet_comment(id):
    user = current_user
    planet_comment = PlanetComment.query.get(id)

    if planet_comment:
        form = PlanetCommentForm()
        form["csrf_token"].data = request.cookies["csrf_token"]
        if planet_comment.user_id == user.id:
            if form.validate_on_submit():
                planet_comment.content = form.data["content"]
                db.session.commit()
                updated_planet_comment = PlanetComment.query.get(id)
                return {"planet_comment": updated_planet_comment.to_dict()}
            if form.errors:
                return {"message": "form errors", "errors": f"{form.errors}"}
        return {"message": "this comment does not belong to this user"}
    return {"message": "planet comment not found"}

# Delete a planet comment route
@planet_comment_routes.route('/<int:id>', methods=["DELETE"])
def delete_planet_comment(id):
    user = current_user
    planet_comment = PlanetComment.query.get(id)

    if planet_comment:
        if planet_comment.user_id == user.id:
            db.session.delete(planet_comment)
            db.session.commit()
            return {"message": "Planet Comment Deleted!"}
        return {"message": "Comment does not belong to this user"}
    return {"message": "Comment not found"}


from fastapi import APIRouter
from App.src.schema import GameResponseSchema, GameRequestSchema
from App.src.models import Game
from typing import List

api = APIRouter(
    prefix="/games",
    tags=["games"],
)

@api.post("/", response_model=GameResponseSchema)
async def create_Games(Games: GameRequestSchema):
    Games = await Game.create(**dict(Games))
    return Games

@api.get("/{id}", response_model=GameResponseSchema)
async def get_Games(id: int):
    Games = await Game.get(id)
    return Games

@api.get("/",response_model=list[GameResponseSchema])
async def get_all_Games():
    Games = await Game.get_all()
    return Games

@api.put('/{id}', response_model=GameResponseSchema)
async def update(id: int,Games: GameRequestSchema):
    Games = await Game.update(id,**dict(Games))
    return Games

@api.delete('/{id}',response_model=bool)
async def delete (id: int):
    return await Game.delete(id)

@api.get('/search/', response_model=list[GameResponseSchema])
async def search(name: str or None = ''):
    return await Game.get_by_name_or_description(name)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Jun 22 18:28:05 2017

@author: aidanrocke
"""

import matplotlib.pyplot as plt
from keras.models import Model
import numpy as np
from scipy.stats import entropy
from keras.models import load_model
import os
import pandas as pd
from keras.utils import np_utils

from scipy.stats import rankdata
from sklearn.decomposition import PCA
import matplotlib.cm as cm

"""
import sys

sys.path.insert(0,'/Users/aidanrocke/Desktop/deep_rectifiers/deep_rectifiers/')
from utils import *
"""

class Activations:
    def __init__(self,models_file_path,num_layers,width,data,labels):
        self.file_path = models_file_path
        self.num_layers = num_layers
        self.width = width
        self.models = [load_model(self.file_path+model) for model in os.listdir(self.file_path) if model.endswith('.h5')]
        self.X_train, self.X_test = data[0], data[1]
        self.train_labels, self.test_labels = labels[0], labels[1]
        self.y_train, self.y_test = data[2], data[3]

        self.num_labels = len(set(self.train_labels))

    def get_activity(X_train,model, layer):
        """
            input:
                model (keras.models.Sequential) : a Keras sequential model
                layer (int): a particular hidden layer in a model
                X (numpy.ndarray): samples that can be fed to a model

            output:
                activity (numpy.ndarray) : activations of a particular hidden layer

        """
        layer = model.layers[layer]
        layer_model = Model(inputs=model.input,outputs=layer.output)

        return layer_model.predict(X_train)

    def percent_active(activations):
        """
            input:
                activations (numpy.ndarray): a multidimensional array of binary
                                             activations

            output:
                fraction (numpy.ndarray) : the fraction of nodes active per sample
        """
        N, M = np.shape(activations)

        fraction = np.zeros(N)

        for i in range(N):
            fraction[i] = np.mean(activations[i])

        return fraction

    def binary_activity(self):
        """
            input:
                models_file_path (str) : location of folder containing trained Keras
                                         models where each model is assumed to have
                                         the same architecture

                num_layers (int) : the number of layers of each model

                width (int) : the width of the hidden layers of each model

                X (numpy.ndarray) : samples that can be fed to a model

            output:
                activity (numpy.ndarray) : a multidimensional array representing
                                           binary activations per sample

                mean_activity (numpy.ndarray) : the fraction of nodes active per sample
        """

        #load models:

        N, M = np.shape(self.X_train)
        epochs = len(self.models)

        mean_activity = np.zeros((epochs,N,self.num_layers))

        activity = np.zeros((epochs,N,self.width*(self.num_layers)))

        for i in range(epochs):

            model = self.models[i]

            for j in range(self.num_layers):
                #get activations:
                activations = np.array(Activations.get_activity(self.X_train,model,j) > 0,dtype=bool)
                activity[i][:,range(j*self.width,(j+1)*self.width)] = activations

                layer_values = np.array(activations > 0,dtype=bool)

                mean_activity[i][:,j] = Activations.percent_active(layer_values.astype(int))

        return activity, mean_activity

    def variable_size_representation(self,subclasses,model):
        """
            input:
                classes (list): a list of integers specifying classes

                model (Sequential) : a particular model to use

            output:
                rankings (Dataframe) : a multidimensional array representing
                                           binary activations per sample
        """
        #one-hot encode the classes:

        classes  = np_utils.to_categorical(np.arange(10))
        encoded_subclasses = classes[[subclasses]]

        #get indices by obtaining boolean array:
        ix1, ix2  = np.array([np.mean(self.y_train == i,1)== 1.0 for i in encoded_subclasses])+0, np.array([np.mean(self.y_test == i,1)== 1.0 for i in encoded_subclasses])

        ix1, ix2 = np.array([np.max(ix1[:,i]) for i in range(np.max(np.shape(ix1)))],dtype=bool), np.array([np.max(ix2[:,i]) for i in range(np.max(np.shape(ix2)))],dtype=bool)

        #let's subset our training data:
        X_train, y_train, train_labels = self.X_train[ix1], self.y_train[ix1], self.train_labels[ix1]

        X_test, y_test= self.X_test[ix2], self.y_test[ix2]

        model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=10, batch_size=5000, verbose=2)

        #get activity per layer:
        N, M = np.shape(X_train)

        activity_per_layer = np.zeros((N,self.num_layers))

        for i in range(self.num_layers):
                #get activations:
                activations = np.array(Activations.get_activity(X_train,model, i) > 0,dtype=bool)

                layer_values = np.array(activations > 0,dtype=bool)

                activity_per_layer[:,i] = Activations.percent_active(layer_values.astype(int))

        #rank the variable sizes:
        mean_activity = np.mean(activity_per_layer,1)

        variable_size = np.zeros(len(subclasses))

        for i in range(len(subclasses)):
            variable_size[i] = np.mean(mean_activity[train_labels == subclasses[i]])

        ranks = rankdata(variable_size)

        rankings = pd.DataFrame(data = ranks.reshape((1,len(subclasses))), index = ['variable_size'], columns=['rank of '+str(i) for i in subclasses]) #creates a new dataframe that's empty

        return rankings

    def visualize_activations(self,activity):
        """
            Two dimensional linear embedding of binary activity.
        """
        pca = PCA(n_components=2)
        pca_result = pca.fit_transform(activity)

        plt.style.use('ggplot')

        bounds = np.linspace(0,10,11)

        #create plots:

        f, (ax) = plt.subplots(1, 1,figsize=(25,15))

        #, sharey=True

        scat = ax.scatter(pca_result[:,0],pca_result[:,1], c=self.train_labels,cmap=cm.Set3)
        ax.set_title('PCA activation clusters',fontsize=15)
        ax.set_facecolor('bisque')

        plt.colorbar(scat, spacing='proportional',ticks=bounds)

        plt.show()

    def visualize_average_sparsity(mean_activity):
        """
            Visualization of sparsity of each hidden layer's activity using histograms
            for each epoch.
        """

        epochs, samples, layers = np.shape(mean_activity)

        f, ax = plt.subplots(layers, epochs,figsize=(20,20))

        plt.style.use('ggplot')

        if layers > 1:

            for i in range(epochs):
                for j in range(layers):

                    ent = entropy(mean_activity[i][:,j],mean_activity[epochs-1][:,j])
                    ax[j,i].hist(mean_activity[i][:,j],color='steelblue',label='entropy = '+str(ent))
                    ax[j,i].set_title('epoch '+str(i+1)+'_layer '+str(j+1))

                    ax[j,i].legend(loc='upper left')

        else:
            for i in range(epochs):
                for j in range(layers):

                    ent = entropy(mean_activity[i][:,j],mean_activity[epochs-1][:,j])
                    ax[i].hist(mean_activity[i][:,j],color='steelblue',label='entropy = '+str(ent))
                    ax[i].set_title('epoch '+str(i+1)+'_layer '+str(j+1))

                    ax[i].legend(loc='upper left')

        plt.show()

    def activation_map(self,activity,epoch):
        """

            input:
                activity (numpy.ndarray) : a multidimensional array representing
                                           binary activations per sample

                labels (numpy.ndarray) : the target label for each sample

                 epoch (int) : a version of a model at an epoch in its training history

            output:

                diff (numpy.ndarray): a map of the average euclidean distance in activation space

        """

        act = activity[epoch]

        diff = np.zeros((10,10))

        for i in range(10):

            avg = np.mean(act[np.where(self.train_labels == i)],0)

            for j in range(10):

                delta = act[np.where(self.train_labels == j)] - avg

                diff[i][j] = np.mean([np.linalg.norm(k) for k in delta])

        return diff

    #analysing of node sharing among subnetworks:

    def nodes_set(self,activity,num_labels):

        nodes_used, vectors = [], []

        for j in range(self.num_labels):

            vectors.append(activity[np.where(self.y_train == j)])

            nodes_used.append(set(np.nonzero(vectors[j])[1]))

        return nodes_used

    def node_sharing(self,activity,num_labels):

        L, M, N = np.shape(activity)

        nodes_shared = np.zeros((L,num_labels,num_labels))

        for i in range(L):

            act = activity[i]

            nodes_used = Activations.nodes_set(act,self.y_train,self.num_labels)

            for j in range(self.num_labels):

                nodes_shared[i,j] = np.array([len(set.intersection(nodes_used[j],nodes_used[k])) for k in range (num_labels)])/float(len(nodes_used[j]))

        return nodes_shared


def main():
    numero = int(input('Digite o limite: '))
    contador = 1

    while contador <= numero:
        if contador == 1:
            soma = 1
        else:
            soma = soma + contador

        contador += 1

    print(f'O somatório é: {soma}')

if __name__ == '__main__':
    main()


import requests
import sys
import simplejson
import csv
from django.db.models.fields import FieldDoesNotExist
from django.db import models
from crunch.main.models import Company
from main.models import Company, tag, ipo, financial_org, investments, funding_rounds, person

def calc_raised(co_obj):

	# For the given company object, get the list of funding rounds
	fr = co_obj.funding_rounds.all()

	# Initialize amount to 0
	a = 0

	for i in fr:
		a = a + i.raised_amount

	return a

#get all cos by finding a tag in tags
def get_by_tag(given_tag):

	#get all companies
	cos = Company.objects.all()

	#create an empty list
	tag_cos = []
	#loop through all the cos
	for c in cos:

		#get the tag list for the company
		t_list = c.tag_list.all()
		#loop through the tag list
		for t in t_list:

			#if the tag matches the given_tag, append the company to the list
			if given_tag in t.tag:
				tag_cos.append(c)

	return tag_cos

#Get all cos by finding a tag in description text or overview
def get_by_desc(given_tag):

	#get all companies
	cos = Company.objects.all()

	#create an empty list
	desc_cos = []
	#loop through all the cos
	for c in cos:

		#get the description of the company
		desc = c.description
		overv = c.overview
		#if the
		if given_tag in desc or given_tag in overv:
			desc_cos.append(c)

	return desc_cos

#Fetch all companies that have ipo'd
def get_ipos():
	cos = Company.objects.all()

	#create an empty list
	ipos = []

	#for c in cos:
		#get ipo for company


COLOUR_TO_HEXADECIMAL_COLOUR = {"AliceBlue": "#f0f8ff", "Amaranth": "Amaranth", "Amber": "#ffbf00",
                                "Amethyst": "#9966cc", "AntiqueWhite": "#faebd7", "Apricot": "#fbceb1",
                                "Aqua": "#00ffff", "Asparagus": "#87a96b", "Aureolin": "#fdee00", "Azure1": "#f0ffff"}

colour_name = input("Which colour are you looking for?: ")
while colour_name != "":
    try:
        print(f"The colour is {COLOUR_TO_HEXADECIMAL_COLOUR[colour_name]}")
    except KeyError:
        print("Sorry, we do not have that color")
    colour_name = input("Which colour are you looking for?: ")


import torch
import torch.nn as nn
import torch.optim as optim
import torch.utils.data as data
import torch.nn.functional as F
import numpy as np
import torch.optim as optim
from torch.autograd import Variable
from model import  Net
from load_data_help import start_item_data
from  config import  config

cfg=config()

dataset=start_item_data(low_count=cfg.low_count,num_steps=cfg.num_steps,batch_size=cfg.batch_size,file=cfg.file)
testdataset=start_item_data(low_count=cfg.low_count,num_steps=cfg.num_steps,batch_size=cfg.batch_size,file=cfg.file,training=False)
model=Net(cfg)
#print(model)

device=torch.device("cuda:0" if  torch.cuda.is_available() else "cpu")
print(device)
loss_fn=nn.CrossEntropyLoss()
def trian(epochs,dataset,model,optimizer=None,testdataset=None):
    for i in range(epochs):
        if optimizer is not None:
            optimizers=optimizer
            #optimizers= optim.lr_scheduler.StepLR(optimizers, 2, 0.1)
        else:
            optimizers=optim.Adam(model.parameters(),lr=cfg.learning_rate)
            #optimizers=optim.lr_scheduler.StepLR(optimizers,2,0.1)
        #optimizers=adjust_learning_rate(optimizers,i)
        train_accuracy_list = []
        train_loss_list = []
        for index, (b_x, b_y) in enumerate(dataset):
            model.train()
            model=model.to(device)
            b_x = b_x.type(torch.LongTensor)
            b_x = Variable(b_x).to(device)
            b_y = b_y.type(torch.LongTensor)
            b_y = Variable(b_y)

            logist=model(b_x)
            logist=torch.softmax(logist,dim=-1)

            preds=torch.argmax(logist,dim=1)
            preds=preds.to(device='cpu')

            correct = torch.eq(preds, b_y)
            correct = torch._cast_Double(correct)
            accuracy = torch.mean(correct)

            loss=loss_fn(logist,b_y)
            train_loss_list.append(loss.item())
            train_accuracy_list.append(accuracy.item())
            optimizers.zero_grad()
            loss.backward()
            optimizers.step()
            #writer.add_graph(model=model,input_to_model=torch._cast_Long(torch.ones(1,10)))
            print("epoch: %d   steps: %d   loss :%3.3f   accuracy:%3.3f " % (i, index, loss, accuracy.item()))

        print("epoch:%d average_loss:%3.3f average_accuracy:%3.3f" % (i, np.mean(train_loss_list), np.mean(train_accuracy_list)))

        torch.save(model, cfg.save_model+'model-{}.pkl'.format(i))

        with torch.no_grad():
            if testdataset is not None:

                test_model=torch.load(cfg.save_model+'model-{}.pkl'.format(i))
                test_model=test_model.to(device)
                test_accuracy_list=[]

                for index_i,(test_x,test_y) in enumerate(testdataset):
                    test_model.eval()
                    test_x=test_x.type(torch.LongTensor)
                    test_x=Variable(test_x).to(device)

                    test_y=test_y.type(torch.LongTensor)
                    test_y=Variable(test_y)

                    test_logist=test_model(test_x)

                    test_pred=torch.softmax(test_logist,dim=1)
                    test_pred=torch.argmax(test_pred,dim=1)

                    test_pred=test_pred.to(device='cpu')
                    test_correct=torch.eq(test_pred,test_y)
                    test_correct=torch._cast_Double(test_correct)
                    test_accuracy=torch.mean(test_correct)
                    test_accuracy_list.append(test_accuracy.item())

                    print("steps: %d accuracy: %3.3f"%(index_i,test_accuracy.item()))

                test_average_accuracy=np.mean(test_accuracy_list)

                print('average accuracy: %3.3f'%test_average_accuracy)

def test(dataset):

    test_model = torch.load('model/agnews/model-0.pkl')
    test_accuracy_list = []
    for index_i, (test_x, test_y) in enumerate(dataset):
        test_model.eval()
        test_x = test_x.type(torch.LongTensor)
        test_x = Variable(test_x).to(device)

        test_y = test_y.type(torch.LongTensor)
        test_y = Variable(test_y)

        test_capsule= test_model(test_x)
        test_legnth = test_capsule.norm(dim=-1)
        test_pred = torch.max(test_legnth, dim=1)[1]
        test_pred=test_pred.to(device='cpu')
        test_correct = torch.eq(test_pred, test_y)
        test_correct = torch._cast_Double(test_correct)
        test_accuracy = torch.mean(test_correct)
        test_accuracy_list.append(test_accuracy.item())

        print("steps: %d accuracy: %3.3f" % (index_i, test_accuracy.item()))

    test_average_accuracy = np.mean(test_accuracy_list)
    print('average accuracy: %3.3f' % test_average_accuracy)

trian(epochs=10,dataset=dataset,model=model,testdataset=testdataset)

#test(dataset=testdataset)


import networkx as nx
import numpy as np

N = 1000
z = 4
n_realizations = 10

graph = nx.complete_graph(N)
#graph = nx.barabasi_albert_graph(N,z)

for i in range(n_realizations):
  with open("/Users/mos/Documents/ULB/MA3.tmp/INFO-F409/Exam/LDProject/graphs/py_graph_{}.txt".format(i),"w") as file:
    for key in graph:
      i = 0
      for el in graph[key]:
        if i == 0:
          file.write("{}".format(el))
          i+=1
        else:
          file.write(",{}".format(el))
      file.write("\n")


import matplotlib.pyplot as plt

def plot_results(df_results):
    # Total debt over time.
    plt.figure()
    plt.title('Total debt over time')
    plt.xlabel('Month Number')
    plt.ylabel('Amount')
    plt.grid(True)
    plt.plot(df_results['month'], df_results['total_debt'], label='total debt')
    plt.plot([0, num_months], [df_results['total_limit'][0], df_results['total_limit'][num_months - 1]], color='red', label='Total available credit limit')
    plt.ylim([0, max(df_results['total_limit'])*1.01])
    plt.legend()

    # Total monthly interest due
    plt.figure()
    plt.title('Total monthly interest due per month')
    plt.xlabel('Month number')
    plt.ylabel('Monthly interest cost')
    plt.grid(True)
    plt.plot(df_results['month'], df_results['total_annual_interest_due']/12)

    # Total credit utilization
    plt.figure()
    plt.title('Percent credit utilization per month')
    plt.xlabel('Month number')
    plt.ylabel('\% Credit Utilization')
    plt.grid(True)
    plt.plot(df_results['month'], df_results['total_credit_utilization'], label='\% credit utilization')
    plt.plot([0,num_months], [1,1], color='red', label='credit_limit')
    plt.ylim([0,1.1])

    # Total Minimum Payments over time
    plt.figure()
    plt.title('Minimum payments per month')
    plt.xlabel('Month number')
    plt.ylabel('Minimum repayment amount')
    plt.grid(True)
    plt.plot(df_results['month'], df_results['total_min_payments'])


from decorators import command
from deps.InfoMessage import InfoMessage
from datetime import datetime
from deps.helpers import update_seen
from pickle import dumps, loads

@command("add", argc=-1, text="!add [challenge_name OR challenge_id] [url or text] - Add some info to a challenge to help others out", username=True)
def add(moose, username, args):
	if len(args) < 2:
		moose.cmd("help", "add")
		return
	challenge_name, description = args[0], args[1:]
	new_info = InfoMessage(username, datetime.now().strftime("%m-%d-%Y %H:%M:%S"), " ".join(description))
	if moose.redis_server.hget("challs", challenge_name) == None:
		moose.redis_server.hset("challs", challenge_name, dumps([new_info]))
	else:
		old = loads(moose.redis_server.hget("challs", challenge_name))
		old.append(new_info)
		moose.redis_server.hset("challs", challenge_name, dumps(old))
	moose.send_message("Added!")
	update_seen(moose, username, challenge_name)


# notes:
# - introducing list of sensors to create
# - introducing settings for random sensor data generation
# - adding code for random time intervals
# - adding code for random sensor selection
# - adding code for random sensor data generation

from random import random

from openmtc_app.onem2m import XAE
from openmtc_onem2m.model import Container

class TestIPE(XAE):
    remove_registration = True

    # sensors to create
    sensors = [
        'Temp-1',
        'Temp-2',
        'Humi-1',
        'Humi-2'
    ]

    # settings for random sensor data generation
    threshold = 0.5
    value_range = 25
    value_offset = 10

    def _on_register(self):

        # init base structure
        label = 'devices'
        container = Container(resourceName=label)
        self._devices_container = self.create_container(None,
                                                        container,
                                                        labels=[label],
                                                        max_nr_of_instances=0)

        # trigger periodically new data generation
        self.run_forever(1, self.get_random_data)

        # log message
        self.logger.debug('registered')

    def get_random_data(self):
        print('')

        # for random time intervals
        if random() > self.threshold:
            print('got some data')

            # select a random sensor
            print('available sensors: %s' % self.sensors)
            print('number of available sensors: %s' % len(self.sensors))
            print('some random sensor: %s' % self.sensors[int(random() * len(self.sensors))])

            # generate random sensor data
            print('random sensor data: %s' % int(random() * self.value_range + self.value_offset))

        else:
            print('no data')

if __name__ == '__main__':
    from openmtc_app.runner import AppRunner as Runner

    host = 'http://localhost:8000'
    app = TestIPE()
    Runner(app).run(host)


from contextlib import contextmanager
from time import time

from oneedgraph import OneEdGraph
from path_finder import PathFinder

def create_path_finder():
    with open('/usr/share/dict/american-english', encoding='utf8') as f:
        g = OneEdGraph.from_words(f)
    return PathFinder(g)

@contextmanager
def timing(name):
    start = time()
    try:
        yield
    finally:
        print(f'{name} took {time() - start} seconds')

if __name__ == '__main__':
    with timing('build'):
        pf = create_path_finder()

    with timing('search'):
        print(pf.shortest_path('cat', 'dog'))

    with timing('search2'):
        print(pf.shortest_path('lead', 'gold'))

    with timing('search2'):
        print(pf.shortest_path('gold', 'lead'))