def multivariate_logrank_test(y, survival, duration_column='duration',
    observed_column='observed'):
    """Compute the multivariate log-rank test for differential survival
    among the groups defined by ``y`` in the survival data in ``survival``,
    under the null-hypothesis that all groups have the same survival function
    (i.e. test whether at least one group has different survival rates)

    Parameters
    ----------
    y:                  pd.Series, groups (clusters, subtypes). the index is
                        the sample names
    survival:           pd.DataFrame with the same index as y, with columns for
                        the duration (survival time for each patient) and whether
                        or not the death was observed. If the death was not
                        observed (sensored), the duration is the time of the last
                        followup.
    duration_column:        the name of the column in  ``survival`` with the duration
    observed_column:    the name of the column in ``survival`` with True/False values
                        for whether death was observed or not

    Returns
    -------
    test_statistic:     the test statistic (chi-square)
    p_value:            the associated p_value
    """
    try:
        import lifelines
    except ImportError:
        raise ImportError(
            'The module ``lifelines`` was not found. It is required for this functionality. You may install it using `pip install lifelines`.'
            )
    ixs = list(set(y.index) & set(survival.index))
    mlr = lifelines.statistics.multivariate_logrank_test(survival.loc[ixs][
        duration_column], y.loc[ixs], survival.loc[ixs][observed_column])
    return mlr.test_statistic, mlr.p_value


def func_namespace(func, deco_args):
    """Generates a unique namespace for a function"""
    kls = None
    if hasattr(func, 'im_func'):
        kls = func.im_class
        func = func.im_func
    deco_key = ' '.join(map(str, deco_args))
    if kls:
        return '%s.%s.%s' % (kls.__module__, kls.__name__, deco_key)
    else:
        return '%s.%s.%s' % (func.__module__, func.__name__, deco_key)


@classmethod
def solve(cls, puzzle):
    """Solve the flood puzzle."""
    return cls._solve(puzzle)


@classmethod
def from_dict(cls, d):
    """
        Create an object instance from a saved dictionary representation.

        Parameters
        ----------
        d : dict

        Returns
        -------
        BinaryLogitStep

        """
    obj = cls(tables=d['tables'], model_expression=d['model_expression'],
        filters=d['filters'], out_tables=d['out_tables'], out_column=d[
        'out_column'], out_filters=d['out_filters'], out_value_true=d[
        'out_value_true'], out_value_false=d['out_value_false'], name=d[
        'name'], tags=d['tags'])
    obj.summary_table = d['summary_table']
    obj.fitted_parameters = d['fitted_parameters']
    return obj


def p_isrc(t):
    """isrc : ISRC_ID ISRC
            | ISRC_ID NUMBER"""
    t[0] = 'isrc', u'{}'.format(t[2])


def interpretValue(value, *args, **kwargs):
    """Interprets a passed value. In this order:
     - If it's callable, call it with the parameters provided
     - If it's a tuple/list/dict and we have a single, non-kwarg parameter, look up that parameter within the tuple/list/dict
     - Else, just return it
     """
    if callable(value):
        return value(*args, **kwargs)
    if isinstance(value, tuple) or isinstance(value, list) or isinstance(value,
        dict):
        if len(args) == 1 and kwargs == {}:
            return value[args[0]]
    return value


def pos_split_list(chr_list):
    """
    Gets position info from chr_list.
    Args:
        chr_list (list): list of chr info with position
    Returns:
        pos_list (list): list with position info
    """
    pos_list = []
    for pos in chr_list:
        if '+' in pos[1]:
            for_pos = pos[1].split('+')
            pos_list.append(for_pos)
        if '-' in pos[1]:
            rev_pos = pos[1].split('-')
            pos_list.append(rev_pos)
    return pos_list


def group_by_end(hits):
    """
    Group hits by their end position.

    Records must grouped by contig and sorted by increasing position on
    contig.
    """
    return


def diffdict(new, old, inexistent_value=None):
    """diffdict(new, old) -> [(key, new_value, old_value),...]

Returns the differences between two dictionaries.
In case of addition or deletion, old or new values are None."""
    changes = []
    for key, val in old.iteritems():
        new_val = new.get(key, Ellipsis)
        if new_val is Ellipsis:
            changes.append((key, inexistent_value, val))
        elif new_val != val:
            changes.append((key, new_val, val))
    for key, val in new.iteritems():
        old_val = old.get(key, Ellipsis)
        if old_val is Ellipsis:
            changes.append((key, val, inexistent_value))
    return changes


def debug_channel(mdf, group, channel, dependency, file=None):
    """ use this to print debug information in case of errors

    Parameters
    ----------
    mdf : MDF
        source MDF object
    group : dict
        group
    channel : Channel
        channel object
    dependency : ChannelDependency
        channel dependency object

    """
    print('MDF', '=' * 76, file=file)
    print('name:', mdf.name, file=file)
    print('version:', mdf.version, file=file)
    print('read fragment size:', mdf._read_fragment_size, file=file)
    print('write fragment size:', mdf._write_fragment_size, file=file)
    print()
    parents, dtypes = mdf._prepare_record(group)
    print('GROUP', '=' * 74, file=file)
    print('sorted:', group['sorted'], file=file)
    print('data location:', group['data_location'], file=file)
    print('data blocks:', group.data_blocks, file=file)
    print('dependencies', group['channel_dependencies'], file=file)
    print('parents:', parents, file=file)
    print('dtypes:', dtypes, file=file)
    print(file=file)
    cg = group['channel_group']
    print('CHANNEL GROUP', '=' * 66, file=file)
    print(cg, cg.cycles_nr, cg.samples_byte_nr, cg.invalidation_bytes_nr,
        file=file)
    print(file=file)
    print('CHANNEL', '=' * 72, file=file)
    print(channel, file=file)
    print(file=file)
    print('CHANNEL ARRAY', '=' * 66, file=file)
    print(dependency, file=file)
    print(file=file)


def get_samp_con():
    """
     get sample naming  convention
    """
    samp_con, Z = '', ''
    while samp_con == '':
        samp_con = input(
            """
        Sample naming convention:
            [1] XXXXY: where XXXX is an arbitrary length site designation and Y
                is the single character sample designation.  e.g., TG001a is the
                first sample from site TG001.    [default]
            [2] XXXX-YY: YY sample from site XXXX (XXX, YY of arbitrary length)
            [3] XXXX.YY: YY sample from site XXXX (XXX, YY of arbitrary length)
            [4-Z] XXXX[YYY]:  YYY is sample designation with Z characters from site XXX
            [5] site name same as sample
            [6] site is entered under a separate column
            [7-Z] [XXXX]YYY:  XXXX is site designation with Z characters with sample name XXXXYYYY
            NB: all others you will have to customize your self
                 or e-mail ltauxe@ucsd.edu for help.
            select one:
"""
            )
        if samp_con == '' or samp_con == '1':
            samp_con, Z = '1', 1
        if '4' in samp_con:
            if '-' not in samp_con:
                print('option [4] must be in form 4-Z where Z is an integer')
                samp_con = ''
            else:
                Z = samp_con.split('-')[1]
                samp_con = '4'
        if '7' in samp_con:
            if '-' not in samp_con:
                print('option [7] must be in form 7-Z where Z is an integer')
                samp_con = ''
            else:
                Z = samp_con.split('-')[1]
                samp_con = '7'
        if samp_con.isdigit() == False or int(samp_con) > 7:
            print('Try again\n ')
            samp_con = ''
    return samp_con, Z


def split_command_line(command_line):
    """This splits a command line into a list of arguments. It splits arguments
    on spaces, but handles embedded quotes, doublequotes, and escaped
    characters. It's impossible to do this with a regular expression, so I
    wrote a little state machine to parse the command line. """
    arg_list = []
    arg = ''
    state_basic = 0
    state_esc = 1
    state_singlequote = 2
    state_doublequote = 3
    state_whitespace = 4
    state = state_basic
    for c in command_line:
        if state == state_basic or state == state_whitespace:
            if c == '\\':
                state = state_esc
            elif c == "'":
                state = state_singlequote
            elif c == '"':
                state = state_doublequote
            elif c.isspace():
                if state == state_whitespace:
                    None
                else:
                    arg_list.append(arg)
                    arg = ''
                    state = state_whitespace
            else:
                arg = arg + c
                state = state_basic
        elif state == state_esc:
            arg = arg + c
            state = state_basic
        elif state == state_singlequote:
            if c == "'":
                state = state_basic
            else:
                arg = arg + c
        elif state == state_doublequote:
            if c == '"':
                state = state_basic
            else:
                arg = arg + c
    if arg != '':
        arg_list.append(arg)
    return arg_list


def _elastic_pool_edition_table_format(editions):
    """
    Formats an elastic pool editions as summary results for display with "-o table".
    """
    from collections import OrderedDict
    from .custom import is_available
    for e in editions:
        for slo in e['supportedElasticPoolPerformanceLevels']:
            sku = slo['sku']
            yield OrderedDict([('sku', sku['name']), ('edition', e['name']),
                ('family', sku['family'] or ' '), ('capacity', sku[
                'capacity']), ('unit', slo['performanceLevel']['unit']), (
                'available', is_available(slo['status']))])


def jwt_response_payload_handler(token, user=None, request=None):
    """
    Returns the response data for both the login and refresh views.
    Override to return a custom response such as including the
    serialized representation of the User.
    """
    return {'token': token, 'user': {'id': user.pk, 'uuid': str(user.uuid)}}


def whitespace_tokenize(text):
    """Runs basic whitespace cleaning and splitting on a peice of text."""
    text = text.strip()
    if not text:
        return []
    tokens = text.split()
    return tokens


def get_portgroup_by_id(task, portgroup_id):
    """Lookup a portgroup by ID on a task object.

    :param task: a TaskManager instance
    :param portgroup_id: ID of the portgroup.
    :returns: A Portgroup object or None.
    """
    for portgroup in task.portgroups:
        if portgroup.id == portgroup_id:
            return portgroup


@staticmethod
def _map_multiple_inputs(inputs: dict, reduce_dim: bool) ->tuple:
    """Creates mapping between multiple input variables and a single output variable.

        Parameters
        ----------
        inputs
            Input variables.
        reduce_dim
            If true, input variables will be summed up, if false, they will be concatenated.
        kwargs
            Additional keyword arguments for the backend.

        Returns
        -------
        tuple
            Summed up or concatenated input variables and the mapping to the respective input variables

        """
    inputs_unique = []
    input_mapping = {}
    for key, var in inputs.items():
        node, in_op, in_var = key.split('/')
        i = 0
        inp = in_var
        while inp in inputs_unique:
            i += 1
            if inp[-2:] == f'_{i - 1}':
                inp[:-2] = f'_{i}'
            else:
                inp = f'{inp}_{i}'
        inputs_unique.append(inp)
        input_mapping[inp] = key
    if reduce_dim:
        inputs_unique = f"sum(({','.join(inputs_unique)}), 0)"
    else:
        idx = 0
        var = inputs[input_mapping[inputs_unique[idx]]]
        while not hasattr(var, 'shape'):
            idx += 1
            var = inputs[input_mapping[inputs_unique[idx]]]
        shape = var['shape']
        if len(shape) > 0:
            inputs_unique = (
                f"reshape(({','.join(inputs_unique)}), ({len(inputs_unique) * shape[0],}))"
                )
        else:
            inputs_unique = f"stack({','.join(inputs_unique)})"
    return inputs_unique, input_mapping


@classmethod
def __dtype_setup__(cls, **kwargs):
    """Extract the object data type from ``kwargs``."""
    return None


def set_timeout(timeout):
    """Set the IO timeout
    Usage:
        >>> set_timeout(1)

    :param timeout: Timeout. Seconds.
    :return: None
    """
    global _timeout
    _timeout = timeout


