import json
import os

class Storage:
    """
    The Storage class provides functionality to store and retrieve data in
    different storage formats.

    Attributes
    ----------
    file_name : str
        The name of the file to store the data.
    storage_type : str
        The type of storage format, such as "JSON" or "CSV".

    Methods
    -------
    store_in_json(data: dict) -> None:
        Stores the data in JSON format.

    retrieve_from_json() -> dict:
        Retrieves the data from JSON format.

    storage_config_mapper() -> dict:
        Returns a mapper dictionary that maps storage types to their respective
        read and write methods.

    read() -> dict:
        Reads the data from the specified storage format.

    write(data: dict) -> None:
        Writes the data to the specified storage format.
    """

    file_name = 'weather_data.json'
    storage_type = "JSON"

    @classmethod
    def store_in_json(cls, data: dict) -> None:
        """
        Stores the data in JSON format.

        Parameters
        ----------
        data : dict
            The data to be stored.

        Returns
        -------
        None

        """

        with open(cls.file_name, 'w') as file:
            json.dump(data, file)

    @classmethod
    def retrieve_from_json(cls) -> dict:
        """
        Retrieves the data from JSON format.

        Returns
        -------
        dict
            The retrieved data.

        """

        if os.path.exists(cls.file_name):
            with open(cls.file_name, 'r') as file:
                data = json.load(file)
            return data
        return {}

    @classmethod
    def storage_config_mapper(cls) -> dict:
        """
        Returns a mapper dictionary that maps storage types to their respective
        read and write methods.

        Returns
        -------
        dict
            The storage type mapper dictionary.

        """

        mapper = {
            "JSON": {
                "read": cls.retrieve_from_json,
                "write": cls.store_in_json
            }
        }
        return mapper

    @classmethod
    def read(cls) -> dict:
        """
        Reads the data from the specified storage format.

        Returns
        -------
        dict
            The retrieved data.

        """

        return cls.storage_config_mapper()[cls.storage_type]["read"]()

    @classmethod
    def write(cls, data: dict) -> None:
        """
        Writes the data to the specified storage format.

        Parameters
        ----------
        data : dict
            The data to be written.

        Returns
        -------
        None

        """

        return cls.storage_config_mapper()[cls.storage_type]["write"](data)


import copy
import re
import warnings
from collections import OrderedDict
from importlib.metadata import version

import numpy as np
import pandas as pd
import pint
from pandas import DataFrame, Series, Index
from pandas.api.extensions import (
    ExtensionArray,
    ExtensionDtype,
    register_dataframe_accessor,
    register_extension_dtype,
    register_series_accessor,
)
from pandas.api.types import is_integer, is_list_like, is_object_dtype, is_string_dtype
from pandas.compat import set_function_name
from pandas.core import nanops
from pandas.core.arrays.base import ExtensionOpsMixin
from pandas.core.indexers import check_array_indexer
from pint import Quantity as _Quantity
from pint import Unit as _Unit
from pint import compat, errors

# Magic 'unit' flagging columns with no unit support, used in
# quantify/dequantify
NO_UNIT = "No Unit"

pandas_version = version("pandas")
pandas_version_info = tuple(
    int(x) if x.isdigit() else x for x in pandas_version.split(".")
)

class PintType(ExtensionDtype):
    """
    A Pint duck-typed class, suitable for holding a quantity (with unit specified) dtype.
    """

    type = _Quantity
    # kind = 'O'
    # str = '|O08'
    # base = np.dtype('O')
    # num = 102
    _metadata = ("units",)
    _match = re.compile(r"(P|p)int\[(?P<units>.+)\]")
    _cache = {}
    ureg = pint.get_application_registry()

    @property
    def _is_numeric(self):
        # type: () -> bool
        return True

    def __new__(cls, units=None):
        """
        Parameters
        ----------
        units : Pint units or string
        """

        if isinstance(units, PintType):
            return units

        elif units is None:
            # empty constructor for pickle compat
            return object.__new__(cls)

        if not isinstance(units, _Unit):
            units = cls._parse_dtype_strict(units)
            # ureg.unit returns a quantity with a magnitude of 1
            # eg 1 mm. Initialising a quantity and taking its unit
            # TODO: Seperate units from quantities in pint
            # to simplify this bit
            units = cls.ureg.Quantity(1, units).units

        try:
            return cls._cache["{:P}".format(units)]
        except KeyError:
            u = object.__new__(cls)
            u.units = units
            cls._cache["{:P}".format(units)] = u
            return u

    @classmethod
    def _parse_dtype_strict(cls, units):
        if isinstance(units, str):
            if units.lower() == "pint[]":
                units = "pint[dimensionless]"
            if units.lower().startswith("pint["):
                if not units[-1] == "]":
                    raise ValueError("could not construct PintType")
                m = cls._match.search(units)
                if m is not None:
                    units = m.group("units")
            if units is not None:
                return units

        raise ValueError("could not construct PintType")

    @classmethod
    def construct_from_string(cls, string):
        """
        Strict construction from a string, raise a TypeError if not
        possible
        """
        if not isinstance(string, str):
            raise TypeError(
                f"'construct_from_string' expects a string, got {type(string)}"
            )
        if isinstance(string, str) and (
            string.startswith("pint[") or string.startswith("Pint[")
        ):
            # do not parse string like U as pint[U]
            # avoid tuple to be regarded as unit
            try:
                return cls(units=string)
            except ValueError:
                pass
        raise TypeError(f"Cannot construct a 'PintType' from '{string}'")

    @classmethod
    def construct_from_quantity_string(cls, string):
        """
        Strict construction from a string, raise a TypeError if not
        possible
        """
        if not isinstance(string, str):
            raise TypeError(
                f"'construct_from_quantity_string' expects a string, got {type(string)}"
            )

        quantity = cls.ureg.Quantity(string)
        return cls(units=quantity.units)

    # def __unicode__(self):
    # return compat.text_type(self.name)

    @property
    def name(self):
        return str("pint[{units}]".format(units=self.units))

    @property
    def na_value(self):
        return self.ureg.Quantity(np.nan, self.units)

    def __hash__(self):
        # make myself hashable
        return hash(str(self))

    def __eq__(self, other):
        try:
            other = PintType(other)
        except (ValueError, errors.UndefinedUnitError):
            return False
        return self.units == other.units

    @classmethod
    def is_dtype(cls, dtype):
        """
        Return a boolean if we if the passed type is an actual dtype that we
        can match (via string or type)
        """
        if isinstance(dtype, str):
            if dtype.startswith("pint[") or dtype.startswith("Pint["):
                try:
                    if cls._parse_dtype_strict(dtype) is not None:
                        return True
                    else:
                        return False
                except ValueError:
                    return False
            else:
                return False
        return super(PintType, cls).is_dtype(dtype)

    @classmethod
    def construct_array_type(cls):
        return PintArray

    def __repr__(self):
        """
        Return a string representation for this object.

        Invoked by unicode(df) in py2 only. Yields a Unicode String in both
        py2/py3.
        """

        return self.name

_NumpyEADtype = (
    pd.core.dtypes.dtypes.PandasDtype
    if pandas_version_info < (2, 1)
    else pd.core.dtypes.dtypes.NumpyEADtype
)

dtypemap = {
    int: pd.Int64Dtype(),
    np.int64: pd.Int64Dtype(),
    np.int32: pd.Int32Dtype(),
    np.int16: pd.Int16Dtype(),
    np.int8: pd.Int8Dtype(),
    # np.float128: pd.Float128Dtype(),
    float: pd.Float64Dtype(),
    np.float64: pd.Float64Dtype(),
    np.float32: pd.Float32Dtype(),
    np.complex128: _NumpyEADtype("complex128"),
    np.complex64: _NumpyEADtype("complex64"),
    # np.float16: pd.Float16Dtype(),
}
dtypeunmap = {v: k for k, v in dtypemap.items()}

