"""
Currently just defines "stats_dict", which is a nice way to gather multiple
numeric statistics (e.g. max, min, median, mode, arithmetic-mean,
geometric-mean, standard-deviation, etc...) about data in an array.
"""
import warnings
import collections
import numpy as np
import ubelt as ub
import sys

# Maybe name or alias or use in kwarray.describe?
def stats_dict(inputs, axis=None, nan=False, sum=False, extreme=True,
               n_extreme=False, median=False, shape=True, size=False,
               quantile='auto'):
    """
    Describe statistics about an input array

    Args:
        inputs (ArrayLike): set of values to get statistics of
        axis (int): if ``inputs`` is ndarray then this specifies the axis
        nan (bool): report number of nan items (TODO: rename to skipna)
        sum (bool): report sum of values
        extreme (bool): report min and max values
        n_extreme (bool): report extreme value frequencies
        median (bool): report median
        size (bool): report array size
        shape (bool): report array shape
        quantile (str | bool | List[float]):
            defaults to 'auto'. Can also be a list of quantiles to compute.
            if truthy computes quantiles.

    Returns:
        collections.OrderedDict:
            dictionary of common numpy statistics
            (min, max, mean, std, nMin, nMax, shape)

    SeeAlso:
        :func:`scipy.stats.describe`
        :func:`pandas.DataFrame.describe`

    Example:
        >>> # xdoctest: +IGNORE_WHITESPACE
        >>> from kwarray.util_averages import *  # NOQA
        >>> axis = 0
        >>> rng = np.random.RandomState(0)
        >>> inputs = rng.rand(10, 2).astype(np.float32)
        >>> stats = stats_dict(inputs, axis=axis, nan=False, median=True)
        >>> import ubelt as ub  # NOQA
        >>> result = str(ub.urepr(stats, nl=1, precision=4, with_dtype=True))
        >>> print(result)
        {
            'mean': np.array([[0.5206, 0.6425]], dtype=np.float32),
            'std': np.array([[0.2854, 0.2517]], dtype=np.float32),
            'min': np.array([[0.0202, 0.0871]], dtype=np.float32),
            'max': np.array([[0.9637, 0.9256]], dtype=np.float32),
            'q_0.25': np.array([0.4271, 0.5329], dtype=np.float64),
            'q_0.50': np.array([0.5584, 0.6805], dtype=np.float64),
            'q_0.75': np.array([0.7343, 0.8607], dtype=np.float64),
            'med': np.array([0.5584, 0.6805], dtype=np.float32),
            'shape': (10, 2),
        }

    Example:
        >>> # xdoctest: +IGNORE_WHITESPACE
        >>> from kwarray.util_averages import *  # NOQA
        >>> axis = 0
        >>> rng = np.random.RandomState(0)
        >>> inputs = rng.randint(0, 42, size=100).astype(np.float32)
        >>> inputs[4] = np.nan
        >>> stats = stats_dict(inputs, axis=axis, nan=True, quantile='auto')
        >>> import ubelt as ub  # NOQA
        >>> result = str(ub.urepr(stats, nl=0, precision=1, strkeys=True))
        >>> print(result)

    Example:
        >>> import kwarray
        >>> import ubelt as ub
        >>> rng = kwarray.ensure_rng(0)
        >>> orig_inputs = rng.rand(1, 1, 2, 3)
        >>> param_grid = ub.named_product({
        >>>     #'axis': (None, 0, (0, 1), -1),
        >>>     'axis': [None],
        >>>     'percent_nan': [0, 0.5, 1.0],
        >>>     'nan': [True, False],
        >>>     'sum': [1],
        >>>     'extreme': [True],
        >>>     'n_extreme': [True],
        >>>     'median': [1],
        >>>     'size': [1],
        >>>     'shape': [1],
        >>>     'quantile': ['auto'],
        >>> })
        >>> for params in param_grid:
        >>>     kwargs = params.copy()
        >>>     percent_nan = kwargs.pop('percent_nan', 0)
        >>>     if percent_nan:
        >>>         inputs = orig_inputs.copy()
        >>>         inputs[rng.rand(*inputs.shape) < percent_nan] = np.nan
        >>>     else:
        >>>         inputs = orig_inputs
        >>>     stats = kwarray.stats_dict(inputs, **kwargs)
        >>>     print('---')
        >>>     print('params = {}'.format(ub.urepr(params, nl=1)))
        >>>     print('stats = {}'.format(ub.urepr(stats, nl=1)))

    Ignore:
        import kwarray
        inputs = np.random.rand(3, 2, 1)
        stats = kwarray.stats_dict(inputs, axis=2, nan=True, quantile='auto')
    """
    stats = collections.OrderedDict([])
    # only use torch if its already in use
    torch = sys.modules.get('torch', None)

    # Ensure input is in numpy format
    if isinstance(inputs, np.ndarray):
        nparr = inputs
    elif isinstance(inputs, list):
        nparr = np.array(inputs)
    elif torch is not None and isinstance(inputs, torch.Tensor):
        nparr = inputs.data.cpu().numpy()
    else:
        nparr = np.array(list(inputs))
    # Check to make sure stats are feasible
    if len(nparr) == 0:
        stats['empty_list'] = True
        if size:
            stats['size'] = 0
    else:
        keepdims = (axis is not None)
        if nan:
            # invalid_mask = np.isnan(nparr)
            # valid_mask = ~invalid_mask
            # valid_values = nparr[~valid_mask]
            min_val = np.nanmin(nparr, axis=axis, keepdims=keepdims)
            max_val = np.nanmax(nparr, axis=axis, keepdims=keepdims)
            mean_ = np.nanmean(nparr, axis=axis, keepdims=keepdims)
            std_  = np.nanstd(nparr, axis=axis, keepdims=keepdims)
        else:
            min_val = nparr.min(axis=axis, keepdims=keepdims)
            max_val = nparr.max(axis=axis, keepdims=keepdims)
            mean_ = nparr.mean(axis=axis, keepdims=keepdims)
            std_  = nparr.std(axis=axis, keepdims=keepdims)

        # Note:
        # the first central moment is 0
        # the first raw moment is the mean
        # the second central moment is the variance
        # the third central moment is the skweness * var ** 3
        # the fourth central moment is the kurtosis * var ** 4
        # the third standardized moment is the skweness
        # the fourth standardized moment is the kurtosis

        if quantile:
            # if not ub.iterable(quantile):
            if quantile is True:
                quantile == 'auto'

            if quantile == 'auto':
                quantile = [0.25, 0.50, 0.75]

        if True:
            stats['mean'] = np.float32(mean_)
            stats['std'] = np.float32(std_)
        if extreme:
            stats['min'] = np.float32(min_val)
            stats['max'] = np.float32(max_val)
        if quantile:
            if quantile == 'auto':
                quantile = [0.25, 0.50, 0.75]
            quant_values = np.quantile(nparr, quantile, axis=axis)
            quant_keys = ['q_{:0.2f}'.format(q) for q in quantile]
            for k, v in zip(quant_keys, quant_values):
                stats[k] = v
        if n_extreme:
            # number of entries with min/max val
            nMin = np.sum(nparr == min_val, axis=axis, keepdims=keepdims)
            nMax = np.sum(nparr == max_val, axis=axis, keepdims=keepdims)
            nMin = nMin.astype(int)
            nMax = nMax.astype(int)
            if nMax.size == 1:
                nMax = nMax.ravel()[0]
            if nMin.size == 1:
                nMin = nMin.ravel()[0]
            stats['nMin'] = nMin
            stats['nMax'] = nMax
        if median:
            stats['med'] = np.nanmedian(nparr, axis=axis)
        if nan:
            stats['num_nan'] = np.isnan(nparr).sum()
        if sum:
            sumfunc = np.nansum if nan else np.sum
            stats['sum'] = sumfunc(nparr, axis=axis)
        if size:
            stats['size'] = nparr.size
        if shape:
            stats['shape'] = nparr.shape
    return stats

def _gmean(a, axis=0, dtype=None, clobber=False):
    """
    Compute the geometric mean along the specified axis.

    Modification of the scikit-learn method to be more memory efficient

    Example
        >>> rng = np.random.RandomState(0)
        >>> C, H, W = 8, 32, 32
        >>> axis = 0
        >>> a = [rng.rand(C, H, W).astype(np.float16),
        >>>      rng.rand(C, H, W).astype(np.float16)]

    """
    if isinstance(a, np.ndarray):
        if clobber:
            # NOTE: we reuse (a), we clobber the input array!
            log_a = np.log(a, out=a)
        else:
            log_a = np.log(a)
    else:
        if dtype is None:
            # if not an ndarray object attempt to convert it
            log_a = np.log(np.array(a, dtype=dtype))
        else:
            # Must change the default dtype allowing array type
            # Note: that this will use memory, but there isn't anything we can
            # do here.
            if isinstance(a, np.ma.MaskedArray):
                a_ = np.ma.asarray(a, dtype=dtype)
            else:
                a_ = np.asarray(a, dtype=dtype)
            # We can reuse `a_` because it was a temp var
            log_a = np.log(a_, out=a_)

    # attempt to reuse memory when computing mean
    mem = log_a[axis]
    mean_log_a = log_a.mean(axis=axis, out=mem)

    # And reuse memory again when computing the final result
    result = np.exp(mean_log_a, out=mean_log_a)
    return result

class NoSupportError(RuntimeError):
    ...