def match_deleted_handler(sender, instance, *args, **kwargs):
    """
    Function to be called prior to a Match being saved.

    This should remove the related LadderEntry objects for the match in
    question.
    """
    instance.ladder_entries.all().delete()


def functional_border_sizes(border_size):
    """Calculate border sizing used in process to gen user specified border size

    If border_size is negative then a stand-in border size is used to allow better keypoint tracking (i think... ?);
    negative border is then applied at end.

    :param border_size: user supplied border size
    :return: (border_size, neg_border_size) tuple of functional border sizes

    >>> functional_border_sizes(100)
    (100, 0)
    >>> functional_border_sizes(-10)
    (100, 110)
    """
    if border_size < 0:
        neg_border_size = 100 + abs(border_size)
        border_size = 100
    else:
        neg_border_size = 0
    return border_size, neg_border_size


def create_luna_client(Label=None, Certificate=None):
    """
    Creates an HSM client.
    See also: AWS API Documentation

    :example: response = client.create_luna_client(
        Label='string',
        Certificate='string'
    )

    :type Label: string
    :param Label: The label for the client.

    :type Certificate: string
    :param Certificate: [REQUIRED]
            The contents of a Base64-Encoded X.509 v3 certificate to be installed on the HSMs used by this client.

    :rtype: dict
    :return: {
        'ClientArn': 'string'
    }

    """
    pass


def __repr__(A):
    """For `print` and `pprint`"""
    return A.to_str()


def _print_payload(payload):
    """Prints payload dict() for debug purposes."""
    for keyword in payload:
        print(keyword, ':', payload[keyword])


def find_duplicates(l):
    """Find and returns a python set with input list duplicates.

    Parameters
    ----------
    l : list
        List to examine.

    Returns
    -------
    duplicates : set
        Python set with input list duplicates.

    Examples
    --------
    >>> from secml.utils.list_utils import find_duplicates
    >>> l = ['1', '1', 2, '3', 2]
    >>> print(find_duplicates(l))
    set(['1', 2])

    References
    ----------
    http://stackoverflow.com/questions/9835762/find-and-list-duplicates-in-python-list

    """
    seen = set()
    seen2times = set()
    seen_add = seen.add
    seen2times_add = seen2times.add
    for item in l:
        if item in seen:
            seen2times_add(item)
        else:
            seen_add(item)
    return seen2times


def fmt_kcut(cut):
    """Format a |KCut|."""
    return 'KCut {}\n{}'.format(cut.direction, cut.partition)


def _getFirstNonSpacePos(text):
    """Provides the index of the first non-space character in the given line"""
    for pos in range(len(text)):
        if text[pos] not in [' ', '\n', '\r']:
            return pos
    return -1


def searchLocIslandsByID(listOfLocIslands, id):
    """Search for a locus island with id equal to id. Return the index of the
first we find, and None if their isn't one.
    """
    for i, isl in enumerate(listOfLocIslands):
        if isl.id == id:
            return i, isl
    return None, None


def strip_path_string(path_string):
    """ Remove the "/" in the end of the string
    and the " " in the begin and the end of the string.
    replace the "." in the string to "/"
    """
    path_string = path_string.strip(' ')
    path_string = path_string.rstrip('/')
    return path_string


def psi_Na_Sr_Cl_MWRB78(T, P):
    """c-c'-a: sodium strontium chloride [MWRB78]."""
    psi = -0.0052
    valid = T == 298.15
    return psi, valid


def disable():
    """ Disable syndication for an object """


def block_diag_multiply(result, value, blocks, block_cumul_dim_0,
    block_cumul_dim_1):
    """result = result + block_diag(blocks)@value"""
    for i in range(len(blocks)):
        start_0 = block_cumul_dim_0[i]
        end_0 = block_cumul_dim_0[i + 1]
        start_1 = block_cumul_dim_1[i]
        end_1 = block_cumul_dim_1[i + 1]
        result[start_0:end_0] += blocks[i] @ value[start_1:end_1]


def fib(n):
    """Fibonacci example function

    Args:
      n (int): integer

    Returns:
      int: n-th Fibonacci number
    """
    assert n > 0
    a, b = 1, 1
    for i in range(n - 1):
        a, b = b, a + b
    return a


@classmethod
def get_testing_options(cls):
    """Get testing options for the filter class.

        Returns:
            list: Mutiple dictionaries of keywords and messages that will
                pass/fail for those keywords.

        """
    return [{'pass': [1, 0]}]


def plus_or_dot(pieces):
    """Return a + if we don't already have one, else return a ."""
    if '+' in pieces.get('closest-tag', ''):
        return '.'
    return '+'


def delete_bot(name=None):
    """
    Deletes all versions of the bot, including the $LATEST version. To delete a specific version of the bot, use the operation.
    If a bot has an alias, you can't delete it. Instead, the DeleteBot operation returns a ResourceInUseException exception that includes a reference to the alias that refers to the bot. To remove the reference to the bot, delete the alias. If you get the same exception again, delete the referring alias until the DeleteBot operation is successful.
    This operation requires permissions for the lex:DeleteBot action.
    See also: AWS API Documentation

    :example: response = client.delete_bot(
        name='string'
    )

    :type name: string
    :param name: [REQUIRED]
            The name of the bot. The name is case sensitive.

    """
    pass


def pointInPolygon(pXY, xy):
    """Needs a doc string"""
    Inside = False
    N = len(pXY)
    p1x, p1y = pXY[0]
    for i in range(N + 1):
        p2x, p2y = pXY[i % N]
        if max(p1y, p2y) >= xy[1] > min(p1y, p2y) and xy[0] <= max(p1x, p2x):
            if p1y != p2y:
                xinters = (xy[1] - p1y) * (p2x - p1x) / (p2y - p1y) + p1x
            if p1x == p2x or xy[0] <= xinters:
                Inside = not Inside
        p1x, p1y = p2x, p2y
    return Inside


def _plot_ulims(ax, x, y, xerr, color, capsize=5, height_fraction=0.25,
    elinewidth=2):
    """
    Plot upper limits as arrows with cap at value of upper limit.

    uplim behaviour has been fixed in matplotlib 1.4
    """
    ax.errorbar(x, y, xerr=xerr, ls='', color=color, elinewidth=elinewidth,
        capsize=0)
    from distutils.version import LooseVersion
    import matplotlib
    mpl_version = LooseVersion(matplotlib.__version__)
    if mpl_version >= LooseVersion('1.4.0'):
        ax.errorbar(x, y, yerr=height_fraction * y, ls='', uplims=True,
            color=color, elinewidth=elinewidth, capsize=capsize, zorder=10)
    else:
        ax.errorbar(x, (1 - height_fraction) * y, yerr=height_fraction * y,
            ls='', lolims=True, color=color, elinewidth=elinewidth, capsize
            =capsize, zorder=10)


def render_pep440_pre(pieces):
    """TAG[.post.devDISTANCE] -- No -dirty.

    Exceptions:
    1: no tags. 0.post.devDISTANCE
    """
    if pieces['closest-tag']:
        rendered = pieces['closest-tag']
        if pieces['distance']:
            rendered += '.post.dev%d' % pieces['distance']
    else:
        rendered = '0.post.dev%d' % pieces['distance']
    return rendered


def set_regions_batch_size(batch: int):
    """ Set the number of regions to be loaded for each batch at the end of the materialize operation.
    This setting is very low level and does not affect the result of the query, but changing this parameter
    could speed up the loading of the results in Python in certain contexts.

    :param batch: Number of regions.
    :return: None
    """
    global __regions_batch_size
    __regions_batch_size = batch


def compact():
    """strip "untrue" things from incoming things"""


def select_border(gesture_mode: int=0, xmin: int=0, xmax: int=0, ymin: int=
    0, ymax: int=0, extend: bool=True):
    """Activate/select the file(s) contained in the border

    :param gesture_mode: Gesture Mode
    :type gesture_mode: int
    :param xmin: X Min
    :type xmin: int
    :param xmax: X Max
    :type xmax: int
    :param ymin: Y Min
    :type ymin: int
    :param ymax: Y Max
    :type ymax: int
    :param extend: Extend, Extend selection instead of deselecting everything first
    :type extend: bool
    """
    pass


@staticmethod
def min_none(a, b):
    """A min() version that discards None values."""
    if a is None:
        return b
    if b is None:
        return a
    return min(a, b)


def _parse_group_line(line):
    """
    Parses a line from /etc/group and returns the information as a
    dictionary.
    """
    result = dict(zip(('groupname', 'password', 'gid', 'members'), line.
        strip().split(':')))
    result['gid'] = result['gid']
    del result['password']
    return result


def _voc_ap(rec, prec):
    """
     Calculate the AP given the recall and precision array
        1st) We compute a version of the measured precision/recall curve with
             precision monotonically decreasing
        2nd) We compute the AP as the area under this curve by numerical integration.

    --- Official matlab code VOC2012---
    mrec=[0 ; rec ; 1];
    mpre=[0 ; prec ; 0];
    for i=numel(mpre)-1:-1:1
            mpre(i)=max(mpre(i),mpre(i+1));
    end
    i=find(mrec(2:end)~=mrec(1:end-1))+1;
    ap=sum((mrec(i)-mrec(i-1)).*mpre(i));
    """
    rec.insert(0, 0.0)
    rec.append(1.0)
    mrec = rec[:]
    prec.insert(0, 0.0)
    prec.append(0.0)
    mpre = prec[:]
    """
     This part makes the precision monotonically decreasing
        (goes from the end to the beginning)
        matlab: for i=numel(mpre)-1:-1:1
                    mpre(i)=max(mpre(i),mpre(i+1));
    """
    for i in range(len(mpre) - 2, -1, -1):
        mpre[i] = max(mpre[i], mpre[i + 1])
    """
     This part creates a list of indexes where the recall changes
        matlab: i=find(mrec(2:end)~=mrec(1:end-1))+1;
    """
    i_list = []
    for i in range(1, len(mrec)):
        if mrec[i] != mrec[i - 1]:
            i_list.append(i)
    """
     The Average Precision (AP) is the area under the curve
        (numerical integration)
        matlab: ap=sum((mrec(i)-mrec(i-1)).*mpre(i));
    """
    ap = 0.0
    for i in i_list:
        ap += (mrec[i] - mrec[i - 1]) * mpre[i]
    return ap, mrec, mpre


def set_signature(library, function_name, argtypes, restype, errcheck):
    """Set the signature of single function in a library.

    :param library: ctypes wrapped library.
    :type library: ctypes.WinDLL or ctypes.CDLL
    :param function_name: name of the function as appears in the header file.
    :type function_name: str
    :param argtypes: a tuple of ctypes types to specify the argument types that the function accepts.
    :param restype: A ctypes type to specify the result type of the foreign function.
                    Use None for void, a function not returning anything.
    :param errcheck: a callabe

    :raises: AttributeError
    """
    func = getattr(library, function_name)
    func.argtypes = argtypes
    if restype is not None:
        func.restype = restype
    if errcheck is not None:
        func.errcheck = errcheck


def flatten(array):
    """Flattens the elements of the provided array, `data`.

        >>> a = [(0, 0), (1, 0), (2, 0), (3, 0)]
        >>> flatten(a)
        [0, 0, 1, 0, 2, 0, 3, 0]

    The flattening process is not recursive, it is only one level deep.
    """
    result = []
    for value in array:
        result.extend(value)
    return result


def render_git_describe(pieces):
    """TAG[-DISTANCE-gHEX][-dirty].

    Like 'git describe --tags --dirty --always'.

    Exceptions:
    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
    """
    if pieces['closest-tag']:
        rendered = pieces['closest-tag']
        if pieces['distance']:
            rendered += '-%d-g%s' % (pieces['distance'], pieces['short'])
    else:
        rendered = pieces['short']
    if pieces['dirty']:
        rendered += '-dirty'
    return rendered