class PintArray(ExtensionArray, ExtensionOpsMixin):
    """Implements a class to describe an array of physical quantities:
    the product of an array of numerical values and a unit of measurement.

    Parameters
    ----------
    values : pint.Quantity or array-like
        Array of physical quantity values to be created.
    dtype : PintType, str, or pint.Unit
        Units of the physical quantity to be created. (Default value = None)
        When values is a pint.Quantity, passing None as the dtype will use
        the units from the pint.Quantity.
    copy: bool
        Whether to copy the values.
    Returns
    -------

    """

    _data = np.array([])
    context_name = None
    context_units = None

    def __init__(self, values, dtype=None, copy=False):
        if dtype is None:
            if isinstance(values, _Quantity):
                dtype = values.units
            elif isinstance(values, PintArray):
                dtype = values._dtype
        if dtype is None:
            raise NotImplementedError

        if not isinstance(dtype, PintType):
            dtype = PintType(dtype)
        self._dtype = dtype

        if isinstance(values, _Quantity):
            values = values.to(dtype.units).magnitude
        elif isinstance(values, PintArray):
            values = values._data
        if isinstance(values, np.ndarray):
            dtype = values.dtype
            if dtype in dtypemap:
                dtype = dtypemap[dtype]
            values = pd.array(values, copy=copy, dtype=dtype)
            copy = False
        elif not isinstance(values, pd.core.arrays.numeric.NumericArray):
            values = pd.array(values, copy=copy)
        if copy:
            values = values.copy()
        self._data = values
        self._Q = self.dtype.ureg.Quantity

    def __getstate__(self):
        # we need to discard the cached _Q, which is not pickleable
        ret = dict(self.__dict__)
        ret.pop("_Q")
        return ret

    def __setstate__(self, dct):
        self.__dict__.update(dct)
        self._Q = self.dtype.ureg.Quantity

    @property
    def dtype(self):
        # type: () -> ExtensionDtype
        """An instance of 'ExtensionDtype'."""
        return self._dtype

    def __len__(self):
        # type: () -> int
        """Length of this array

        Returns
        -------
        length : int
        """
        return len(self._data)

    def __getitem__(self, item):
        # type (Any) -> Any
        """Select a subset of self.
        Parameters
        ----------
        item : int, slice, or ndarray
            * int: The position in 'self' to get.
            * slice: A slice object, where 'start', 'stop', and 'step' are
              integers or None
            * ndarray: A 1-d boolean NumPy ndarray the same length as 'self'
        Returns
        -------
        item : scalar or PintArray
        """
        if is_integer(item):
            return self._Q(self._data[item], self.units)

        item = check_array_indexer(self, item)

        return self.__class__(self._data[item], self.dtype)

    def __setitem__(self, key, value):
        # need to not use `not value` on numpy arrays
        if isinstance(value, (list, tuple)) and (not value):
            # doing nothing here seems to be ok
            return

        if isinstance(value, _Quantity):
            value = value.to(self.units).magnitude
        elif is_list_like(value) and len(value) > 0:
            if isinstance(value[0], _Quantity):
                value = [item.to(self.units).magnitude for item in value]
            if len(value) == 1:
                value = value[0]

        key = check_array_indexer(self, key)
        # Filter out invalid values for our array type(s)
        try:
            self._data[key] = value
        except IndexError as e:
            msg = "Mask is wrong length. {}".format(e)
            raise IndexError(msg)

    def _formatter(self, boxed=False):
        """Formatting function for scalar values.
        This is used in the default '__repr__'. The returned formatting
        function receives scalar Quantities.

        # type: (bool) -> Callable[[Any], Optional[str]]

        Parameters
        ----------
        boxed: bool, default False
            An indicated for whether or not your array is being printed
            within a Series, DataFrame, or Index (True), or just by
            itself (False). This may be useful if you want scalar values
            to appear differently within a Series versus on its own (e.g.
            quoted or not).

        Returns
        -------
        Callable[[Any], str]
            A callable that gets instances of the scalar type and
            returns a string. By default, :func:`repr` is used
            when ``boxed=False`` and :func:`str` is used when
            ``boxed=True``.
        """
        float_format = pint.formatting.remove_custom_flags(
            self.dtype.ureg.default_format
        )

        def formatting_function(quantity):
            if isinstance(quantity.magnitude, float):
                return "{:{float_format}}".format(
                    quantity.magnitude, float_format=float_format
                )
            else:
                return str(quantity.magnitude)

        return formatting_function

    def isna(self):
        # type: () -> np.ndarray
        """Return a Boolean NumPy array indicating if each value is missing.

        Returns
        -------
        missing : np.array
        """
        return self._data.isna()

    def astype(self, dtype, copy=True):
        """Cast to a NumPy array with 'dtype'.

        Parameters
        ----------
        dtype : str or dtype
            Typecode or data-type to which the array is cast.
        copy : bool, default True
            Whether to copy the data, even if not necessary. If False,
            a copy is made only if the old dtype does not match the
            new dtype.

        Returns
        -------
        array : ndarray
            NumPy ndarray with 'dtype' for its dtype.
        """
        if isinstance(dtype, str) and (
            dtype.startswith("Pint[") or dtype.startswith("pint[")
        ):
            dtype = PintType(dtype)
        if isinstance(dtype, PintType):
            if dtype == self._dtype and not copy:
                return self
            else:
                return PintArray(self.quantity.to(dtype.units).magnitude, dtype)
        # do *not* delegate to __array__ -> is required to return a numpy array,
        # but somebody may be requesting another pandas array
        # examples are e.g. PyArrow arrays as requested by "string[pyarrow]"
        if is_object_dtype(dtype):
            return self._to_array_of_quantity(copy=copy)
        if is_string_dtype(dtype):
            return pd.array([str(x) for x in self.quantity], dtype=dtype)
        if isinstance(self._data, ExtensionArray):
            return self._data.astype(dtype, copy=copy)
        return pd.array(self.quantity.m, dtype, copy)

    @property
    def units(self):
        return self._dtype.units

    @property
    def quantity(self):
        return self._Q(self.numpy_data, self._dtype.units)

    def take(self, indices, allow_fill=False, fill_value=None):
        """Take elements from an array.

        # type: (Sequence[int], bool, Optional[Any]) -> PintArray

        Parameters
        ----------
        indices : sequence of integers
            Indices to be taken.
        allow_fill : bool, default False
            How to handle negative values in `indices`.
            * False: negative values in `indices` indicate positional indices
              from the right (the default). This is similar to
              :func:`numpy.take`.
            * True: negative values in `indices` indicate
              missing values. These values are set to `fill_value`. Any other
              other negative values raise a ``ValueError``.
        fill_value : any, optional
            Fill value to use for NA-indices when `allow_fill` is True.
            This may be ``None``, in which case the default NA value for
            the type, ``self.dtype.na_value``, is used.

        Returns
        -------
        PintArray

        Raises
        ------
        IndexError
            When the indices are out of bounds for the array.
        ValueError
            When `indices` contains negative values other than ``-1``
            and `allow_fill` is True.
        Notes
        -----
        PintArray.take is called by ``Series.__getitem__``, ``.loc``,
        ``iloc``, when `indices` is a sequence of values. Additionally,
        it's called by :meth:`Series.reindex`, or any other method
        that causes realignemnt, with a `fill_value`.
        See Also
        --------
        numpy.take
        pandas.api.extensions.take
        Examples
        --------
        """
        from pandas.core.algorithms import take
        from pandas.api.types import is_scalar

        data = self._data
        if allow_fill and fill_value is None:
            fill_value = self.dtype.na_value
        if isinstance(fill_value, _Quantity):
            fill_value = fill_value.to(self.units).magnitude
            if not is_scalar(fill_value) and not fill_value.ndim:
                # deal with Issue #165; for unit registries with force_ndarray_like = True,
                # magnitude is in fact an array scalar, which will get rejected by pandas.
                fill_value = fill_value[()]

        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            # Turn off warning that PandasArray is deprecated for ``take``
            result = take(data, indices, fill_value=fill_value, allow_fill=allow_fill)

        return PintArray(result, dtype=self.dtype)

    def copy(self, deep=False):
        data = self._data
        if deep:
            data = copy.deepcopy(data)
        else:
            data = data.copy()

        return type(self)(data, dtype=self.dtype)

    @classmethod
    def _concat_same_type(cls, to_concat):
        output_units = to_concat[0].units

        data = []
        for a in to_concat:
            converted_values = a.quantity.to(output_units).magnitude
            data.append(np.atleast_1d(converted_values))

        return cls(np.concatenate(data), output_units)

    @classmethod
    def _from_sequence(cls, scalars, dtype=None, copy=False):
        """
        Initialises a PintArray from a list like of quantity scalars or a list like of floats and dtype
        -----
        Usage
        PintArray._from_sequence([Q_(1,"m"),Q_(2,"m")])
        """
        master_scalar = None
        try:
            master_scalar = next(i for i in scalars if hasattr(i, "units"))
        except StopIteration:
            if isinstance(scalars, PintArray):
                dtype = scalars._dtype
            if dtype is None:
                raise ValueError(
                    "Cannot infer dtype. No dtype specified and empty array"
                )
        if dtype is None:
            if not isinstance(master_scalar, _Quantity):
                raise ValueError("No dtype specified and not a sequence of quantities")
            dtype = PintType(master_scalar.units)

        if isinstance(master_scalar, _Quantity):
            scalars = [
                (item.to(dtype.units).magnitude if hasattr(item, "to") else item)
                for item in scalars
            ]
        return cls(scalars, dtype=dtype, copy=copy)

    @classmethod
    def _from_sequence_of_strings(cls, scalars, dtype=None, copy=False):
        if not dtype:
            dtype = PintType.construct_from_quantity_string(scalars[0])
        return cls._from_sequence([dtype.ureg.Quantity(x) for x in scalars])

    @classmethod
    def _from_factorized(cls, values, original):
        from pandas.api.types import infer_dtype

        if infer_dtype(values) != "object":
            values = pd.array(values, copy=False)
        return cls(values, dtype=original.dtype)

    def _values_for_factorize(self):
        # factorize can now handle differentiating various types of null values.
        # These can only occur when the array has object dtype.
        # However, for backwards compatibility we only use the null for the
        # provided dtype. This may be revisited in the future, see GH#48476.
        arr = self._data
        if arr.dtype.kind == "O":
            return np.array(arr, copy=False), self.dtype.na_value
        return arr._values_for_factorize()

    def value_counts(self, dropna=True):
        """
        Returns a Series containing counts of each category.

        Every category will have an entry, even those with a count of 0.

        Parameters
        ----------
        dropna : boolean, default True
            Don't include counts of NaN.

        Returns
        -------
        counts : Series

        See Also
        --------
        Series.value_counts
        """

        from pandas import Series

        # compute counts on the data with no nans
        data = self._data
        nafilt = pd.isna(data)
        na_value = pd.NA  # NA value for index, not data, so not quantified
        data = data[~nafilt]
        index = list(set(data))

        data_list = data.tolist()
        array = [data_list.count(item) for item in index]

        if not dropna:
            index.append(na_value)
            array.append(nafilt.sum())

        return Series(np.asarray(array), index=index)

    def unique(self):
        """Compute the PintArray of unique values.

        Returns
        -------
        uniques : PintArray
        """
        from pandas import unique

        data = self._data
        return self._from_sequence(unique(data), dtype=self.dtype)

    def __contains__(self, item) -> bool:
        if not isinstance(item, _Quantity):
            return False
        elif pd.isna(item.magnitude):
            return self.isna().any()
        else:
            return super().__contains__(item)

    @property
    def data(self):
        return self._data

    @property
    def numpy_data(self):
        data = self.data
        if data.dtype in dtypeunmap:
            try:
                data = data.astype(dtypeunmap[data.dtype])
            except Exception:
                # We might get here for integer arrays with <NA> values
                # In that case, the returned quantity will have dtype=O, which is less useful.
                pass
        if hasattr(data, "to_numpy"):
            data = data.to_numpy()
        return data

    @property
    def nbytes(self):
        return self._data.nbytes

    # The _can_hold_na attribute is set to True so that pandas internals
    # will use the ExtensionDtype.na_value as the NA value in operations
    # such as take(), reindex(), shift(), etc.  In addition, those results
    # will then be of the ExtensionArray subclass rather than an array
    # of objects
    _can_hold_na = True

    @property
    def _ndarray_values(self):
        # type: () -> np.ndarray
        """Internal pandas method for lossy conversion to a NumPy ndarray.
        This method is not part of the pandas interface.
        The expectation is that this is cheap to compute, and is primarily
        used for interacting with our indexers.
        """
        return np.array(self)

    @classmethod
    def _create_method(cls, op, coerce_to_dtype=True):
        """
        A class method that returns a method that will correspond to an
        operator for an ExtensionArray subclass, by dispatching to the
        relevant operator defined on the individual elements of the
        ExtensionArray.
        Parameters
        ----------
        op : function
            An operator that takes arguments op(a, b)
        coerce_to_dtype :  bool
            boolean indicating whether to attempt to convert
            the result to the underlying ExtensionArray dtype
            (default True)
        Returns
        -------
        A method that can be bound to a method of a class
        Example
        -------
        Given an ExtensionArray subclass called MyExtensionArray, use
        >>> __add__ = cls._create_method(operator.add)
        in the class definition of MyExtensionArray to create the operator
        for addition, that will be based on the operator implementation
        of the underlying elements of the ExtensionArray
        """

        def _binop(self, other):
            def validate_length(obj1, obj2):
                # validates length
                # CHANGED: do not convert to listlike (why should we? pint.Quantity is perfecty able to handle that...)
                try:
                    if len(obj1) != len(obj2):
                        raise ValueError("Lengths must match")
                except TypeError:
                    pass

            def convert_values(param):
                # convert to a quantity or listlike
                if isinstance(param, cls):
                    return param.quantity
                elif isinstance(param, (_Quantity, _Unit)):
                    return param
                elif (
                    is_list_like(param)
                    and len(param) > 0
                    and isinstance(param[0], _Quantity)
                ):
                    units = param[0].units
                    return type(param[0])([p.m_as(units) for p in param], units)
                else:
                    return param

            if isinstance(other, (Series, DataFrame, Index)):
                return NotImplemented
            lvalues = self.quantity
            validate_length(lvalues, other)
            rvalues = convert_values(other)
            # If the operator is not defined for the underlying objects,
            # a TypeError should be raised
            res = op(lvalues, rvalues)

            if op.__name__ == "divmod":
                return (
                    cls.from_1darray_quantity(res[0]),
                    cls.from_1darray_quantity(res[1]),
                )

            if coerce_to_dtype:
                try:
                    res = cls.from_1darray_quantity(res)
                except TypeError:
                    pass

            return res

        op_name = f"__{op}__"
        return set_function_name(_binop, op_name, cls)

    @classmethod
    def _create_arithmetic_method(cls, op):
        return cls._create_method(op)

    @classmethod
    def _create_comparison_method(cls, op):
        return cls._create_method(op, coerce_to_dtype=False)

    @classmethod
    def from_1darray_quantity(cls, quantity):
        if not is_list_like(quantity.magnitude):
            raise TypeError("quantity's magnitude is not list like")
        return cls(quantity.magnitude, quantity.units)

    def __array__(self, dtype=None, copy=False):
        if dtype is None or is_object_dtype(dtype):
            return self._to_array_of_quantity(copy=copy)
        if is_string_dtype(dtype):
            return np.array([str(x) for x in self.quantity], dtype=str)
        return np.array(self._data, dtype=dtype, copy=copy)

    def _to_array_of_quantity(self, copy=False):
        qtys = [
            self._Q(item, self._dtype.units)
            if not pd.isna(item)
            else self.dtype.na_value
            for item in self._data
        ]
        with warnings.catch_warnings(record=True):
            return np.array(qtys, dtype="object", copy=copy)

    def searchsorted(self, value, side="left", sorter=None):
        """
        Find indices where elements should be inserted to maintain order.

        .. versionadded:: 0.24.0

        Find the indices into a sorted array `self` (a) such that, if the
        corresponding elements in `v` were inserted before the indices, the
        order of `self` would be preserved.

        Assuming that `a` is sorted:

        ======  ============================
        `side`  returned index `i` satisfies
        ======  ============================
        left    ``self[i-1] < v <= self[i]``
        right   ``self[i-1] <= v < self[i]``
        ======  ============================

        Parameters
        ----------
        value : array_like
            Values to insert into `self`.
        side : {'left', 'right'}, optional
            If 'left', the index of the first suitable location found is given.
            If 'right', return the last such index.  If there is no suitable
            index, return either 0 or N (where N is the length of `self`).
        sorter : 1-D array_like, optional
            Optional array of integer indices that sort array a into ascending
            order. They are typically the result of argsort.

        Returns
        -------
        indices : array of ints
            Array of insertion points with the same shape as `value`.

        See Also
        --------
        numpy.searchsorted : Similar method from NumPy.
        """
        # Note: the base tests provided by pandas only test the basics.
        # We do not test
        # 1. Values outside the range of the `data_for_sorting` fixture
        # 2. Values between the values in the `data_for_sorting` fixture
        # 3. Missing values.
        arr = self._data
        if isinstance(value, _Quantity):
            value = value.to(self.units).magnitude
        elif is_list_like(value) and len(value) > 0 and isinstance(value[0], _Quantity):
            value = [item.to(self.units).magnitude for item in value]
        return arr.searchsorted(value, side=side, sorter=sorter)

    def map(self, mapper, na_action=None):
        """
        Map values using an input mapping or function.

        Parameters
        ----------
        mapper : function, dict, or Series
            Mapping correspondence.
        na_action : {None, 'ignore'}, default None
            If 'ignore', propagate NA values, without passing them to the
            mapping correspondence. If 'ignore' is not supported, a
            ``NotImplementedError`` should be raised.

        Returns
        -------
        If mapper is a function, operate on the magnitudes of the array and

        """
        if pandas_version_info < (2, 1):
            ser = pd.Series(self._to_array_of_quantity())
            arr = ser.map(mapper, na_action).values
        else:
            from pandas.core.algorithms import map_array

            arr = map_array(self, mapper, na_action)

        master_scalar = None
        try:
            master_scalar = next(i for i in arr if hasattr(i, "units"))
        except StopIteration:
            # JSON mapper formatting Qs as str don't create PintArrays
            # ...and that's OK.  Caller will get array of values
            return arr
        return PintArray._from_sequence(arr, PintType(master_scalar.units))

    def _reduce(self, name, *, skipna: bool = True, keepdims: bool = False, **kwds):
        """
        Return a scalar result of performing the reduction operation.

        Parameters
        ----------
        name : str
            Name of the function, supported values are:
            { any, all, min, max, sum, mean, median, prod,
            std, var, sem, kurt, skew }.
        skipna : bool, default True
            If True, skip NaN values.
        **kwargs
            Additional keyword arguments passed to the reduction function.
            Currently, `ddof` is the only supported kwarg.

        Returns
        -------
        scalar

        Raises
        ------
        TypeError : subclass does not define reductions
        """

        functions = {
            "any": nanops.nanany,
            "all": nanops.nanall,
            "min": nanops.nanmin,
            "max": nanops.nanmax,
            "sum": nanops.nansum,
            "mean": nanops.nanmean,
            "median": nanops.nanmedian,
            "std": nanops.nanstd,
            "var": nanops.nanvar,
            "sem": nanops.nansem,
            "kurt": nanops.nankurt,
            "skew": nanops.nanskew,
        }
        if name not in functions:
            raise TypeError(f"cannot perform {name} with type {self.dtype}")

        if isinstance(self._data, ExtensionArray):
            try:
                result = self._data._reduce(
                    name, skipna=skipna, keepdims=keepdims, **kwds
                )
            except NotImplementedError:
                result = functions[name](self.numpy_data, **kwds)

        if name in {"all", "any", "kurt", "skew"}:
            return result
        if name == "var":
            if keepdims:
                return PintArray(result, f"pint[({self.units})**2]")
            return self._Q(result, self.units**2)
        if keepdims:
            return PintArray(result, self.dtype)
        return self._Q(result, self.units)

    def _accumulate(self, name: str, *, skipna: bool = True, **kwds):
        if name == "cumprod":
            raise TypeError("cumprod not supported for pint arrays")
        functions = {
            "cummin": np.minimum.accumulate,
            "cummax": np.maximum.accumulate,
            "cumsum": np.cumsum,
        }

        if isinstance(self._data, ExtensionArray):
            try:
                result = self._data._accumulate(name, **kwds)
            except NotImplementedError:
                result = functions[name](self.numpy_data, **kwds)

        return self._from_sequence(result, self.units)