class RunningStats(ub.NiceRepr):
    """
    Track mean, std, min, and max values over time with constant memory.

    Dynamically records per-element array statistics and can summarized them
    per-element, across channels, or globally.

    TODO:
        - [ ] This may need a few API tweaks and good documentation

    Example:
        >>> import kwarray
        >>> run = kwarray.RunningStats()
        >>> ch1 = np.array([[0, 1], [3, 4]])
        >>> ch2 = np.zeros((2, 2))
        >>> img = np.dstack([ch1, ch2])
        >>> run.update(np.dstack([ch1, ch2]))
        >>> run.update(np.dstack([ch1 + 1, ch2]))
        >>> run.update(np.dstack([ch1 + 2, ch2]))
        >>> # No marginalization
        >>> print('current-ave = ' + ub.urepr(run.summarize(axis=ub.NoParam), nl=2, precision=3))
        >>> # Average over channels (keeps spatial dims separate)
        >>> print('chann-ave(k=1) = ' + ub.urepr(run.summarize(axis=0), nl=2, precision=3))
        >>> print('chann-ave(k=0) = ' + ub.urepr(run.summarize(axis=0, keepdims=0), nl=2, precision=3))
        >>> # Average over spatial dims (keeps channels separate)
        >>> print('spatial-ave(k=1) = ' + ub.urepr(run.summarize(axis=(1, 2)), nl=2, precision=3))
        >>> print('spatial-ave(k=0) = ' + ub.urepr(run.summarize(axis=(1, 2), keepdims=0), nl=2, precision=3))
        >>> # Average over all dims
        >>> print('alldim-ave(k=1) = ' + ub.urepr(run.summarize(axis=None), nl=2, precision=3))
        >>> print('alldim-ave(k=0) = ' + ub.urepr(run.summarize(axis=None, keepdims=0), nl=2, precision=3))
        """

    def __init__(run, nan_policy='omit', check_weights=True, **kwargs):
        """
        Args:
            nan_policy (str): indicates how we will handle nan values
               * if "omit" - set weights of nan items to zero.
               * if "propogate" - propogate nans.
               * if "raise" - then raise a ValueError if nans are given.

           check_weights (bool):
               if True, we check the weights for zeros (which can also
               implicitly occur when data has nans). Disabling this check will
               result in faster computation, but it is your responsibility to
               ensure all data passed to update is valid.
        """
        if len(kwargs):
            if 'nan_behavior' in kwargs:
                nan_behavior = kwargs.pop('nan_behavior', None)
                if nan_behavior == 'ignore':
                    nan_behavior = 'omit'
                nan_policy = nan_behavior
                ub.schedule_deprecation(
                    'kwarray', 'nan_policy', 'use nan_policy instead',
                    deprecate='0.6.10', error='0.7.0', remove='0.8.0')
            if len(kwargs):
                raise ValueError(f'Unsupported arguments: {list(kwargs.keys())}')

        run.raw_max = -np.inf
        run.raw_min = np.inf
        run.raw_total = 0
        run.raw_squares = 0
        run.n = 0
        run.nan_policy = nan_policy
        run.check_weights = check_weights
        if run.nan_policy not in {'omit', 'propogate'}:
            if run.nan_policy == 'omit':
                if run.check_weights:
                    raise ValueError(
                        'To prevent foot-shooting, check weights must be '
                        'initialized to True when nan_policy is omit'
                    )
            raise KeyError(run.nan_policy)

    def __nice__(self):
        return '{}'.format(self.shape)

    @property
    def shape(run):
        try:
            return run.raw_total.shape
        except Exception:
            return None

    def _update_from_other(run, other):
        """
        Combine this runner with another one.
        """
        run.raw_max = np.maximum(run.raw_max, other.raw_max)
        run.raw_min = np.minimum(run.raw_min, other.raw_min)
        run.raw_total = run.raw_total + other.raw_total
        run.raw_squares = run.raw_squares + other.raw_squares
        run.n = run.n + other.n

    def update_many(run, data, weights=1):
        """
        Assumes first data axis represents multiple observations

        Example:
            >>> import kwarray
            >>> rng = kwarray.ensure_rng(0)
            >>> run = kwarray.RunningStats()
            >>> data = rng.randn(1, 2, 3)
            >>> run.update_many(data)
            >>> print(run.current())
            >>> data = rng.randn(2, 2, 3)
            >>> run.update_many(data)
            >>> print(run.current())
            >>> data = rng.randn(3, 2, 3)
            >>> run.update_many(data)
            >>> print(run.current())
            >>> run.update_many(1000)
            >>> print(run.current())
            >>> assert np.all(run.current()['n'] == 7)

        Example:
            >>> import kwarray
            >>> rng = kwarray.ensure_rng(0)
            >>> run = kwarray.RunningStats()
            >>> data = rng.randn(1, 2, 3)
            >>> run.update_many(data.ravel())
            >>> print(run.current())
            >>> data = rng.randn(2, 2, 3)
            >>> run.update_many(data.ravel())
            >>> print(run.current())
            >>> data = rng.randn(3, 2, 3)
            >>> run.update_many(data.ravel())
            >>> print(run.current())
            >>> run.update_many(1000)
            >>> print(run.current())
            >>> assert np.all(run.current()['n'] == 37)
        """
        data = np.asarray(data)
        if run.nan_policy == 'omit':
            weights = weights * (~np.isnan(data)).astype(float)
        elif run.nan_policy == 'propogate':
            ...
        elif run.nan_policy == 'raise':
            if np.any(np.isnan(data)):
                raise ValueError('nan policy is raise')
        else:
            raise AssertionError('should not be here')
        has_ignore_items = False
        if ub.iterable(weights):
            ignore_flags = (weights == 0)
            has_ignore_items = np.any(ignore_flags)

        if has_ignore_items:
            data = data.copy()
            # Replace the bad value with somehting sensible for each operation.
            data[ignore_flags] = 0

            # Multiply data by weights
            w_data = data * weights

            run.raw_total += w_data.sum(axis=0)
            run.raw_squares += (w_data ** 2).sum(axis=0)
            data[ignore_flags] = -np.inf
            run.raw_max = np.maximum(run.raw_max, data.max(axis=0))
            data[ignore_flags] = +np.inf
            run.raw_min = np.minimum(run.raw_min, data.min(axis=0))
        else:
            w_data = data * weights
            run.raw_total += w_data.sum(axis=0)
            run.raw_squares += (w_data ** 2).sum(axis=0)
            run.raw_max = np.maximum(run.raw_max, data.max(axis=0))
            run.raw_min = np.minimum(run.raw_min, data.min(axis=0))
        run.n += weights.sum(axis=0)

    def update(run, data, weights=1):
        """
        Updates statistics across all data dimensions on a per-element basis

        Example:
            >>> import kwarray
            >>> data = np.full((7, 5), fill_value=1.3)
            >>> weights = np.ones((7, 5), dtype=np.float32)
            >>> run = kwarray.RunningStats()
            >>> run.update(data, weights=1)
            >>> run.update(data, weights=weights)
            >>> rng = np.random
            >>> weights[rng.rand(*weights.shape) > 0.5] = 0
            >>> run.update(data, weights=weights)

        Example:
            >>> import kwarray
            >>> run = kwarray.RunningStats()
            >>> data = np.array([[1, np.nan, np.nan], [0, np.nan, 1.]])
            >>> run.update(data)
            >>> print('current = {}'.format(ub.urepr(run.current(), nl=1)))
            >>> print('summary(axis=None) = {}'.format(ub.urepr(run.summarize(), nl=1)))
            >>> print('summary(axis=1) = {}'.format(ub.urepr(run.summarize(axis=1), nl=1)))
            >>> print('summary(axis=0) = {}'.format(ub.urepr(run.summarize(axis=0), nl=1)))
            >>> data = np.array([[2, 0, 1], [0, 1, np.nan]])
            >>> run.update(data)
            >>> data = np.array([[3, 1, 1], [0, 1, np.nan]])
            >>> run.update(data)
            >>> data = np.array([[4, 1, 1], [0, 1, 1.]])
            >>> run.update(data)
            >>> print('----')
            >>> print('current = {}'.format(ub.urepr(run.current(), nl=1)))
            >>> print('summary(axis=None) = {}'.format(ub.urepr(run.summarize(), nl=1)))
            >>> print('summary(axis=1) = {}'.format(ub.urepr(run.summarize(axis=1), nl=1)))
            >>> print('summary(axis=0) = {}'.format(ub.urepr(run.summarize(axis=0), nl=1)))
        """
        if run.nan_policy == 'omit':
            weights = weights * (~np.isnan(data)).astype(float)
        elif run.nan_policy == 'propogate':
            ...
        elif run.nan_policy == 'raise':
            if np.any(np.isnan(data)):
                raise ValueError('nan policy is raise')
        else:
            raise AssertionError('should not be here')

        has_ignore_items = False
        if ub.iterable(weights):
            ignore_flags = (weights == 0)
            has_ignore_items = np.any(ignore_flags)

        if has_ignore_items:
            data = data.copy()
            # Replace the bad value with somehting sensible for each operation.
            data[ignore_flags] = 0

            # Multiply data by weights
            w_data = data * weights

            run.raw_total += w_data
            run.raw_squares += w_data ** 2
            data[ignore_flags] = -np.inf
            run.raw_max = np.maximum(run.raw_max, data)
            data[ignore_flags] = +np.inf
            run.raw_min = np.minimum(run.raw_min, data)
        else:
            w_data = data * weights
            run.raw_total += w_data
            run.raw_squares += w_data ** 2
            run.raw_max = np.maximum(run.raw_max, data)
            run.raw_min = np.minimum(run.raw_min, data)
        run.n += weights

    def _sumsq_std(run, total, squares, n):
        """
        Sum of squares method to compute standard deviation
        """
        numer = (n * squares - total ** 2)
        # FIXME: this isn't exactly correct when we have fractional weights.
        # Integer weights should be ok. I suppose it really is
        # what "type" of weights they are (see numpy weighted quantile
        # discussion)
        denom = (n * (n - 1.0))
        std = np.sqrt(numer / denom)
        return std

    def summarize(run, axis=None, keepdims=True):
        """
        Compute summary statistics across a one or more dimension

        Args:
            axis (int | List[int] | None | NoParamType):
                axis or axes to summarize over,
                if None, all axes are summarized.
                if ub.NoParam, no axes are summarized the current result is
                returned.

            keepdims (bool, default=True):
                if False removes the dimensions that are summarized over

        Returns:
            Dict: containing minimum, maximum, mean, std, etc..

        Raises:
            NoSupportError : if update was never called with valid data

        Example:
            >>> # Test to make sure summarize works across different shapes
            >>> base = np.array([1, 1, 1, 1, 0, 0, 0, 1])
            >>> run0 = RunningStats()
            >>> for _ in range(3):
            >>>     run0.update(base.reshape(8, 1))
            >>> run1 = RunningStats()
            >>> for _ in range(3):
            >>>     run1.update(base.reshape(4, 2))
            >>> run2 = RunningStats()
            >>> for _ in range(3):
            >>>     run2.update(base.reshape(2, 2, 2))
            >>> #
            >>> # Summarizing over everything should be exactly the same
            >>> s0N = run0.summarize(axis=None, keepdims=0)
            >>> s1N = run1.summarize(axis=None, keepdims=0)
            >>> s2N = run2.summarize(axis=None, keepdims=0)
            >>> #assert ub.util_indexable.indexable_allclose(s0N, s1N, rel_tol=0.0, abs_tol=0.0)
            >>> #assert ub.util_indexable.indexable_allclose(s1N, s2N, rel_tol=0.0, abs_tol=0.0)
            >>> assert s0N['mean'] == 0.625
        """
        with np.errstate(divide='ignore'):
            with warnings.catch_warnings():
                warnings.filterwarnings('ignore', 'invalid value encountered', category=RuntimeWarning)
                if axis is ub.NoParam:
                    total = run.raw_total
                    squares = run.raw_squares
                    maxi = run.raw_max
                    mini = run.raw_min
                    n = run.n
                    info = ub.odict([
                        ('n', n),
                        ('max', maxi),
                        ('min', mini),
                        ('total', total),
                        ('squares', squares),
                        ('mean', total / n),
                        ('std', run._sumsq_std(total, squares, n)),
                    ])
                    return info
                else:
                    if np.all(run.n <= 0):
                        raise NoSupportError('No statistics have been accumulated')
                    total   = run.raw_total.sum(axis=axis, keepdims=keepdims)
                    squares = run.raw_squares.sum(axis=axis, keepdims=keepdims)
                    maxi    = run.raw_max.max(axis=axis, keepdims=keepdims)
                    mini    = run.raw_min.min(axis=axis, keepdims=keepdims)
                    if not hasattr(run.raw_total, 'shape'):
                        n = run.n
                    elif axis is None:
                        n = (run.n * np.ones_like(run.raw_total)).sum(axis=axis, keepdims=keepdims)
                    else:
                        n = (run.n * np.ones_like(run.raw_total)).sum(axis=axis, keepdims=keepdims)

                    info = ub.odict([
                        ('n', n),
                        ('max', maxi),
                        ('min', mini),
                        ('total', total),
                        ('squares', squares),
                        ('mean', total / n),
                        ('std', run._sumsq_std(total, squares, n)),
                    ])
                    return info

    def current(run):
        """
        Returns current staticis on a per-element basis
        (not summarized over any axis)
        """
        info = run.summarize(axis=ub.NoParam)
        return info