def context_set_boolean(data_path: str='', value: bool=True):
    """Set a context value

    :param data_path: Context Attributes, RNA context string
    :type data_path: str
    :param value: Value, Assignment value
    :type value: bool
    """
    pass


def profile_mask(features, q=2.0, zap_channels=[]):
    """ Compute profile mask, flagging outliers.

    Parameters
    ----------
    features: pandas.DataFrame
        Output of the featurize() function.
    q: float, optional (default: 2.0)
        Parameter that controls the min and max values that define the 'inlier' or
        'normality' range. For every feature, the first and third quartiles (Q1 and Q3)
        are calculated, and R = Q3 - Q1 is the interquartile range. The min and max
        acceptable values are then defined as:

        vmin = Q1 - q x R
        vmax = Q3 + q x R

        The original recommendation of Tukey is q = 1.5.
    zap_channels: list or array of ints
        Frequency channel indices to forcibly flag as outliers. These are excluded
        from the analysis as well, and they will not be considered when calculating
        the inlier range for every feature.

    Returns
    -------
    stats: pandas.DataFrame
        DataFrame containing the results. Columns are individual features, and rows are
        individual statistics (quartiles, iqr, min and max values).
    mask: ndarray
        A two dimensional boolean numpy array, with shape (num_subints, num_channels).
        A value of True means that the associated profile is an outlier.
    """
    do_zap = zap_channels is not None and len(zap_channels) > 0
    if do_zap:
        X = features.drop(zap_channels, level=1)
    else:
        X = features
    stats = X.quantile([0.25, 0.5, 0.75])
    stats = stats.rename({(0.25): 'q1', (0.5): 'med', (0.75): 'q3'})
    stats.loc['iqr'] = stats.loc['q3'] - stats.loc['q1']
    stats.loc['vmin'] = stats.loc['q1'] - q * stats.loc['iqr']
    stats.loc['vmax'] = stats.loc['q3'] + q * stats.loc['iqr']
    mask = (features > stats.loc['vmax']) | (features < stats.loc['vmin'])
    mask = mask.sum(axis=1).values.astype(bool).reshape(features.index.levshape
        )
    if do_zap:
        mask[:, (zap_channels)] = True
    return stats, mask


@classmethod
def _split(cls, text, end='\n'):
    """Replace sentence boundaries with newlines and append a newline.

        :param text: string to line break at sentences
        :param end: appended to the end of the update text

        >>> Markdown._split("Hello, world!", end='')
        'Hello, world!'

        >>> Markdown._split("Hello, world! How are you? I'm fine. Good.")
        "Hello, world!\\nHow are you?\\nI'm fine.\\nGood.\\n"

        """
    stripped = text.strip()
    if stripped:
        return cls.REGEX_SENTENCE_BOUNDARIES.sub('\n', stripped) + end
    else:
        return ''


def writePhen(phen, filename, missing='9', sep='\t'):
    """
    must contain phen['iid'] and phen['vals']
    """
    N = phen['iid'].shape[0]
    M = phen['vals'].shape[1]
    assert N == phen['vals'].shape[0
        ], "number of individuals do not match up in phen['vals'] and phen['ids']"
    with open(filename, 'w') as f:
        for i in range(0, N):
            tmpstr = phen['iid'][i][0] + sep + phen['iid'][i][1]
            for m in range(0, M):
                tmpstr += sep + str(phen['vals'][i][m])
            tmpstr += '\n'
            f.write(tmpstr)


def mk_infix(prefix):
    """Create an infix based on the given prefix."""
    infix = ''
    if prefix is not None:
        infix = '%s_' % prefix
    return infix


@classmethod
def _update_times(cls, time):
    """ This method should be called internaly only.

            Updates all timers
        """
    for timer in cls.query_timers:
        cls.query_timers[timer] += time


def properties():
    """Toggle the properties region visibility

    """
    pass


def photaddline(tab, sourceid):
    """
    Loop through the dictionary list **tab** creating a line for the source specified in **sourceid**

    Parameters
    ----------
    tab:
      Dictionary list of all the photometry data
    sourceid:
      ID of source in the photometry table (source_id)

    Returns
    -------
    tmpdict: dict
        Dictionary with all the data for the specified source

    """
    colnames = tab[0].keys()
    tmpdict = dict()
    for i in range(len(tab)):
        if tab[i]['source_id'] != sourceid:
            continue
        for elem in colnames:
            if elem not in ['comments', 'epoch', 'instrument_id',
                'magnitude', 'magnitude_unc', 'publication_id', 'system',
                'telescope_id']:
                tmpdict[elem] = tab[i][elem]
            elif elem == 'band':
                continue
            else:
                tmpstr = tab[i]['band'] + '.' + elem
                tmpdict[tmpstr] = tab[i][elem]
    return tmpdict


def safe_get_key(config, key, fallback=None):
    """ Class to safely pull key from config or a fallback value """
    try:
        return config[key]
    except KeyError:
        pass
    return fallback


def get_shared_secret(priv, pub):
    """ Derive the share secret between ``priv`` and ``pub``

        :param `Base58` priv: Private Key
        :param `Base58` pub: Public Key
        :return: Shared secret
        :rtype: hex

        The shared secret is generated such that::

            Pub(Alice) * Priv(Bob) = Pub(Bob) * Priv(Alice)

    """
    pub_point = pub.point()
    priv_point = int(repr(priv), 16)
    res = pub_point * priv_point
    res_hex = '%032x' % res.x()
    res_hex = '0' * (64 - len(res_hex)) + res_hex
    return res_hex


def in_line(xmin_line, xmax_line, ymin_line, xmin_new, xmax_new, ymax_new):
    """Heuristic for determining whether a character is in a line.

    Note:
        Currently dependent on the order in which characters are
        added. For example, a character may vertically overlap with a
        line, but adding it to the line would be out of reading order.
        This should be fixed in a future version.

    Args:
        xmin_line (:obj:`list` of :obj:`int`): Minimum x-coordinate of
            characters in the line the new character is tested against.
        xmax_line (:obj:`list` of :obj:`int`): Maximum x-coordinate of
            characters in the line the new character is tested against.
        ymin_line (int): Minimum y-coordinate of line the new character
            is tested against.
        xmin_new (int): Minimum x-coordinate of new character.
        xmax_new (int): Maximum x-coordinate of new character.
        ymax_new (int): Maximum y-coordinate of new character.

    Returns:
        bool:
            The new character vertically overlaps with the
            "average" character in the line.
    """
    xmin_avg = sum(xmin_line) / len(xmin_line)
    xmax_avg = sum(xmax_line) / len(xmax_line)
    return (xmin_avg <= xmax_new and xmax_avg >= xmin_new and ymax_new >=
        ymin_line)


def delay(secondsLater):
    """
        Delay the scheduled call.

        @param secondsLater: how many seconds from its current firing time to delay

        @raises twisted.internet.error.AlreadyCalled: if the call has already
            happened.
        @raises twisted.internet.error.AlreadyCancelled: if the call has already
            been cancelled.
        """


def datasetLinkFile(ds):
    """Get a linked filename from a dataset."""
    return '/' if ds.linked is None else ds.linked.filename


def vertex_weight_set_active(weight_group: int=-1):
    """Set as active vertex group

    :param weight_group: Weight Index, Index of source weight in active vertex group
    :type weight_group: int
    """
    pass


def inverse_weighting_function(distance, bin_width=None):
    """
    The "inverse" weighting function used in Yaffe and Tanay 2011.

    Parameters
    ----------
    distance : float
        The distance to compute a weight for, in base pairs.
    bin_width : Optional[int]
        The bin width in base pairs. Used to make results equivalent to Yaffe
        and Tanay 2011 by scaling ``distance`` to units of bins. Pass None to
        simply leave the distance in units of base pairs

    Returns
    -------
    float
        A weight appropriate for this distance.
    """
    if bin_width is not None:
        return 1 / (distance / float(bin_width) + 1)
    return float(1) / (distance + 1)


def _is_descriptor(obj):
    """Returns True if obj is a descriptor, False otherwise."""
    return hasattr(obj, '__get__') or hasattr(obj, '__set__') or hasattr(obj,
        '__delete__')


def globify_date(filename):
    """Replace date formats with single character wildcards"""
    filename = filename.replace('%Y', '????')
    filename = filename.replace('%m', '??')
    filename = filename.replace('%d', '??')
    filename = filename.replace('%H', '??')
    filename = filename.replace('%M', '??')
    filename = filename.replace('%S', '??')
    return filename


def render_git_describe(pieces):
    """TAG[-DISTANCE-gHEX][-dirty].

    Like 'git describe --tags --dirty --always'.

    Exceptions:
    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
    """
    if pieces['closest-tag']:
        rendered = pieces['closest-tag']
        if pieces['distance']:
            rendered += '-%d-g%s' % (pieces['distance'], pieces['short'])
    else:
        rendered = pieces['short']
    if pieces['dirty']:
        rendered += '-dirty'
    return rendered


def _add_parens(required, text):
    """
    Add parens around a license expression if `required` is True, otherwise
    return `text` unmodified.
    """
    return '({})'.format(text) if required else text


def underline(text):
    """Given a string, return a series of dash with the same length.

    :param text: Text used as reference to create a line of len(text)
                    dashes.
    """
    return '-' * len(text)


def submit():
    """
    salar submit              : Submit your tool to pypi.python.org
    """
    text = 'Please edit your own ~/.pypirc and setup.py, and then run this command below:\n' + """  cd <name>; python setup.py bdist_wheel upload
"""
    print(text)


@staticmethod
def addable_cells(obj):
    """
        List object addable cells

        TESTS ::

            sage: from sage.combinat.parallelogram_polyomino import ParallelogramPolyomino
            sage: from sage_widget_adapters.combinat.parallelogram_polyomino_grid_view_adapter import ParallelogramPolyominoGridViewAdapter
            sage: pp = ParallelogramPolyomino([[0, 1, 0, 1], [1, 1, 0, 0]])
            sage: ParallelogramPolyominoGridViewAdapter.addable_cells(pp)
            [(1, 0), (2, 1), (1, 2)]
        """
    cells = []
    upper_heights = obj.upper_heights()
    for i, c in enumerate(upper_heights[1:]):
        if c != upper_heights[i]:
            cells.append((c - 1, i + 1))
    lower_heights = obj.lower_heights()
    for i, c in enumerate(lower_heights[1:]):
        if c != lower_heights[i]:
            cells.append((lower_heights[i], i))
    height, width = obj.geometry()
    cells += [(height, width - 1), (height - 1, width)]
    return cells


def all_handler(ctx, param, value):
    """Get tags from a template file or command line."""
    if ctx.obj and ctx.obj.get('like') and value is not None:
        ctx.obj['all_like'] = value
        value = ctx.obj.get('like')
    return value


def static(**kwargs):
    """
    Return a predefined ``dict`` when the given regex matches.
    """
    return lambda values: kwargs


def get_station_and_time(wxdata: [str]) ->([str], str, str):
    """
    Returns the report list and removed station ident and time strings
    """
    if not wxdata:
        return wxdata, None, None
    station = wxdata.pop(0)
    if not wxdata:
        return wxdata, station, None
    qtime = wxdata[0]
    if wxdata and qtime.endswith('Z') and qtime[:-1].isdigit():
        rtime = wxdata.pop(0)
    elif wxdata and len(qtime) == 6 and qtime.isdigit():
        rtime = wxdata.pop(0) + 'Z'
    else:
        rtime = None
    return wxdata, station, rtime