PintArray._add_arithmetic_ops()
PintArray._add_comparison_ops()
register_extension_dtype(PintType)

@register_dataframe_accessor("pint")
class PintDataFrameAccessor(object):
    def __init__(self, pandas_obj):
        self._obj = pandas_obj

    def quantify(self, level=-1):
        df = self._obj
        df_columns = df.columns.to_frame()
        unit_col_name = df_columns.columns[level]
        units = df_columns[unit_col_name]
        df_columns = df_columns.drop(columns=unit_col_name)

        df_new = DataFrame(
            {
                i: PintArray(df.values[:, i], unit)
                if unit != NO_UNIT
                else df.values[:, i]
                for i, unit in enumerate(units.values)
            }
        )

        df_new.columns = df_columns.index.droplevel(unit_col_name)
        df_new.index = df.index

        return df_new

    def dequantify(self):
        def formatter_func(dtype):
            formatter = "{:" + dtype.ureg.default_format + "}"
            return formatter.format(dtype.units)

        df = self._obj

        df_columns = df.columns.to_frame()
        df_columns["units"] = [
            formatter_func(df[col].dtype)
            if isinstance(df[col].dtype, PintType)
            else NO_UNIT
            for col in df.columns
        ]

        data_for_df = OrderedDict()
        for i, col in enumerate(df.columns):
            if isinstance(df[col].dtype, PintType):
                data_for_df[tuple(df_columns.iloc[i])] = df[col].values.data
            else:
                data_for_df[tuple(df_columns.iloc[i])] = df[col].values

        df_new = DataFrame(data_for_df, columns=data_for_df.keys())

        df_new.columns.names = df.columns.names + ["unit"]
        df_new.index = df.index

        return df_new

    def to_base_units(self):
        obj = self._obj
        df = self._obj
        index = object.__getattribute__(obj, "index")
        # name = object.__getattribute__(obj, '_name')
        return DataFrame(
            {
                col: (
                    df[col].pint.to_base_units()
                    if isinstance(df[col].dtype, PintType)
                    else df[col]
                )
                for col in df.columns
            },
            index=index,
        )

    def convert_object_dtype(self):
        df = self._obj
        df_new = pd.DataFrame()
        for col in df.columns:
            s = df[col]
            if s.dtype == "object":
                try:
                    df_new[col] = s.pint.convert_object_dtype()
                except AttributeError:
                    df_new[col] = s
            else:
                df_new[col] = s
        return df_new

@register_series_accessor("pint")
class PintSeriesAccessor(object):
    def __init__(self, pandas_obj):
        if self._is_object_dtype_and_quantity(pandas_obj):
            self.pandas_obj = pandas_obj
        else:
            self._validate(pandas_obj)
            self.pandas_obj = pandas_obj
            self.quantity = pandas_obj.values.quantity
            self._index = pandas_obj.index
            self._name = pandas_obj.name

    @staticmethod
    def _validate(obj):
        if not is_pint_type(obj):
            raise AttributeError(
                "Cannot use 'pint' accessor on objects of "
                "dtype '{}'.".format(obj.dtype)
            )

    @staticmethod
    def _is_object_dtype_and_quantity(obj):
        return obj.dtype == "object" and all(
            [(isinstance(item, _Quantity) or pd.isna(item)) for item in obj.values]
        )

    def convert_object_dtype(self):
        return pd.Series(
            data=PintArray._from_sequence(self.pandas_obj.values),
            index=self.pandas_obj.index,
            name=self.pandas_obj.name,
        )

class Delegated:
    # Descriptor for delegating attribute access to from
    # a Series to an underlying array
    to_series = True

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

class DelegatedProperty(Delegated):
    def __get__(self, obj, type=None):
        index = object.__getattribute__(obj, "_index")
        name = object.__getattribute__(obj, "_name")
        result = getattr(object.__getattribute__(obj, "quantity"), self.name)
        if self.to_series:
            if isinstance(result, _Quantity):
                result = PintArray(result)
            return Series(result, index, name=name)
        else:
            return result

class DelegatedScalarProperty(DelegatedProperty):
    to_series = False

class DelegatedMethod(Delegated):
    def __get__(self, obj, type=None):
        index = object.__getattribute__(obj, "_index")
        name = object.__getattribute__(obj, "_name")
        method = getattr(object.__getattribute__(obj, "quantity"), self.name)

        def delegated_method(*args, **kwargs):
            result = method(*args, **kwargs)
            if self.to_series:
                if isinstance(result, _Quantity):
                    result = PintArray.from_1darray_quantity(result)
                result = Series(result, index, name=name)
            return result

        return delegated_method

class DelegatedScalarMethod(DelegatedMethod):
    to_series = False

for attr in [
    "debug_used",
    "default_format",
    "dimensionality",
    "dimensionless",
    "force_ndarray",
    "shape",
    "u",
    "unitless",
    "units",
]:
    setattr(PintSeriesAccessor, attr, DelegatedScalarProperty(attr))
for attr in ["imag", "m", "magnitude", "real"]:
    setattr(PintSeriesAccessor, attr, DelegatedProperty(attr))

for attr in [
    "check",
    "compatible_units",
    "format_babel",
    "ito",
    "ito_base_units",
    "ito_reduced_units",
    "ito_root_units",
    "plus_minus",
    "put",
    "to_tuple",
    "tolist",
]:
    setattr(PintSeriesAccessor, attr, DelegatedScalarMethod(attr))
for attr in [
    "clip",
    "from_tuple",
    "m_as",
    "searchsorted",
    "to",
    "to_base_units",
    "to_compact",
    "to_reduced_units",
    "to_root_units",
    "to_timedelta",
]:
    setattr(PintSeriesAccessor, attr, DelegatedMethod(attr))

def is_pint_type(obj):
    t = getattr(obj, "dtype", obj)
    try:
        return isinstance(t, PintType) or issubclass(t, PintType)
    except Exception:
        return False

try:
    # for pint < 0.21 we need to explicitly register
    compat.upcast_types.append(PintArray)
except AttributeError:
    # for pint = 0.21 we need to add the full names of PintArray and DataFrame,
    # which is to be added in pint > 0.21
    compat.upcast_type_map.setdefault("pint_pandas.pint_array.PintArray", PintArray)
    compat.upcast_type_map.setdefault("pandas.core.frame.DataFrame", DataFrame)

{'take': 'pandas.core.algorithms.take', 'is_scalar': 'pandas.api.types.is_scalar'}

{'take': 'pandas.core.algorithms.take', 'is_scalar': 'pandas.api.types.is_scalar', 'infer_dtype': 'pandas.api.types.infer_dtype', 'Series': 'pandas.Series', 'unique': 'pandas.unique', 'map_array': 'pandas.core.algorithms.map_array'}._from_sequence

{'take': 'pandas.core.algorithms.take', 'is_scalar': 'pandas.api.types.is_scalar', 'infer_dtype': 'pandas.api.types.infer_dtype', 'Series': 'pandas.Series', 'unique': 'pandas.unique', 'map_array': 'pandas.core.algorithms.map_array'}._add_arithmetic_ops

{'take': 'pandas.core.algorithms.take', 'is_scalar': 'pandas.api.types.is_scalar', 'infer_dtype': 'pandas.api.types.infer_dtype', 'Series': 'pandas.Series', 'unique': 'pandas.unique', 'map_array': 'pandas.core.algorithms.map_array'}._add_comparison_ops

{'take': 'pandas.core.algorithms.take', 'is_scalar': 'pandas.api.types.is_scalar', 'infer_dtype': 'pandas.api.types.infer_dtype', 'Series': 'pandas.Series', 'unique': 'pandas.unique', 'map_array': 'pandas.core.algorithms.map_array'}.from_1darray_quantity