def _combine_mean_stds(means, stds, nums=None, axis=None, keepdims=False,
                       bessel=True):
    r"""
    Args:
        means (array): means[i] is the mean of the ith entry to combine

        stds (array): stds[i] is the std of the ith entry to combine

        nums (array | None):
            nums[i] is the number of samples in the ith entry to combine.
            if None, assumes sample sizes are infinite.

        axis (int | Tuple[int] | None):
            axis to combine the statistics over

        keepdims (bool):
            if True return arrays with the same number of dimensions they were
            given in.

        bessel (int):
            Set to 1 to enables bessel correction to unbias the combined std
            estimate.  Only disable if you have the true population means, or
            you think you know what you are doing.

    References:
        https://stats.stackexchange.com/questions/55999/is-it-possible-to-find-the-combined-standard-deviation

    Sympy:
        >>> # xdoctest: +REQUIRES(env:SHOW_SYMPY)
        >>> # What about the case where we don't know population size of the
        >>> # estimates. We could treat it as a fixed number, or perhaps take the
        >>> # limit as n -> infinity.
        >>> import sympy
        >>> import sympy as sym
        >>> from sympy import symbols, sqrt, limit, IndexedBase, summation
        >>> from sympy import Indexed, Idx, symbols
        >>> means = IndexedBase('m')
        >>> stds = IndexedBase('s')
        >>> nums = IndexedBase('n')
        >>> i = symbols('i', cls=Idx)
        >>> k = symbols('k', cls=Idx)
        >>> #
        >>> combo_mean = symbols('C')
        >>> #
        >>> bessel = 1
        >>> total = summation(nums[i], (i, 1, k))
        >>> combo_mean_expr = summation(nums[i] * means[i], (i, 1, k)) / total
        >>> p1 = summation((nums[i] - bessel) * stds[i], (i, 1, k))
        >>> p2 = summation(nums[i] * ((means[i] - combo_mean) ** 2), (i, 1, k))
        >>> #
        >>> combo_std_expr = sqrt((p1 + p2) / (total - bessel))
        >>> print('------------------------------------')
        >>> print('General Combined Mean / Std Formulas')
        >>> print('C = combined mean')
        >>> print('S = combined std')
        >>> print('------------------------------------')
        >>> print(ub.hzcat(['C = ', sym.pretty(combo_mean_expr, use_unicode=True, use_unicode_sqrt_char=True)]))
        >>> print(ub.hzcat(['S = ', sym.pretty(combo_std_expr, use_unicode=True, use_unicode_sqrt_char=True)]))
        >>> print('')
        >>> print('---------')
        >>> print('Now assuming all sample sizes are the same constant value N')
        >>> print('---------')
        >>> # Now assume all n[i] = N (i.e. a constant value)
        >>> N = symbols('N')
        >>> combo_mean_const_n_expr = combo_mean_expr.copy().xreplace({nums[i]: N})
        >>> combo_std_const_n_expr = combo_std_expr.copy().xreplace({nums[i]: N})
        >>> p1_const_n = p1.copy().xreplace({nums[i]: N})
        >>> p2_const_n = p2.copy().xreplace({nums[i]: N})
        >>> total_const_n = total.copy().xreplace({nums[i]: N})
        >>> #
        >>> print(ub.hzcat(['C = ', sym.pretty(combo_mean_const_n_expr, use_unicode=True, use_unicode_sqrt_char=True)]))
        >>> print(ub.hzcat(['S = ', sym.pretty(combo_std_const_n_expr, use_unicode=True, use_unicode_sqrt_char=True)]))
        >>> #
        >>> print('')
        >>> print('---------')
        >>> print('Take the limit as N -> infinity')
        >>> print('---------')
        >>> #
        >>> # Limit doesnt directly but we can break it into parts
        >>> lim_C = limit(combo_mean_const_n_expr, N, float('inf'))
        >>> lim_p1 = limit(p1_const_n / (total_const_n - bessel), N, float('inf'))
        >>> lim_p2 = limit(p2_const_n / (total_const_n - bessel), N, float('inf'))
        >>> lim_expr = sym.sqrt(lim_p1 + lim_p2)
        >>> print(ub.hzcat(['lim(C, N->inf) = ', sym.pretty(lim_C)]))
        >>> print(ub.hzcat(['lim(S, N->inf) = ', sym.pretty(lim_expr)]))

    Ignore:
        # lim0_p1 = limit(p1 / (total - 1), n, 0)
        # lim0_p2 = limit(p2 / (total - 1), n, 0)
        # lim0_expr = sym.sqrt(lim0_p1 + lim0_p2)
        # print(sym.pretty(lim0_expr))

        kcase = combo_std_expr.subs({k: 2})
        print(sym.pretty(kcase))
        print(sym.pretty(sympy.simplify(kcase)))
        limit(kcase, N, float('inf'))
        limit(combo_std_expr, N, float('inf'))

    Example:
        >>> from kwarray.util_averages import *  # NOQA
        >>> from kwarray.util_averages import _combine_mean_stds
        >>> means = np.array([1.2, 3.2, 4.1])
        >>> stds = np.array([4.2, 0.2, 2.1])
        >>> nums = np.array([10, 100, 10])
        >>> _combine_mean_stds(means, stds, nums)
        >>> means = np.array([1, 2, 3])
        >>> stds = np.array([1, 2, 3])
        >>> #
        >>> nums = np.array([1, 1, 1]) / 3
        >>> print(_combine_mean_stds(means, stds, nums, bessel=True), '- .3 B')
        >>> print(_combine_mean_stds(means, stds, nums, bessel=False), '- .3')
        >>> nums = np.array([1, 1, 1])
        >>> print(_combine_mean_stds(means, stds, nums, bessel=True), '- 1 B')
        >>> print(_combine_mean_stds(means, stds, nums, bessel=False), '- 1')
        >>> nums = np.array([10, 10, 10])
        >>> print(_combine_mean_stds(means, stds, nums, bessel=True), '- 10 B')
        >>> print(_combine_mean_stds(means, stds, nums, bessel=False), '- 10')
        >>> nums = np.array([1000, 1000, 1000])
        >>> print(_combine_mean_stds(means, stds, nums, bessel=True), '- 1000 B')
        >>> print(_combine_mean_stds(means, stds, nums, bessel=False), '- 1000')
        >>> #
        >>> nums = None
        >>> print(_combine_mean_stds(means, stds, nums, bessel=True), '- inf B')
        >>> print(_combine_mean_stds(means, stds, nums, bessel=False), '- inf')

    Example:
        >>> from kwarray.util_averages import *  # NOQA
        >>> from kwarray.util_averages import _combine_mean_stds
        >>> means = np.stack([np.array([1.2, 3.2, 4.1])] * 100, axis=0)
        >>> stds = np.stack([np.array([4.2, 0.2, 2.1])] * 100, axis=0)
        >>> nums = np.stack([np.array([10, 100, 10])] * 100, axis=0)
        >>> cm1, cs1, _ = _combine_mean_stds(means, stds, nums, axis=None)
        >>> print('combo_mean = {}'.format(ub.urepr(cm1, nl=1)))
        >>> print('combo_std  = {}'.format(ub.urepr(cs1, nl=1)))
        >>> means = np.stack([np.array([1.2, 3.2, 4.1])] * 1, axis=0)
        >>> stds = np.stack([np.array([4.2, 0.2, 2.1])] * 1, axis=0)
        >>> nums = np.stack([np.array([10, 100, 10])] * 1, axis=0)
        >>> cm2, cs2, _ = _combine_mean_stds(means, stds, nums, axis=None)
        >>> print('combo_mean = {}'.format(ub.urepr(cm2, nl=1)))
        >>> print('combo_std  = {}'.format(ub.urepr(cs2, nl=1)))
        >>> means = np.stack([np.array([1.2, 3.2, 4.1])] * 5, axis=0)
        >>> stds = np.stack([np.array([4.2, 0.2, 2.1])] * 5, axis=0)
        >>> nums = np.stack([np.array([10, 100, 10])] * 5, axis=0)
        >>> cm3, cs3, combo_num = _combine_mean_stds(means, stds, nums, axis=1)
        >>> print('combo_mean = {}'.format(ub.urepr(cm3, nl=1)))
        >>> print('combo_std  = {}'.format(ub.urepr(cs3, nl=1)))
        >>> assert np.allclose(cm1, cm2) and np.allclose(cm2,  cm3)
        >>> assert not np.allclose(cs1, cs2)
        >>> assert np.allclose(cs2, cs3)

    Example:
        >>> from kwarray.util_averages import *  # NOQA
        >>> from kwarray.util_averages import _combine_mean_stds
        >>> means = np.random.rand(2, 3, 5, 7)
        >>> stds = np.random.rand(2, 3, 5, 7)
        >>> nums = (np.random.rand(2, 3, 5, 7) * 10) + 1
        >>> cm, cs, cn = _combine_mean_stds(means, stds, nums, axis=1, keepdims=1)
        >>> assert cm.shape == cs.shape == cn.shape
        >>> print(f'cm.shape={cm.shape}')
        >>> cm, cs, cn = _combine_mean_stds(means, stds, nums, axis=(0, 2), keepdims=1)
        >>> assert cm.shape == cs.shape == cn.shape
        >>> print(f'cm.shape={cm.shape}')
        >>> cm, cs, cn = _combine_mean_stds(means, stds, nums, axis=(1, 3), keepdims=1)
        >>> assert cm.shape == cs.shape == cn.shape
        >>> print(f'cm.shape={cm.shape}')
        >>> cm, cs, cn = _combine_mean_stds(means, stds, nums, axis=None)
        >>> assert cm.shape == cs.shape == cn.shape
        >>> print(f'cm.shape={cm.shape}')
        cm.shape=(2, 1, 5, 7)
        cm.shape=(1, 3, 1, 7)
        cm.shape=(2, 1, 5, 1)
        cm.shape=()
    """
    if nums is None:
        # Assume the limit as nums -> infinite
        combo_num = None
        combo_mean = np.average(means, weights=None, axis=axis)
        combo_mean = _postprocess_keepdims(means, combo_mean, axis)
        numer_p1 = stds.sum(axis=axis, keepdims=1)
        numer_p2 = (((means - combo_mean) ** 2)).sum(axis=axis, keepdims=1)
        numer = numer_p1 + numer_p2
        denom = len(stds)
        combo_std = np.sqrt(numer / denom)
    else:
        combo_num = nums.sum(axis=axis, keepdims=1)
        weights = nums / combo_num
        combo_mean = np.average(means, weights=weights, axis=axis)
        combo_mean = _postprocess_keepdims(means, combo_mean, axis)
        numer_p1 = (np.maximum(nums - bessel, 0) * stds).sum(axis=axis, keepdims=1)
        numer_p2 = (nums * ((means - combo_mean) ** 2)).sum(axis=axis, keepdims=1)
        numer = numer_p1 + numer_p2
        denom = np.maximum(combo_num - bessel, 0)
        combo_std = np.sqrt(numer / denom)

    if not keepdims:
        indexer = _no_keepdim_indexer(combo_mean, axis)
        combo_mean = combo_mean[indexer]
        combo_std = combo_std[indexer]
        if combo_num is not None:
            combo_num = combo_num[indexer]

    return combo_mean, combo_std, combo_num