def deny_permission_to_principal(permission_id, principal_id):
    """Assert that the permission is denied to the principal.
        """


def getParents():
    """Returns a list starting with the object's parent followed by
        each of its parents.

        Raises a TypeError if the object is not connected to a containment
        root.

        """


@classmethod
def class_key(cls):
    """Nice order of classes."""
    return 2, 0, cls.__name__


@staticmethod
def create_osc_msg(dictionary):
    """ Converts a Python dictionary into an OSC style list """
    msg = []
    for key, value in dictionary.items():
        msg += [key, value]
    return msg


@classmethod
def create(cls, pskc, value):
    """Construct an encryped value from a plaintext value."""
    if not isinstance(value, type(b'')):
        value = value.encode()
    cipher_value = pskc.encryption.encrypt_value(value)
    mac_value = None
    if pskc.mac.algorithm:
        mac_value = pskc.mac.generate_mac(cipher_value)
    return cls(cipher_value, mac_value, pskc.encryption.algorithm)


def meta_transform(html, options, state):
    """
	@param html: a DOM node for the top level html element
	@param options: invocation options
	@type options: L{Options<pyRdfa.options>}
	@param state: top level execution state
	@type state: L{State<pyRdfa.state>}
	"""
    from ..host import HostLanguage
    if not options.host_language in [HostLanguage.xhtml, HostLanguage.html5,
        HostLanguage.xhtml5]:
        return
    for meta in html.getElementsByTagName('meta'):
        if meta.hasAttribute('name') and not meta.hasAttribute('property'):
            meta.setAttribute('property', meta.getAttribute('name'))


def merge_dicts(dicts_a, dicts_b):
    """Merges two lists of dictionaries by key attribute.

    Example:
        da = [{'key': 'a', 'value': 1}, {'key': 'b', 'value': 2}]
        db = [{'key': 'b', 'value': 3, 'color':'pink'}, {'key': 'c', 'value': 4}]
        merge_dicts(da, db) = [{'key': 'a', 'value': 1}, {'key': 'b', 'value': 3, 'color':'pink'}]
    Args:
        dicts_a (list of objs): First dictionary.
        dicts_b (list of objs): Second dictionary.

    Returns:
        list of objs: List of merged dicts.
    """
    for dict_a in dicts_a:
        for dict_b in dicts_b:
            if dict_a['key'] == dict_b['key']:
                for k, v in dict_b.items():
                    dict_a[k] = v
    return dicts_a


@classmethod
def home(cls):
    """Return a new path pointing to the user's home directory (as
        returned by os.path.expanduser('~')).

        :rtype: Path
        """
    return cls(cls()._flavour.gethomedir(None))


@staticmethod
def pointers2namemmaps(p):
    """
        Get a map from source to transformed IRF node names.
        :param p: ``dict``; map from source to transformed IRF nodes.
        :return: ``dict``; map from source to transformed IRF node names.
        """
    fw = {}
    bw = {}
    for t in p:
        for t_pc in p[t]:
            if not t.name() in fw:
                fw[t.name()] = []
            if not t_pc.name() in fw[t.name()]:
                fw[t.name()].append(t_pc.name())
            if not t_pc.name() in bw:
                bw[t_pc.name()] = []
            if not t_pc.name() in bw[t_pc.name()]:
                bw[t_pc.name()].append(t.name())
    return fw, bw


def weight_paint_toggle():
    """Toggle weight paint mode in 3D view

    """
    pass


def check_for_split(G, edge):
    """
    Given an edge in tuple form, check if it splits the
    graph into two disjoint clusters. If so, it returns
    True. Otherwise, False.
    """
    try:
        return not G.edge_disjoint_paths(source=edge[0], target=edge[1])
    except Exception as e:
        return False


def toggle_render():
    """Toggle rendered shading mode of the viewport

    """
    pass


def _collapse_arches(options, pkgs):
    """Collapse arches into a single set."""
    keywords = set()
    stable_keywords = set()
    unstable_keywords = set()
    for pkg in pkgs:
        for x in pkg.keywords:
            if x[0] == '~':
                unstable_keywords.add(x[1:])
            elif x in options.arches:
                stable_keywords.add(x)
    if options.unstable:
        keywords.update(unstable_keywords)
    if options.only_unstable:
        keywords.update(unstable_keywords.difference(stable_keywords))
    if not keywords or options.stable:
        keywords.update(stable_keywords)
    return sorted(keywords.intersection(options.native_arches)) + sorted(
        keywords.intersection(options.prefix_arches))


def set_contract_strategy(strategy):
    """Get the default contraction strategy - the option supplied as
    ``optimize`` to ``opt_einsum``.
    """
    global _DEFAULT_CONTRACTION_STRATEGY
    _DEFAULT_CONTRACTION_STRATEGY = strategy


def render_pep440_pre(pieces):
    """TAG[.post.devDISTANCE] -- No -dirty.

    Exceptions:
    1: no tags. 0.post.devDISTANCE
    """
    if pieces['closest-tag']:
        rendered = pieces['closest-tag']
        if pieces['distance']:
            rendered += '.post.dev%d' % pieces['distance']
    else:
        rendered = '0.post.dev%d' % pieces['distance']
    return rendered


@staticmethod
def append_url_with_query_parameters(url, parameters):
    """Appends the given set of parameters to the given query string.

        Args:
            url (str): The query url string to append the parameters.
            parameters (dict): The parameters to append.

        Returns:
            str: Url with appended query parameters.

        """
    if url is None:
        raise ValueError('url is null')
    if parameters is None:
        return url
    has_params = '?' in url
    for key in parameters:
        element = parameters[key]
        if element is None:
            continue
        separator = '&' if has_params else '?'
        if isinstance(element, list):
            url = url + '{0}{1}[]={2}'.format(separator, key, '&{0}[]='.
                format(key).join(element))
        else:
            url = url + '{0}{1}={2}'.format(separator, key, str(parameters[
                key]))
        has_params = True
    return url


def pytest_html_results_summary(prefix, summary, postfix):
    """ Called before adding the summary section to the report """
    pass


def set_bit(data: int, bit: int, is_on: bool) ->int:
    """Set the value of a bit in a bitmask on or off.

    Uses the low bit is 0 and the high bit is 7.
    """
    if isinstance(data, bytes):
        bitmask = int.from_bytes(data, byteorder='big')
    else:
        bitmask = data
    if is_on:
        return bitmask | 1 << bit
    return bitmask & (255 & ~(1 << bit))


def set_focus(event):
    """ sets focus to canvas """
    event.widget.focus_set()


@classmethod
def showcase_edit_comment(cls, val):
    """
        Create an instance of this class set to the ``showcase_edit_comment``
        tag with value ``val``.

        :param ShowcaseEditCommentType val:
        :rtype: EventType
        """
    return cls('showcase_edit_comment', val)


def get_frequency_count_str(values_list, value):
    """Counts frequency for columns containing strings

     :param values_list: list
        list of all the values
    :param value: string
        name of the column
    :return:
        dictionary named by the value name and containing all frequencies
        for rows as integer values
    """
    frequency_values_dict = {}
    tmp_dict = {}
    tmp_set_of_str = {''}
    for feature in values_list:
        if feature not in tmp_set_of_str:
            tmp_dict[feature] = 1
            tmp_set_of_str.add(feature)
        else:
            tmp_dict[feature] = tmp_dict.get(feature) + 1
    frequency_values_dict['{} frequencies'.format(value)] = tmp_dict
    return frequency_values_dict


def DT_2(dul):
    """Data transfer DT-2.

    On receiving a P-DATA-TF request, send P-DATA indication

    State-event triggers: Sta6 + Evt10

    References
    ----------
    1. DICOM Standard 2015b, PS3.8, Table 9-7, "Associate Establishment
       Related Actions"

    Parameters
    ----------
    dul : pynetdicom.dul.DULServiceProvider
        The DICOM Upper Layer Service instance for the local AE

    Returns
    -------
    str
        Sta6, the next state of the state machine
    """
    dul.assoc.dimse.receive_primitive(dul.primitive)
    return 'Sta6'


def update_repo(name):
    """Update all the repos in the system"""
    print(f'Update repo {name}')


@classmethod
def make_iv(cls, gene: int) ->'Stats':
    """Create IV stats from a Pokémon's gene.

        :param gene: An ``int`` generated by the PRNG.
        :return: A ``Stats`` instance.
        """
    return cls(hp=gene % 32, attack=(gene >> 5) % 32, defense=(gene >> 10) %
        32, speed=(gene >> 16) % 32, special_attack=(gene >> 21) % 32,
        special_defense=(gene >> 26) % 32)


def close_boundaries_sensibly(model):
    """
    Return a cobra model with all boundaries closed and changed constraints.

    In the returned model previously fixed reactions are no longer constrained
    as such. Instead reactions are constrained according to their
    reversibility. This is to prevent the FBA from becoming infeasible when
    trying to solve a model with closed exchanges and one fixed reaction.

    Parameters
    ----------
    model : cobra.Model
        The metabolic model under investigation.

    Returns
    -------
    cobra.Model
        A cobra model with all boundary reactions closed and the constraints
        of each reaction set according to their reversibility.

    """
    for rxn in model.reactions:
        if rxn.reversibility:
            rxn.bounds = -1, 1
        else:
            rxn.bounds = 0, 1
    for boundary in model.boundary:
        boundary.bounds = 0, 0


def main():
    """ A place-holder command line module."""
    print('Placeholder function for future command line implementations.')


def always_str_list(list_or_str):
    """Makes sure list_or_str is always a tuple or list

    Parameters
    ----------
    list_or_str: str or str iterable (tuple, list, ...)
        Parameter to set as iterable if single str.

    Returns
    -------
    Iterable
        Iterable equivalent to list_or_str."""
    if isinstance(list_or_str, str):
        return list_or_str,
    return list_or_str


def percent(value: int) ->int:
    """A int between 0 and 100, inclusive"""
    return min(100, max(0, int(value)))


def calc_real(ydata):
    """Extract real part from complex data

    Parameters
    ----------
    ydata : :obj:`xarray.DataArray`
        y-axis data to be processed

    Returns
    -------
    real : :obj:`xarray.DataArray`
        Real part of :attr:`ydata`
    """
    real = ydata.real
    return real


@staticmethod
def close_ns(symbol):
    """generates a closing names statement from a symbol"""
    closing = ' '.join(['}' for x in symbol.module.name_parts])
    name = '::'.join(symbol.module.name_parts)
    return '{0} // namespace {1}'.format(closing, name)


def chunks(l, n):
    """Function to split a list into evenly sized chunks"""
    for i in range(0, len(l) - n + 1):
        yield l[i:i + n]


def find_smallest_headers(content):
    """
    find the smallest header level
    :param content:
    :type content:
    :return:
    :rtype:
    """
    ignore = False
    lines = content.splitlines()
    headers = []
    for line in lines:
        if line.startswith('`'):
            ignore = not ignore
            break
        if line.startswith('#') and not ignore:
            headers.append(line.split(' ')[0])
    headers = set(headers)
    level = sorted(headers, key=len)
    if len(level) == 0:
        level = 1
    else:
        level = len(level[0])
    return level


def dfsu_details(x, y):
    """
    Get min and max for input x and y ndarrays; shape (num_nodes,)
    """
    min_x = x.min()
    max_x = x.max()
    min_y = y.min()
    max_y = y.max()
    return min_x, max_x, min_y, max_y


def rebuild_proxy():
    """Rebuild all selected proxies and timecode indices using the job system

    """
    pass


def integer_as_number_of_bits(size):
    """Returns the minimum number of bits needed to fit given positive
    integer.

    """
    if size == 0:
        return 0
    else:
        return size.bit_length()