from tensorflow.keras.models import load_model
import matplotlib.pyplot as plt
import os
import cv2
import numpy as np
from tensorflow.keras.preprocessing import image
from tensorflow.keras.applications.vgg16 import preprocess_input, decode_predictions
import sys
from PyQt5.QtWidgets import *
from PyQt5 import QtGui
    # QAction, QApplication,QMainWindow ,QWidget, QPushButton, QMessageBox, QLabel, QLineEdit, QTextEdit, QGridLayout, QListWidget, QTableWidget,QFileDialog
from PyQt5.QtGui import *

class Window(QWidget):

    def __init__(self):
        super().__init__()
        self.title = "고궁판별기"
        self.top = 200
        self.left = 500
        self.width = 400
        self.height = 300
        self.InitWindow()

    def InitWindow(self):
        self.setWindowIcon(QtGui.QIcon("icon.png"))
        self.setWindowTitle(self.title)
        self.text_edit = QTextEdit(self)
        self.text_edit.setGeometry(120, 200, 200, 50)
        self.setGeometry(self.left, self.top, self.width, self.height)
        vbox = QVBoxLayout()
        self.btn1 = QPushButton("Open Image")
        self.btn1.clicked.connect(self.getImage)
        vbox.addWidget(self.btn1)
        self.label = QLabel("result")
        vbox.addWidget(self.label)
        vbox.addWidget(self.text_edit)
        self.setLayout(vbox)
        self.show()

    def getImage(self):
        fname,_ = QFileDialog.getOpenFileName(self)
        imagePath = fname
        pixmap = QPixmap(imagePath).scaled(350,300)
        self.label.setPixmap(QPixmap(pixmap))
        self.resize(pixmap.width(), pixmap.height())
        if fname:
         data = fname
         print(data)
         #data500_VGG16_flatten_Dropout_model
         # model = load_model('projects_pretrained_change_setps_and_val_steps4(epoch50_and_data(each500)flatten_Dropout_)before_fine_tuning.h5')
         model = load_model('projects_pretrained_change_setps_and_val_steps4(256size)_add_class3(epoch50_and_data(each100)flatten_adam_softmax)before_fine_tuning.h5')
         # model =load_model('projects_pretrained_change_setps_and_val_steps4(128size)_add_class3(epoch50_and_data(each100)flatten_Dropout_adam_softmax)before_fine_tuning.h5')
         #data800_VGG16_flatten_Dropout_no_argumnet_model
         # model = load_model('projects_pretrained(Dropout_epoch50_and_data(each800)no_data_argu)before_fine_tuning.h5')projects_pretrained_change_setps_and_val_steps4(128size)_add_class3(epoch50_and_data(each100)flatten_Dropout_adam_softmax)before_fine_tuning

         #data100_VGG16_flatten
         # model =load_model('projects_pretrained_change_setps_and_val_steps4(epoch50_and_data(each100)flatten)before_fine_tuning.h5')
         img_path = data
         img = cv2.imread(data)
         img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
         img = image.load_img(img_path, target_size=(256, 256))
         img_tensor = image.img_to_array(img)
         img_tensor = np.expand_dims(img_tensor, axis=0)
         img_tensor = preprocess_input(img_tensor)
         pre = model.predict(img_tensor)
         merge = ('china:',round(pre[0][0]*100,2),'%','japan:',round(pre[0][1]*100,2),'%','korea:',round(pre[0][2]*100,2),'%')
         self.text_edit.setText(str(merge))

App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())


# Module app.
# Description: Create Flask app, import blueprint
# combine Flask and SOAP services.
# Author : Dung Ho
# Email: dung.ho@edu.turkuamk.fi

from controllers.api import api
from controllers.soap import wsgi_application as soap
from flask import Flask
from werkzeug.middleware.dispatcher import DispatcherMiddleware

def create_app():
    # Create a Flask application
    app = Flask(
        __name__,
        template_folder='templates',
        static_folder='static',
    )

    # Register Blueprint
    app.register_blueprint(api)

    # Using DispatcherMiddleware to combine Flask and SOAP services
    app.wsgi_app = DispatcherMiddleware(
        app.wsgi_app,
        {
            '/soap': soap
        }
    )

    return app


import csv
import numpy as np
import matplotlib.pyplot as plt

def lookahead_moving_average(data, window):
    ma = []
    for i in range(len(data)):
        avg = 0
        if i + window > len(data):
            window -= 1
        for j in range(window):
            avg += data[i+j]
        ma.append(avg/float(window))
    return np.array(ma, dtype=float)

def single_exp_smoothing(data, alpha):
    S_t = data[0]
    ses = []
    for d in data:
        S_t = alpha * d + (1 - alpha) * S_t
        ses.append(S_t)
    return np.array(ses, dtype=float)

def double_exp_smoothing(data, alpha, gamma):
    S_t = data[0]
    b_t = data[1] - data[0]
    S_tt, b_tt = 0, 0
    des = []
    for d in data:
        S_tt = alpha * d + (1 - alpha) * S_t
        b_tt = gamma * (S_tt - S_t) + (1 - gamma) * b_t
        S_t = S_tt
        b_t = b_tt
        des.append(S_tt + b_tt)
    return np.array(des, dtype=float)

d = []
with open('data.csv', 'r') as csvfile:
    reader = csv.reader(csvfile, delimiter=',')
    for row in reader:
        d.append(row)
dataset = np.array(d, dtype=float)

time = dataset[:, 0]
data = dataset[:, 1]

plt.figure(1)
plt.subplot(511)
plt.title('look head moving average')
plt.plot(time, data, color='black', label='raw', lw=0.3)
ma = lookahead_moving_average(data, window=151)
plt.plot(time, data-ma, color='red', label='window=151', lw=1)
plt.ylabel('data')
plt.legend(bbox_to_anchor=(1.005, 1), loc=2, borderaxespad=0.)

plt.subplot(512)
plt.title('single exponential smoothing')
colours = ['red', 'blue', 'green', 'yellow']
alphas = [0.2, 0.3, 0.5, 0.8]
plt.plot(time, data, color='black', label='raw', lw=0.3)
for i in range(len(alphas)):
    ses = single_exp_smoothing(data, alpha=alphas[i])
    a_label = 'alpha={}'.format(alphas[i])
    plt.plot(time, data-ses, color=colours[i], label=a_label)
plt.legend(bbox_to_anchor=(1.005, 1), loc=2, borderaxespad=0.)

plt.subplot(513)
plt.title('double exponential smoothing for alpha = .2')
plt.plot(time, data, color='black', label='raw', lw=0.3)

des = double_exp_smoothing(data, 0.2, 0.2)
plt.plot(time, data-des, color='blue', label='.2, .2')
des = double_exp_smoothing(data, 0.2, 0.5)
plt.plot(time, data-des, color='green', label='.2, .5')
des = double_exp_smoothing(data, 0.2, 0.8)
plt.plot(time, data-des, color='red', label='.2, .8')
plt.legend(bbox_to_anchor=(1.005, 1), loc=2, borderaxespad=0.)

plt.subplot(514)
plt.title('double exponential smoothing for alpha = .5')
plt.plot(time, data, color='black', label='raw', lw=0.3)
des = double_exp_smoothing(data, 0.5, 0.2)
plt.plot(time, data-des, color='blue', label='.5, .2')
des = double_exp_smoothing(data, 0.5, 0.5)
plt.plot(time, data-des, color='green', label='.5, .5')
des = double_exp_smoothing(data, 0.5, 0.8)
plt.plot(time, data-des, color='red', label='.5, .8')
plt.legend(bbox_to_anchor=(1.005, 1), loc=2, borderaxespad=0.)

plt.subplot(515)
plt.title('double exponential smoothing for alpha = .8')
plt.plot(time, data, color='black', label='raw', lw=0.3)
des = double_exp_smoothing(data, 0.8, 0.2)
plt.plot(time, data-des, color='blue', label='.8, .2')
des = double_exp_smoothing(data, 0.8, 0.5)
plt.plot(time, data-des, color='green', label='.8, .5')
des = double_exp_smoothing(data, 0.8, 0.8)
plt.plot(time, data-des, color='red', label='.8, .5')
plt.legend(bbox_to_anchor=(1.005, 1), loc=2, borderaxespad=0.)

plt.show()


import torch_geometric
from torch_geometric.datasets import TUDataset
from data.gurobi import get_ground_truth
from torch_geometric.data import DataLoader, Data
from torch_geometric.utils import degree, get_laplacian
import torch.nn.functional as F
from data.gurobi import solve_gurobi_maxclique
from data.gurobi import self_implement_degree
import networkx as nx
from torch_geometric.utils.convert import from_networkx

import pickle
import torch
import numpy as np
import random
import os

def assign_features(graph,args):
    if args.problem=='tsp':
        args.input_feat_dim=2
    elif args.features=='random':
        if graph.x is not None:
            graph.x = torch.rand(graph.x.shape[0])
        else:
            graph.x = torch.rand(graph.num_nodes)
    elif args.features=='one':
        if graph.x is not None:
            graph.x = torch.ones(graph.x.shape[0])
        else:
            graph.x = torch.ones(graph.num_nodes)
        args.input_feat_dim=1
    elif args.features=='degree':
        args.input_feat_dim=1
        edge_index= graph.edge_index
        row, _ = edge_index
        #degs=self_implement_degree(row, graph.x.shape[0])
        degs = degree(row, num_nodes = graph.x.shape[0])
        x = (degs/degs.norm(1))*1.
        x = x.unsqueeze(-1)
        graph.x = x
    elif args.features=='lap_pe':
        n=graph.x.shape[0]

        a = get_laplacian(graph.edge_index)

        L = torch.zeros((n, n))

        row, col = a[0]

        L[row, col] = a[1]
        L[col, row] = a[1]
        # Eigenvectors with numpy
        EigVals, EigVecs = np.linalg.eigh(L.numpy())
        EigVals, EigVecs = EigVals[: args.n_eigs], EigVecs[:, : args.n_eigs]  # Keep up to the maximum desired number of frequencies

        # Normalize and pad EigenVectors
        EigVecs = torch.from_numpy(EigVecs).float()
        EigVecs = F.normalize(EigVecs, p=2, dim=1, eps=1e-12, out=None)

        EigVals = torch.from_numpy(EigVals).float()
        EigVals = EigVals.repeat(n,1)

        if n<args.n_eigs:
            EigVals = F.pad(EigVals, (0, args.n_eigs-n), value=0.)
            EigVecs = F.pad(EigVecs, (0, args.n_eigs-n), value=0.)

        graph.e_vals, graph.e_vecs = EigVals, EigVecs

def get_baseline(graph,args):
    nx_graph = torch_geometric.utils.convert.to_networkx(graph).to_undirected()
    #breakpoint()
    if 'clique' in args.problem:
        baseline = len(nx.algorithms.approximation.max_clique(nx_graph))
    if 'indep_set' in args.problem:
        baseline = len(nx.algorithms.approximation.maximum_independent_set(nx_graph))
    if 'cut' in args.problem:
        baseline = nx.algorithms.approximation.one_exchange(nx_graph)[0]
    return baseline