def _no_keepdim_indexer(result, axis):
    """
    Computes an indexer to postprocess a result with keepdims=True
    that will modify the result as if keepdims=False
    """
    if axis is None:
        indexer = [0] * len(result.shape)
    else:
        indexer = [slice(None)] * len(result.shape)
        if isinstance(axis, (list, tuple)):
            for a in axis:
                indexer[a] = 0
        else:
            indexer[axis] = 0
    indexer = tuple(indexer)
    return indexer

def _postprocess_keepdims(original, result, axis):
    """
    Can update the result of a function that does not support keepdims to look
    as if keepdims was supported.
    """
    # Newer versions of numpy have keepdims on more functions
    if axis is not None:
        expander = [slice(None)] * len(original.shape)
        if isinstance(axis, (list, tuple)):
            for a in axis:
                expander[a] = None
        else:
            expander[axis] = None
        result = result[tuple(expander)]
    else:
        expander = [None] * len(original.shape)
        result = np.array(result)[tuple(expander)]
    return result

if __name__ == '__main__':
    """
    CommandLine:
        python ~/code/kwarray/kwarray/util_averages.py
    """
    import xdoctest
    xdoctest.doctest_module(__file__)


class Solution(object):
    def groupAnagrams(self, strs):
        """
        :type strs: List[str]
        :rtype: List[List[str]]
        """
        map = {}
        for s in strs:
            sorted_s = ''.join(sorted(s))
            if sorted_s in map:
                map[sorted_s].append(s)
            else:
                map[sorted_s] = [s]

        result = []
        for k in map.keys():
            result.append(map[k])

        return result


import __main__
import cv2
import numpy
import pyscreenshot as ImageGrab
# im = ImageGrab.grab()
# im.save('sample.png','PNG')
ob = []
for i in range(0, 7):
    ob.append(cv2.imread('sample.png'))
red_temp = cv2.imread('red.png')
blue_temp = cv2.imread('blue.png')
green_temp = cv2.imread('green.png')
purple_temp = cv2.imread('purple.png')
yellow_temp = cv2.imread('yellow.png')
lists = []
max_value = [0,0]
min_value = [1000,1000]
def pattern_match(image, original_image):
    matches = cv2.matchTemplate(original_image, image, cv2.TM_CCORR_NORMED)
    threshold = 0.93
    flag = True
    _list = []
    for y in range(matches.shape[0]):
        for x in range(matches.shape[1]):
            flag = True
            if matches[y][x] >= threshold:
                for i,value in enumerate(_list):
                    if abs(_list[i][0]-x) <= 10 and abs(_list[i][1]-y) <= 10:
                        flag = False
                        break
                if flag:
                    _list.append([x,y])
                    if __main__.max_value[0] <= x and __main__.max_value[1] <= y:
                        __main__.max_value = [x,y]
                    elif __main__.min_value[0] >= x and __main__.min_value[1] >= y:
                        __main__.min_value = [x,y]
    for i,value in enumerate(_list):
        _x = _list[i][0]
        _y = _list[i][1]
        # cv2.rectangle(original_image, (_x,_y), (_x+50, _y+50), (255,0,0), 2)
    lists.append(_list)

pattern_match(red_temp, ob[0])
# cv2.imshow('red', ob[0])
pattern_match(blue_temp, ob[1])
# cv2.imshow('blue', ob[1])
pattern_match(green_temp, ob[2])
# cv2.imshow('green', ob[2])
pattern_match(yellow_temp, ob[3])
# cv2.imshow('yellow', ob[3])
pattern_match(purple_temp, ob[4])
# cv2.imshow('purple', ob[4])

diff_x = (max_value[0]-min_value[0]) / 5
diff_y = (max_value[1]-min_value[1]) / 4
board = [[6,6,6,6,6,6],[6,6,6,6,6,6],[6,6,6,6,6,6],[6,6,6,6,6,6],[6,6,6,6,6,6]]
for color,i in enumerate(lists):
    index_i = index_j = 0
    for j in i:
        x = j[0]
        y = j[1]
        index_i =(int)((x-min_value[0]+diff_x/2)/diff_x)
        index_j =(int)((y-min_value[1]+diff_y/2)/diff_y)
        board[index_j][index_i] = color + 1
#print(board)
result = ""
drop = ""
for i in board:
    for j in i:
        if j == 1:
            drop = "R"
        elif j == 2:
            drop = "B"
        elif j == 3:
            drop = "G"
        elif j == 4:
            drop = "Y"
        elif j == 5:
            drop = "P"
        else:
            drop = "H"
        result += drop + " "
    result += "\n"
print(result)


from flask import Flask
from flask_cors import CORS

def create_app(config_filename):
    app=Flask(__name__)
    CORS(app)
    # cors = CORS(app, resources={r"/foo": {"origins": "http://localhost:port"}})
    # CORS(app, origins="http://localhost:5000", allow_headers=[
    # "Content-Type", "Authorization", "Access-Control-Allow-Credentials"],
    # supports_credentials=True)

    app.config.from_object(config_filename)
    app.config['SECRET_KEY']='Elegance-1234'

    from app import api_bp
    app.register_blueprint(api_bp, url_prefix='/api')

    from Model import db
    db.init_app(app)

    return app

if __name__=="__main__":
    app=create_app("config")

    app.run('172.16.20.103',debug=True)


#!/usr/bin/env python3

from flask import (
				Blueprint,
				redirect,
				render_template,
				request,
				session
			)

home_control = Blueprint('home', __name__, url_prefix="")

@home_control.route('/', methods=["GET"])
def home():
	data = {'searched': False}
	if 'user' in session:
		data['logedin'] = True
		if 'seller' in session:
			data['sales'] = True
		else:
			data['sales'] = False
	else:
		data['logedin'] = False
		data['sales'] = False

	return render_template("search/search.html", data=data)


from xai.brain.wordbase.verbs._gig import _GIG

#calss header
class _GIGS(_GIG, ):
	def __init__(self,):
		_GIG.__init__(self)
		self.name = "GIGS"
		self.specie = 'verbs'
		self.basic = "gig"
		self.jsondata = {}


from heapq import nlargest
import argparse
import os
import sys

import nltk
nltk.download('stopwords')
from nltk.corpus import stopwords

def pdf_wfreq(url, wf=100):
    txt_file = 'text2analyse'
    cmd1 = 'wget ' + "\"" + url + "\""  + ' -O ' + (txt_file + '.pdf')
    cmd2 = 'pdftotext -enc UTF-8 ' + txt_file + '.pdf'  + ' ' + txt_file + '.txt'

    os.system(cmd1)
    os.system(cmd2)

    with open(txt_file+'.txt', "r") as f:
        word_dict = {}
        words = f.read().split()
        stop_ws = set(stopwords.words('english'))
        for i in words:
            i = i.lower()
            if i not in stop_ws:
                try:
                    i.encode('ascii')
                    if i in word_dict:
                        word_dict[i] += 1
                    else:
                        word_dict[i] = 1
                except UnicodeEncodeError:
                    continue

        most_freq = nlargest(wf, word_dict, key=word_dict.get)
        for i in most_freq:
            print(i + ':', word_dict[i])