def taputil_find_header(headers, key):
    """Searches for the specified keyword

    Parameters
    ----------
    headers : HTTP(s) headers object, mandatory
        HTTP(s) response headers
    key : str, mandatory
        header key to be searched for

    Returns
    -------
    The requested header value or None if the header is not found
    """
    for entry in headers:
        if key.lower() == entry[0].lower():
            return entry[1]
    return None


def cell_source(cell):
    """Return the source of the current cell, as an array of lines"""
    source = cell.source
    if source == '':
        return ['']
    if source.endswith('\n'):
        return source.splitlines() + ['']
    return source.splitlines()


def check_log_settings(args):
    """
    Quick method to check the consistency of log settings
    from the namespace.
    :param args: a Namespace
    :return: args
    """
    if args.log == 'stderr':
        args.json_conf['log_settings']['log'] = None
    elif args.log is not None:
        args.json_conf['log_settings']['log'] = args.log
    if args.log_level is not None:
        args.json_conf['log_settings']['log_level'] = args.log_level
    elif args.verbose is True:
        args.json_conf['log_settings']['log_level'] = 'DEBUG'
    elif args.noverbose is True:
        args.json_conf['log_settings']['log_level'] = 'ERROR'
    return args


def getThreadPool():
    """
        Return the threadpool used by L{IReactorInThreads.callInThread}.
        Create it first if necessary.

        @rtype: L{twisted.python.threadpool.ThreadPool}
        """


def test_fail(message: str=None):
    """
    Forced failure of the test, can be used in rare conditions instead of checking obviously wrong conditions.
    :param message: is the optional message
    :return: None
    """
    raise AssertionError(message if message else 'Test was forcibly failed!')


def is_lyr_def(xlsfile):
    """
    if the xlsx file is used to define layer.
    NOT for Multiple layers, or group layers.
    """
    if xlsfile.endswith('.xlsx'):
        if '_mul' in xlsfile or '_grp' in xlsfile:
            return False
        else:
            return True
    else:
        return False


def scan_setup_py():
    """Validate the contents of setup.py against Versioneer's expectations."""
    found = set()
    setters = False
    errors = 0
    with open('setup.py', 'r') as f:
        for line in f.readlines():
            if 'import versioneer' in line:
                found.add('import')
            if 'versioneer.get_cmdclass()' in line:
                found.add('cmdclass')
            if 'versioneer.get_version()' in line:
                found.add('get_version')
            if 'versioneer.VCS' in line:
                setters = True
            if 'versioneer.versionfile_source' in line:
                setters = True
    if len(found) != 3:
        print('')
        print('Your setup.py appears to be missing some important items')
        print('(but I might be wrong). Please make sure it has something')
        print('roughly like the following:')
        print('')
        print(' import versioneer')
        print(' setup( version=versioneer.get_version(),')
        print('        cmdclass=versioneer.get_cmdclass(),  ...)')
        print('')
        errors += 1
    if setters:
        print("You should remove lines like 'versioneer.VCS = ' and")
        print("'versioneer.versionfile_source = ' . This configuration")
        print('now lives in setup.cfg, and should be removed from setup.py')
        print('')
        errors += 1
    return errors


def directory_new(directory: str='', open: bool=False):
    """Create a new directory

    :param directory: Directory, Name of new directory
    :type directory: str
    :param open: Open, Open new directory
    :type open: bool
    """
    pass


def deflate_string(as_bytes: bytes) ->str:
    """ Inverse of inflate_string.

    Takes the undecoded binary string.
    """
    zero_loc = as_bytes.find(0)
    if zero_loc < 0:
        return as_bytes.decode()
    return as_bytes[:zero_loc].decode()


def to_sg(plato):
    """
    Convert from plato to specific gravity
    """
    return 1 + plato / (258.6 - plato / 258.2 * 227.1)


def draw_tail_none(context):
    """
    Draw an 'x' on the line end to indicate no navigability at
    association tail.
    """
    cr = context.cairo
    cr.line_to(0, 0)
    cr.move_to(6, -4)
    cr.rel_line_to(8, 8)
    cr.rel_move_to(0, -8)
    cr.rel_line_to(-8, 8)
    cr.stroke()


@classmethod
def _from_et(cls, root, parent):
    """
        Create a :class:`Connect` from a :code:`connect` element.

        :param root: The element tree tree to parse.
        :param parent: :class:`EagleFilePart` that should hold the resulting :class:`EagleFilePart`
        :rtype: :class:`Connect`
        """
    n = cls()
    n._init_from_et(root, parent)
    return n


def loop_multi_select(ring: bool=False):
    """Select a loop of connected edges by connection type

    :param ring: Ring
    :type ring: bool
    """
    pass


def add_link(req, rel, href, title=None, mimetype=None, classname=None, **attrs
    ):
    """Add a link to the chrome info that will be inserted as <link> element in
    the <head> of the generated HTML
    """
    linkid = '%s:%s' % (rel, href)
    linkset = req.chrome.setdefault('linkset', set())
    if linkid in linkset:
        return
    link = {'href': href, 'title': title, 'type': mimetype, 'class': classname}
    link.update(attrs)
    links = req.chrome.setdefault('links', {})
    links.setdefault(rel, []).append(link)
    linkset.add(linkid)


def add(iterable, ignore=False):
    """Sums iterable. If ignore=True all elements except those that are None are added. If ignore=False, None is returned if any element is None. """
    x = None
    for i in range(len(iterable)):
        if not iterable[i] is None:
            if x is None:
                x = iterable[i]
            else:
                x = x + iterable[i]
        elif not ignore:
            return None
    return x


def normalize_sent(r, sent_len, avg_len):
    """
  normalizes the ranking of sentences
  based on effect of their length on ranking
  also reduces chances that noisy short sentences that might have
  passed through the NLP toolkit make it into summaries or answers
  """
    if not r:
        r = 0
    if sent_len > 2 * avg_len or sent_len < min(5, avg_len / 4):
        return 0
    factor = 1 / (1 + abs(sent_len - avg_len) + sent_len)
    return r * factor


def list_and_sort_gaussians(img, patch=None, root=None, sort_by='index'):
    """Returns sorted lists of Gaussians and their names and patch names.

    patch - can be "single", "gaussian", "source", or None

    Returns (outlist, outnames, patchnames)
    outlist is [[g1, g2, g3], [g4], ...]
    outnames is [['root_i2_s1_g1', 'root_i2_s1_g2', 'root_i2_s1_g3'], ...]
    patchnames is ['root_patch_s1', 'root_patch_s2', ...]

    The names are root_iXX_sXX_gXX (or wXX_iXX_sXX_gXX for wavelet Gaussians)
    """
    import numpy as N
    from . import functions as func
    if root is None:
        root = img.parentname
    gauslist = []
    gausname = []
    outlist = []
    outnames = []
    patchnames = []
    patchnames_sorted = []
    gausflux = []
    gausindx = []
    patchflux = []
    patchindx = []
    patchnums = []
    use_mask = False
    if patch not in ['single', 'gaussian', 'source', None]:
        mask_file = img.opts.bbs_patches_mask
        patches_mask, hdr = func.read_image_from_file(mask_file, img, img.indir
            )
        use_mask = True
        act_pixels = patches_mask[0, 0]
        rank = len(act_pixels.shape)
        import scipy.ndimage as nd
        connectivity = nd.generate_binary_structure(rank, rank)
        mask_labels, count = nd.label(act_pixels, connectivity)
    src_list = img.sources
    for src in src_list:
        for g in src.gaussians:
            gauslist.append(g)
            gausflux.append(g.total_flux)
            gausindx.append(g.gaus_num)
            jstr = '_w' + str(g.jlevel)
            gausname.append(root + jstr + '_i' + str(src.island_id) + '_s' +
                str(src.source_id) + '_g' + str(g.gaus_num))
            if patch == 'gaussian':
                outlist.append(gauslist)
                outnames.append(gausname)
                patchnames.append(root + '_patch' + jstr + '_g' + str(g.
                    gaus_num))
                patchflux.append(N.sum(gausflux))
                patchindx.append(g.gaus_num)
                gauslist = []
                gausname = []
                gausflux = []
                gausindx = []
            if use_mask:
                patchnums.append(mask_labels[g.centre_pix[0], g.centre_pix[1]])
        if patch == 'source':
            sorted_gauslist = list(gauslist)
            sorted_gausname = list(gausname)
            if sort_by == 'flux':
                indx = N.argsort(N.array(gausflux)).tolist()
                indx.reverse()
            elif sort_by == 'index':
                indx = N.argsort(N.array(gausindx)).tolist()
            else:
                indx = range(len(gausindx))
            for i, si in enumerate(indx):
                sorted_gauslist[i] = gauslist[si]
                sorted_gausname[i] = gausname[si]
            outlist.append(sorted_gauslist)
            outnames.append(sorted_gausname)
            patchnames.append(root + '_patch' + '_s' + str(src.source_id))
            patchflux.append(N.sum(gausflux))
            patchindx.append(src.source_id)
            gauslist = []
            gausname = []
            gausflux = []
    if use_mask:
        unique_patch_ids = set(patchnums)
        if 0 in unique_patch_ids:
            from . import mylogger
            mylog = mylogger.logging.getLogger('PyBDSM.write_gaul')
            mylog.warning(
                'Some sources fall outside of the regions defined in the mask file. These sources are not included in the output sky model.'
                )
        for p in unique_patch_ids:
            if p != 0:
                in_patch = N.where(patchnums == p)
                outlist.append(N.array(gauslist)[in_patch].tolist())
                outnames.append(N.array(gausname)[in_patch].tolist())
                patchnames.append('patch_' + str(p))
                patchflux.append(N.sum(N.array(gausflux)[in_patch]))
                patchindx.append(p)
    if patch == 'single' or patch is None:
        outlist = [list(gauslist)]
        outlist_sorted = [list(gauslist)]
        outnames = [list(gausname)]
        outnames_sorted = [list(gausname)]
        if patch == 'single':
            patchnames = [root + '_patch']
        else:
            patchnames = [None]
        if sort_by == 'flux':
            indx = N.argsort(N.array(gausflux)).tolist()
            indx.reverse()
        elif sort_by == 'index':
            indx = N.argsort(N.array(gausindx)).tolist()
        else:
            indx = list(range(len(gausindx)))
        for i, si in enumerate(indx):
            outlist_sorted[0][i] = outlist[0][si]
            outnames_sorted[0][i] = outnames[0][si]
            patchnames_sorted = list(patchnames)
    else:
        outlist_sorted = list(outlist)
        outnames_sorted = list(outnames)
        patchnames_sorted = list(patchnames)
        if sort_by == 'flux':
            indx = N.argsort(N.array(patchflux)).tolist()
            indx.reverse()
        elif sort_by == 'index':
            indx = N.argsort(N.array(patchindx)).tolist()
        else:
            indx = list(range(len(gausindx)))
        for i, si in enumerate(indx):
            outlist_sorted[i] = outlist[si]
            outnames_sorted[i] = outnames[si]
            patchnames_sorted[i] = patchnames[si]
    return outlist_sorted, outnames_sorted, patchnames_sorted


def vertices_rectangle(size):
    """Returns a list of vertices describing a rectangle.

    Notes
    -----
    The resulting vertices can be plotted with the class
    stimuli.Shape(vertex_list=...).

    Parameters
    ----------
    size : (int, int)
        size (width, height) of the rectangle

    Returns
    -------
    vtx : list of vertices

    """
    return [(size[0] - 1, 0), (0, -size[1] + 1), (-size[0] + 1, 0), (0,
        size[1] - 1)]


def show_help():
    """Print some help text that describes how to use this script."""
    print(__doc__)


def get_vert_ngrams_right(c):
    """Not implemented."""
    return