def get_datasets(args):
    datasets=[]

    for name in args.dataset_names:

        if name=="TWITTER":
            stored_dataset = open('data/TWITTER_SNAP_2.p', 'rb')
            dataset = pickle.load(stored_dataset)
            #dataset=pickle.load(open(f"data/TWITTER_SNAP_2.p",'rb'))
            dataset=[Data(x=graph["x"], edge_index=graph["edge_index"]) for graph in list(dataset)]
        elif name=="ErdosRenyi":
            how_many_graph_sizes = args.ER_howmany
            graph_size_ub = args.ER_graph_size_ub
            graph_sizes = np.round(np.linspace(int(np.round(graph_size_ub/10)),graph_size_ub,how_many_graph_sizes))
            if os.path.exists(f'data/ground_truths/ErdosRenyi{how_many_graph_sizes}_{graph_size_ub}.p'):
                dictlist = pickle.load(open(f'data/ground_truths/ErdosRenyi{how_many_graph_sizes}_{graph_size_ub}.p','rb'))
                dataset = [Data.from_dict(graph) for graph in dictlist]
            else:
                num_graphs = 10
                graph_list = []
                pyg_graphs = []
                for counter,size in enumerate(graph_sizes):
                    for k in range(num_graphs):
                        print(f"Curr graph size : {counter+1}/{how_many_graph_sizes}, curr graph: {k+1}/{num_graphs}")
                        graph = nx.erdos_renyi_graph(int(size), p = args.ER_prob)
                        pyg_graph = from_networkx(graph)
                #pyg_graph.gurobi_scores = clique_sizes
                        pyg_graphs += [pyg_graph]

                dictlist = [graph.to_dict() for graph in pyg_graphs]
                dataset= pyg_graphs
                pickle.dump(dictlist, open(f'data/ground_truths/ErdosRenyi{how_many_graph_sizes}_{graph_size_ub}.p','wb'))

        elif name=="BA":
            how_many_graph_sizes = args.ER_howmany
            graph_size_ub = args.ER_graph_size_ub
            graph_sizes = np.round(np.linspace(int(np.round(graph_size_ub/10)),graph_size_ub,how_many_graph_sizes))
            if os.path.exists(f'data/ground_truths/ErdosRenyi{how_many_graph_sizes}_{graph_size_ub}.p'):
                dictlist = pickle.load(open(f'data/ground_truths/ErdosRenyi{how_many_graph_sizes}_{graph_size_ub}.p','rb'))
                dataset = [Data.from_dict(graph) for graph in dictlist]
            else:
                num_graphs = 10
                graph_list = []
                pyg_graphs = []
                for counter,size in enumerate(graph_sizes):
                    for k in range(num_graphs):
                        print(f"Curr graph size : {counter+1}/{how_many_graph_sizes}, curr graph: {k+1}/{num_graphs}")
                        graph = nx.barabasi_albert_graph(int(size), int(size)/2)
                        pyg_graph = from_networkx(graph)
                #pyg_graph.gurobi_scores = clique_sizes
                        pyg_graphs += [pyg_graph]

                dictlist = [graph.to_dict() for graph in pyg_graphs]
                dataset= pyg_graphs
                pickle.dump(dictlist, open(f'data/ground_truths/ErdosRenyi{how_many_graph_sizes}_{graph_size_ub}.p','wb'))

        else:
            dataset = TUDataset(root=f"./tmp/{name}", name=name)
            dataset = list(dataset)

        total_samples = int(np.floor(len(dataset)*args.dataset_scale))
        dataset = dataset[:total_samples]
        random.shuffle(dataset)

        #Get gurobi ground truths for maxcut  and clean the data a bit
        ground_truth_string = args.problem + name
        if args.ER_scale_experiment:
            how_many_graph_sizes = args.ER_howmany
            graph_size_ub = args.ER_graph_size_ub
            ground_truth_string = ground_truth_string + '_' + str(how_many_graph_sizes) +'_' + str(graph_size_ub) + '_' +str(args.time_limit) + '_' + str(args.ER_prob)
        ground_truths = []
        print(f"Problem name and dataset: {ground_truth_string}")
        if os.path.exists(f'data/ground_truths/{ground_truth_string}.p'):
            ground_truths = pickle.load(open(f'data/ground_truths/{ground_truth_string}.p','rb'))
            print("Ground truths found! Skipping ground truth computation...")
        else:
             print('Ground truths not found! Computing ground truths...')
             for counter, graph in enumerate(dataset):
                if (counter+1) % 100 == 0:
                    print(f'Count: {counter+1}')
                graph_info = {}
                num_nodes = graph.num_nodes
                num_edges = graph.num_edges
                ground = get_ground_truth(graph, args)
                graph_info['num_nodes'] = num_nodes
                graph_info['num_edges'] = num_edges
                graph_info['ground_truth'] = ground
                ground_truths += [graph_info]
             pickle.dump(ground_truths, open(f"data/ground_truths/{ground_truth_string}.p",'wb'))
             print("Ground truths saved.")

        #Assigning node features
        print("Assigning node features...")
        connected_idx=[]
        for counter, graph in enumerate(dataset):

            if graph.x is None:
                #breakpoint()
                graph.x=torch.zeros(graph.edge_index.max().item()+1)
            assert graph.x.shape[0] > graph.edge_index.max().item()

            assign_features(graph, args)
            if args.reinforce_with_baseline:
                graph.baseline = get_baseline(graph, args)
               # breakpoint()

            if (counter+1) % 100 == 0:
                print(f'Count: {counter+1}')

            #ground = get_ground_truth(graph, args)
            #Match stored ground truths with our data and check if everything went well
            found_ground = False
            for graph_key in ground_truths:
                if ((graph.num_nodes==graph_key['num_nodes']) and (graph.num_edges==graph_key['num_edges'])):
                    graph.ground = graph_key['ground_truth']
                    found_ground = True
            if not found_ground:
                "WARNING! NO GROUND TRUTH MATCH FOUND"
                breakpoint()

            if graph.ground>0:
                connected_idx.append(counter)

            if args.print_best:
                print(graph.ground)

        if args.extension=='karger':
            dataset=[dataset[idx] for idx in connected_idx]
            print(f'{100*(1-(len(connected_idx)/len(dataset)))}% of graphs removed due to not being connected.')

        print('Done!')
        datasets.append(dataset)
        #breakpoint()
        return datasets

def get_loaders(dataset, batch_size):
    num_trainpoints = int(np.floor(0.6*len(dataset)))
    num_valpoints = int(np.floor(0.3*num_trainpoints))
    num_testpoints = len(dataset) - (num_trainpoints + num_valpoints)

    traindata= dataset[0:num_trainpoints]
    valdata = dataset[num_trainpoints:num_trainpoints + num_valpoints]
    testdata = dataset[num_trainpoints + num_valpoints:]

    train_loader = DataLoader(traindata, batch_size, shuffle=True)
    test_loader  = DataLoader(testdata,  batch_size, shuffle=False)
    val_loader   = DataLoader(valdata,   batch_size, shuffle=False)

    return train_loader, test_loader, val_loader


from django.urls import path
from . import views

urlpatterns = [

    path('login/' , views.login_view , name='login_page_user'),
    path('logout/' , views.logout_view , name='logout_page_user'),
    path('dashboard/' , views.user_dashboard , name='dashboard_user'),
    path('appointments/' , views.hospital_selection , name='hospital_selection'),
    path('appointments/registration_form' , views.registration_view , name='registration_form'),
    path('appointments/confirmation' , views.confirmation , name='confirmation_page'),
]


# 주요 라이브러리의 문법과 유의점
# 표준 라이브러리 = 특정한 프로그래밍 언어에서 자주 사용되는 표준 소스코드를 미리 구현해놓은 라이브러리

# 내장함수 - 기본 입출력, 정렬기능 등을 포함하는 기본 내장 라이브러리
# itertools - 반복되는 형태의 데이터를 처리하는 기능을 제공하는 라이브러리, 순열, 조합 라이브러리 제공
# heapq - 힙(Heap) 기능을 제공하는 라이브러리. 우선순위 큐 기능을 구현하기 위해 사용
# bisect - 이진 탐색(Binary Search) 기능을 제공하는 라이브러리
# collections - 덱(deque), 카운터(Counter) 등의 유용한 자료구조를 포함하는 라이브러리

# https://docs.python.org/ko/3/library/index.html

# 내장 함수
result = sum([1,2,3,4,5,6,7,8,9])
print(result)

result = min(4,2,3,4,5,11,1)
print(result)

result = eval("3*7*5") # 문자열로된 수식을 변환후 계산
print(result)

# itertools
# permutations
# - 리스트와 같은 iterable 객체에서 r개의 데이터를 뽑아 일렬로 나열하는 모든 경우(순열) 계산
# - 클래스이므로 객체 초기화 이후에는 리스트 자료형으로 변환해서 사용해야한다
from itertools import permutations
data = ['A', 'B', 'C']
result = list(permutations(data, 3)) # 모든순열(경우) 구함
print(result)

# combinations
# - 리스트와 같은 iterable 객체에서 r개의 데이터를 뽑아 순서를 고려하지 않고 나열하는 모든 경우(조합)을 계산
# - 클래스이므로 객체 초기화 이후에는 리스트 자료형으로 변환하여 사용해야 한다
from itertools import combinations
data = ['A', 'B', 'C']
result = list(combinations(data, 2)) # 중복 없음
print(result)

# product
from itertools import product
data = ['A', 'B', 'C']
result = list(product(data, repeat=2)) # 중복 포함
print(result)

# heapq
# heap 기능을 사용하기 위해
# 다익스트라 최단 경로 알고리즘 및 당양한 알고리즘에서 우선순위 큐 기능을 구현하고자 할 때 사용
# PriorityQueue 라이브러리도 사용 가능
import heapq

def heapsort(iterable):
    h = []
    result = []
    # 모든 원소를 차례대로 힙에 삽입
    for value in iterable:
        heapq.heappush(h, value)
    # 힙에 삽입된 모든 원소를 차례대로 꺼내어 담기
    for i in range(len(h)):
        result.append(heapq.heappop(h))
    return result

result = heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8,0])
print(result)


import random
import numpy as np
import mathutils
import bpy
from bpy_extras.object_utils import world_to_camera_view

from src.utils import CAMERA_Z_UPPER_LIMIT, CAMERA_X_LIMIT