import sys
from rooms import room_menu
from customers import customer_menu
from myprint import print_center, input_center
from database import get_database
if __name__ == '__main__':
    database, cursor = get_database()
    if database is None:
        print("The Database does not exist or not accessible.")
        sys.exit(1)
    while True:
        print()
        print_center("==============================")
        print_center("=======AbhiShek's Hotels======")
        print_center("==============================")
        print_center("1. Manage Rooms")
        print_center("2. Manage Customers")
        print_center("0. Exit")
        print()
        choice = int(input_center("Enter your choice: "))
        if choice == 1:
            room_menu(database, cursor)
        elif choice == 2:
            customer_menu(database, cursor)
        elif choice == 0:
            break
        else:
            print("Invalid choice (Press 0 to exit)")
    database.close();
    print_center("GoodBye")


import test
import kvs
import querier

@test.mock.patch('querier.Stemmer.stem', side_effect=lambda x: x)
class QueryTestCase(test.TestCase):
    def setUp(self):
        self.labels_kvs = kvs.Dict()
        self.labels = {  # keyword => wiki category
            'azhar': set([
                'http://dbpedia.org/resource/Azhar_Levi_Sianturi',
                'http://dbpedia.org/resource/Azhar_College',
                'http://dbpedia.org/resource/Azhar_al-Dulaimi',
                'http://dbpedia.org/resource/Azhar_Usman'
            ]),
            'azharuddin': set([
                'http://dbpedia.org/resource/Azhikodan_Raghavan'
            ])
        }
        self.images = {  # wiki category => URL
            'http://dbpedia.org/resource/Azhar_Levi_Sianturi': set([
                'http://en.wikipedia.org/wiki/Special:FilePath/'
                'Azhar_-_Live_in_Holland_2004.jpg'
            ]),
            'http://dbpedia.org/resource/Azhar_College': set([
                'http://commons.wikimedia.org/wiki/Special:FilePath/The_Crest_'
                'of_Azhar_College_Akurana_Kandy.png'
            ]),
            'http://dbpedia.org/resource/Azhar_al-Dulaimi': set([
                'http://commons.wikimedia.org/wiki/Special:FilePath/Azhar_'
                'Dulaymi_\\u2013_Killed_19_May.jpg'
            ]),
            'http://dbpedia.org/resource/Azhar_Usman': set([
                'http://en.wikipedia.org/wiki/Special:FilePath/AzharUsman.jpg'
            ]),
            'http://dbpedia.org/resource/Azhikodan_Raghavan': set([
                'http://commons.wikimedia.org/wiki/Special:'
                'FilePath/Com_azhikodan.jpg'
            ])
        }
        self.labels_kvs = kvs.Dict()
        for label, categories in self.labels.iteritems():
            for category in categories:
                self.labels_kvs.put(label, category)

        self.images_kvs = kvs.Dict()
        for category, urls in self.images.iteritems():
            for url in urls:
                self.images_kvs.put(category, url)

    def _get_urls(self, words):
        return set([
            u for w in words for c in self.labels[w] for u in self.images[c]
        ])

    def test_query_keyword(self, mock):
        words = ['azhar']
        urls = self._get_urls(words)
        matches = querier.query(words, self.images_kvs, self.labels_kvs)
        self.assertItemsEqual(urls, matches)
        self.assertIsInstance(matches, list)

    def test_query_keywords_two(self, mock):
        words = ['azhar', 'azharuddin']
        urls = self._get_urls(words)
        matches = querier.query(words, self.images_kvs, self.labels_kvs)
        self.assertItemsEqual(urls, matches)

    def test_query_no_keyword_match(self, mock):
        try:
            querier.query(['noop'], self.images_kvs, self.labels_kvs)
        except KeyError:
            self.fail('Unexpected KeyError.')

if __name__ == '__main__':
    test.main()


"""
leetcode 387. First Unique Character in a String

Given a string, find the first non-repeating character in it
and return its index. If it doesn't exist, return -1.

"""

class Solution(object):
    def firstUniqChar(self, s):
        """
        :type s: str
        :rtype: int
        """

        dic = {}
        for char in s:
            dic[char] = dic.get(char, 0) + 1

        for i, char in enumerate(s):
            if dic[char] and dic[char] == 1:
                return i
        return -1


from typing import List, cast
from vinyl.lex import *
from ._node import *

__all__ = [
    'Parser'
]

class Parser:
    @property
    def lexer(self) -> PeekLexer:
        return self._lexer

    def __init__(self, lexer: PeekLexer):
        self._lexer = lexer

    @classmethod
    def from_stream(cls, istream: StreamBase):
        return cls(PeekLexer.from_stream(istream))

    def parse(self) -> List[BaseNode]:
        nodes = []
        try:
            while True:
                token = self._lexer.peek()
                if not token:
                    break
                if self._is_keyword(token, KeywordTokenKind.LET):
                    nodes.append(self._consume_variable_declaration())
                elif self._is_keyword(token, KeywordTokenKind.DEF):
                    nodes.append(self._consume_function_definition())
                elif self._is_symbol(token, SymbolTokenKind.SEMI_COLON):
                    self._lexer.read()
                else:
                    raise SyntacticalError(token, 'Unexpected {}: "{}"'.format(token.short_name(), token.text))

        except SyntacticalError as e:
            raise e

        return nodes

    def _consume_function_definition(self) -> FunctionDefinitionNode:
        self._consume_keyword(KeywordTokenKind.DEF, 'Function definitions must begin with "{}"')
        name = self._consume_identifier('The {}: "{}" is not a valid function name')

        self._consume_symbol(SymbolTokenKind.PAREN_OPEN, 'Expected "{}" to begin function argument list')
        args = []
        if not self._is_symbol(self._lexer.peek(), SymbolTokenKind.PAREN_CLOSE):
            while True:
                identifier = self._consume_identifier('The {}: "{}" is not a valid argument name')
                type_name = self._consume_type_name('The {} "{}" is not a valid argument type')
                args.append(ArgumentNode(identifier, type_name))
                if not self._is_symbol(self._lexer.peek(), SymbolTokenKind.COMMA):
                    break
                else:
                    self._lexer.read()
        self._consume_symbol(SymbolTokenKind.PAREN_CLOSE, 'Expected "{}" to end function argument list')

        return_type = None
        if not self._is_symbol(self._lexer.peek(), SymbolTokenKind.BRACE_OPEN):
            return_type = self._consume_type_name('Unexpected {}: "{}" as function return type')

        block = self._consume_block('the function body of "{}"'.format(name.identifier.text))

        return FunctionDefinitionNode(name, args, return_type, block)

    def _consume_block(self, block_type: str) -> List[StatementNode]:
        self._consume_symbol(SymbolTokenKind.BRACE_OPEN, 'Expected "{{}}" to begin {}'.format(block_type))
        block = []
        while not self._is_symbol(self._lexer.peek(), SymbolTokenKind.BRACE_CLOSE):
            block.append(self._consume_statement())

        self._consume_symbol(SymbolTokenKind.BRACE_CLOSE, 'Expected "{{}}" to end {}'.format(block_type))
        return block

    def _consume_statement(self) -> StatementNode:
        statement = None
        token = self._lexer.peek()
        if self._is_keyword(token, KeywordTokenKind.LET):
            statement = self._consume_variable_declaration()
        elif self._is_keyword(token, KeywordTokenKind.IF):
            statement = self._consume_if_statement()

        else:
            self._consume_symbol(SymbolTokenKind.SEMI_COLON, 'Expected "{}" to end statement')
        return statement

    def _consume_if_statement(self) -> IfStatementNode:
        self._consume_keyword(KeywordTokenKind.IF, 'If statements must begin with "{}"')
        expression = self._consume_expression()
        when_true = self._consume_block('true-condition of if statement')
        when_false = []
        if self._is_keyword(self._lexer.peek(), KeywordTokenKind.ELSE):
            self._lexer.read()
            when_false = self._consume_block('false-condition of if statement')
        return IfStatementNode(expression, when_true, when_false)

    def _consume_variable_declaration(self) -> VariableDeclarationNode:
        self._consume_keyword(KeywordTokenKind.LET, 'Variable declarations must begin with "{}"')
        identifier = self._consume_identifier('The {}: "{}" is not a valid variable name')
        type_name = self._consume_type_name('The {} "{}" is not a valid variable type')
        value = None
        if self._is_symbol(self._lexer.peek(), SymbolTokenKind.EQUAL):
            self._lexer.read()
            value = self._consume_expression()
        return VariableDeclarationNode(identifier, type_name, value)

    def _consume_expression(self) -> ExpressionNode:
        self._lexer.read()
        pass

    def _consume_type_name(self, error_message: str) -> TypeNameNode:
        token = self._lexer.peek()
        if not self._is_identifier(token):
            raise SyntacticalError(token, error_message.format(token.short_name(), token.text))
        return TypeNameNode(cast(IdentifierToken, self._lexer.read()))

    def _consume_identifier(self, error_message: str) -> IdentifierNode:
        token = self._lexer.peek()
        if not self._is_identifier(token):
            raise SyntacticalError(token, error_message.format(token.short_name(), token.text))
        return IdentifierNode(cast(IdentifierToken, self._lexer.read()))

    def _consume_symbol(self, kind: SymbolTokenKind, error_message: str) -> SymbolToken:
        token = self._lexer.peek()
        if not self._is_symbol(token, kind):
            raise SyntacticalError(token, error_message.format(kind.value))
        return self._lexer.read()

    def _consume_keyword(self, kind: KeywordTokenKind, error_message: str) -> KeywordToken:
        token = self._lexer.peek()
        if not self._is_keyword(token, kind):
            raise SyntacticalError(token, error_message.format(kind.value))
        return self._lexer.read()

    @staticmethod
    def _is_identifier(token: BaseToken) -> bool:
        return isinstance(token, IdentifierToken)

    @staticmethod
    def _is_keyword(token: BaseToken, kind: KeywordTokenKind) -> bool:
        return isinstance(token, KeywordToken) and cast(KeywordToken, token).kind is kind

    @staticmethod
    def _is_symbol(token: BaseToken, kind: SymbolTokenKind) -> bool:
        return isinstance(token, SymbolToken) and cast(SymbolToken, token).kind is kind


# -*- coding: utf-8 -*-
"""
test_priority
~~~~~~~~~~~~~

Test the priority logic of Hyper-h2.
"""
import pytest

import h2.connection
import h2.errors
import h2.events
import h2.exceptions
import h2.stream