@staticmethod
def _get_wall_upload_server(session, group_id):
    """
        https://vk.com/dev/photos.getWallUploadServer
        """
    response = session.fetch('photos.getWallUploadServer', group_id=group_id)
    return response['upload_url']


def linear_interpolate(a, b, v1, v2, i):
    """Linear interpolation"""
    if v1 == v2:
        return a
    else:
        return a + (b - a) * (i - v1) / (v2 - v1)


def remove_leading_trailing_whitespace_lines(src):
    """
    Remove any leading or trailing whitespace lines.

    Parameters
    ----------
    src : str
        Input code.

    Returns
    -------
    str
        Code with trailing whitespace lines removed.
    """
    lines = src.splitlines()
    non_whitespace_lines = []
    for i, l in enumerate(lines):
        if l and not l.isspace():
            non_whitespace_lines.append(i)
    imin = min(non_whitespace_lines)
    imax = max(non_whitespace_lines)
    return '\n'.join(lines[imin:imax + 1])


def face_select_reveal(select: bool=True):
    """Reveal hidden faces

    :param select: Select
    :type select: bool
    """
    pass


def get_num_frames_in_event(event):
    """
    Gets the number of frames in an event retrieved from Pilatus files (or HiDRA).

    For the Pilatus detector, an event corresponds to the content of a single CBF data
    file. Since the Pilatus detector writes one frame per file, this function always
    returns 1.

    NOTE: This function is designed to be injected as a member function into an
    :class:`~onda.utils.data_event.DataEvent` object.

    Arguments:

        event (:class:`~onda.utils.data_event.DataEvent`): an object storing the event
            data.

    Returns:

        int: the number of frames in the event.
    """
    del event
    return 1


def _print(txt):
    """print line without /r, /n or white space"""
    print(txt.rstrip())


@classmethod
def binder_remove_page_details(cls, val):
    """
        Create an instance of this class set to the
        ``binder_remove_page_details`` tag with value ``val``.

        :param BinderRemovePageDetails val:
        :rtype: EventDetails
        """
    return cls('binder_remove_page_details', val)


def convert_to_standard_units(mdf):
    """ Converts the input data to {'pos':'m', 'time':'s', 'fields':'nT', 'grads':'nT/m' """
    mdf_standard = mdf.deepcopy()
    fac = {'p': 1e-12, 'n': 1e-09, 'u': 1e-06, 'm': 0.001, ' ': 1.0, 'k':
        1000.0, 'M': 1000000.0, 'G': 1000000000.0, 'T': 1000000000000.0}
    upos_prefix = str.rjust(mdf_standard.units.get('pos', 'm'), 2)[0]
    mdf_standard.rescale_pos(fac[upos_prefix])
    mdf_standard.units['pos'] = 'm'
    ufields_prefix = str.rjust(mdf_standard.units.get('fields', 'T'), 2)[0]
    mdf_standard.rescale_fields(1000000000.0 * fac[ufields_prefix])
    mdf_standard.units['fields'] = 'nT'
    ugrads_numerator_prefix = str.rjust(mdf_standard.units.get('grads',
        'nT/m').split('/')[0], 2)[0]
    ugrads_denominator_prefix = str.rjust(mdf_standard.units.get('grads',
        'nT/m').split('/')[1], 2)[0]
    mdf_standard.rescale_grads(1000000000.0 * fac[ugrads_numerator_prefix] *
        fac[ugrads_denominator_prefix] ** -1)
    mdf_standard.units['grads'] = 'nT/m'
    fac_time = {'us': 1e-06, 'ms': 0.001, 's': 1.0, 'min': 60, 'h': 60 * 60,
        'd': 60 * 60 * 24, 'w': 60 * 60 * 24 * 7}
    utime = mdf_standard.units.get('time', 's')
    mdf_standard.rescale_time(fac_time[utime])
    mdf_standard.units['time'] = 's'
    return mdf_standard


def _create_param(dimension, default_value):
    """Create a parameter dictionary based on dimension and default_value"""
    return dict(name=dimension.name, type=dimension.type, value=default_value)


def strToIntWithSIMultipliers(s):
    """Take a string of the form number[k|m|g] or just number and convert to an actual number
    '0'-> 0, '5k'->5000 etc. Does not do division!!!! m is mega not milli!!!"""
    s = s.lower()
    if s.endswith('k'):
        return int(s[:-1]) * 1000
    elif s.endswith('m'):
        return int(s[:-1]) * 1000000
    elif s.endswith('g'):
        return int(s[:-1]) * 1000000000
    else:
        return int(s[:-1])


@staticmethod
def write_float(value, file):
    """
        Writes a float as a field to a CSV file.

        :param float value: The float.
        :param T file: The file.
        """
    file.write(str(value))


def match_movie_length():
    """Set image’s user’s length to the one of this video

    """
    pass


def wrap_css_lines(css, line_length=80):
    """Wrap the lines of the given CSS to an approximate length."""
    lines, line_start = [], 0
    for i, char in enumerate(css):
        if char == '}' and i - line_start >= line_length:
            lines.append(css[line_start:i + 1])
            line_start = i + 1
    if line_start < len(css):
        lines.append(css[line_start:])
    return '\n'.join(lines)


def plus_or_dot(pieces):
    """Return a + if we don't already have one, else return a ."""
    if '+' in pieces.get('closest-tag', ''):
        return '.'
    return '+'


def is_wat(res):
    """
    Shortcut to check for water residues
    """
    return res.id[0].startswith('W')


def work_around_issue_6785():
    """See https://github.com/sphinx-doc/sphinx/issues/6785
    """
    from sphinx.ext import autodoc
    assert autodoc.PropertyDocumenter.priority > autodoc.AttributeDocumenter.priority
    autodoc.PropertyDocumenter.priority = -100


def meanXperY(x, y):
    """find the mean x for each label y"""
    sums = dict()
    counts = dict()
    for i in range(len(x)):
        try:
            sums[y[i]] += x[i]
            counts[y[i]] += 1
        except KeyError:
            sums[y[i]] = x
            counts[y[i]] = 1
    means = dict()
    for yKey in sums:
        means[yKey] = sums[yKey] / float(counts[yKey])
    return means


def plantloopfieldlists(data):
    """return the plantloopfield list"""
    objkey = 'plantloop'.upper()
    numobjects = len(data.dt[objkey])
    return [['Name', 'Plant Side Inlet Node Name',
        'Plant Side Outlet Node Name', 'Plant Side Branch List Name',
        'Demand Side Inlet Node Name', 'Demand Side Outlet Node Name',
        'Demand Side Branch List Name']] * numobjects


def getListForAddress(address):
    """Returns an IMailingList object corresponding to the address given,
           or None iuf no list is found."""


def fib(n):
    """Fibonacci example function

    Args:
      n (int): integer

    Returns:
      int: n-th Fibonacci number
    """
    assert n > 0
    a, b = 1, 1
    for i in range(n - 1):
        a, b = b, a + b
    return a


def word_list(words):
    """Group a list of words into a string with a list separated by commas
    and the word 'and'.

    Parameters
    ----------
    words: list of str
        A list of strings (words) to group together into a word list.

    Returns
    -------
    str

    Examples
    --------
    >>> word_list('February')
    'February'
    >>> word_list(['February', 'March'])
    'February and March'
    >>> word_list(['February', 'March', 'April', 'May'])
    'February, March, April and May'
    """
    if isinstance(words, str):
        words = [words]
    num_words = len(words)
    if num_words == 0:
        return ''
    elif num_words == 1:
        return words[0]
    elif num_words == 2:
        return ' and '.join(words)
    else:
        return ', '.join(words[0:-1]) + ' and ' + words[-1]


def history(roomJID, messages):
    """
        Send history to create a MUC based on a one on one chat.

        See: http://xmpp.org/extensions/xep-0045.html#continue

        @param roomJID: The room jabber/xmpp entity id.
        @type roomJID: L{JID<twisted.words.protocols.jabber.jid.JID>}

        @param messages: The history to send to the room as an ordered list of
            message, represented by a dictionary with the keys C{'stanza'},
            holding the original stanza a
            L{Element<twisted.words.xish.domish.Element>}, and C{'timestamp'}
            with the timestamp.
        @type messages: C{list} of
            L{Element<twisted.words.xish.domish.Element>}
        """


@classmethod
def add_displays(cls, *args):
    """Each arg is added to the ``list_display`` property without any
        extra wrappers, using only the regular django functionality"""
    for arg in args:
        cls.list_display.append(arg)


def attr_has_same_shape(first_obj, second_obj, attr):
    """
    Given two objects, check if the given arraylike attributes of those
    objects have the same shape. If one object has an attribute value of
    ``None``, the other must too.

    Args:
        first_obj (obj): A object with an arraylike ``attr`` attribute.
        second_obj (obj): Another object with an arraylike ``attr`` attribute.
        attr (str): The name of the attribute to test.

    Returns:
        bool: `True` if attributes are the same shape
    """
    first, second = getattr(first_obj, attr), getattr(second_obj, attr)
    if first is None or second is None:
        return first is second
    else:
        return first.shape == second.shape


def channels_click(extend: bool=False):
    """Handle clicks to select NLA channels

    :param extend: Extend Select
    :type extend: bool
    """
    pass


def time_complexities():
    """
    Return information on functions
    time complexity
    :return: string
    """
    return 'O(V + E) where V = Number of vertices and E = Number of Edges'


def invalidatecaches():
    """Invalidate cached data due to the repository mutating."""


def format_heading(level, text):
    """Create a heading of <level> [1, 2 or 3 supported]."""
    underlining = ['=', '-', '~'][level - 1] * len(text)
    return '%s\n%s\n\n' % (text, underlining)


def get_class(classname):
    """
    Returns the class object associated with the dot-notation classname.

    Taken from here: http://stackoverflow.com/a/452981

    :param classname: the classname
    :type classname: str
    :return: the class object
    :rtype: object
    """
    parts = classname.split('.')
    module = '.'.join(parts[:-1])
    m = __import__(module)
    for comp in parts[1:]:
        m = getattr(m, comp)
    return m


def getSearchableText():
    """Return a sequence of unicode strings to be indexed.

        Each unicode string in the returned sequence will be run
        through the splitter pipeline; the combined stream of words
        coming out of the pipeline will be indexed.

        returning None indicates the object should not be indexed
        """


def warnings_formatter(message, category=UserWarning, filename='', lineno=-
    1, line=''):
    """Monkey patch for warnings.warn to suppress cruft output."""
    return '{0}\n'.format(message)


def p_expression_rshift(p):
    """expression : expression RSHIFT expression"""
    p[0] = p[1] >> p[3]


def cmd_quit(args):
    """Terminate session. No read access required.
        """


def count_values(tokens):
    """Identify the number of values ahead of the current token."""
    ntoks = 0
    for tok in tokens:
        if tok.isspace() or tok == ',':
            continue
        elif tok in ('=', '/', '$', '&'):
            if ntoks > 0 and tok == '=':
                ntoks -= 1
            break
        else:
            ntoks += 1
    return ntoks


def deduplication_approximated_run_check(columns, df):
    """
    Check for consistency between parameters and the dataframe, an assertion
    error will incur if the check is not passed.

    :param columns: Columns on which to run the metric
    :type columns: list
    :param df: Dataframe on which to run the metric
    :type df: DataFrame
    """
    if columns is not None:
        for col in columns:
            assert col in df.columns, "Column '%s' is not a column part of the dataframe" % col