class CameraRandomizer(object):

    def __init__(self, camera, parent_cup, two_cups_env):
        self.camera = camera
        self.parent_cup = parent_cup
        self.two_cups_env = two_cups_env
        self.reset_camera_position()

    def north_coord_limit(self, cup_coords, camera_coord):

        max_idx = np.argmax([np.abs(coord[0] - camera_coord[0]) for coord in cup_coords])
        limit_coord = np.array(cup_coords[max_idx])
        limit_coord[2] = max([coord[2] for coord in cup_coords])
        return limit_coord

    def south_coord_limit(self, cup_coords, camera_coord):

        min_idx = np.argmin([np.abs(coord[0] - camera_coord[0]) for coord in cup_coords])
        limit_coord = np.array(cup_coords[min_idx])
        limit_coord[2] = min([coord[2] for coord in cup_coords])

        return limit_coord

    def sample_z_position(self, north_limit):
        return random.uniform(north_limit[2] + 1, CAMERA_Z_UPPER_LIMIT)

    def sample_x_position(self, view_angle, south_limit, z):

        # lower limit
        z_delta = np.abs(z - south_limit[2])
        x_low = south_limit[0] + z_delta / np.tan(view_angle / 2)
        return random.uniform(1.2 * x_low, CAMERA_X_LIMIT[1])

    def sample_x_rotation(self, view_angle, north_limit, south_limit, z, x):

        # low angle
        delta_x = np.abs(x - north_limit[0])
        delta_z = np.abs(z - north_limit[2])
        low_angle = np.arctan(delta_x / delta_z) - view_angle / 2
        low_angle = low_angle * 1.1

        # high angle
        delta_x = np.abs(x - south_limit[0])
        delta_z = np.abs(z - south_limit[2])
        high_angle = np.arctan(delta_x / delta_z) + view_angle / 2
        high_angle = high_angle * 0.95
        high_angle = min(np.pi/2 - 0.2, high_angle)

        return random.uniform(low_angle, high_angle)

    def west_and_east_limits(self, cup_coords, camera_y):
        side1_idx = np.argmax([np.abs(coord[1] - camera_y) for coord in cup_coords])
        side1 = np.array(cup_coords[side1_idx])
        side2_idx = np.argmax([np.abs(coord[1] - side1[1]) for coord in cup_coords])
        side2 = np.array(cup_coords[side2_idx])

        if side2[1] < side1[1]:
            west_limit = side2
            east_limit = side1
        else:
            west_limit = side1
            east_limit = side2

        return west_limit, east_limit

    def sample_y_position(self, west_limit, east_limit, sample_x):

        vertical_camera_angle = bpy.data.cameras['Camera'].angle_x

        # west limit
        x_delta = sample_x - west_limit[0]
        y_west = west_limit[1] + np.tan(vertical_camera_angle/2) * x_delta

        if y_west < 0:
            y_west = y_west * 1.1
        else:
            y_west = y_west * 0.9

        # west limit
        x_delta = sample_x - east_limit[0]
        y_east = east_limit[1] - np.tan(vertical_camera_angle/2) * x_delta

        if y_east < 0:
            y_east = y_east * 0.9
        else:
            y_east = y_east * 1.1

        return random.uniform(y_west, y_east)

    def random_z_rotation(self, view_angle, sample_y, sample_x, west_limit, east_limit):

        # highest angle
        delta_y = np.abs(sample_y - west_limit[1])
        delta_x = np.abs(sample_x - west_limit[0])
        theta = np.arctan(delta_y/ delta_x)

        if sample_y < west_limit[1]:
            west_angle = view_angle/2 + theta
        else:
            west_angle = view_angle/2 - theta

        # lowest angle
        delta_y = np.abs(sample_y - east_limit[1])
        delta_x = np.abs(sample_x - east_limit[0])
        theta = np.arctan(delta_y/ delta_x)

        if sample_y < east_limit[1]:
            east_angle = view_angle/2 - theta
        else:
            east_angle = view_angle/2 + theta

        return np.pi/2 + 0.95 * random.uniform(-west_angle, east_angle)

    def reset_camera_position(self):
        bpy.context.scene.update()
        self.camera = bpy.context.scene.objects['Camera']
        self.parent_cup = bpy.context.scene.objects['cup_1']
        self.camera.rotation_euler = mathutils.Vector([90, 0, 90]) * 2 * np.pi / 360
        self.camera.location = (4, 0, 6)

    def do_randomzation(self):

        self.reset_camera_position()
        cup = self.parent_cup
        mw = cup.matrix_world
        cup_coords = [np.array(mw * v.co) for v in cup.data.vertices] # Global coordinates of vertices

        # second cup
        if (self.two_cups_env):

            cup2 = bpy.context.scene.objects['cup_2']
            mw = cup2.matrix_world
            cup_coords2 = [np.array(mw * v.co) for v in cup2.data.vertices] # Global coordinates of vertices

            cup_coords = cup_coords + cup_coords2

        camera_coord = self.camera.location

        north_limit = self.north_coord_limit(cup_coords, camera_coord)
        south_limit = self.south_coord_limit(cup_coords, camera_coord)
        west_limit, east_limit = self.west_and_east_limits(cup_coords, camera_coord[1])

        sample_z = self.sample_z_position(north_limit)
        # rotation
        sample_x = self.sample_x_position(bpy.data.cameras['Camera'].angle_y, south_limit, sample_z)
        sample_x_rotation = self.sample_x_rotation(bpy.data.cameras['Camera'].angle_y, north_limit, south_limit, sample_z, sample_x)

        sample_y = self.sample_y_position(west_limit, east_limit, sample_x)
        sample_z_rotation = self.random_z_rotation(bpy.data.cameras['Camera'].angle_x, sample_y, sample_x, west_limit, east_limit)

        return sample_x, sample_y, sample_z, sample_x_rotation, sample_z_rotation, [north_limit, south_limit, west_limit, east_limit]

    def change_camera_position(self):

        x, y, z, sample_x_rotation, sample_z_rotation, limits = self.do_randomzation()
        self.camera.location = (x, y, z)
        self.camera.rotation_euler[0] = sample_x_rotation
        self.camera.rotation_euler[2] = sample_z_rotation
        success = self.coords_within_image(limits)
        return success

    def coords_within_image(self, coords):

        scene = bpy.context.scene
        scene.update()
        cs, ce = self.camera.data.clip_start, self.camera.data.clip_end

        object_names = [obj.name for obj in list(bpy.data.objects)]
        random_objects = []
        image_coords = []

        for name in object_names:

            if 'random' == name[:6]:
                obj = bpy.data.objects[name]
                mat_world = obj.matrix_world
                verts = (mat_world * vert.co for vert in obj.data.vertices)
                coords_2d = [world_to_camera_view(scene, self.camera, coord) for coord in verts]
                image_coords.append(coords_2d)
                random_objects.append(obj)

        def random_object_is_blocking(obj_coords, limit_coord):

            for co in obj_coords:
                if np.abs(co.x - limit_coord.x) < 0.01 and np.abs(co.y - limit_coord.y) < 0.01 and co.z < limit_coord.z:
                    return True
            return False

        for idx, coord in enumerate(coords):
            coord = mathutils.Vector(coord)
            co_ndc = world_to_camera_view(scene, self.camera, coord)

            if not((0.0 < co_ndc.x < 1.0 and
                0.0 < co_ndc.y < 1.0 and cs < co_ndc.z < ce)):

                return False

            update_objects = []
            update_image_coords = []
            for i in range(len(image_coords)):

                if random_object_is_blocking(image_coords[i], co_ndc):
                    obstacle = random_objects[i]
                    print('POP', obstacle.name)
                    bpy.data.objects.remove(obstacle)
                else:
                    update_objects.append(random_objects[i])
                    update_image_coords.append(image_coords[i])
            random_objects = update_objects
            image_coords = update_image_coords

        return True

def blender_run():
    cr = CameraRandomizer(bpy.data.objects['Camera'], bpy.data.objects['cup_1'])
    cr.change_camera_position()

if __name__== '__main__':
    import sys, os
    sys.path.append(os.getcwd())
    blender_run()


from plexapi.server import PlexServer
import os
from dotenv import load_dotenv
import sys
import textwrap
import logging
import urllib3.exceptions
from urllib3.exceptions import ReadTimeoutError
from requests import ReadTimeout
from helpers import booler, get_plex, get_all_from_library, load_and_upgrade_env
from alive_progress import alive_bar

from logs import setup_logger, plogger, blogger, logger
from pathlib import Path
from datetime import datetime, timedelta
# current dateTime
now = datetime.now()

# convert to string
RUNTIME_STR = now.strftime("%Y-%m-%d %H:%M:%S")

SCRIPT_NAME = Path(__file__).stem

# DONE 0.2.0: chattier about where we're getting items
# DONE 0.2.1: Use booler helper to ensure correct var reading

VERSION = "0.2.1"

env_file_path = Path(".env")

ACTIVITY_LOG = f"{SCRIPT_NAME}.log"
setup_logger('activity_log', ACTIVITY_LOG)

plogger(f"Starting {SCRIPT_NAME} {VERSION} at {RUNTIME_STR}", 'info', 'a')

if load_and_upgrade_env(env_file_path) < 0:
    exit()

LIBRARY_NAME = os.getenv("LIBRARY_NAME")
LIBRARY_NAMES = os.getenv("LIBRARY_NAMES")
UNMATCHED_ONLY = booler(os.getenv("UNMATCHED_ONLY"))

if LIBRARY_NAMES:
    LIB_ARRAY = LIBRARY_NAMES.split(",")
else:
    LIB_ARRAY = [LIBRARY_NAME]

tmdb_str = "tmdb://"
tvdb_str = "tvdb://"

def progress(count, total, status=""):
    bar_len = 40
    filled_len = int(round(bar_len * count / float(total)))

    percents = round(100.0 * count / float(total), 1)
    bar = "=" * filled_len + "-" * (bar_len - filled_len)
    stat_str = textwrap.shorten(status, width=80)

    sys.stdout.write("[%s] %s%s ... %s\r" % (bar, percents, "%", stat_str.ljust(80)))
    sys.stdout.flush()

plex = get_plex()

if LIBRARY_NAMES == 'ALL_LIBRARIES':
    LIB_ARRAY = []
    all_libs = plex.library.sections()
    for lib in all_libs:
        if lib.type == 'movie' or lib.type == 'show':
            LIB_ARRAY.append(lib.title.strip())

for lib in LIB_ARRAY:
    the_lib = plex.library.section(lib)
    plogger(f"getting items from [{lib}]...", 'info', 'a')

    if UNMATCHED_ONLY:
        print(f"getting UNMATCHED items from [{lib}]...")
        items = get_all_from_library(plex, the_lib, None, {'unmatched': True})
    else:
        items = get_all_from_library(plex, the_lib)

    item_total = len(items)
    plogger(f"looping over {item_total} items...", 'info', 'a')
    item_count = 0

    plex_links = []
    external_links = []

    if the_lib.type == 'movie':
        agents = [
            "com.plexapp.agents.imdb",
            "tv.plex.agents.movie",
            "com.plexapp.agents.themoviedb"
        ]
    elif the_lib.type == 'show':
        agents = [
            "com.plexapp.agents.thetvdb",
            "tv.plex.agents.series"
        ]
    else:
        agents = [
            "com.plexapp.agents.fanarttv",
            "com.plexapp.agents.none",
            "tv.plex.agents.music",
            "com.plexapp.agents.opensubtitles",
            "com.plexapp.agents.imdb",
            "com.plexapp.agents.lyricfind",
            "com.plexapp.agents.thetvdb",
            "tv.plex.agents.movie",
            "tv.plex.agents.series",
            "com.plexapp.agents.plexthememusic",
            "org.musicbrainz.agents.music",
            "com.plexapp.agents.themoviedb",
            "com.plexapp.agents.htbackdrops",
            "com.plexapp.agents.movieposterdb",
            "com.plexapp.agents.localmedia",
            "com.plexapp.agents.lastfm"
        ]

    with alive_bar(len(items), dual_line=True, title=f"Rematching") as bar:
        for item in items:
            tmpDict = {}
            item_count = item_count + 1
            matched_it = False

            for agt in agents:
                if not matched_it:
                    try:
                        progress_str = f"{item.title} - agent {agt}"
                        bar.text(progress_str)

                        item.fixMatch(auto=True, agent=agt)

                        matched_it = True

                        progress_str = f"{item.title} - DONE"
                        bar.text(progress_str)

                    except urllib3.exceptions.ReadTimeoutError:
                        progress(item_count, item_total, "ReadTimeoutError: " + item.title)
                    except urllib3.exceptions.HTTPError:
                        progress(item_count, item_total, "HTTPError: " + item.title)
                    except ReadTimeoutError:
                        progress(item_count, item_total, "ReadTimeoutError-2: " + item.title)
                    except ReadTimeout:
                        progress(item_count, item_total, "ReadTimeout: " + item.title)
                    except Exception as ex:
                        progress(item_count, item_total, "EX: " + item.title)
                        logging.error(ex)
            bar()


import sys
from collections import deque
N,M,V=map(int, sys.stdin.readline().split())
dfs_visit=[]
bfs_visit=[]
graph=[[0]*(N+1) for _ in range(N+1)]
for _ in range(M):
    a,b=map(int, sys.stdin.readline().split())
    graph[a][b]=1
    graph[b][a]=1

def dfs(v):
    dfs_visit.append(v)
    print(v,end=' ')
    for i in range(len(graph[v])):
        if graph[v][i] == 1 and i not in dfs_visit :
            dfs(i)

def bfs(v):
    queue=deque()
    queue.append(v)
    bfs_visit.append(v)
    while queue :
        pop_num=queue.popleft()
        print(pop_num, end=' ')
        for i in range(len(graph[pop_num])):
            if graph[pop_num][i] == 1 and i not in bfs_visit:
                queue.append(i)
                bfs_visit.append(i)
dfs(V)
print()
bfs(V)


import os
import json

from engine import Engine

class Runner():
    def __init__(self, flow_name, test_name):
        input_path = f'./cassettes/{flow_name}/{test_name}.json'
        input_data = json.load(open(input_path)) if os.path.exists(input_path) else {}

        self._engine = Engine(
            file_path=f'./workflows/{flow_name}.json',
            input=input_data
        )
        self._expected_output = json.load(open(f'./cassettes/{flow_name}/{test_name}.json'))

    def run(self):
        # Test
        self._engine.run()
        return json.loads(json.dumps(self._engine.activity, default=dict))


#!/usr/bin/env python