class TestPriority(object):
    """
    Basic priority tests.
    """
    example_request_headers = [
        (':authority', 'example.com'),
        (':path', '/'),
        (':scheme', 'https'),
        (':method', 'GET'),
    ]

    def test_receiving_priority_emits_priority_update(self, frame_factory):
        """
        Receiving a priority frame emits a PriorityUpdated event.
        """
        c = h2.connection.H2Connection(client_side=False)
        c.initiate_connection()
        c.receive_data(frame_factory.preamble())
        c.clear_outbound_data_buffer()

        f = frame_factory.build_priority_frame(
            stream_id=1,
            weight=255,
        )
        events = c.receive_data(f.serialize())

        assert len(events) == 1
        assert not c.data_to_send()

        event = events[0]
        assert isinstance(event, h2.events.PriorityUpdated)
        assert event.stream_id == 1
        assert event.depends_on == 0
        assert event.weight == 256
        assert event.exclusive is False

    def test_headers_with_priority_info(self, frame_factory):
        """
        Receiving a HEADERS frame with priority information on it emits a
        PriorityUpdated event.
        """
        c = h2.connection.H2Connection(client_side=False)
        c.initiate_connection()
        c.receive_data(frame_factory.preamble())
        c.clear_outbound_data_buffer()

        f = frame_factory.build_headers_frame(
            headers=self.example_request_headers,
            stream_id=3,
            flags=['PRIORITY'],
            stream_weight=15,
            depends_on=1,
            exclusive=True,
        )
        events = c.receive_data(f.serialize())

        assert len(events) == 2
        assert not c.data_to_send()

        event = events[1]
        assert isinstance(event, h2.events.PriorityUpdated)
        assert event.stream_id == 3
        assert event.depends_on == 1
        assert event.weight == 16
        assert event.exclusive is True

    def test_streams_may_not_depend_on_themselves(self, frame_factory):
        """
        A stream adjusted to depend on itself causes a Protocol Error.
        """
        c = h2.connection.H2Connection(client_side=False)
        c.initiate_connection()
        c.receive_data(frame_factory.preamble())
        c.clear_outbound_data_buffer()

        f = frame_factory.build_headers_frame(
            headers=self.example_request_headers,
            stream_id=3,
            flags=['PRIORITY'],
            stream_weight=15,
            depends_on=1,
            exclusive=True,
        )
        c.receive_data(f.serialize())
        c.clear_outbound_data_buffer()

        f = frame_factory.build_priority_frame(
            stream_id=3,
            depends_on=3,
            weight=15
        )
        with pytest.raises(h2.exceptions.ProtocolError):
            c.receive_data(f.serialize())

        expected_frame = frame_factory.build_goaway_frame(
            last_stream_id=3,
            error_code=h2.errors.PROTOCOL_ERROR,
        )
        assert c.data_to_send() == expected_frame.serialize()


"""
Creates a corpus from Wikipedia dump file.
Inspired by:
https://www.kdnuggets.com/2017/11/building-wikipedia-text-corpus-nlp.html
"""

import sys
from gensim.corpora import WikiCorpus

def tokenize(content, token_min_len = 1, token_max_len = 50, lower = False):
    #override original method in wikicorpus.py
    return [token.encode('utf8') for token in content.split()
           if len(token) <= 50 and not token.startswith('_')]

def make_corpus(in_f, out_f, num_articles):
    """Convert Wikipedia xml dump file to text corpus"""
    output = open(out_f, 'w+')
    wiki = WikiCorpus(in_f, tokenizer_func = tokenize)

    i = 0
    for text in wiki.get_texts():
        output.write((bytes(' ', 'utf-8').join(text)).decode('utf-8') + '\n')
        i += 1
        if (i % 100 == 0):
            print('Processed ' + str(i) + ' articles')
        if (i >= num_articles):
            break
    output.close()
    print('Processing complete!')

if __name__ == '__main__':
    if len(sys.argv) != 4:
        print('Usage: python dump.py <wikipedia_dump_file> <processed_text_file> <num_articles>')
        sys.exit(1)
    in_f = sys.argv[1]
    out_f = sys.argv[2]
    num_articles = int(sys.argv[3])
    make_corpus(in_f, out_f, num_articles)


import os
from test.utils import AsyncTestCase
from typing import List

from werk24._version import __version__
from werk24.exceptions import UnsupportedMediaType
from werk24.models.ask import W24Ask, W24AskPageThumbnail, W24AskVariantCAD
from werk24.models.techread import (W24TechreadExceptionType,
                                    W24TechreadMessageType, W24TechreadRequest)
from werk24.techread_client import W24TechreadClient

from .utils import get_drawing, get_model

class TestTechreadClient(AsyncTestCase):
    """ Test case for the basic Techread functionality
    """

    def test_client_version(self) -> None:
        """ Test whether Client sends version

        User Story: As Werk24 API developer I want to
        know which client versionns are still being used,
        so that I can decide whether it is safe to deprecate
        an old feature

        Github Issue #1
        """
        request = W24TechreadRequest(asks=[])
        self.assertEqual(__version__, request.client_version)

    async def test_client_without_session(self) -> None:
        """ Test whether Client without started session throws RuntimeError

        User Story: As API user I want to obtail a clear error message if
        I make a request to the client without entering a session, so that
        I can change my code swiftly.
        """
        environs = os.environ
        client = W24TechreadClient(
            environs['W24TECHREAD_SERVER_HTTPS'],
            environs['W24TECHREAD_SERVER_WSS'],
            environs['W24TECHREAD_VERSION'])

        with self.assertRaises(RuntimeError):
            async with client:
                pass

    async def test_client_usernames(self):
        """ Test access username

        User Story: As API user I want to access my own username,
        so that I can verify that the login process worked correctly.
        """
        client = W24TechreadClient.make_from_env(None)
        async with client as session:
            self.assertEqual(type(session.username), str)

    async def test_upload_model(self) -> None:
        """ Test whether we can upload an associaed model.

        User Story: As API user, want to be able to upload an associated
        model file, so that I can support Werk24's training effort
        """
        asks: List[W24Ask] = [W24AskVariantCAD(is_training=True)]
        drawing = get_drawing()
        model = get_model()

        client = W24TechreadClient.make_from_env(None)
        async with client as session:
            async for _ in session.read_drawing(drawing, asks, model):
                pass

    async def test_string_as_drawing_bytes(self) -> None:
        """ Test whether submitting a string as drawing_bytes
        raises the correct exception.

        See Github Issue #13
        """
        client = W24TechreadClient.make_from_env()

        with self.assertRaises(UnsupportedMediaType):
            async with client as session:
                await session.read_drawing("", asks=[]).__anext__()

    async def test_string_as_model_bytes(self) -> None:
        """ Test whether submitting a string as model_bytes
        raises the correct exception.

        See Github Issue #13
        """
        client = W24TechreadClient.make_from_env()

        with self.assertRaises(UnsupportedMediaType):
            async with client as session:
                await session.read_drawing(b"", asks=[], model="").__anext__()

    async def test_uploading_huge_file(self) -> None:
        """ Huge file produces DRAWING_FILE_SIZE_TOO_LARGE?
        """
        client = W24TechreadClient.make_from_env()
        asks: List[W24Ask] = [W24AskVariantCAD(is_training=True)]

        # create a new file that is larger than the limit of 5 MB
        file_size = 10*1024*1024 + 10
        file = b"0"*file_size

        # perform the call
        async with client as session:
            async for msg in session.read_drawing(file, asks=asks):
                self.assertEqual(
                    msg.exceptions[0].exception_type,
                    W24TechreadExceptionType.DRAWING_FILE_SIZE_TOO_LARGE)
                return

    async def test_unsupported_file_format(self) -> None:
        """ Unsupported file format triggers DRAWING_FILE_FORMAT_UNSUPPORTED?
        """

        client = W24TechreadClient.make_from_env()
        asks: List[W24Ask] = [W24AskPageThumbnail()]

        async with client as session:
            async for message in session.read_drawing(b"", asks=asks):
                if message.message_type == W24TechreadMessageType.ASK:

                    self.assertEqual(
                        message.exceptions[0].exception_type,
                        W24TechreadExceptionType.DRAWING_FILE_FORMAT_UNSUPPORTED)


#! /usr/bin/python

n=int(input("생성할 피보나치 수는? : "))

fibo=[1,1]

for i in range(0, n-2, 1) :
	fibo.append(fibo[i]+fibo[i+1])
print(fibo)
print("F%d=%d"%(n,fibo[n-1]))


############################################################
# -*- coding: utf-8 -*-
#
# Python-based Tool for interaction with the 10micron mounts
# GUI with PyQT5 for python
# Python  v3.5
#
# Michael Würtenberger
# (c) 2016, 2017
#
# Licence APL2.0
#
############################################################

# import basic stuff
import logging
import threading
import socket
import time

from tkinter import *
# matplotlib
import matplotlib
#matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import matplotlib.image as img
import numpy as np