def get_unique_variable_names(source, repeat_kwd, all_count_names=[]):
    """Returns a list of possible variables names that
       are not found in the original source and have not been used
       anywhere.
       These variables will be used in expressions such as

           for _COUNT_42 in range(n):

       which will replace

           repeat n:
    """
    nb = source.count(repeat_kwd)
    if nb == 0:
        return []
    base_name = '_COUNT_'
    var_names = []
    i = 0
    j = 0
    while j < nb:
        tentative_name = base_name + str(i)
        if source.count(tentative_name
            ) == 0 and tentative_name not in all_count_names:
            var_names.append(tentative_name)
            all_count_names.append(tentative_name)
            j += 1
        i += 1
    return var_names


def create_environment(environment):
    """Persists given `environment` object and returns it."""


def do_OP_WITHIN(vm):
    """
    >>> s = [b'b', b'a', b'c']
    >>> do_OP_WITHIN(s, False)
    >>> print(s == [b''])
    True
    >>> s = [b'd', b'a', b'c']
    >>> do_OP_WITHIN(s, False)
    >>> print(s == [b''])
    True
    """
    v3, v2, v1 = [vm.pop_int() for i in range(3)]
    ok = v2 <= v1 < v3
    vm.append(vm.bool_to_script_bytes(ok))


def make_driver():
    """Make a webdriver for selenium with appropriate options"""
    from selenium.webdriver import Chrome
    from selenium.webdriver.chrome.options import Options
    options = Options()
    options.add_argument('--headless')
    options.add_argument('--disable-gpu')
    driver = Chrome(chrome_options=options)
    driver.implicitly_wait(4)
    return driver


@classmethod
def autocomplete(cls, argv):
    """This is supplied to make subclassing and testing argument completion methods easier"""
    pass


@classmethod
def from_existing_session(cls, session: object, driver_options: str=None
    ) ->'Core':
    """Creates a new Core object with the entered 'session' reused."""
    return cls(None, False, False, driver_options, None, session)


def print_line(l):
    """
    print line if starts with ...
    """
    print_lines = ['# STOCKHOLM', '#=GF', '#=GS', ' ']
    if len(l.split()) == 0:
        return True
    for start in print_lines:
        if l.startswith(start):
            return True
    return False


def implemented_function(symfunc, implementation):
    """Add numerical ``implementation`` to function ``symfunc``.

    ``symfunc`` can be an ``UndefinedFunction`` instance, or a name string.
    In the latter case we create an ``UndefinedFunction`` instance with that
    name.

    Be aware that this is a quick workaround, not a general method to create
    special symbolic functions. If you want to create a symbolic function to be
    used by all the machinery of Diofant you should subclass the ``Function``
    class.

    Parameters
    ==========

    symfunc : ``str`` or ``UndefinedFunction`` instance
       If ``str``, then create new ``UndefinedFunction`` with this as
       name.  If `symfunc` is a diofant function, attach implementation to it.
    implementation : callable
       numerical implementation to be called by ``evalf()`` or ``lambdify``

    Returns
    =======

    afunc : diofant.FunctionClass instance
       function with attached implementation

    Examples
    ========

    >>> f = implemented_function(Function('f'), lambda x: x+1)
    >>> lam_f = lambdify(x, f(x))
    >>> lam_f(4)
    5

    """
    from ..core.function import UndefinedFunction
    if isinstance(symfunc, str):
        symfunc = UndefinedFunction(symfunc)
    elif not isinstance(symfunc, UndefinedFunction):
        raise ValueError(
            'symfunc should be either a string or an UndefinedFunction instance.'
            )
    symfunc._imp_ = staticmethod(implementation)
    return symfunc


def move_up():
    """Move selected strips up a track if there’s room

    """
    pass


def _variable_is_a_function(variable):
    """
    Checks if a specified variable is a function by checking if it implements
    the __call__ method.

    This means that the object doesn't have to be a function to pass this
    function, just implement __call__

    @return: True if the variable is a function
    @rtype: bool
    """
    return hasattr(variable, '__call__')


def embed_dicom_and_nifti_metadata(dcmfiles, niftifile, infofile, bids_info):
    """Embed metadata from nifti (affine etc) and dicoms into infofile (json)

    `niftifile` should exist. Its affine's orientation information is used while
    establishing new `NiftiImage` out of dicom stack and together with `bids_info`
    (if provided) is dumped into json `infofile`

    Parameters
    ----------
    dcmfiles
    niftifile
    infofile
    bids_info: dict
      Additional metadata to be embedded. `infofile` is overwritten if exists,
      so here you could pass some metadata which would overload (at the first
      level of the dict structure, no recursive fancy updates) what is obtained
      from nifti and dicoms

    """
    import nibabel as nb
    import os.path as op
    import json
    import re
    from heudiconv.utils import save_json
    from heudiconv.external.dcmstack import ds
    stack = ds.parse_and_stack(dcmfiles, force=True).values()
    if len(stack) > 1:
        raise ValueError('Found multiple series')
    stack = next(iter(stack))
    if not op.exists(niftifile):
        raise NotImplementedError(
            '%s does not exist. We are not producing new nifti files here any longer. Use dcm2niix directly or .convert.nipype_convert helper .'
             % niftifile)
    orig_nii = nb.load(niftifile)
    aff = orig_nii.affine
    ornt = nb.orientations.io_orientation(aff)
    axcodes = nb.orientations.ornt2axcodes(ornt)
    new_nii = stack.to_nifti(voxel_order=''.join(axcodes), embed_meta=True)
    meta_info = ds.NiftiWrapper(new_nii).meta_ext.to_json()
    meta_info = json.loads(meta_info)
    if bids_info:
        meta_info.update(bids_info)
    save_json(infofile, meta_info)


def submit_pr_arguments(parser):
    """ Submit an existing pull request for review.
    """
    parser.add_argument('name', type=str, action='store', nargs=1, help=
        'pull request name')
    parser.add_argument('-m', '--message', action='store', help=
        'Message to add on submit.')


@classmethod
def getModule(cls):
    """
        Get the module name (e.g. "dhcp", "wireless") for a ConfigObject class.
        """
    parts = cls.__module__.split('.')
    return parts[-1]


@classmethod
def list(cls, context, limit=None, marker=None, sort_key=None, sort_dir=None):
    """Return a list of VolumeConnector objects.

        :param context: security context
        :param limit: maximum number of resources to return in a single result
        :param marker: pagination marker for large data sets
        :param sort_key: column to sort results by
        :param sort_dir: direction to sort. "asc" or "desc".
        :returns: a list of :class:`VolumeConnector` objects
        :raises: InvalidParameterValue if sort_key does not exist
        """
    db_connectors = cls.dbapi.get_volume_connector_list(limit=limit, marker
        =marker, sort_key=sort_key, sort_dir=sort_dir)
    return cls._from_db_object_list(context, db_connectors)


def setValue(value):
    """Change criterion value.
        """


@classmethod
def spec(cls, id_, name, sizes):
    """Create an ArgumentType to be used in ValidActions."""
    return cls(id_, name, sizes, None, None, None)


def return_schema_name(raw_schema_version_string: str,
    raw_schema_type_string: str, schema_prefix: str=None):
    """ Takes Schema Version and Schema Type and returns a transformed schema name.
    Optionally takes a schema prefix to attach to the front. """
    schema_version_string = raw_schema_version_string.replace('-', '_'
        ).replace('.', '_')
    schema_name = schema_version_string + '_' + raw_schema_type_string.lower()
    if schema_prefix and schema_name:
        schema_name = schema_prefix + '_' + schema_name
    return schema_name


def get_installed_package_names(command):
    """Given a Command object, return a list of package names"""
    pkgs = []
    if command.is_set() and command.is_install():
        for word in command.words:
            pkgs.append(word)
    return pkgs


def call_with_or_without_args(def_to_call, dv_args):
    """
	Helper for def return_when_def_is_true.
	This def checks dv_args and if its value is None,
	it calls param def_to_call without any arguments,
	otherside calls with dv_args as param list,
	key=paramater name, value=paramater value.
	"""
    if dv_args is None:
        return def_to_call()
    else:
        return def_to_call(**dv_args)


@staticmethod
def __get_list_pixel_pass(image, color):
    """tra ve nhung toa do co mau khac vs color
        """
    list_pixel_full = []
    list_pixel_pass = []
    img_size = image.size
    pixel_img = image.load()
    for y in range(img_size[1]):
        for x in range(img_size[0]):
            list_pixel_full.append((x, y))
            pixel_color = pixel_img[x, y]
            if pixel_color != color:
                list_pixel_pass.append((x, y))
    return list_pixel_full, list_pixel_pass


def present_params(paramlist, spacing=0, maxchars=90, linecont=', &'):
    """Creates the (paramlist) for a method call formatted nicely for calls
    with lots of parameters."""
    line = []
    length = 0
    result = []
    for param in paramlist:
        extra = len(list(param))
        if length + extra + 2 + spacing > maxchars:
            result.append(', '.join(line) + linecont)
            line = [param]
            length = extra + 2
        else:
            line.append(param)
            length += extra + 2
    result.append(', '.join(line))
    return '\n{}'.format(' '.join(['' for i in range(spacing + 3)])).join(
        result)


def reset_queues(queues):
    """Resets original queue._put() method."""
    for queue in queues:
        with queue.mutex:
            queue._put = queue._pebble_old_method
        delattr(queue, '_pebble_old_method')
        delattr(queue, '_pebble_lock')


def getName(obj):
    """
        Get the name an object was traversed via.
        """


def resume():
    """
        Invoked when notification for this listener is being resumed.

        Any actions taken by L{suspend} may be reversed by this method.
        """


def from_pairs(pairs):
    """Returns a dict from the given list of pairs.

    Args:
        pairs (list): List of key-value pairs.

    Returns:
        dict

    Example:

        >>> from_pairs([['a', 1], ['b', 2]]) == {'a': 1, 'b': 2}
        True

    .. versionadded:: 4.0.0
    """
    return dict(pairs)


@classmethod
def get(cls):
    """
        Get an instance of this Config class with all the configuration loaded
        from default locations. The locations are determined by
        Meta.filename_list attribute.

        :returns: fresh :class:`Config` instance

        """
    self = cls()
    self.read(cls.Meta.filename_list)
    return self


def lower(value):
    """Convert to lower case
    """
    return str(value).lower()


@classmethod
def load(cls, file_path, unflatten=True):
    """Load the data all at once (classmethod).

        # Arguments
            file_path: Zarr file path
            unflatten: see `load_all`
        """
    with cls(file_path) as f:
        return f.load_all(unflatten=unflatten)


def l2o(path):
    """
    Formats a list (['bla',0,'bla']) into an ODS path format ('bla.0.bla')

    :param path: list of strings and integers

    :return: ODS path format
    """
    return '.'.join(filter(None, map(str, path)))


def get_protocol(request):
    """
    Returns the protocol request is using ('http' | 'https')
    """
    return 'https' if request.is_secure() else 'http'


@classmethod
def get_username(cls, user):
    """Return the username for given user"""
    raise NotImplementedError('Implement in subclass')


def getList():
    """ To get file list.
	"""
    file_list = []
    for y in range(2016, 2019):
        for m in range(1, 13):
            if y == 2016 and m < 7:
                continue
            if len(str(m)) == 1:
                m = '0' + str(m)
            file_list.append('train' + str(y) + str(m) + '.csv')
    return file_list


def does_sprite_contain(outer_sprite, inner_sprite):
    """
    Indicate whether

    :param outer_sprite:

    :param inner_sprite:

    :return:
    """
    outer_sprite_x1, outer_sprite_y1 = outer_sprite.top_left
    outer_sprite_x2, outer_sprite_y2 = outer_sprite.bottom_right
    inner_sprite_x1, inner_sprite_y1 = inner_sprite.top_left
    inner_sprite_x2, inner_sprite_y2 = inner_sprite.bottom_right
    return (outer_sprite_x1 <= inner_sprite_x1 and inner_sprite_x2 <=
        outer_sprite_x2 and outer_sprite_y1 <= inner_sprite_y1 and
        inner_sprite_y2 <= outer_sprite_y2)