import numpy as np
import pandas as pd
import scipy.stats
import sklearn.linear_model
import sys

try:
    indata = sys.argv[1]
except:
    sys.stderr.write("Usage: ./get_gc_residuals.py <INDATA>\n")
    sys.exit(1)

if indata == "-":
    f = sys.stdin
else: f = open(indata, "r")

# Read data
data = pd.read_csv(f, sep="\t", names=["chrom","start","readcount","gc"])

# Regress gc on readcount
xvals = np.array(data["gc"]).reshape((data.shape[0], 1))
yvals = np.array(data["readcount"]).reshape((data.shape[0], 1))
model = sklearn.linear_model.LinearRegression()
model.fit(xvals, yvals)
pred = model.predict(xvals)
data["pred"] = pred
data["resid"] = data["readcount"] - data["pred"]

# Look at model fit
#sys.stderr.write(str(model.score(xvals, yvals))+"\n")
sys.stderr.write(str(scipy.stats.pearsonr(xvals, yvals))+"\n")

# Output residuals
data[["chrom","start","resid","readcount"]].to_csv(sys.stdout, index=False, sep="\t")


#!/usr/bin/env python3
"""
Build and publish Docker images.
"""
import argparse
import functools
import itertools
import os
import subprocess
import shutil

import jinja2

# The docker binary to use for executing commands
DOCKER_BINARY = os.environ.get("DOCKER_BINARY", shutil.which("docker"))
# Base path of where the docker images are organized
BASE_PATH = os.path.dirname(os.path.abspath(__file__))

# Tree of images to be built (identified by filesystem
# paths) and their parents. Leaf nodes are lists while
# everything else is dictionaries. When a particular
# image wants to be rebuilt, all of its parents are too.
# We rely on docker caching to ensure this is not super
# dead slow.
IMAGES = {
    "buster-sssd": {
        "golang111-sssd/base": ["golang111-sssd/web"],
        "jdk11-sssd/base": ["jdk11-sssd/web"],
        "php73-sssd/base": ["php73-sssd/web"],
        "python37-sssd/base": ["python37-sssd/web"],
        "ruby25-sssd/base": ["ruby25-sssd/web"],
        "html-sssd/web": [],
    },
    "buster-standalone": [],
    "bullseye-sssd": {
        "jdk17-sssd/base": ["jdk17-sssd/web"],
        "mono68-sssd/base": [],
        "node12-sssd/base": ["node12-sssd/web"],
        "node16-sssd/base": ["node16-sssd/web"],
        "perl532-sssd/base": ["perl532-sssd/web"],
        "php74-sssd/base": ["php74-sssd/web"],
        "python39-sssd/base": ["python39-sssd/web"],
        "ruby27-sssd/base": ["ruby27-sssd/web"],
        "tcl86-sssd/base": ["tcl86-sssd/web"],
    },
    "bullseye-standalone": [],
    # buildpack stacks
    "bullseye0/base": ["bullseye0/build", "bullseye0/run"],
    "bookworm-sssd": {
        "mariadb-sssd/base": [],
        "node18-sssd/base": ["node18-sssd/web"],
        "perl536-sssd/base": ["perl536-sssd/web"],
        "php82-sssd/base": ["php82-sssd/web"],
        "python311-sssd/base": ["python311-sssd/web"],
        "ruby31-sssd/base": ["ruby31-sssd/web"],
    },
}

# Unbuffer print output (https://stackoverflow.com/a/40161931/8171)
print = functools.partial(print, flush=True)

def make_docker_tag(name, registry, image_prefix, tag):
    return "{registry}/{prefix}-{sanitized_name}:{tag}".format(
        registry=registry,
        prefix=image_prefix,
        sanitized_name=name.replace("/", "-"),
        tag=tag,
    )

def make_dockerfile(name, registry, image_prefix, tag, jinja_env):
    ctx = {"registry": registry, "image_prefix": image_prefix, "tag": tag, "image_path": name}
    tmpl = jinja_env.get_template("{}/Dockerfile.template".format(name))
    dockerfile = tmpl.render(**ctx)
    if dockerfile is None:
        raise RuntimeError("Generated empty Dockerfile for {}".format(name))

    out_file = os.path.join(BASE_PATH, name, "Dockerfile")
    with open(out_file, "wt") as f_out:
        f_out.write(dockerfile)

def rm_dockerfile(name):
    os.unlink(os.path.join(BASE_PATH, name, "Dockerfile"))

def build_image(name, registry, image_prefix, no_cache, tag, jinja_env):
    print("\x1b[32m" + ("#" * 78) + "\x1b[0m")
    print(
        "\x1b[32m  Building {}\x1b[0m".format(
            make_docker_tag(name, registry, image_prefix, tag)
        )
    )
    print("\x1b[32m" + ("#" * 78) + "\x1b[0m")
    make_dockerfile(name, registry, image_prefix, tag, jinja_env)
    args = [
        DOCKER_BINARY,
        "build",
        "-t",
        make_docker_tag(name, registry, image_prefix, tag),
        "-f",
        f"{name}/Dockerfile",
    ]
    if no_cache:
        args.append("--no-cache")
    args.append(BASE_PATH)
    subprocess.check_call(args)
    rm_dockerfile(name)

def push_image(name, registry, image_prefix, tag):
    subprocess.check_call(
        [
            DOCKER_BINARY,
            "push",
            make_docker_tag(name, registry, image_prefix, tag),
        ]
    )

def lineage_of(name):
    def children_of(node):
        if type(node) == dict:
            children = list(node.keys())
            for k, v in node.items():
                children += children_of(v)
            return children
        return node

    def ancestors_of(node, cur_lineage):
        if name in node:
            cur_lineage.append(name)
            if type(node) == dict:
                cur_lineage.extend(children_of(node[name]))
            return cur_lineage

        if type(node) == dict:
            for k, v in node.items():
                ret = ancestors_of(v, cur_lineage + [k])
                if ret:
                    return ret
        return None

    return ancestors_of(IMAGES, [])

def main():
    argparser = argparse.ArgumentParser()
    argparser.add_argument(
        "image",
        help="Which image to build. Will also build all ancestors + descendents of image",
        choices=list(
            itertools.chain(*[lineage_of(base) for base in IMAGES.keys()])
        ),
    )
    argparser.add_argument(
        "--push",
        action="store_true",
        help="Push the images to the repository afterwards",
    )
    argparser.add_argument(
        "--docker-registry",
        default="docker-registry.tools.wmflabs.org",
        help="Name of docker registry to tag images with & push to",
    )
    argparser.add_argument(
        "-t",
        "--tag",
        default="testing",
        help=(
            "Tag for this image.  "
            "The default is testing and other options is latest.  "
            "Latest is what should be shipped to webservice."
        ),
        type=str,
        choices=["latest", "testing"],
    )
    argparser.add_argument(
        "--image-prefix",
        default="toolforge",
        help=(
            "Prefix to use for each image name to make sure they are easily"
            " differentiable"
        ),
    )
    argparser.add_argument(
        "--no-cache",
        action="store_true",
        help="Do not use docker's cache when building images, build from scratch",
    )
    argparser.add_argument(
        "--single",
        "-s",
        action="store_true",
        help="Build only a single image rather than full chain",
    )

    args = argparser.parse_args()
    if args.single:
        images = (args.image,)
    else:
        images = lineage_of(args.image)
    print("Building following images: ", images)

    # Setup template engine
    jinja_env = jinja2.Environment(
        loader=jinja2.FileSystemLoader(BASE_PATH),
        trim_blocks=True,
        lstrip_blocks=True,
    )

    # Separate build and push step so we do not push images if
    # any of them fail
    for image in images:
        build_image(
            image,
            args.docker_registry,
            args.image_prefix,
            args.no_cache,
            args.tag,
            jinja_env,
        )

    if args.push:
        for image in images:
            push_image(image, args.docker_registry, args.image_prefix, args.tag)

if __name__ == "__main__":
    main()


import torch
import torchvision
import torchvision.transforms as transforms
import torch.optim as optim
import torch.nn as nn

import matplotlib.pyplot as plt
import numpy as np

classes = (
    "plane",
    "car",
    "bird",
    "cat",
    "deer",
    "dog",
    "frog",
    "horse",
    "ship",
    "truck",
)

net = torchvision.models.vgg19_bn(num_classes=len(classes))

if __name__ == "__main__":
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

    transform = transforms.Compose(
        [transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]
    )
    batch_size = 10

    trainset = torchvision.datasets.CIFAR10(
        root="./data", train=True, download=True, transform=transform
    )
    trainloader = torch.utils.data.DataLoader(
        trainset, batch_size=batch_size, shuffle=True, num_workers=8
    )

    testset = torchvision.datasets.CIFAR10(
        root="./data", train=False, download=True, transform=transform
    )
    testloader = torch.utils.data.DataLoader(
        testset, batch_size=batch_size, shuffle=False, num_workers=8
    )

    print("Start Training")

    net.to(device)
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

    train_loss = []
    test_loss = []
    train_acc = []
    test_acc = []

    for epoch in range(40):
        print(f"Epoch: {epoch + 1}")
        running_loss = 0.0
        train_correct = 0
        train_total = 0
        for i, data in enumerate(trainloader, 0):
            inputs, labels = data[0].to(device), data[1].to(device)
            optimizer.zero_grad()
            outputs = net(inputs)
            loss = criterion(outputs, labels)
            predicted = torch.argmax(outputs, 1)
            train_correct += (predicted == labels).sum().item()
            train_total += labels.size(0)
            loss.backward()
            optimizer.step()
            running_loss += loss.item()

        val_loss = 0.0
        val_correct = 0
        val_total = 0
        for i, data in enumerate(testloader, 0):
            inputs, labels = data[0].to(device), data[1].to(device)
            outputs = net(inputs)
            loss = criterion(outputs, labels)
            val_loss += loss.item()
            predicted = torch.argmax(outputs, 1)
            val_correct += (predicted == labels).sum().item()
            val_total += labels.size(0)

        train_loss.append(running_loss / len(trainloader))
        test_loss.append(val_loss / len(testloader))
        train_acc.append(train_correct / train_total)
        test_acc.append(val_correct / val_total)

        print(f"[{epoch + 1}, {i + 1:5d}]")
        print(f"\tloss: {train_loss[-1]:.3f} val loss: {test_loss[-1]:.3f}")
        print(f"\taccuracy: {train_acc[-1]:.3f} val accuracy: {test_acc[-1]:.3f}")

    fig, axs = plt.subplots(2, 1, layout='constrained')
    axs[0].plot(train_loss, label="Train")
    axs[0].plot(test_loss, label="Test")
    axs[0].set_xlabel('Epoch')
    axs[0].set_ylabel('Loss')
    axs[0].legend(loc="upper right")
    axs[0].set_title("Loss")
    axs[0].grid(True)

    axs[1].plot(train_acc, label="Train")
    axs[1].plot(test_acc, label="Test")
    axs[1].set_xlabel('Epoch')
    axs[1].set_ylabel('Accuracy')
    axs[1].legend(loc="upper left")
    axs[1].set_title("Accuracy")
    axs[1].grid(True)

    print(train_loss)
    print(test_loss)
    print(train_acc)
    print(test_acc)

    print("Finished Training")
    torch.save(net.state_dict(), "./cifar_net.pth")


from PyQt6 import (
    QtWidgets as qtw,
    QtCore as qtc
)

from widgets.list_items.note_list_item import NoteListItem
from data.note_repository import NoteRepository