class Handcontroller:
    logger = logging.getLogger(__name__)                                                                                # enable logging
    PORT = 3491
    MOUNTIP = '192.168.2.15'

    def __init__(self, app):
        self.app = app
        self.connected = False
        self.socket = None
        self.value_azimuth = 0
        self.value_altitude = 0
        self.sendCommandLock = threading.Lock()

    def mountIP(self):
        # value = self.app.ui.le_mountIP.text().split('.')
        value = '192.168.2.15'.split('.')
        if len(value) != 4:
            self.logger.error('formatIP       -> wrong input value:{0}'.format(value))
            self.app.messageQueue.put('Wrong IP configuration for mount, please check!')
            return
        v = []
        for i in range(0, 4):
            v.append(int(value[i]))
        ip = '{0:d}.{1:d}.{2:d}.{3:d}'.format(v[0], v[1], v[2], v[3])
        return ip

    def connect(self):                                                                                # runnable of the thread
        try:
            if self.socket is None:
                self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.socket.settimeout(60)
            self.socket.connect((self.MOUNTIP, self.PORT))
            self.connected = True                                                                                # setting connection status from driver
        except Exception as e:                                                                                # error handling
            self.logger.error('connect TCP    -> Socket connect error: {0}'.format(e))                                      # to logger
            self.socket = None
            self.connected = False                                                                                # connection broken
        finally:                                                                                # we don't stop, but try it again
            pass

    def disconnect(self):
        try:
            self.connected = False
            if self.socket:
                self.socket.shutdown(1)
                self.socket.close()
                self.socket = None
        except Exception as e:                                                                                # error handling
            self.logger.error('disconnect TCP -> Socket disconnect error: {0}'.format(e))                                   # to logger
            self.connected = False                                                                                # connection broken
        finally:                                                                                # we don't stop, but try it again
            pass

    def commandBlind(self, command):
        totalSent = 0
        command = (':' + command + '#').encode()
        try:
            while totalSent < len(command):
                sent = self.socket.send(command[totalSent:])
                if sent == 0:
                    raise RuntimeError("Socket connection broken")
                totalSent = totalSent + sent
        except Exception as e:                                                                                # error handling
            self.logger.error('commandBlind   -> Socket send error: {0}'.format(e))                                         # to logger
            self.disconnect()                                                                                # connection broken
        finally:                                                                                # we don't stop, but try it again
            pass

    def commandString(self, command):
        self.commandBlind(command)
        try:
            chunks = []
            while True:
                chunk = self.socket.recv(1024)
                if chunk == b'':
                    raise RuntimeError("Socket connection broken")
                chunks.append(chunk)
                print(chunk)
                if chunk[len(chunk)-1] == 3:
                    break
        except Exception as e:                                                                                # error handling
            self.logger.error('commandBlind   -> Socket receive error: {0}'.format(e))                                      # to logger
            self.disconnect()                                                                                # connection broken
        finally:                                                                                # we don't stop, but try it again
            # noinspection PyUnboundLocalVariable
            return chunks

if __name__ == "__main__":

    test = b'\x02\x00\x80\xc0\xa0\x91\x82\x85\xd8\xf4\x90\x8a\xe6\xc3\xc6\xfc\xe0\xb1\x93\xcc\x86\xf2\x91\x80\xc0\xf6\x03\x02\x00\x80\xc0\xa0\xa1\x82\xc1\xde\xec\xb0\xdc\xc4\x86\x8b\xb1\xd2\xe7\xb7\x88\x8c\xd7\x93\xc8\xdc\xf0\x03\x02\x00\x80\xc0\xa0\xb1\x81\xc0\xe0\xb0\xef\xcc\x86\x92\xb9\xc8\xf0\xa2\x90\x88\x84\x82\x81\x80\xc0\x89\x03\x02\x00\x80\xc0\xa0\xc1\x82\xc1\x82\xa0\x99\x8c\xe6\x9d\xf9\xd0\xe0\xa7\x90\x88\x84\x82\x81\x80\xc0\x9d\x03\x02\x00\x80\xc0\xa0\xd1\x82\xd1\xde\xa0\xb1\xd9\xad\xe7\xa3\xc9\xca\xa0\xb8\x9b\xed\xc2\x83\x85\xf0\xc6\x03\x02\x00\x83\x80\x0b\x03\x02\x00\x8b\x9b\x80\x92\x03\x02\x00\x83\xc0\x9f\xf0.\x03\x02\x00\x83\xff\xe7\xf0i\x03'
    #a = Handcontroller(None)
    #a.connect()
    matplotlib.interactive(True)
    while True:
        #test = np.array(a.commandString('GS'))
        # b = np.reshape(test, (256, 128))
        b = np.zeros((256, 128))

        plt.imshow(b)
        break
    # time.sleep(3)
    # a.disconnect()


import matplotlib.pyplot as plt

def mean(l):
    l = list(l)
    return sum(l) / len(l)

names = [
    '1-Coev-RS',
    '1-Coev',
    '1-Evol-RS',
    '2-Coev',
    '2-Coev-RS'
]

files = [
    'cel-rs.csv',
    'cel.csv',
    'rsel.csv',
    '2cel.csv',
    '2cel-rs.csv'
]

colors = [
    '#00ff00',
    '#000000',
    '#0000ff',
    '#ff8da1',
    '#ff0000'
]

plt.figure(figsize=(6.7, 6.7))
plt.tick_params(top=True, right=True, bottom=True, left=True, direction='in')
plt.xlim((0, 200))
plt.ylim((0.6, 1))

for i in range(len(files)):
    nameOfAlgorithm = names[i]
    nameOfDataset = files[i]
    color = colors[i]

    x = []
    y = []
    file = open(nameOfDataset).read().strip().split('\n')
    for line in file[1:]:
        data = line.split(',')
        x.append(float(data[0]))
        y.append(mean(map(float, data[2:])))

    plt.plot(x, y, label=nameOfAlgorithm, linewidth=0.9, color=color)

plt.xlabel('Rozegranych gier')
plt.ylabel('Odsetek wygranych gier')
plt.legend(fontsize='xx-large', loc='lower right', fancybox=False)
plt.show()


#Se citesc pe rând temperaturile medii ale fiecărei luni a unui an, ca numere întregi. Să se afişeze cu două zecimale media anuală a temperaturilor pozitive şi a celor negative.
s_p=0
s_n=0
nr_p=0
nr_n=0
l=1
while l<=12:
    t=eval(input('Introduceti temperatura lunii:'))
    if t>=0:
        s_p+=t
        nr_p+=1
    if t<0:
        s_n+=t
        nr_n+=1
    l+=1
print(f'Media anuala a temperaturilor pozitive este {round(s_p/nr_p, 2)}, iar media anuala a temperaturilor negative este {round(s_n/nr_n, 21)}')


# -*- coding: utf-8 -*-
"""
Created on Tue Oct 12 10:37:20 2021

@author: swd7788
"""

import pandas as pd
from pymongo import MongoClient
import requests

from TATA_assignment.database_operations import database_operations

csv_path=r"C:\Users\swd7788\Downloads\CGB_-_Consumer_Complaints_Data__2017_ (1).csv"

csv_path="https://opendata.fcc.gov/api/views/cw62-ya68/rows.csv?accessType=DOWNLOAD&sorting=true"

data2 = pd.read_csv(csv_path)

data=requests.get(url=csv_path)

test=list(data)

csv_Data=pd.read_csv(csv_path)

non_nan_csv_Data=csv_Data.fillna("")

dictionary_data=non_nan_csv_Data.to_dict('records')
insert_data=dictionary_data[0]

insert_data2=dictionary_data[:5]

url='mongodb://localhost:27017/'

database_name="telecom_customers"
collection_name="feedback"

obj=database_operations(url)
obj.create_connection()
obj.connect_database(database_name,collection_name)

# to insert one document
obj.insert_data(insert_data)

#bulk insert
obj.insert_many(insert_data2)

database_data=obj.find_data()


import pandas as pd
import numpy as np
import sys

def preprocessingclaims(servdat,claimdat, servre, preoprefta, admsdat, metri, b, tempsort_d, metricsneedingleftmerge, sizefla):#, reference_optional=None):
    """
    Before implementing this function, the servdat should be preprocessed to restrict it to the metric being examined.
    --- the operative metrics are exempt from this.

        Args:
            servdat = services pd.dataframe
            claimdat = ICD code claims pd.dataframe
            preoprefta = Reference of questionable preop testing pd.dataframe
            admsdat = admission history pd.dataframe
            metri = metric category
            b = Raw ICD code type imported from claims SQL data (depends on whether updating CW criteria or converting claims backward)

    """

    # This code addresses differences between metric structures/definitions
    #################################
    if (metri == 'narc' and admsdat is not None):
        servdat.rename(columns={'EVT_DATE':'TEST_DATE','CODE':'TEST_CODE'},inplace=True)
        servdat.drop(['RX_DOSE' ,'RX_UNIT' ,'DISP_AMT' ,'DISP_UNIT', 'Drug Names','FREQUENCY' ], axis=1, inplace=True)
        servdat=insert_admsdata(servdat,admsdat,metri)

        ###############################
        servdat['adms_flag']=False
        servdat.loc[servdat['dys_difftime_noadms_criteria']<tempsort_d,'adms_flag']=True
        servdat['dys_difftime_lastdischarge']=servdat.TEST_DATE.sub(servdat.DIS_DT)/np.timedelta64(1,'D')
        servdat.loc[servdat['dys_difftime_lastdischarge']<tempsort_d,'adms_flag']=True
        print(servdat.columns.values)

        print('size before admission data dropped')
        servdat.drop(['ADM_MRN' ,'ADM_DT', 'DIS_DT','dys_difftime_noadms_criteria'], axis=1, inplace=True)
        print(servdat.columns.values)
        print(sys.getsizeof(servdat))

        #to limit memory use
        del admsdat
    elif (metri in ['nonpreop','catpreop'] and admsdat is not None):
        # for card testing in pts w/ surgeries: merge in the surgeries, cull, and then, merge in prior admissions
        servdat_d=servdat[servdat.CODE.isin(servre.code[servre.key==metri])]
        preop_codes=preoprefta.proc_code[preoprefta.key==metri]

        #to limit memory use
        del preoprefta
        print('length of servdat_d unique CPT codes:')
        print(len(servdat_d.groupby('CODE').count()))
        servdat=servdat_d.merge(servdat[servdat.CODE.isin(preop_codes)][['MRN','ENC_ID','EVT_DATE','CODE']],on='MRN',how='inner')
        print('length of servdat_d unique CPT codes after restricted to those with surgeries')
        print(len(servdat.groupby('CODE_x').count()))
        #to limit memory use
        del servdat_d

        #prep
        servdat.rename(columns={'EVT_DATE_x':'TEST_DATE','CODE_x':'TEST_CODE','CODE_y':'SURG_CODE','ENC_ID_y':'SURG_ENC_ID','EVT_DATE_y':'SURG_DATE'},inplace=True)
        # this line is repetitive for some metrics (lbp, etc)
        servdat=servdat[servdat['TEST_CODE'].isin(servre.code[servre.key==metri])].sort_values('TEST_DATE',ascending=True)

        #to limit memory use
        del servre

        servdat=servdat[servdat.TEST_DATE<servdat.SURG_DATE]
        servdat=insert_admsdata(servdat,admsdat,metri)

        #to limit memory use
        del admsdat
        ##################################### NEW
        servdat['adms_flag']=False
        servdat.loc[servdat['dys_difftime_noadms_criteria']<tempsort_d,'adms_flag']=True
        servdat['dys_difftime_lastdischarge']=servdat.TEST_DATE.sub(servdat.DIS_DT)/np.timedelta64(1,'D')
        servdat.loc[servdat['dys_difftime_lastdischarge']<tempsort_d,'adms_flag']=True

    elif metri in ['lbp','bph','card','cerv','dexa','vitd','feed','psyc']:
        print('renaming servdat columns')
        servdat.rename(columns={'EVT_DATE':'TEST_DATE','CODE':'TEST_CODE'},inplace=True)
    else:
        raise KeyError("Error in preprocessingclaims(), which depends on metric and admsdata being correctly paired.")