def Ack():
    """
    Response packet for some request.
    """
    return 'Ack'


def _convert_template_option(template):
    """Convert Tabula app template to tabula-py option

    Args:
        template (dict): Tabula app template

    Returns:
        `obj`:dict: tabula-py option
    """
    option = {}
    extraction_method = template.get('extraction_method')
    if extraction_method == 'guess':
        option['guess'] = True
    elif extraction_method == 'lattice':
        option['lattice'] = True
    elif extraction_method == 'stream':
        option['stream'] = True
    option['pages'] = template.get('page')
    option['area'] = [round(template['y1'], 3), round(template['x1'], 3),
        round(template['y2'], 3), round(template['x2'], 3)]
    return option


def render_pep440_pre(pieces):
    """TAG[.post.devDISTANCE] -- No -dirty.

    Exceptions:
    1: no tags. 0.post.devDISTANCE
    """
    if pieces['closest-tag']:
        rendered = pieces['closest-tag']
        if pieces['distance']:
            rendered += '.post.dev%d' % pieces['distance']
    else:
        rendered = '0.post.dev%d' % pieces['distance']
    return rendered


@conf
def find_openf95(conf):
    """Find the Open64 Fortran Compiler (will look in the environment variable 'FC')"""
    fc = conf.find_program(['openf95', 'openf90'], var='FC')
    conf.get_open64_version(fc)
    conf.env.FC_NAME = 'OPEN64'
    conf.env.FC_MOD_CAPITALIZATION = 'UPPER.mod'


@staticmethod
def positional_to_model(value):
    """Converts a positional argument to a model value"""
    return value


@staticmethod
def disconnect(controller_widget, control_name, control_instance):
    """ Disconnect an 'Enum' controller trait and an 'EnumControlWidget'
        controller widget control.

        Parameters
        ----------
        controller_widget: ControllerWidget (mandatory)
            a controller widget that contains the controller we want to update
        control_name: str(mandatory)
            the name of the controller widget control we want to synchronize
            with the controller
        control_instance: QComboBox (mandatory)
            the instance of the controller widget control we want to
            synchronize with the controller
        """
    widget_hook, controller_hook = control_instance._controller_connections
    controller_widget.controller.on_trait_change(controller_hook, name=
        control_name, remove=True)
    control_instance.activated.disconnect(widget_hook)
    del control_instance._controller_connections


def resolve_name(name):
    """Resolve a name like ``module.object`` to an object and return it.

    Raise `ImportError` if the module or name is not found.
    """
    parts = name.split('.')
    cursor = len(parts) - 1
    module_name = parts[:cursor]
    attr_name = parts[-1]
    while cursor > 0:
        try:
            ret = __import__('.'.join(module_name), fromlist=[attr_name])
            break
        except ImportError:
            if cursor == 0:
                raise
            cursor -= 1
            module_name = parts[:cursor]
            attr_name = parts[cursor]
            ret = ''
    for part in parts[cursor:]:
        try:
            ret = getattr(ret, part)
        except AttributeError:
            raise ImportError(name)
    return ret


def keras_wrap(model, target, output, loss):
    """ Convenience function for wrapping a Keras loss function.
	"""
    import keras.objectives as O
    import keras.backend as K
    if isinstance(loss, str):
        loss = O.get(loss)
    shape = model.outputs[target].value._keras_shape
    ins = [(target, K.placeholder(ndim=len(shape), dtype=K.dtype(model.
        outputs[target].value), name=target))]
    out = loss(ins[0][1], output)
    return ins, out


def add_wire_length_args(parser):
    """Add arguments for specifying sets of wire lengths available for a given
	system."""
    wire_length_group = parser.add_argument_group('available wire lengths')
    wire_length_group.add_argument('--wire-length', '-l', type=float,
        metavar='L', action='append', nargs='+', help=
        'specify one or more available wire lengths in meters')
    wire_length_group.add_argument('--minimum-slack', type=float, metavar=
        'H', default=0.05, help=
        'the minimum slack to allow in a wire connecting two boards in meters')


def byte_display(size):
    """
    Returns a string with the correct unit (KB, MB), given the size in bytes.
    """
    if size == 0:
        return '0 KB'
    if size <= 1024:
        return '%s bytes' % size
    if size > 1048576:
        return '%0.02f MB' % (size / 1048576.0)
    return '%0.02f KB' % (size / 1024.0)


@staticmethod
def always(src, dst, fn):
    """Always overwrite files on conflict."""
    return True


def _node_parse_command_and_opt(**opts_dict):
    """Return 'command' and 'command_opt' from **opts_dict.

    Find which command has a non null attribute and returns it.

    >>> _node_parse_command_and_opt(firmware_path='/tmp/test',
    ...                             profile_name=None,
    ...                             profile_path=None,
    ...                             command='with_argument')
    ('flash', '/tmp/test')

    >>> _node_parse_command_and_opt(firmware_path=None,
    ...                             profile_name='consumption',
    ...                             profile_path=None,
    ...                             command='with_argument')
    ('profile', 'consumption')

    >>> _node_parse_command_and_opt(firmware_path=None,
    ...                             profile_name=None,
    ...                             profile_path='/tmp/prof.json',
    ...                             command='with_argument')
    ('profile-load', '/tmp/prof.json')

    # Case where the command is not managed
    >>> _node_parse_command_and_opt(firmware_path=None,
    ...                             profile_name=None,
    ...                             profile_path=None,
    ...                             command='with_argument')
    Traceback (most recent call last):
    ...
    ValueError: Unknown command
    """
    commands_arguments = {'flash': 'firmware_path', 'profile':
        'profile_name', 'profile-load': 'profile_path'}
    for command, argname in commands_arguments.items():
        cmd_opt = opts_dict.get(argname, None)
        if cmd_opt is not None:
            return command, cmd_opt
    raise ValueError('Unknown command')


def get_shapes_generator(mobj):
    """
    Returns a generator of all shape nodes for the provided transform node
    :param mobj: MObject, MObject to get teh shape nodes of
    :return: generator
    """
    import maya.OpenMaya as OpenMaya
    if not mobj.apiType() == OpenMaya.MFn.kTransform:
        return
    path = OpenMaya.MDagPath.getAPathTo(mobj)
    num_shapes = OpenMaya.MScriptUtil()
    num_shapes.createFromInt(0)
    num_shapes_ptr = num_shapes.asUintPtr()
    path.numberOfShapesDirectlyBelow(num_shapes_ptr)
    for index in range(OpenMaya.MScriptUtil(num_shapes_ptr).asUint()):
        p = OpenMaya.MDagPath.getAPathTo(mobj)
        p.extendToShapeDirectlyBelow(index)
        yield p.node()


@staticmethod
def _handle_hearbeat(*args, **kwargs):
    """
        By default, does nothing.
        :param args:
        :param kwargs:
        :return:
        """
    pass


def _get_base_url(request):
    """
    Construct a base URL, given a request object.

    This comprises the protocol prefix (http:// or https://) and the host,
    which can include the port number. For example:
    http://www.openquake.org or https://www.openquake.org:8000.
    """
    if request.is_secure():
        base_url = 'https://%s'
    else:
        base_url = 'http://%s'
    base_url %= request.META['HTTP_HOST']
    return base_url


def _ensure_sparse_format(spmatrix, accept_sparse, dtype, copy,
    force_all_finite, accept_large_sparse):
    """Convert a sparse matrix to a given format.

    Checks the sparse format of spmatrix and converts if necessary.

    Parameters
    ----------
    spmatrix : scipy sparse matrix
        Input to validate and convert.

    accept_sparse : string, boolean or list/tuple of strings
        String[s] representing allowed sparse matrix formats ('csc',
        'csr', 'coo', 'dok', 'bsr', 'lil', 'dia'). If the input is sparse but
        not in the allowed format, it will be converted to the first listed
        format. True allows the input to be any format. False means
        that a sparse matrix input will raise an error.

    dtype : string, type or None
        Data type of result. If None, the dtype of the input is preserved.

    copy : boolean
        Whether a forced copy will be triggered. If copy=False, a copy might
        be triggered by a conversion.

    force_all_finite : boolean or 'allow-nan', (default=True)
        Whether to raise an error on np.inf and np.nan in X. The possibilities
        are:

        - True: Force all values of X to be finite.
        - False: accept both np.inf and np.nan in X.
        - 'allow-nan': accept only np.nan values in X. Values cannot be
          infinite.

        .. versionadded:: 0.20
           ``force_all_finite`` accepts the string ``'allow-nan'``.

    Returns
    -------
    spmatrix_converted : scipy sparse matrix.
        Matrix that is ensured to have an allowed type.
    """
    if dtype is None:
        dtype = spmatrix.dtype
    changed_format = False
    if isinstance(accept_sparse, str):
        accept_sparse = [accept_sparse]
    if accept_sparse is False:
        raise TypeError(
            'A sparse tensor was passed, but dense data is required. Use X.todense() to convert to a dense tensor.'
            )
    elif isinstance(accept_sparse, (list, tuple)):
        if len(accept_sparse) == 0:
            raise ValueError(
                "When providing 'accept_sparse' as a tuple or list, it must contain at least one string value."
                )
    elif accept_sparse is not True:
        raise ValueError(
            "Parameter 'accept_sparse' should be a string, boolean or list of strings. You provided 'accept_sparse={}'."
            .format(accept_sparse))
    if dtype != spmatrix.dtype:
        spmatrix = spmatrix.astype(dtype)
    elif copy and not changed_format:
        spmatrix = spmatrix.copy()
    return spmatrix


def __call__(cls, *args, **kwargs):
    """Execute check_required_attributes() when class is called."""
    class_object = type.__call__(cls, *args, **kwargs)
    class_object.check_required_attributes()
    return class_object


@classmethod
def _hash_key_attribute(cls):
    """
        Returns the attribute class for the hash key
        """
    return cls.get_attributes()[cls._hash_keyname]


def expandRanges(ranges, size):
    """Expand Range sets, given those sets and the length of the resource.

    Expansion means relative start values and open ends
    """
    expanded = []
    add = expanded.append
    for start, end in ranges:
        if start < 0:
            start = size + start
        end = end or size
        if end > size:
            end = size
        if start < size:
            add((start, end))
    return expanded


@classmethod
def rewind_policy_changed_details(cls, val):
    """
        Create an instance of this class set to the
        ``rewind_policy_changed_details`` tag with value ``val``.

        :param RewindPolicyChangedDetails val:
        :rtype: EventDetails
        """
    return cls('rewind_policy_changed_details', val)


@classmethod
def alias(cls, typemap, base, *names):
    """ Declare an alternate (humane) name for a measurement protocol parameter """
    cls.parameter_alias[base] = typemap, base
    for i in names:
        cls.parameter_alias[i] = typemap, base


def p_statement_show_create_table(p):
    """statement : SHOW CREATE TABLE identifier"""
    p[0] = p[1:]


def get_first_publication_date():
    """Get the earliest publication date of any version of this Content.
        Needed for rss/atom feeds.
        """


def p_enum_constant_list_2(t):
    """enum_constant_list : enum_constant COMMA enum_constant_list"""
    t[0] = t[1] + t[3]


def extract_fields(header, field_name, save_rest=False):
    """
    Extract the specified fields from the pairs header and returns
    a list of corresponding values, even if a single field was found.
    Additionally, can return the list of intact non-matching entries.
    """
    fields = []
    rest = []
    for l in header:
        if l.lstrip('#').startswith(field_name + ':'):
            fields.append(l.split(':', 1)[1].strip())
        elif save_rest:
            rest.append(l)
    if save_rest:
        return fields, rest
    else:
        return fields