class NotesList(qtw.QWidget):
    def __init__(self, conStr, openNoteFunc, createNoteFunc):
        super().__init__()
        self.conStr = conStr
        self.repo = NoteRepository(self.conStr)

        self.openNoteFunc = openNoteFunc
        self.createNoteFunc = createNoteFunc

        self.mainLayout = qtw.QVBoxLayout()
        self.scrollWidget = qtw.QWidget()
        self.scrollItems = qtw.QVBoxLayout()
        self.scrollArea = qtw.QScrollArea()

        self.build()

    def build(self):
        self.populateScrollItems()

        self.scrollArea.setWidgetResizable(True)
        self.scrollWidget.setLayout(self.scrollItems)
        self.scrollArea.setWidget(self.scrollWidget)

        self.scrollArea.setHorizontalScrollBarPolicy(qtc.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
        self.scrollArea.setVerticalScrollBarPolicy(qtc.Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
        self.scrollItems.setAlignment(qtc.Qt.AlignmentFlag.AlignTop)

        self.mainLayout.addWidget(self.scrollArea)

        newNoteButton = qtw.QPushButton("New Note")
        newNoteButton.clicked.connect(self.newNoteClicked)
        self.mainLayout.addWidget(newNoteButton)

        self.setLayout(self.mainLayout)

    def populateScrollItems(self):
        for i in reversed(range(self.scrollItems.count())):
            self.scrollItems.itemAt(i).widget().setParent(None)

        for note in self.repo.getAllNotes():
            noteWidget = NoteListItem(note, self.conStr, self.openNoteFunc, self.populateScrollItems)
            self.scrollItems.addWidget(noteWidget)

    def newNoteClicked(self):
        self.createNoteFunc()
        self.populateScrollItems()


import pygame
import os
import BoardState
from Constants import *

'''
-loads sprites for all of the different pieces
-blits them onto the board
-updates the board
'''
class Game(object):
    '''
     - Initializes the Game
     - The screen parameter is the main screen where the game will appear, it is saved in the field screen
     - The board field stores the BoardState Object

    '''
    def __init__(self, screen):
        self.Board = BoardState.BoardState()
        self.screen = screen
        self.mouseClicked = -1
        self.prevClicked = -1
        self.moved = False
        self.validMoves = [0] * 64
        self.validSprite = pygame.image.load(os.path.join('Sprites', 'validMoves.png' ))
    '''
     -Updates what is displayed on the screen
    '''
    def DisplayBoard(self):
        #initalizes and displays chessboard backround
        backround = pygame.image.load(os.path.join('Sprites', 'Board.png' ))
        self.screen.blit(backround,(0,0))

        # Initializing indicator sprites for source and destination spots for moving pieces and then
        # blitting indicators to the screen
        Destination = pygame.image.load(os.path.join('Sprites', 'Destination.png'))
        Source = pygame.image.load(os.path.join('Sprites', 'Source.png'))
        if(self.prevClicked != -1 and not self.moved):
            sRow = int(self.prevClicked / 8)
            sRow = sRow * 100
            sColumn = int(self.prevClicked % 8)
            sColumn = sColumn * 100
            self.screen.blit(Source, (sColumn, sRow))
        if(self.mouseClicked != -1 and not self.moved):
            dRow = int(self.mouseClicked / 8)
            dRow = dRow * 100
            dColumn = int(self.mouseClicked % 8)
            dColumn = dColumn * 100
            self.screen.blit(Destination, (dColumn, dRow))

        for i in range(B_START, B_END):
            row = int(i / 8)
            row = row * 100 + 20
            column = int(i % 8)
            column = column * 100 + 20
            if(self.validMoves[i] != 0):
                self.screen.blit(self.validSprite, (column - 20 , row - 20 ))
            if(self.Board.boardArray[i] != 0):
                self.screen.blit(self.Board.boardArray[i].sprite, (column , row ))
        pygame.display.flip()

    '''
    -sets the mouse clicked  and previous clicked fields
    -sets them in terms of board square4
    '''
    def getMousePos(self):
        position = pygame.mouse.get_pos()
        x = position[0]
        y = position[1]
        x = int(x / 100)
        y = int(y / 100)
        self.prevClicked = self.mouseClicked
        pos = (y * 8) + x
        self.mouseClicked = pos
        if(self.Board.boardArray[pos] != 0):
            self.Board.boardArray[pos].calculateMoves()
            self.validMoves = self.Board.boardArray[pos].moves
        self.moved = False
    '''
    - moves a piece from prev clicked to mouseclicked positions
    '''
    def movePiece(self):
        self.Board.move(self.prevClicked, self.mouseClicked)
        self.moved = True


from gensim.models import Word2Vec
from sklearn.decomposition import PCA
from matplotlib import pyplot

#define training data
sentences = [['this', 'is', 'my', 'first', 'sentence', 'for', 'this', 'test', 'on', 'word2vec'],
['this', 'is', 'the', 'second', 'sentence'],
['all', 'comedy', 'comes', 'in', 'threes'],
['i', 'am', 'all', 'four', 'female', 'politicians', 'and', 'all', 'that', 'jazz'],
['and', 'the', 'deed', 'was', 'done', 'i', 'had', 'gotten', 'to', 'five']]

#train model
model = Word2Vec(sentences, min_count=1) #Word2Vec(vocab=31, size=100, alpha=0.025)

#fit 2D Principal Component for Analysis model to vectors
X = model[model.wv.vocab]
pca = PCA(n_components=2)
result = pca.fit_transform(X)

#create scatter plot of projection
pyplot.scatter(result[:,0], result[:,1])
words = list(model.wv.vocab)
for i, word in enumerate(words):
    pyplot.annotate(word, xy=(result[i,0], result[i, 1]))
pyplot.show()


import json
from tqdm import tqdm
from util.wikidata_query import WikiDataQuerier

train_file = './train.json'
test_file = './test.json'

with open(train_file, 'r') as f:
    train_items = json.load(f)

with open(test_file, 'r') as f:
    test_items = json.load(f)

querier = WikiDataQuerier()

entity2hypers = {}

def get_hyper(dataset):
    for relation_id, items in tqdm(dataset.items()):
        entity_list = set()
        for item in items:
            entity_list.add(item['h']['id'])
            entity_list.add(item['t']['id'])
        entity_list = list(entity_list)
        hyper_results = querier.fetch_hypernym_labels_by_entity_ids(entity_list)['results']['bindings']

        for res in hyper_results:
            entity_id = res['item']['value'].split('/')[-1]
            entity_label = res['itemLabel']['value']
            class_id = res['class']['value'].split('/')[-1]
            class_label = res['classLabel']['value']

            if entity_id not in entity2hypers:
                hyper_set = set()
                hyper_set.add(class_id + ' ' + class_label)
                entity2hypers[entity_id] = hyper_set
            else:
                hyper_set = entity2hypers[entity_id]
                hyper_set.add(class_id + ' ' + class_label)
                entity2hypers[entity_id] = hyper_set

print('fetch hyper of train set')
get_hyper(train_items)
print('fetch hyper of test set')
get_hyper(test_items)

e2h = {}
for entity_id, hyper_set in entity2hypers.items():
    hyper_list = []
    for hyper in list(hyper_set):
        class_id = hyper.split(' ')[0]
        class_label = hyper.split(' ')[1:]
        hyper_list.append({'id': class_id, 'label': class_label})
    e2h[entity_id] = hyper_list
with open('./e2h.json', 'w') as f:
    json.dump(e2h, f, indent=4)


from astropy import time
from datetime import datetime
from asdf.exceptions import ValidationError
import pytest

from stdatamodels.jwst.datamodels import JwstDataModel

def test_strict_validation_enum():
    with JwstDataModel(strict_validation=True) as dm:
        assert dm.meta.instrument.name is None
        with pytest.raises(ValidationError):
            # FOO is not in the allowed enumerated values
            dm.meta.instrument.name = 'FOO'

def test_strict_validation_type():
    with JwstDataModel(strict_validation=True) as dm:
        with pytest.raises(ValidationError):
            # Schema requires a float
            dm.meta.target.ra = "FOO"

def test_strict_validation_date():
    with JwstDataModel(strict_validation=True) as dm:
        time_obj = time.Time(dm.meta.date)
        assert isinstance(time_obj, time.Time)
        date_obj = datetime.strptime(dm.meta.date, '%Y-%m-%dT%H:%M:%S.%f')
        assert isinstance(date_obj, datetime)


"""
Serial tests for tar
"""

import pytest
from pathlib import Path
import numpy as np
import lyncs_io as io
from lyncs_io.testing import (
    dtype_loop,
    shape_loop,
    ext_loop,
    tar_mode_loop,
    tempdir,
    generate_rand_arr,
)

@tar_mode_loop
@ext_loop
@dtype_loop
@shape_loop
def test_serial_tar(tempdir, dtype, shape, mode, ext):
    """
    Test all the basic functionality of saving, loading
    and getting the header of a file in a tarball
    """
    arr = generate_rand_arr(shape, dtype)

    ftmp = tempdir + f"tarball{mode}/foo{ext}"
    io.save(arr, ftmp)

    assert (arr == io.load(ftmp)).all()
    assert (arr == io.load(ftmp, format="Tar")).all()
    assert io.load(ftmp).shape == io.head(ftmp)["shape"]
    assert io.load(ftmp).dtype == io.head(ftmp)["dtype"]

    path = Path(ftmp)
    assert (arr == io.load(path.parent)[path.name]).all()

    # Test that an exception is raised when
    # trying to append to a compressed tarball
    with pytest.raises(ValueError):
        io.save(arr, tempdir + f"tarball.tar.gz/foo{ext}")
        io.save(arr, tempdir + f"tarball.tar.gz/foo{ext}")

    # Testing Head
    ftmp = tempdir + f"tarball{mode}/"
    assert list(io.head(ftmp).keys()) == list(io.load(ftmp).keys())
    assert io.load(ftmp)["foo.npy"].shape == io.head(ftmp)["foo.npy"]["shape"]

    ftmp = tempdir + "map_tar.tar"
    mydict = {
        "random": {
            "arr0.npy": generate_rand_arr(shape, dtype),
            "arr1.npy": generate_rand_arr(shape, dtype),
        },
        "zeros.npy": np.zeros((4, 4, 4, 4)),
    }
    io.save(mydict, ftmp)

    loaded_dict = io.load(ftmp, all_data=True)

    assert (mydict["random"]["arr0.npy"] == loaded_dict["random"]["arr0.npy"]).all()
    assert (mydict["random"]["arr1.npy"] == loaded_dict["random"]["arr1.npy"]).all()
    assert (mydict["zeros.npy"] == loaded_dict["zeros.npy"]).all()


import csv
import utils

def loadDataset(fileName):
    with open(fileName, 'rU') as trainingInput:
        # detect the "dialect" of this type of csv file
        try:
            dialect = csv.Sniffer().sniff(trainingInput.read(1024))
        except:
            # if we fail to detect the dialect, defautl to Microsoft Excel
            dialect = 'excel'
        trainingInput.seek(0)
        trainingRows = csv.reader(trainingInput, dialect)

        allTweets = []
        allTweetSentiments = []
        entireDataset = []
        for row in trainingRows:
            # csv only gives us an iterable, not the data itself
            entireDataset.append(row)

    return entireDataset

entireDataset = loadDataset('testdata.manual.2009.06.14.csv')

# these are the same emoticons that cover 98.6% of the nltk twitter corpus
emoticons = {
    '4': [':)','(:',': )','( :','=)','(=','= )','( =',':D',': D',':p',': p',':-)','(-:',':- )','( -:'],
    '0': [':(','):',': (',') :','=(',')=','= (',') =',':D',': D',':p',': p',':-(',')-:',':- (',') -:']
}

theirAlgosPredictions = []

for row in entireDataset:
    tweet = row[5]

    # set default sentiment score to 2 (neutral)
    sentimentScore = 2

    # try to find a positive emoticon
    for emoticon in emoticons['4']:
        if emoticon in tweet:
            sentimentScore = 4

    # try to find a negative emoticon
    for emoticon in emoticons['0']:
        if emoticon in tweet:
            # if we have already found a positive emoticon for this message, call it neutral
            if sentimentScore == 4:
                sentimentScore = 2
            else:
                sentimentScore = 0

    # add their algorithm's prediction as the first item in each row
    row.insert(0, sentimentScore)

headerRow = ['Their algorithm\'s predictions','Manually Scored Sentiment','ID','Date','Search term used to gather tweet','User','Text']
entireDataset.insert(0, headerRow)

utils.writeData(entireDataset, 'testdata.with.their.algos.predictions.csv')