#-------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------
#-- SECOND PHASE OF THIS ALGORITHM    -     START MERGING CLAIMS  --------------------
#-------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------

    #MERGE TO ICD CLAIMS
    print('servdat columns before claims {} merged:'.format(b))
    print(servdat.columns.values)
    print('sizefla is {}.'.format(sizefla))
    if sizefla==1:
        origservdat=servdat

        print('----------------------------------------------')
        servdat=servdat.merge(claimdat,on='MRN',how='left')
        print('size 1')
        origservdat['EVT_DATE']= np.datetime64('2000-01-01')
        origservdat['ICD{}_subcode'.format(b)] = 'ZZZZ_PREPROCESSING_INSERT'
        origservdat['hcclev'] = 'ZZZZ_PREPROCESSING_INSERT'
        origservdat['ccslev'] = 'ZZZZ_PREPROCESSING_INSERT'

        print(origservdat.columns.values)
        print('======================')
        print(servdat.columns.values)
        claimdat=None
        servdat.EVT_DATE.fillna(np.datetime64('1900-01-01'), inplace=True)
        servdat = pd.concat([servdat, origservdat])
        print('sizef 2')
        print(servdat.head(1))
    elif metri in metricsneedingleftmerge:
        origservdat=servdat
        origservdat['EVT_DATE']= np.datetime64('2000-01-01')
        servdat=servdat.merge(claimdat,on='MRN',how='left')
        print('check 1')
        origservdat['ICD{}_subcode'.format(b)] = 'ZZZZ_PREPROCESSING_INSERT'
        origservdat['hcclev'] = 'ZZZZ_PREPROCESSING_INSERT'
        origservdat['ccslev'] = 'ZZZZ_PREPROCESSING_INSERT'
        claimdat=None
        servdat.EVT_DATE.fillna(np.datetime64('1900-01-01'), inplace=True)
        print('check 2')
        servdat = pd.concat([servdat, origservdat])
        print('check 3')
    else:
    # for those metrics that didn't require memory restriction
        servdat=servdat.merge(claimdat,on='MRN',how='inner')
        claimdat=None
    servdat=servdat.rename(columns={'EVT_DATE':'CLAIM_DATE'},inplace=False)
    print('servdat columns after claims merged:')
    print(servdat.columns.values)
    #TIME DIFF BTWN TEST AND CLAIMS
    print('calc dys diff time test')
    servdat['dys_difftime_test_code']=servdat.TEST_DATE.sub(servdat.CLAIM_DATE)/np.timedelta64(1,'D')
    print(sys.getsizeof(servdat))
    print('getting rid of test/service rows merged with claims that came after test/service.')
    servdat=servdat[servdat['dys_difftime_test_code']>=0]
    print(sys.getsizeof(servdat))
    print('sorting claim date')
    servdat=servdat.sort_values(['MRN','CLAIM_DATE'],ascending=True)
    print('drop any w/o ICD')
#    servdat=servdat[~pd.isnull(servdat['ICD{}_subcode'.format(b)])]
    servdat.dropna(subset=['ICD{}_subcode'.format(b)],inplace=True)
    print(sys.getsizeof(servdat))
    print('add test date_a')
    servdat['TEST_DATE_a']=servdat['TEST_DATE'].values.astype('datetime64[D]')
    print(sys.getsizeof(servdat))
    return(servdat)

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

def insert_admsdata(servda, admsda, metr):
#    servda=servda.merge(admsda[['ADM_MRN','ADM_ENC_ID','ADM_DT','DIS_DT']], left_on='MRN', right_on='ADM_MRN', how='left')
    servda=servda.merge(admsda[['ADM_MRN','ADM_DT','DIS_DT']], left_on='MRN', right_on='ADM_MRN', how='left')
    #funnel
    if metr in ['nonpreop','catpreop']:
        servda.rename(columns={'SURG_DATE':'IDX_DATE'},inplace=True)
        servda['IDX_DATE_a']=servda['IDX_DATE'].values.astype('datetime64[D]')
        servda['ADM_DT_a']=servda['ADM_DT'].values.astype('datetime64[D]')
        print('preop loop entered')
        servda.loc[servda['IDX_DATE_a']==servda['ADM_DT_a'],'ADM_DT']=None
        servda.loc[servda['IDX_DATE_a']==servda['ADM_DT_a'],'DIS_DT']=None
        servda.loc[servda['IDX_DATE_a']==servda['ADM_DT_a'],'ADM_DT_a']=None

    elif metr=='narc':
        servda.rename(columns={'TEST_DATE':'IDX_DATE'},inplace=True)
        servda['IDX_DATE_a']=servda['IDX_DATE'].values.astype('datetime64[D]')
        servda['ADM_DT_a']=servda['ADM_DT'].values.astype('datetime64[D]')
        print('narc loop entered')
    #Need this so the column can be used for .groupby() later
    servda.ADM_DT.fillna(np.datetime64('1900-01-01'), inplace=True)
    servda.ADM_DT_a.fillna(np.datetime64('1900-01-01'), inplace=True)
    servda.DIS_DT.fillna(np.datetime64('1900-01-02'), inplace=True)
    # keep only the rows where the merge matched surgery/prescription that occured after admissions, and select only most recent adms
    servda=servda[servda['IDX_DATE']>=servda['ADM_DT']]
    servda=servda[servda['IDX_DATE']>=servda['DIS_DT']]
    # defunct code: cols=['ADM_MRN','ADM_ENC_ID','ADM_DT', 'DIS_DT','MRN']+[x for x in servda if x not in ['ADM_MRN','ADM_ENC_ID','ADM_DT','DIS_DT','MRN']]
    servda['dys_difftime_noadms_criteria']=servda.IDX_DATE_a.sub(servda.ADM_DT_a)/np.timedelta64(1,'D')
    if metr in ['nonpreop','catpreop']:
        servda.rename(columns={'IDX_DATE':'SURG_DATE'},inplace=True)
    elif metr=='narc':
        servda.rename(columns={'IDX_DATE':'TEST_DATE'},inplace=True)
    else:
        raise ValueError("insert_admsdata function is being misapplied to an invalid metric.")

    # code to get only most recent ADM_DT for each index test code & date by patient
    servda_select = servda.groupby(['MRN', 'TEST_CODE', 'TEST_DATE'])['ADM_DT_a'].max()
    servda_select=servda_select.reset_index()
    servda_select['parsed']=1
    servda_select.rename(columns={'MRN':'MRN_s','TEST_CODE':'TEST_CODE_s','TEST_DATE':'TEST_DATE_s',
                                                                'ADM_DT_a':'ADM_DT_a_s'},inplace=True)
    servda=servda.merge(servda_select,
                         left_on= ['MRN', 'TEST_CODE', 'TEST_DATE','ADM_DT_a'],
                         right_on= ['MRN_s', 'TEST_CODE_s', 'TEST_DATE_s','ADM_DT_a_s'],
                         how= 'inner')
    # code to get only most recent DIS_DT for each index test code, test date and admission date by patient
    servda_select = servda.groupby(['MRN', 'TEST_CODE', 'TEST_DATE','ADM_DT_a'])['DIS_DT'].max()
    servda_select=servda_select.reset_index()
    servda_select['parsed']=1
    servda_select.rename(columns={'MRN':'MRN_s','TEST_CODE':'TEST_CODE_s','TEST_DATE':'TEST_DATE_s','ADM_DT_a':'ADM_DT_a_s','DIS_DT':'DIS_DT_s'},inplace=True)
    servda=servda.merge(servda_select,
                         left_on=['MRN', 'TEST_CODE', 'TEST_DATE','ADM_DT_a','DIS_DT'],
                         right_on= ['MRN_s', 'TEST_CODE_s', 'TEST_DATE_s','ADM_DT_a_s','DIS_DT_s'],
                         how= 'inner')

    servda=servda.drop(['MRN_s_x','TEST_CODE_s_x','TEST_DATE_s_x', 'ADM_DT_a_s_x' ,'parsed_x', 'MRN_s_y',
                        'TEST_CODE_s_y' ,'TEST_DATE_s_y' ,'ADM_DT_a_s_y' ,'DIS_DT_s', 'parsed_y'],axis=1)

    #to limit memory use
    del servda_select
    return (servda)


# Data Structures
# 1. Dictionaries
# 2. Lists / arrays [1.1.7.11]
# 3. Sets

# Dictionaries: Define a key to find a value quickly
# d = dict() works as well as d = {}
# You can create a populated dict() as well
d = {
    'bob': 0,
    'sarah': 0,
    'defeated by': {'paper', 'dynamite'},
    'defeats': {'scissors'}
}

print(d['bob'])
d['bob'] += 1
print(d['bob'])
print(d)
d['russell'] = 7
print(d)
print(f"You are defeated by {d['defeated by']}")
print(d.get('other', 42))

# Lists: Keep elements in order and access them
lst = [1, 7, 1, 11]
print(lst)
lst.append(2)
print(lst)
lst.remove(11)
print(lst)
lst.sort()
print(lst)

# Sets: Check for distinct elements
st = {1, 1, 11, 7}
st.add(1)
st.add(1)
st.add(1)
st.add(11)
print(st)

# Create a dictionary:
d = dict(bill=2, zoe=7, michael=4) # or d = {'bill': 2, 'zoe': 7, 'michael': 4}

# Access the value by key:
name = 'zoe'
print(f"Wins by {name} are {d[name]}")

# Safer access:
wins = d.get(name)
if wins:
    print(f"There are {wins} wins.")
else:
    print (f"{name} has never won a game.")


# We want to search and replace strings in texts.

# For simple texts, use str.replace() is OK.

text = 'oh yeah, oh no, oh my god, fuck yeah'
print (text.replace('oh', 'fuck'))

# For some more complex ones, use module re, method sub().

text1 = 'Today is 8/5/2016. PyCon starts 3/13/2013.'
import re
print (re.sub(r'(\d+)/(\d+)/(\d+)', r'\3-\1-\2', text1))