def absolute_or_percentage_within(string, low, high):
    """
    Parse a string giving a value as either an absolute float value or a
    percentage. Throws a ValueError when outside the stated range.
    """
    string = string.strip()
    if string.endswith('%'):
        perc = float(string.rstrip('%')) / 100.0
        value = low + (high - low) * perc
    else:
        value = float(string)
    if not low <= value <= high:
        raise ValueError('Value must be between {} and {}'.format(low, high))
    return value


def unregister(viewer):
    """
        Stop tracking the *viewer*.
        """


def p_expression_to_list_of_something(p):
    """
    code_expression_parenthetical : '(' list_of_expressions ')'
    """
    p[0] = p[2]


def filter_ice_border(ice_thick):
    """Sets the ice thickness at the border of the domain to zero."""
    ice_thick[(0), :] = 0
    ice_thick[(-1), :] = 0
    ice_thick[:, (0)] = 0
    ice_thick[:, (-1)] = 0
    return ice_thick


@staticmethod
def stuff_predictor_into_envelope(predictor: dict) ->dict:
    """Insert a serialized embedded predictor into a module envelope, to facilitate deser."""
    return dict(module_type='PREDICTOR', config=predictor, active=False,
        schema_id='43c61ad4-7e33-45d0-a3de-504acb4e0737')


def with_std_options(arg_parser):
    """Embellish the provided `arg_parser` with standard options.
    """
    arg_parser.add_argument('-a', '--account', metavar='<ACCOUNT-ID>',
        action='store', help=
        'For cloud, see https://api.draftable.com/account/credentials')
    arg_parser.add_argument('-b', '--base-url', metavar='<BASE-URL>',
        action='store', help='Only for Enterprise self-hosted')
    arg_parser.add_argument('-e', '--env-name', metavar='<ENV-NAME>',
        action='store', help='Name from file $HOME/.draftable')
    arg_parser.add_argument('-t', '--token', metavar='<TOKEN>', action=
        'store', help=
        'For cloud, see https://api.draftable.com/account/credentials')
    arg_parser.add_argument('-S', '--unverified-ssl', action='store_true',
        help=
        "Don't verify SSL validity; useful for self-hosted self-signed SSL")
    return arg_parser


def get_class(path):
    """
  Gets the class of a given file (name of the subdirectory it is in)
  """
    absolute_subdirectory = path[:path.rfind('/')]
    return absolute_subdirectory[absolute_subdirectory.rfind('/') + 1:]


@staticmethod
def IsValid(arg):
    """Check whether an argument is valid

        Args:
            arg (obj): Object which is getting checked
        Returns:
            (bool) Returns true on success or false on failure
        """
    if not arg:
        return False
    return True


@classmethod
def build(cls, id_data, id_rho):
    """constructor wrapper"""
    data = cls()
    data.id_data = id_data
    data.id_rho = id_rho
    return data


def get_jsonpath_val(json_obj, path_str):
    """Get json attribute value from a path.

  Args:
    json_obj: json object.
    path_str: attribute path as key1.key2.key3
  Returns:
    value of the given path, if not valid, return None.
  """
    keys = path_str.split('.')
    cur_val = None
    for cur_key in keys:
        if cur_key in json_obj:
            cur_val = json_obj[cur_key]
        else:
            cur_val = None
            break
    return cur_val


def dayOfYear():
    """Return the day of the year, in context of the timezone
        representation of the object"""


@classmethod
def get_name(cls):
    """ Returns the name of the evaluation hook.
		"""
    return 'transcript'


def inRegionDict(chrom, start, end, regionDict):
    """Checks the given mutation location to see if it is in the dictionary of regions"""
    if regionDict[chrom]:
        for locs in regionDict[chrom]:
            if locs[0] == 0 and locs[1] == 0:
                return True
            elif int(start) >= int(locs[0]) and int(end) <= int(locs[1]):
                return True
    return False


def get_tweets_iter(toolkit_collection, since, until, cap):
    """
    Returns a pymongo cursor to iterate over a maximum of `cap` tweets,
    between `since` and `until`. Uses sampling if there are really more
    tweets than `cap` in that period.
    """
    tweets = toolkit_collection.since(since).until(until)
    count = tweets.count()
    sample_rate = cap / count if count > cap else None
    if sample_rate:
        tweets = tweets.sample(sample_rate)
    return tweets


def create_uvsphere(bm: 'bmesh.types.BMesh', u_segments: int, v_segments:
    int, diameter: float, matrix: 'mathutils.Matrix', calc_uvs: bool) ->dict:
    """Creates a grid with a variable number of subdivisions

    :param bm: The bmesh to operate on.
    :type bm: 'bmesh.types.BMesh'
    :param u_segments: number of u segments
    :type u_segments: int
    :param v_segments: number of v segment
    :type v_segments: int
    :param diameter: diameter
    :type diameter: float
    :param matrix: matrix to multiply the new geometry with
    :type matrix: 'mathutils.Matrix'
    :param calc_uvs: calculate default UVs
    :type calc_uvs: bool
    :return:  verts: output vertstype list of (bmesh.types.BMVert)
    """
    pass


def _coeff_isneg(a):
    """Return True if the leading Number is negative.

    Examples
    ========

    >>> _coeff_isneg(-3*pi)
    True
    >>> _coeff_isneg(Integer(3))
    False
    >>> _coeff_isneg(-oo)
    True
    >>> _coeff_isneg(Symbol('n', negative=True))  # coeff is 1
    False

    """
    if a.is_Mul or a.is_MatMul:
        a = a.args[0]
    return a.is_Number and a.is_negative


def merge_dicts(*dict_args):
    """
    Given any number of dicts, shallow copy and merge into a new dict,
    precedence goes to key value pairs in latter dicts.
    https://stackoverflow.com/questions/38987/how-to-merge-two-dictionaries-in-a-single-expression
    """
    result = {}
    for dictionary in dict_args:
        result.update(dictionary)
    return result


def index():
    """Return the position (starting with "0") within the iteration
        """


def select_linked(extend: bool=False):
    """Select bones related to selected ones by parent/child relationships

    :param extend: Extend, Extend selection instead of deselecting everything first
    :type extend: bool
    """
    pass


@classmethod
def get_valid_keys(cls):
    """
        Return a list of valid keys to be passed to the __init__
        """
    return list(cls._default_fields)


@classmethod
def is_datasource_for(cls, data, header, **kwargs):
    """Determines if header corresponds to an AIA image"""
    return str(header.get('instrume', '')).startswith(
        'GOES-R Series Solar Ultraviolet Imager')


def export_items(items, export_file, quiet=False):
    """
    Exports the given `items` to the given text `export_file`.  If `quiet` is
    `False`, only errors will be printed.
    """
    with open(export_file, 'w') as df:
        for item in items:
            if item.eng_name:
                print('# {} ({})'.format(item.eng_name, item.get_level_eng(
                    )), file=df)
            else:
                print('# unknown item', file=df)
            print(item.get_serial_base64(), file=df)
            print('', file=df)
    if not quiet:
        print('Wrote {} items (in base64 format) to {}'.format(len(items),
            export_file))


def curve_detail(detail_value):
    """Change the resolution used to draw bezier curves.

    :param detail_value: New resolution to be used.
    :type detail_value: int
    """
    global curve_resolution
    curve_resolution = detail_value


def unique_key(adict):
    """ Obtain a unique key given a dictionary."""
    allkeys = list(adict.keys())
    done = False
    n = 1
    while not done:
        newkey = '__l%s' % n
        if newkey in allkeys:
            n += 1
        else:
            done = True
    return newkey


def uuid_adapter(obj, request):
    """Format the fields.UUID to return String

    ::

        from pyramid.renderers import JSON
        from uuid import UUID
        json_renderer = JSON()
        json_renderer.add_adapter(UUID, uuid_adapter)
        config.add_renderer('json', json_renderer)

    :param obj: uuid obj
    :rtype: str
    """
    return str(obj.hex)


@classmethod
def parser(cls, **kwargs):
    """Construct argument parser"""
    parser = super().parser(**kwargs)
    persist = parser.add_mutually_exclusive_group()
    persist.add_argument('--persist', action='store_true', default=True,
        help='Refresh and persist (default)')
    persist.add_argument('--no-persist', action='store_false', dest=
        'persist', help='Refresh only')
    strict = parser.add_mutually_exclusive_group()
    strict.add_argument('--strict', action='store_true', help=
        'Identify matching entries only by permanent UUID')
    strict.add_argument('--no-strict', action='store_false', dest='strict',
        default=False, help='Guess matching entries where possible (default)')
    delete = parser.add_mutually_exclusive_group()
    delete.add_argument('--delete', action='store_true', help=
        'Allow deletion of entries')
    delete.add_argument('--no-delete', action='store_false', dest='delete',
        default=False, help='Disable deleted entries (default)')
    parser.add_argument('config', help='Configuration file')
    return parser


def isfloat(value):
    """
    Check input for float conversion.

    :param value: input value
    :type value:str
    :return: result as bool (true if input_value is a number and false otherwise)
    """
    try:
        float(value)
        return True
    except Exception:
        return False


def get_ui_library():
    """
    Returns the library that is being used
    """
    try:
        import PyQt5
        qt = 'PyQt5'
    except ImportError:
        try:
            import PyQt4
            qt = 'PyQt4'
        except ImportError:
            try:
                import PySide2
                qt = 'PySide2'
            except ImportError:
                try:
                    import PySide
                    qt = 'PySide'
                except ImportError:
                    raise ImportError('No valid Gui library found!')
    return qt


def formula_2013_01_01(foyer_fiscal, period, parameters):
    """
        Prelèvement forfaitaire libératoire (PFL) sur les revenus du capital
        Notes :
          (1) La formule avant 2013 provient de l'ancienne variable 'imp_lib'.
              A priori, cette ancienne formule n'est pas entièrement correcte (application d'un taux unique à la case 2EE par exemple) et mériterait d'être corrigée.
          (2) Cette variable ne comprend pas la taxation forfaitaire à 24% associée
              à la base f2fa, qui est prise en compte via la variable tax_rvcm_forfaitaire,
              qui est incluse dans irpp. Cette taxaiton à 24% est certes forfaitaire,
              mais apparemment pas à la source. Elle serait calculée au moment de l'irpp,
              d'où le fait de l'inclure dans la variable IRPP.
        """
    assurance_vie_pl_non_anonyme_plus8ans_depuis1990 = foyer_fiscal(
        'assurance_vie_pl_non_anonyme_plus8ans_depuis1990', period)
    assurance_vie_pl_non_anonyme_plus6ans_avant1990 = foyer_fiscal(
        'assurance_vie_pl_non_anonyme_plus6ans_avant1990', period)
    assurance_vie_pl_non_anonyme_moins4ans_depuis1990 = foyer_fiscal(
        'assurance_vie_pl_non_anonyme_moins4ans_depuis1990', period)
    assurance_vie_pl_non_anonyme_4_8_ans_depuis1990 = foyer_fiscal(
        'assurance_vie_pl_non_anonyme_4_8_ans_depuis1990', period)
    assurance_vie_pl_anonyme = foyer_fiscal('assurance_vie_pl_anonyme', period)
    produit_epargne_solidaire = foyer_fiscal('produit_epargne_solidaire',
        period)
    produit_etats_non_cooperatif = foyer_fiscal('produit_etats_non_cooperatif',
        period)
    param_pfl_av = (parameters(period).taxation_capital.pfl_av.
        bons_ou_contrats_de_capitalisation_et_placements_de_meme_nature_assurance_vie_lors_du_denouement_du_contrat
        )
    param_pfl = parameters(period).taxation_capital.pfl
    pfl = -(param_pfl_av.souscrits_apres_le_1_1_90_et_le_pour_une_duree_de.
        duree_8_ans_et_plus_pour_les_produits_acquis_apres_le_01_01_1998_avec_abattement_sur_l_ir_5
         * assurance_vie_pl_non_anonyme_plus8ans_depuis1990 + param_pfl_av.
        souscrits_entre_le_1_1_83_et_le_31_12_89_pour_une_duree_de.
        duree_6_ans_et_plus_pour_les_produits_acquis_apres_le_01_01_1998_avec_abattement_sur_l_ir_5
         * assurance_vie_pl_non_anonyme_plus6ans_avant1990 + param_pfl_av.
        souscrits_apres_le_1_1_90_et_le_pour_une_duree_de.
        duree_moins_de_4_ans *
        assurance_vie_pl_non_anonyme_moins4ans_depuis1990 + param_pfl_av.
        souscrits_apres_le_1_1_90_et_le_pour_une_duree_de.duree_4_a_8_ans *
        assurance_vie_pl_non_anonyme_4_8_ans_depuis1990 + param_pfl_av.
        avec_anonymat * assurance_vie_pl_anonyme + param_pfl.
        produits_epargne_solidaire_partage * produit_epargne_solidaire +
        param_pfl.produits_vers_etats_non_cooperatifs *
        produit_etats_non_cooperatif)
    return pfl


def calculate_bounding_box_from_image(im, curr_page):
    """This function uses a PIL routine to get the bounding box of the rendered
    image."""
    xMax, y_max = im.size
    bounding_box = im.getbbox()
    if not bounding_box:
        bounding_box = xMax / 2, y_max / 2, xMax / 2, y_max / 2
    bounding_box = list(bounding_box)
    bounding_box[1] = y_max - bounding_box[1]
    bounding_box[3] = y_max - bounding_box[3]
    full_page_box = curr_page.mediaBox
    convert_x = float(full_page_box.getUpperRight_x() - full_page_box.
        getLowerLeft_x()) / xMax
    convert_y = float(full_page_box.getUpperRight_y() - full_page_box.
        getLowerLeft_y()) / y_max
    final_box = [bounding_box[0] * convert_x, bounding_box[3] * convert_y,
        bounding_box[2] * convert_x, bounding_box[1] * convert_y]
    return final_box


def isretweet(tweet):
    """
    Checks if a given tweet is a retweet.
    If tweet is a string, returns True when text starts with 'RT '.
    If tweet is a tweepy.Status object, returns True when ``retweeted_status`` or
    ``retweeted_status_id`` is set.

    Args:
        tweet (str/tweepy.Status/dict): A string, tweepy.Status object, or Status-like dict.

    Returns:
        bool
    """
    try:
        return bool(tweet.retweeted)
    except AttributeError:
        try:
            return bool(tweet.get('retweeted_status') or tweet.get(
                'retweeted_status_id'))
        except AttributeError:
            try:
                return tweet[:3].upper() == 'RT '
            except AttributeError:
                pass
    return False


def get_sta_coords(stfile):
    """Stub which reads in the HASH example station file"""
    f = open(stfile)
    sta_coords = {}
    for s in f:
        sta = s[0:4]
        lat = float(s[42:50])
        lon = float(s[51:61])
        elv = float(s[62:67]) / 1000.0
        if sta in sta_coords:
            pass
        else:
            sta_coords[sta] = [lat, lon, elv]
    f.close()
    return sta_coords


@staticmethod
def _getCodes(map, bit_chain):
    """Returns a list with the corresponding fields as set in the bitChain (hex string)
        """
    code_list = []
    bit_chain = int(bit_chain, 16)
    map_length = len(map)
    for i in reversed(list(range(map_length))):
        if bit_chain & 2 ** i:
            code_list.append(map[map_length - i - 1])
    return code_list


def parser_to_dict(parser):
    """ Given a parser, generate mongo args """
    args = {}
    if parser.id:
        args['id'] = parser.id
    if parser.name:
        args['name'] = parser.name
    if parser.status:
        args['status'] = parser.status
    if parser.owner:
        args['owner'] = parser.owner
    if parser.recruiter:
        args['recruiter'] = parser.recruiter
    if parser.code_review:
        args['code_review'] = parser.code_review
    return args


def _cite_setup_parser(parser):
    """
    Set up the openmdao subparser for the 'openmdao cite' command.

    Parameters
    ----------
    parser : argparse subparser
        The parser we're adding options to.
    """
    parser.add_argument('file', nargs=1, help=
        'Python file containing the model.')
    parser.add_argument('-o', default=None, action='store', dest='outfile',
        help='Name of output file.  By default, output goes to stdout.')
    parser.add_argument('-c', '--class', action='append', default=[], dest=
        'classes', help='Find citation for this class.')


def restrict(query, **kw):
    """return *query* potentially with additional restrictions."""


def Clip(a, b, c):
    """
    Clips the value in `a` based on the extremes `b` and `c`.

    :param `a`: the value to analyze;
    :param `b`: a minimum value;
    :param `c`: a maximum value.
    """
    return (a < b and [b] or [(a > c and [c] or [a])[0]])[0]


def p_InterfaceMembers_empty(p):
    """InterfaceMembers : """
    p[0] = []


def _getActivePassive(obj1, obj2):
    """ Returns which is the active and the passive objects. """
    speed1 = abs(obj1.lonspeed) if obj1.isPlanet() else -1.0
    speed2 = abs(obj2.lonspeed) if obj2.isPlanet() else -1.0
    if speed1 > speed2:
        return {'active': obj1, 'passive': obj2}
    else:
        return {'active': obj2, 'passive': obj1}


def make_anisotropic(dim, anis, y, z):
    """Re-stretch given axes."""
    if dim == 1:
        return y, z
    if dim == 2:
        return y * anis[0], z
    if dim == 3:
        return y * anis[0], z * anis[1]
    return None


@classmethod
def get_default_format(klass):
    """Return the current default format."""
    return klass._default_format


def _get_count(queryset):
    """Determine an object count, supporting either queryset or regular list. Optimized to use only `id`"""
    try:
        return queryset.values('id').count()
    except (AttributeError, TypeError):
        return len(queryset)


@classmethod
def from_htmlfile(cls, path, encoding=None):
    """ Load the color mapping from WebAnnotator-annotated HTML file """
    with open(path, 'rb') as f:
        return cls.from_htmlbytes(f.read(), encoding=encoding)


def lbfft22mbar(press_lbfft2):
    """Convert pressure value from lb/ft^2 to mbar"""
    return press_lbfft2 / 2.08854


def _tr_paren(line_info):
    """Translate lines escaped with: /"""
    return '%s%s(%s)' % (line_info.pre, line_info.ifun, ', '.join(line_info
        .the_rest.split()))


def __call__(service_name, service_user_id, raw_user):
    """returns string, unique amongst plugins userids
        """


def _calc_uvw_per_ant(cache, name, ant):
    """Calculate (u,v,w) coordinates per antenna using sensor cache contents."""
    array_antenna = cache.get('Antennas/array/antenna')[0]
    antenna = cache.get('Antennas/%s/antenna' % (ant,))[0]
    basis = cache.get('Antennas/array/basis_' + name[-1])
    baseline_m = array_antenna.baseline_toward(antenna)
    coord = basis.dot(baseline_m)
    cache[name] = coord
    return coord


def hexify(value):
    """ Takes variously formatted hex values and outputs them as a int """
    out = 0
    if value:
        out = int(value.replace('0x', ''), 16) if isinstance(value, str
            ) else value
    return out


def name_from_hcs_orient_vcs(hcs, orient=None, vcs=None):
    """
    Construct a coordinate system name from an hcs, orientation and vcs.  If orient or vcs are None or
    empty, the name will not include these parts.

    :param hcs:     horizontal coordinate system string
    :param orient:  orientation string
    :param vcs:     vertical coordinate system string
    :returns: "hcs <orient> [vcs]"

    .. versionadded:: 9.2
    """
    if orient:
        orient = ' <' + orient + '>'
    else:
        orient = ''
    if vcs:
        vcs = ' [' + vcs + ']'
    else:
        vcs = ''
    return hcs + orient + vcs


def get_spore_method_name(keys: list, action: str) ->str:
    """

    TODO: better annotations in python3.6
    TODO: enhance name of func. not optimal yet !
    """
    if not keys:
        return action
    object_name = '_'.join(keys)
    if action in ('list',):
        if not object_name.endswith('s'):
            object_name = object_name + 's'
    elif object_name.endswith('s'):
        object_name = object_name.rstrip('s')
    return '{}_{}'.format(action, object_name)


def add_plugins_to_uninstall(ctx, plugins_to_uninstall, sequence):
    """Adds a task to the sequence that uninstalls the plugins.
    """
    if not sequence or not ctx or not plugins_to_uninstall:
        return
    sequence.add(ctx.send_event(
        'Uninstalling deployment and workflow plugins'), ctx.execute_task(
        task_name='cloudify_agent.operations.uninstall_plugins', kwargs={
        'plugins': plugins_to_uninstall, 'delete_managed_plugins': False}))


@classmethod
def hash_from_func(cls, func):
    """Return a hashlib-compatible object for the multihash `func`.

        If the `func` is registered but no hashlib-compatible constructor is
        available for it, `None` is returned.  If the `func` is not
        registered, a `KeyError` is raised.

        >>> h = FuncReg.hash_from_func(Func.sha2_256)
        >>> h.name
        'sha256'
        """
    new = cls._func_hash[func].new
    return new() if new else None


def revoke_cluster_security_group_ingress(ClusterSecurityGroupName=None,
    CIDRIP=None, EC2SecurityGroupName=None, EC2SecurityGroupOwnerId=None):
    """
    Revokes an ingress rule in an Amazon Redshift security group for a previously authorized IP range or Amazon EC2 security group. To add an ingress rule, see  AuthorizeClusterSecurityGroupIngress . For information about managing security groups, go to Amazon Redshift Cluster Security Groups in the Amazon Redshift Cluster Management Guide .
    See also: AWS API Documentation

    :example: response = client.revoke_cluster_security_group_ingress(
        ClusterSecurityGroupName='string',
        CIDRIP='string',
        EC2SecurityGroupName='string',
        EC2SecurityGroupOwnerId='string'
    )

    :type ClusterSecurityGroupName: string
    :param ClusterSecurityGroupName: [REQUIRED]
            The name of the security Group from which to revoke the ingress rule.

    :type CIDRIP: string
    :param CIDRIP: The IP range for which to revoke access. This range must be a valid Classless Inter-Domain Routing (CIDR) block of IP addresses. If CIDRIP is specified, EC2SecurityGroupName and EC2SecurityGroupOwnerId cannot be provided.

    :type EC2SecurityGroupName: string
    :param EC2SecurityGroupName: The name of the EC2 Security Group whose access is to be revoked. If EC2SecurityGroupName is specified, EC2SecurityGroupOwnerId must also be provided and CIDRIP cannot be provided.

    :type EC2SecurityGroupOwnerId: string
    :param EC2SecurityGroupOwnerId: The AWS account number of the owner of the security group specified in the EC2SecurityGroupName parameter. The AWS access key ID is not an acceptable value. If EC2SecurityGroupOwnerId is specified, EC2SecurityGroupName must also be provided. and CIDRIP cannot be provided.
            Example: 111122223333

    :rtype: dict
    :return: {
        'ClusterSecurityGroup': {
            'ClusterSecurityGroupName': 'string',
            'Description': 'string',
            'EC2SecurityGroups': [
                {
                    'Status': 'string',
                    'EC2SecurityGroupName': 'string',
                    'EC2SecurityGroupOwnerId': 'string',
                    'Tags': [
                        {
                            'Key': 'string',
                            'Value': 'string'
                        },
                    ]
                },
            ],
            'IPRanges': [
                {
                    'Status': 'string',
                    'CIDRIP': 'string',
                    'Tags': [
                        {
                            'Key': 'string',
                            'Value': 'string'
                        },
                    ]
                },
            ],
            'Tags': [
                {
                    'Key': 'string',
                    'Value': 'string'
                },
            ]
        }
    }

    """
    pass


def getAffiliation(entity):
    """
        Get affiliation of entity with this node.

        @param entity: JID of entity.
        @type entity: L{JID<twisted.words.protocols.jabber.jid.JID>}
        @return: deferred that returns C{'owner'}, C{'publisher'}, C{'outcast'}
                 or C{None}.
        """


@classmethod
def node_info(cls, node, attrpath, attrpaths, siblings, level, value_dims):
    """
        Given a node, return relevant information.
        """
    if hasattr(node, 'children'):
        lvl, lines = level, [(level, cls.component_type(node))]
    elif hasattr(node, 'main'):
        lvl, lines = cls.adjointlayout_info(node, siblings, level, value_dims)
    elif getattr(node, '_deep_indexable', False):
        lvl, lines = cls.ndmapping_info(node, siblings, level, value_dims)
    elif hasattr(node, 'unit_format'):
        lvl, lines = level, [(level, repr(node))]
    else:
        lvl, lines = cls.element_info(node, siblings, level, value_dims)
    if attrpath is not None:
        padding = cls.padding(attrpaths)
        fst_lvl, fst_line = lines[0]
        lines[0] = fst_lvl, '.' + attrpath.ljust(padding) + ' ' + fst_line
    return lvl, lines


def _make_header_wsgi_env_key(http_header: str) ->str:
    """Convert HTTP header to WSGI environ key format.

    HTTP_ Variables corresponding to the client-supplied HTTP request
    headers (i.e., variables whose names begin with "HTTP_").
    See https://www.python.org/dev/peps/pep-3333/ for more details

    >>> print(_make_header_wsgi_env_key("X-USERNAME"))
    HTTP_X_USERNAME
    """
    return 'HTTP_' + http_header.replace('-', '_').upper()


def fc_get_limits(mu_bins, x_bins, acceptance_intervals):
    """Find lower and upper limit from acceptance intervals.

    For more information see :ref:`documentation <feldman_cousins>`.

    Parameters
    ----------
    mu_bins : array-like
        The bins used in mue direction.
    x_bins : array-like
        The bins of the x distribution
    acceptance_intervals : array-like
        The output of fc_construct_acceptance_intervals_pdfs.

    Returns
    -------
    lower_limit : array-like
        Feldman Cousins lower limit x-coordinates
    upper_limit : array-like
        Feldman Cousins upper limit x-coordinates
    x_values : array-like
        All the points that are inside the acceptance intervals
    """
    upper_limit = []
    lower_limit = []
    x_values = []
    number_mu = len(mu_bins)
    number_bins_x = len(x_bins)
    for mu in range(number_mu):
        upper_limit.append(-1)
        lower_limit.append(-1)
        x_values.append([])
        acceptance_interval = acceptance_intervals[mu]
        for x in range(number_bins_x):
            if acceptance_interval[x] == 1:
                x_value = x_bins[x]
                x_values[-1].append(x_value)
                if upper_limit[-1] == -1:
                    upper_limit[-1] = x_value
                if x == number_bins_x - 1:
                    lower_limit[-1] = x_value
                else:
                    lower_limit[-1] = x_bins[x + 1]
    return lower_limit, upper_limit, x_values


def get_git_description():
    """Open .git/description and determine if description exists."""
    try:
        with open('./.git/description', 'r') as git_desc:
            for line in git_desc:
                if line.startswith('Unnamed repository;'):
                    return 'YOUR PROJECT DESCRIPTION HERE'
                else:
                    return git_desc.read()
    except FileNotFoundError:
        return 'YOUR PROJECT DESCRIPTION HERE'


def bone_layers(layers: bool=(False, False, False, False, False, False,
    False, False, False, False, False, False, False, False, False, False,
    False, False, False, False, False, False, False, False, False, False,
    False, False, False, False, False, False)):
    """Change the layers that the selected bones belong to

    :param layers: Layer, Armature layers that bone belongs to
    :type layers: bool
    """
    pass


def print_bold(msg, end='\n'):
    """Convenience function to print a message in bold style

    Optionally you can also specify how the bold text should end. By default
    it ends with a new line character.

    :arg msg: Message to be converted to bold style
    :arg end: Tell how the printed string should end (newline, space etc)
    """
    print('\x1b[1m' + msg + '\x1b[0m', end=end)


@staticmethod
def dtype_to_struct(dt, structname='mystruct', enums=None):
    """Convert a NumPy dtype object describing a record array to
        a typedef struct statement.

        The second argument is the name of the structure.
        If any of the columns are enum types, enums must
        be a dictionary with the keys the column names, and the values
        are a tuple containing the name of the enum type as the first item
        and a tuple or list of possible values as the second item.

        Parameters
        ----------
        dt : :class:`numpy.dtype`
            The dtype of a NumPy record array.
        structname : :class:`str`, optional
            The name to give the structure in the yanny file.  Defaults to
            'MYSTRUCT'.
        enums : :class:`dict`, optional
            A dictionary containing enum information.  See details above.

        Returns
        -------
        :class:`dict`
            A dictionary suitable for setting the 'symbols' dictionary of a
            new yanny object.

        Examples
        --------
        """
    dtmap = {'i2': 'short', 'i4': 'int', 'i8': 'long', 'f4': 'float', 'f8':
        'double'}
    returnenums = list()
    if enums is None:
        enums = dict()
    else:
        for e in enums:
            lines = list()
            lines.append('typedef enum {')
            for n in enums[e][1]:
                lines.append('    {0},'.format(n))
            lines[-1] = lines[-1].strip(',')
            lines.append('}} {0};'.format(enums[e][0].upper()))
            returnenums.append('\n'.join(lines))
    lines = list()
    lines.append('typedef struct {')
    for c in dt.names:
        if dt[c].kind == 'V':
            t = dt[c].subdtype[0].str[1:]
            l = dt[c].subdtype[1][0]
            s = dt[c].subdtype[0].itemsize
        else:
            t = dt[c].str[1:]
            l = 0
            s = dt[c].itemsize
        line = '    '
        if t[0] in 'SU':
            if c in enums:
                line += enums[c][0].upper()
            else:
                line += 'char'
        else:
            line += dtmap[t]
        line += ' {0}'.format(c)
        if l > 0:
            line += '[{0:d}]'.format(l)
        if t[0] in 'SU' and c not in enums:
            line += '[{0:d}]'.format(s)
        line += ';'
        lines.append(line)
    lines.append('}} {0};'.format(structname.upper()))
    return {structname.upper(): list(dt.names), 'enum': returnenums,
        'struct': ['\n'.join(lines)]}


def create_dictionary(file_abs_path):
    """Create dictionary.
    Input:
        file_abs_path -- file abs path.
    Output:
        dictionary -- dictionary.

    """
    dictionary = {}
    with open(file_abs_path, 'r') as f:
        lines = f.read().splitlines()
    for i in range(0, len(lines), 2):
        dictionary[lines[i]] = lines[i + 1]
    return dictionary


def show_mip(data, **kwargs):
    """Display a maximum intensity projection for the data, using three subplots"""
    import matplotlib.pyplot as plt
    fig = plt.figure()
    fig.add_subplot(221).imshow(data.max(0), **kwargs)
    fig.add_subplot(222).imshow(data.max(1), **kwargs)
    fig.add_subplot(223).imshow(data.max(2), **kwargs)
    return fig


@classmethod
def disable(cls):
    """Disables DOM agent for the given page.
        """
    return cls.build_send_payload('disable', {}), None


def as_twos_comp(value: int) ->int:
    """Interpret number as 32-bit twos comp value."""
    if value & 2147483648 != 0:
        flipped_value = ~value & 4294967295
        return -(flipped_value + 1)
    else:
        return value


def do_list(value):
    """Convert the value into a list.  If it was a string the returned list
    will be a list of characters.
    """
    return list(value)


def file_name_parser(line):
    """
    Parses lines of the following form: extracts only the seconds part

        File: to_html.py

    :param line: string
    :return: string containing the name of the file
    """
    ie = line.find(':')
    if ie == -1:
        return ''
    else:
        return line[ie + 1:].strip()


def has_scheduled_methods(cls):
    """Decorator; use this on a class for which some methods have been
    decorated with :func:`schedule` or :func:`schedule_hint`. Those methods
    are then tagged with the attribute `__member_of__`, so that we may
    serialise and retrieve the correct method. This should be considered
    a patch to a flaw in the Python object model."""
    for member in cls.__dict__.values():
        if hasattr(member, '__wrapped__'):
            member.__wrapped__.__member_of__ = cls
    return cls


@classmethod
def delete_all(cls):
    """
        deletes all documents from the collection
        :return: the count of deleted documents
        """
    return cls.get_collection().delete_many({}).deleted_count


@classmethod
def from_atom(class_, atom, pos=None, _offset=None):
    """Create a Col definition from a PyTables atom.

        An optional position may be specified as the pos argument.

        """
    prefix = atom.prefix()
    kwargs = atom._get_init_args()
    colclass = class_._class_from_prefix[prefix]
    return colclass(pos=pos, _offset=_offset, **kwargs)


def _inv_impl(expr, op, **kw):
    """See :meth:`.ColumnOperators.__inv__`."""
    if hasattr(expr, 'negation_clause'):
        return expr.negation_clause
    else:
        return expr._negate()


def setAddNotificationTarget(f):
    """
        Cause the 'add notification' function to be 'f'.

        If 'f' is not callable and is a string, treat it as a physical
        path to a Zope Script object (Python Script, External Method,
        et. al).

        'add notify' functions need accept two arguments: 'item',
        which is the transient object being destroyed, and 'container',
        which is the transient object container which is performing
        the destruction.  For example::

          def addNotify(item, container):
              print("id of 'item' arg was %s" % item.getId())
        """


def mutate(client):
    """
    Makes mutation agent.

    ..  container:: example

        Scales duration of last note notes in staff:

        >>> staff = abjad.Staff("c'4 e'4 d'4 f'4")
        >>> abjad.show(staff) # doctest: +SKIP

        ..  docs::

            >>> abjad.f(staff)
            \\new Staff
            {
                c'4
                e'4
                d'4
                f'4
            }

        >>> abjad.mutate(staff[-2:]).scale(abjad.Multiplier(3, 2))
        >>> abjad.show(staff) # doctest: +SKIP

        ..  docs::

            >>> abjad.f(staff)
            \\new Staff
            {
                c'4
                e'4
                d'4.
                f'4.
            }

    ..  container:: example

        Returns mutation agent:

        >>> abjad.mutate(staff[-2:])
        Mutation(client=Selection([Note("d'4."), Note("f'4.")]))

    """
    import abjad
    return abjad.Mutation(client=client)


def string_to_bool(value):
    """
    Convert string to bool

    :param value: string or bool
    :type value: str or bool
    :return: bool
    """
    if isinstance(value, bool):
        return value
    return value.lower() in ['true', '1', 't', 'y', 'yes']


def MAXINDEX(df, n, price='Close'):
    """
    Index of highest value over a specified period
    Returns: list of ints = jhta.MAXINDEX(df, n, price='Close')
    """
    max_index_list = []
    if n == len(df[price]):
        start = None
        for i in range(len(df[price])):
            if df[price][i] != df[price][i]:
                max_index = float('NaN')
            else:
                if start is None:
                    start = i
                end = i + 1
                max_index = df[price][start:end].index(max(df[price][start:
                    end]))
            max_index_list.append(max_index)
    else:
        for i in range(len(df[price])):
            if i + 1 < n:
                max_index = float('NaN')
            else:
                start = i + 1 - n
                end = i + 1
                max_index = df[price][start:end].index(max(df[price][start:
                    end]))
            max_index_list.append(max_index)
    return max_index_list


def get_declaration(ufunc, c_name, c_proto, cy_proto, header, proto_h_filename
    ):
    """
    Construct a Cython declaration of a function coming either from a
    pxd or a header file. Do sufficient tricks to enable compile-time
    type checking against the signature expected by the ufunc.
    """
    defs = []
    defs_h = []
    var_name = c_name.replace('[', '_').replace(']', '_').replace(' ', '_')
    if header.endswith('.pxd'):
        defs.append('from .%s cimport %s as %s' % (header[:-4], ufunc.
            cython_func_name(c_name, prefix=''), ufunc.cython_func_name(
            c_name)))
        proto_name = '_proto_%s_t' % var_name
        defs.append('ctypedef %s' % cy_proto.replace('(*)', proto_name))
        defs.append('cdef %s *%s_var = &%s' % (proto_name, proto_name,
            ufunc.cython_func_name(c_name, specialized=True)))
    else:
        new_name = '%s "%s"' % (ufunc.cython_func_name(c_name), c_name)
        defs.append('cdef extern from "%s":' % proto_h_filename)
        defs.append('    cdef %s' % cy_proto.replace('(*)', new_name))
        defs_h.append('#include "%s"' % header)
        defs_h.append('%s;' % c_proto.replace('(*)', c_name))
    return defs, defs_h, var_name


def _get_shard_index(job_name, task_id):
    """ Returns the current shard index """
    if job_name != 'learner':
        return None
    return task_id


def google_extra_values(backend, details, response, uid, user, *args, **kwargs
    ):
    """Populates a UserProfile Object when a new User is created via Google Auth"""
    profile = user.social_profile
    if not profile.manually_edited:
        user.last_name = response.get('name').get('familyName', '')
        user.first_name = response.get('name').get('givenName', '')
        user.save()
        profile.gender = response.get('gender', '')
        profile.image_url = response.get('image').get('url', '')
        profile.url = response.get('url', '')
        profile.description = response.get('occupation', '')
        profile.save()


def reset(cls):
    """
        Reset the instance of the singleton
        Call close on the instance
        """
    if cls.__dict__.get('__it__') is not None:
        it = cls.__it__
        cls.__it__ = None
        it.close()


@staticmethod
def get_offset(position: float, target_size: float, image_size: float):
    """Calculates a offset which contains the position
        in a range from offset to offset + target_size.

        Args:
            position (float): the centered position, if possible
                Specified as factor of the image size,
                so it should be an element of [0, 1].
            target_size (int): the image size of the wanted result
            image_size (int): the image size

        Returns:
            int: the offset
        """
    return int(min(max(0, position * image_size - target_size / 2),
        image_size - target_size))


def theta_fluc_from_theta_v_fluc(data, units, notation=None, return_full_df
    =True, inplace_units=True):
    """
    Derived from theta_v = theta(1 + 0.61 q)

    Parameters
    ----------
    data: pandas.dataframe
        dataframe with q, q', theta, theta_v'
    units: dict
        units dictionary
    notation: pymicra.Notation
        Notation object or None

    Returns
    -------
    float
        standard deviation of the thermodynamic temperature
    """
    import numpy as np
    from . import algs
    defs = algs.get_notation(notation)
    data = data.copy()
    if defs.mean_specific_humidity in data.columns:
        q_mean = data[defs.mean_specific_humidity]
    else:
        q_mean = data[defs.specific_humidity].mean()
    if defs.mean_thermodyn_temp in data.columns:
        theta_mean = data[defs.mean_thermodyn_temp]
    else:
        theta_mean = data[defs.thermodyn_temp].mean()
    theta_fluc = (data[defs.virtual_temperature_fluctuations] - 0.61 *
        theta_mean * data[defs.specific_humidity_fluctuations]) / (1.0 +
        0.61 * q_mean)
    theta_fluc_unit = units[defs.virtual_temperature_fluctuations]
    if return_full_df:
        data.loc[:, (defs.thermodyn_temp_fluctuations)] = theta_fluc
        out = data
    else:
        theta_fluc.name = defs.thermodyn_temp_fluctuations
        out = theta_fluc
    if inplace_units:
        units.update({defs.thermodyn_temp_fluctuations: theta_fluc_unit})
    else:
        out = out, theta_fluc_unit
    return out


def env_validator(passed_kwargs, merged_kwargs):
    """ a validator to check that env is a dictionary and that all environment variable
    keys and values are strings. Otherwise, we would exit with a confusing exit code 255. """
    invalid = []
    env = passed_kwargs.get('env', None)
    if env is None:
        return invalid
    if not isinstance(env, dict):
        invalid.append(('env', 'env must be a dict. Got {!r}'.format(env)))
        return invalid
    for k, v in passed_kwargs['env'].items():
        if not isinstance(k, str):
            invalid.append(('env', 'env key {!r} must be a str'.format(k)))
        if not isinstance(v, str):
            invalid.append(('env',
                'value {!r} of env key {!r} must be a str'.format(v, k)))
    return invalid


def rsp_decode_parts(data):
    """ An internal variant of run-length decoder.
        It yields parts of decoded data.
    """
    parts = data.split(b'*')
    i = iter(parts)
    prev = next(i)
    yield prev
    for cur in i:
        if cur:
            n = ord(cur[:1]) - 29
            yield prev[-1:] * n
            yield cur[1:]
        else:
            yield prev[-1:] * 13
            try:
                cur = next(i)
            except StopIteration:
                break
            yield cur
        prev = cur


def pushingmarkerfor(obsstore, ispushed, node):
    """true if some markers are to be pushed for node

    We cannot just look in to the pushed obsmarkers from the pushop because
    discovery might have filtered relevant markers. In addition listing all
    markers relevant to all changesets in the pushed set would be too expensive
    (O(len(repo)))

    (note: There are cache opportunity in this function. but it would requires
    a two dimensional stack.)
    """
    successorsmarkers = obsstore.successors
    stack = [node]
    seen = set(stack)
    while stack:
        current = stack.pop()
        if ispushed(current):
            return True
        markers = successorsmarkers.get(current, ())
        for m in markers:
            nexts = m[1]
            if not nexts:
                nexts = m[5] or ()
            for n in nexts:
                if n not in seen:
                    seen.add(n)
                    stack.append(n)
    return False


def bare_msg_type(msg_type):
    """
    Compute the bare data type, e.g. for arrays, get the underlying array item type

    :param msg_type: ROS msg type (e.g. 'std_msgs/String'), ``str``
    :returns: base type, ``str``
    """
    if msg_type is None:
        return None
    if '[' in msg_type:
        return msg_type[:msg_type.find('[')]
    return msg_type


def _dict_to_strings(kwds):
    """Convert all values in a dictionary to strings."""
    ot = {}
    assert isinstance(kwds, dict)
    for k, v in kwds.items():
        ot[k] = str(v)
    return ot


def _summary(function):
    """
    Derive summary information from a function's docstring or name. The summary is
    the first sentence of the docstring, ending in a period, or if no dostring is
    present, the function's name capitalized.
    """
    if not function.__doc__:
        return f'{function.__name__.capitalize()}.'
    result = []
    for word in function.__doc__.split():
        result.append(word)
        if word.endswith('.'):
            break
    return ' '.join(result)


def black():
    """The world is black."""
    return [True, True, True, True]


def set_user_info(user, odesk_user):
    """Updates given ``user`` information (first and last name, email)
    based on ``odesk_user`` dictionary and saves the object.

    :param user: :class:`django.contrib.auth.models.User` instance
    :param odesk_user: a dictionary containing authenticated user information
                       received from oDesk HR API at /users/me
    """
    user.first_name = odesk_user['first_name']
    user.last_name = odesk_user['last_name']
    user.email = odesk_user['email']
    user.save()
    return user


def batch_qs(qs, batch_size=1000):
    """
    Returns a queryset batch in the given queryset.

    Usage:
        # Make sure to order your querset
        article_qs = Article.objects.order_by('id')
        for qs in batch_qs(article_qs):
            for article in qs:
                print article.body
    """
    total = qs.count()
    for start in range(0, total, batch_size):
        end = min(start + batch_size, total)
        yield qs[start:end]


def resolution_matches(video, screen_size=None, **kwargs):
    """Whether the video matches the `resolution`.

    :param video: the video.
    :type video: :class:`~subliminal.video.Video`
    :param str screen_size: the video resolution
    :return: whether there's a match
    :rtype: bool

    """
    return video.resolution and screen_size == video.resolution


def matplotlib_colourmap(name, samples=16):
    """
    Import a colourmap from a matplotlib

    Parameters
    ----------
    name : str
        Name of the matplotlib colourmap preset to import
    samples : int
        Number of samples to take for LinearSegmentedColormap type

    Returns
    -------
    list
        List of colours ready to be loaded by colourmap()
    """
    try:
        import matplotlib.pyplot as plt
        cmap = plt.get_cmap(name)
        if hasattr(cmap, 'colors'):
            data = cmap.colors
            if len(data) == 256 and samples is not None:
                subsample = int(256 / samples)
                data = data[0::subsample]
            return data
        if samples == None:
            samples = 16
        colours = []
        for i in range(samples):
            pos = i / float(samples - 1)
            colours.append(cmap(pos))
        return colours
    except Exception as e:
        return name
    return []


@classmethod
def generate_toy_data_model(cls, *args, **kwargs):
    """Generate toy data model according to the expectation values.

        All arguments are passed to :meth:`generate_toy_data`.

        """
    return cls(cls.generate_toy_data(*args, **kwargs))


def ULTOSC(df):
    """
    Ultimate Oscillator
    """


def transform_aabb(transform_matrix, aabb):
    """
    Apply a transformation to an axis aligned bounding box.

    The result is a new AABB in the same coordinate system as the original AABB.
    The new AABB contains all corner points of the original AABB after applying the given transformation.

    Args
        transform: The transformation to apply.
        x1: The minimum x value of the AABB.
        y1: The minimum y value of the AABB.
        x2: The maximum x value of the AABB.
        y2: The maximum y value of the AABB.
    Returns
        The new AABB as tuple (x1, y1, x2, y2)
    """
    x1, y1, x2, y2 = aabb
    points = transform_matrix.dot([[x1, x2, x1, x2], [y1, y2, y2, y1], [1,
        1, 1, 1]])
    min_corner = points.min(axis=1)
    max_corner = points.max(axis=1)
    return [min_corner[0], min_corner[1], max_corner[0], max_corner[1]]


def execCommandList(model_object, commands, desc=None, use_undostack=True):
    """
    This is a wrapper for performing QUndoCommands, meant to ensure
    uniform handling of the undoStack and macro descriptions.

    When using the undoStack, commands are pushed onto self.undoStack()
    as part of a macro with description desc. Otherwise, command redo
    methods are called directly.
    """
    if use_undostack:
        us = model_object.undoStack()
        us.beginMacro(desc)
        for c in commands:
            us.push(c)
        us.endMacro()
    else:
        for c in commands:
            c.redo()


def getArguments(parser):
    """Provides additional validation of the arguments collected by argparse."""
    return parser.parse_args()


def _plot_ci_band(ax, x, ci, color, err_kws, **kwargs):
    """Plot translucent error bands around the central tendancy."""
    low, high = ci
    if 'alpha' not in err_kws:
        err_kws['alpha'] = 0.2
    ax.fill_between(x, low, high, facecolor=color, **err_kws)


def set_loss_bias(bias: float):
    """
    Near 1.0 reduces false positives
    Near 0.0 reduces false negatives
    """
    global LOSS_BIAS
    LOSS_BIAS = bias


@classmethod
def add_hook(cls, hook_type, hook_func):
    """Add a new hook of specified type.

        :param cls: class that registers hooks
        :param hook_type: hook type, e.g., '__pre_parse_args__'
        :param hook_func: hook function
        """
    if hook_type not in cls._hooks_map:
        cls._hooks_map[hook_type] = []
    cls._hooks_map[hook_type].append(hook_func)


@staticmethod
def add_mount_point(*_, **__):
    """ Nothing to do. Implemented just for interface compatibility. """


def is_ignored_roi(roi, ignore_data):
    """Determine whether a specific ROI should be ignored

    Parameters
    ----------
    roi: drymass.roi.ROI
        ROI instance
    ignore_data: list of str
        List of strings of the form "image_index" or
        "image_index.roi_index" that identify ROIs that
        should be ignored. For instance
        ["1.0", "2.1", "3"].
    """
    imid = roi.image_index
    roid = roi.roi_index
    if ignore_data and (str(imid) in ignore_data or '{}.{}'.format(imid,
        roid) in ignore_data):
        return True
    else:
        return False


def constrains(source, ipaddress):
    """Service Layer to check constrains"""
    return source.constrains(ipaddress.get_ipaddress())


@classmethod
def decode_ssh_private(cls, packet):
    """Decode an SSH format U2F Ed25519 private key"""
    public_value = packet.get_string()
    application = packet.get_string()
    flags = packet.get_byte()
    key_handle = packet.get_string()
    reserved = packet.get_string()
    return public_value, application, flags, key_handle, reserved


def render_pep440_old(pieces):
    """TAG[.postDISTANCE[.dev0]] .

    The ".dev0" means dirty.

    Eexceptions:
    1: no tags. 0.postDISTANCE[.dev0]
    """
    if pieces['closest-tag']:
        rendered = pieces['closest-tag']
        if pieces['distance'] or pieces['dirty']:
            rendered += '.post%d' % pieces['distance']
            if pieces['dirty']:
                rendered += '.dev0'
    else:
        rendered = '0.post%d' % pieces['distance']
        if pieces['dirty']:
            rendered += '.dev0'
    return rendered


@classmethod
def for_label(cls, value, validate=True):
    """
        Convert the constant into a CSS class that can be used with a <label>.

        Args:
            value: the size.
            validate: check whether the size is one of the predefined
                values. Defaults to True.

        Raises:
            ValueError: if validate is True and the size in invalid.

        Returns:
            str: the CSS class used to set the font size for a label heading.

        """
    if validate and not cls.is_valid(value):
        raise ValueError('Unexpected size', value)
    return 'govuk-label--%s' % value


def _get_version() ->str:
    """Get the current r2c-cli version based on __init__"""
    from bento import __version__
    return __version__


def getItems(authorized_groups, unrestricted, maxItems=None):
    """ Get all authorised items
        If C{maxItems} is not given, all authorised items in the node are returned,
        just like C{getItemsById}. Otherwise, C{maxItems} limits
        the returned items to a maximum of that number of most recently
        published and authorised items.

        @param authorized_groups: we want to get items that these groups can access
        @param unrestricted: if true, don't check permissions (i.e.: get all items)
        @param maxItems: if given, a natural number (>0) that limits the
                          returned number of items.
        @return: deferred that fires a C{list} of (item, access_model, id)
        if unrestricted is True, else a C{list} of items.
        """


def is_forking(argv):
    """
    Return whether commandline indicates we are forking
    """
    if len(argv) >= 2 and argv[1] == '--billiard-fork':
        return True
    else:
        return False


def escape_quotes(qstr):
    """
    Escape backslashes.

    #FIXME:  This *may* prove to be a performance bottleneck and should
             perhaps be implemented in C (as it was in 4Suite RDF)

    Ported from Ft.Lib.DbUtil
    """
    if qstr is None:
        return ''
    tmp = qstr.replace('\\', '\\\\')
    tmp = tmp.replace("'", "\\'")
    return tmp


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 determine_credit(submissions):
    """Adds submissions of zero length to the no-credit list.
    Adds others to the credit list.
    Returns a dictionary with keys credit and nocredit, with the lists as values
    """
    credit = []
    nocredit = []
    for s in submissions:
        if 'body' in s.keys() and s['body'] is not None and len(s['body']) > 2:
            credit.append(s['student_id'])
        else:
            nocredit.append(s['student_id'])
    return {'credit': credit, 'nocredit': nocredit}


def merge_codes(a, b, sep='-'):
    """
    Merge network-station-location-channel codes of a pair of traces.
    """
    o = []
    for xa, xb in zip(a.nslc_id, b.nslc_id):
        if xa == xb:
            o.append(xa)
        else:
            o.append(sep.join((xa, xb)))
    return o


@classmethod
def convert(cls, value):
    """
        Convert the value to an int.

        Parameters
        ----------
            value
                The value to convert

        Returns
        -------
            :class:`int`
                The value converted

        .. versionadded:: 0.0.3
        """
    return int(value)


def mkpath(filepath, workpath, subpath=''):
    """
    Combine file fragments workpath and filepath. Optionally add a subpath of
    workpath to filepath. When path is new, make needed directories before
    returning the combined path.

    @param filepath: local file path fragment.
    @type filepath: basestring
    @param workpath: local work path fragment.
    @type workpath: basestring
    @param subpath: Optional file path fragement.
    @type subpath: basestring
    @return: Qualified full file path
    @rtype: basestring
    @requires: os
    """
    import os
    pathtofile = os.path.split(filepath)
    workpath = os.path.join(workpath, subpath, pathtofile[0])
    if not os.path.exists(workpath):
        os.makedirs(workpath)
    return os.path.join(workpath, pathtofile[1])


def compute_M1_nl(formula, abundance):
    """Compute intensity of the second isotopologue M1.

    Handle element X with specific abundance.

    Parameters
    ----------
    formula : pyteomics.mass.Composition
        Chemical formula, as a dict of the number of atoms for each element:
        {element_name: number_of_atoms, ...}.
    abundance : dict
        Dictionary of abundances of isotopes:
        {"element_name[isotope_number]": relative abundance, ..}.

    Returns
    -------
    float
        Value of M1.

    Notes
    -----
    X represents C with default isotopic abundance.

    """
    M1_intensity = formula['C'] * abundance['C[12]'] ** (formula['C'] - 1
        ) * abundance['C[13]'] * abundance['X[12]'] ** formula['X'
        ] * abundance['H[1]'] ** formula['H'] * abundance['N[14]'] ** formula[
        'N'] * abundance['O[16]'] ** formula['O'] * abundance['S[32]'
        ] ** formula['S'] + formula['X'] * abundance['C[12]'] ** formula['C'
        ] * abundance['X[12]'] ** (formula['X'] - 1) * abundance['X[13]'
        ] * abundance['H[1]'] ** formula['H'] * abundance['N[14]'] ** formula[
        'N'] * abundance['O[16]'] ** formula['O'] * abundance['S[32]'
        ] ** formula['S'] + formula['H'] * abundance['C[12]'] ** formula['C'
        ] * abundance['X[12]'] ** formula['X'] * abundance['H[1]'] ** (formula
        ['H'] - 1) * abundance['H[2]'] * abundance['N[14]'] ** formula['N'
        ] * abundance['O[16]'] ** formula['O'] * abundance['S[32]'] ** formula[
        'S'] + formula['N'] * abundance['C[12]'] ** formula['C'] * abundance[
        'X[12]'] ** formula['X'] * abundance['H[1]'] ** formula['H'
        ] * abundance['N[14]'] ** (formula['N'] - 1) * abundance['N[15]'
        ] * abundance['O[16]'] ** formula['O'] * abundance['S[32]'] ** formula[
        'S'] + formula['O'] * abundance['C[12]'] ** formula['C'] * abundance[
        'X[12]'] ** formula['X'] * abundance['H[1]'] ** formula['H'
        ] * abundance['N[14]'] ** formula['N'] * abundance['O[16]'] ** (formula
        ['O'] - 1) * abundance['O[17]'] * abundance['S[32]'] ** formula['S'
        ] + formula['S'] * abundance['C[12]'] ** formula['C'] * abundance[
        'X[12]'] ** formula['X'] * abundance['H[1]'] ** formula['H'
        ] * abundance['N[14]'] ** formula['N'] * abundance['O[16]'] ** formula[
        'O'] * abundance['S[32]'] ** (formula['S'] - 1) * abundance['S[33]']
    return M1_intensity


@classmethod
def from_date(cls, d):
    """ Abstract class method.

        For instance, ``Month.from_date(datetime.date(2012, 6, 6))`` returns a ``Month(2012, 6)``."""
    raise NotImplementedError


def flatten_points(points):
    """Given a list of points, flatten them starting from x and going to y.

    Example:
        `flatten_points([Point(x=1,y=2), Point(x=2,y=3)])`
        -->
        `[1, 2, 2, 3]`"""
    numbers = []
    for point in points:
        numbers.append(point.x)
        numbers.append(point.y)
    return numbers


@staticmethod
def _setup_output_file(output_file):
    """
        Open a log file if necessary and return the file handle. This will create a file if it does not exist

        Parameters
        ----------
        output_file : str
            Path to a file where the logs should be written to

        Returns
        -------
        Handle to the opened log file, if necessary. None otherwise
        """
    if not output_file:
        return None
    return open(output_file, 'wb')


def hex_str(n):
    """
    Thrift uses a binary representation of trace and span ids
    HTTP headers use a hexadecimal representation of the same
    """
    return '%0.16x' % (n,)


def _get_binop_operator(cursor):
    """
    Returns the operator token of a binary operator cursor.

    :param cursor: A cursor of kind BINARY_OPERATOR.
    :return:       The token object containing the actual operator or None.
    """
    children = list(cursor.get_children())
    operator_min_begin = children[0].location.line, children[0].location.column
    operator_max_end = children[1].location.line, children[1].location.column
    for token in cursor.get_tokens():
        if operator_min_begin < (token.extent.start.line, token.extent.
            start.column) and operator_max_end >= (token.extent.end.line,
            token.extent.end.column):
            return token
    return None


def _set_summary_fields(ctx):
    """Sets document summary fields.

    """
    if len(ctx.doc.esm_model_grids):
        ctx.ext.summary_fields += ctx.doc.esm_model_grids[0
            ].short_name, ctx.doc.esm_model_grids[0].long_name
    elif len(ctx.doc.esm_exchange_grids):
        ctx.ext.summary_fields += ctx.doc.esm_exchange_grids[0
            ].short_name, ctx.doc.esm_exchange_grids[0].long_name


def is_8bit_normal_register(x):
    """ Returns whether the given string x is a "normal" 8 bit register. Those are 8 bit registers
    which belongs to the normal (documented) Z80 instruction set as operands (so a', f', ixh, etc
    are excluded).
    """
    return x.lower() in {'a', 'b', 'c', 'd', 'e', 'i', 'h', 'l'}


@classmethod
def create(cls, **kwargs):
    """Create model instance

        :kwargs: will be passed to build_create_data for validation
        """
    data = cls.build_create_data(**kwargs)
    resp = cls.client.api_session.post(f'/{cls.TYPE}', json={'data': data})
    return cls.from_json(resp.json())


@classmethod
def run_katello_service_stop(cls, options=None):
    """Build foreman-maintain advanced procedure run
         service-stop"""
    cls.command_sub = 'service-stop'
    if options is None:
        options = {}
    result = cls._construct_command(options)
    return result


def comma_float(val: str) ->float:
    """
    Get float for a string that may contain commas in stead of dots
    :param val: the value to be casted to float
    :return: float
    """
    if ',' in val and '.' not in val:
        return float(val.replace(',', '.'))
    elif '.' in val and ',' not in val:
        return float(val)
    elif ',' not in val and '.' not in val:
        return float(val)
    else:
        raise ValueError('Cannot parse string with both commas and dots')


@staticmethod
def exc_value(exc_type, exc_value, exc_tb):
    """
        Returns the first argument of the exception instance. In the case of
        :exc:`SystemExit` this is the expected return code of the script.
        """
    return exc_value.args[0]


def _tess_report_paths(file_name):
    """ TESS Report File """
    eeeee = file_name[24:29]
    zzzz = file_name[30:34]
    ffff = file_name[34:38]
    pppp = file_name[38:42]
    llll = file_name[42:46]
    parts = ['tess', 'public', 'tid', eeeee, zzzz, ffff, pppp, llll, file_name]
    return ['/'.join(parts)]


def isImageType(t):
    """
    Checks if an object is an image object.

    .. warning::

       This function is for internal use only.

    :param t: object to check if it's an image
    :returns: True if the object is an image
    """
    return hasattr(t, 'im')


def mute_toggle():
    """Toggle muting of the nodes

    """
    pass


def columns_and_constraints_to_descriptor(prefix, tablename, columns,
    constraints, autoincrement_column):
    """Convert ElasticSearch Mapping to descriptor.
    """
    raise NotImplementedError


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

    Like 'git describe --tags --dirty --always -long'.
    The distance/hash is unconditional.

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


def farnsworth(wpm=20, cwpm=None):
    """
	Generate Morse timings based on ARRL Farnsworth timing

	This permits optionally specifying a different overall words
	per minute. The character WPM determines the timings of the
	dits, dahs, and intra-letter spaces; the overall WPM determines
	the timings of the inter-letter and inter-word spaces.
	"""
    if not cwpm:
        cwpm = wpm
    cwpm = max(cwpm, wpm)
    dit = 1.2 / cwpm
    t_a = (60 * cwpm - 37.2 * wpm) / (cwpm * wpm)
    return {'dit': dit, 'dah': dit * 3, 'inter_symbol': dit, 'inter_letter':
        t_a * 3 / 19.0, 'inter_word': t_a * 7 / 19.0}


def check_nocachekey(option):
    """
    checks if an option is a NoCacheKey option or Etag

    :param option:
    :return:
    """
    return (option.number & 30 == 28) | (option.number == 4)


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

        :param SsoRemoveCertType val:
        :rtype: EventType
        """
    return cls('sso_remove_cert', val)


def func_gt(parser, x, y):
    """Returns true, if ``x`` is greater than ``y``."""
    try:
        if int(x) > int(y):
            return '1'
    except ValueError:
        pass
    return ''


@classmethod
def parse_l2_depth(cls, instmt, raw):
    """
        Parse raw data to L2 depth
        :param instmt: Instrument
        :param raw: Raw data in JSON
        """
    l2_depth = instmt.get_l2_depth()
    keys = list(raw.keys())
    if cls.get_order_book_timestamp_field_name(
        ) in keys and cls.get_bids_field_name(
        ) in keys and cls.get_asks_field_name() in keys:
        timestamp = raw[cls.get_order_book_timestamp_field_name()]
        timestamp = timestamp.replace('T', ' ').replace('Z', '').replace('-',
            '')
        l2_depth.date_time = timestamp
        bids = raw[cls.get_bids_field_name()]
        bids = sorted(bids, key=lambda x: x[0], reverse=True)
        for i in range(0, len(bids)):
            l2_depth.bids[i].price = float(bids[i][0]) if type(bids[i][0]
                ) != float else bids[i][0]
            l2_depth.bids[i].volume = float(bids[i][1]) if type(bids[i][1]
                ) != float else bids[i][1]
        asks = raw[cls.get_asks_field_name()]
        asks = sorted(asks, key=lambda x: x[0])
        for i in range(0, len(asks)):
            l2_depth.asks[i].price = float(asks[i][0]) if type(asks[i][0]
                ) != float else asks[i][0]
            l2_depth.asks[i].volume = float(asks[i][1]) if type(asks[i][1]
                ) != float else asks[i][1]
    else:
        raise Exception(
            'Does not contain order book keys in instmt %s-%s.\nOriginal:\n%s'
             % (instmt.get_exchange_name(), instmt.get_instmt_name(), raw))
    return l2_depth


def get_key0(adict):
    """Gets the "first" key in a dictionary

    The entry is kind of irrelevant.
    """
    keys = list(adict.keys())
    return keys[0]


def region_blend():
    """Blend in and out overlapping region

    """
    pass


@classmethod
def from_document(cls, amostra_client, document):
    """
        Convert a dict returned by the server to our traitlets-based object.
        """
    contents = {}
    for sample_uuid, location in document['contents'].items():
        sample = amostra_client.samples.find_one({'uuid': sample_uuid})
        contents[sample] = location
    document['contents'] = contents
    return super().from_document(amostra_client, document)


def get_both_filenames(filename):
    """ Get a list of both filenames for FUV data

    Regardless if rootname_corrtag_a.fits or rootname_corrtag_b.fits
    is passed in, both will be returned in a list.

    Parameters
    ----------
    filename : str
        full path to COS file

    Returns
    -------
    files : tuple
        rootname_corrtag_a.fits, rotname_corrtag_b.fits

    """
    if '_a.fits' in filename:
        other_filename = filename.replace('_a.fits', '_b.fits')
    elif '_b.fits' in filename:
        other_filename = filename.replace('_b.fits', '_a.fits')
    else:
        raise ValueError("filename doesn't match FUV convention".format(
            filename))
    filename_list = [filename, other_filename]
    filename_list.sort()
    return filename_list[0], filename_list[1]


@staticmethod
def get_error_class(remote_err):
    """
        This is a function to get the error class of a remote thrown error when using callRemote.
        :param remote_err: :obj:`twisted.spread.pb.RemoteError`
        :return: class
        """
    error_name = remote_err.remoteType.split(b'.')[-1].decode()
    error_class = eval(error_name)
    return error_class


def add_dicts(*args):
    """
    Combine dicts. If there are duplicate keys, raise an error.
    """
    new = {}
    for arg in args:
        for key in arg:
            if key in new:
                raise ValueError('Duplicate key: %r' % key)
            new[key] = arg[key]
    return new


def get_coverage_minimum_statement(coverage_percent, minimum_coverage):
    """
    Check if the coverage is above the minimum required coverage and return a
    statement to this effect.
    """
    if coverage_percent >= minimum_coverage:
        return ' meets minimum of %.2f%%' % (minimum_coverage,)
    return ' is below minimum of %.2f%%' % (minimum_coverage,)


def calculate_voltage(percent):
    """Convert fan speed in percent (0-100) to nearest valid voltage (4.0V to 12.0V in steps of 0.5V).
    Values below 33% will be defined as "0V" (fan will be stopped).
    """
    if percent < 33:
        return 0.0
    elif percent >= 33 and percent < 36:
        return 4.0
    elif percent >= 36 and percent < 40:
        return 4.5
    elif percent >= 40 and percent < 44:
        return 5.0
    elif percent >= 44 and percent < 48:
        return 5.5
    elif percent >= 48 and percent < 52:
        return 6.0
    elif percent >= 52 and percent < 56:
        return 6.5
    elif percent >= 56 and percent < 60:
        return 7.0
    elif percent >= 60 and percent < 64:
        return 7.5
    elif percent >= 64 and percent < 68:
        return 8.0
    elif percent >= 68 and percent < 72:
        return 8.5
    elif percent >= 72 and percent < 76:
        return 9.0
    elif percent >= 76 and percent < 80:
        return 9.5
    elif percent >= 80 and percent < 84:
        return 10.0
    elif percent >= 84 and percent < 88:
        return 10.5
    elif percent >= 88 and percent < 93:
        return 11.0
    elif percent >= 93 and percent < 98:
        return 11.5
    else:
        return 12.0


def _python_version_is_compatible(warning_str=
    'pyTorch supports Python version 2.7, 3.5, 3.6, 3.7.',
    warning_already_issued=False, list_of_compatible_versions=[2.7, 3.5, 3.6]):
    """Helper function for VersionWarning class that issues
    a warning (if a warning has not already been issued),
    whenever the python version is not in the
    list_of_compatible_versions.
    """
    import sys
    v = sys.version_info[0] + 0.1 * sys.version_info[1]
    if v in list_of_compatible_versions:
        return True
    elif not warning_already_issued:
        import warnings
        warning = (
            """
        {}
        cleanlab supports Python versions 2.7, 3.4, 3.5, 3.6.
        You are using Python version {}.
        You'll need to use a version compatible with both."""
            .format(warning_str, v))
        warnings.warn(warning)
        warning_already_issued = True
    return False


@classmethod
def parse(cls, fp, data_objects=None, close=True):
    """
            This method parses the file and return a list of DataObjects
            with both header and data properties filled in accordingly.
            The filename argument is always required. If no file object is passed
            as keyword argument, it only serves as a label. Otherwise a new file
            object is created.
            File objects are closed unless close is set to False.
            Existing DataObjects can be passed as well and will then
            be used instead of creating new ones.
        """
    filename, fp, close = cls._get_file(fp, close=close)
    data_objects = cls._parse_header(filename, fp, data_objects=data_objects)
    data_objects = cls._parse_data(filename, fp, data_objects=data_objects)
    if close:
        fp.close()
    return data_objects


def p_event(parser):
    """
    event   : event_core SPACE event_arguments
            | event_core SPACE
            | event_core
    """
    parser[0] = parser[1]
    try:
        parser[0] += parser[2]
    except IndexError:
        pass
    try:
        parser[0] += parser[3]
    except IndexError:
        pass
    return parser


def dderiv_v_r_midplane(a_0, v_r, v_φ, deriv_B_r, deriv_B_φ, dderiv_B_θ, γ,
    η_perp_sq, η_H, η_P, Y_6, Y_5, Y_4, Y_3, Y_2, Y_1):
    """
    Compute v_r'' around the midplane
    """
    return (v_φ * Y_4 / Y_5 + 4 * γ ** 2 * v_r ** 2 + a_0 / 2 * (dderiv_B_θ *
        deriv_B_r + 2 * deriv_B_φ ** 2 * (1 / 4 - γ) + Y_3 - Y_2 * η_H /
        η_P + η_H * Y_4 / (η_perp_sq * Y_5) + 2 * dderiv_B_θ * (1 / 4 - γ) +
        Y_1 * (deriv_B_r + 1 / 4 - γ))) / Y_6


def sign(data=None, name=None, attr=None, out=None, **kwargs):
    """Returns element-wise sign of the input.

    Example::

       sign([-2, 0, 3]) = [-1, 0, 1]

    The storage type of ``sign`` output depends upon the input storage type:

       - sign(default) = default
       - sign(row_sparse) = row_sparse
       - sign(csr) = csr

    Defined in src/operator/tensor/elemwise_unary_op_basic.cc:L759

    Parameters
    ----------
    data : Symbol
        The input array.

    name : string, optional.
        Name of the resulting symbol.

    Returns
    -------
    Symbol
        The result symbol.
    """
    return 0,


def isTrue(value):
    """
    Returns True if value is something we consider to be "on".
    Otherwise, return False.
    """
    if type(value) == str:
        return value.lower() == 'on'
    elif value:
        return True
    return False


def add(initial: int=0, number: int=0) ->int:
    """Return sum of *intial* and *number*.
    :param initial: Initial value.
    :type initial: int
    :param number: Value to add to initial.
    :type number: int
    :return: Sum of initial and number.
    :rtype: int
    """
    return initial + number


@classmethod
def set_items(cls, s2m):
    """
        This class method allows setting of some class variables
        :param s2m:
        :return:
        """
    cls.s2m = s2m


def get_vault_access_policy(accountId=None, vaultName=None):
    """
    This operation retrieves the access-policy subresource set on the vault; for more information on setting this subresource, see Set Vault Access Policy (PUT access-policy) . If there is no access policy set on the vault, the operation returns a 404 Not found error. For more information about vault access policies, see Amazon Glacier Access Control with Vault Access Policies .
    See also: AWS API Documentation

    Examples
    The example retrieves the access-policy set on the vault named example-vault.
    Expected Output:

    :example: response = client.get_vault_access_policy(
        vaultName='string'
    )

    :type accountId: string
    :param accountId: The AccountId value is the AWS account ID of the account that owns the vault. You can either specify an AWS account ID or optionally a single '- ' (hyphen), in which case Amazon Glacier uses the AWS account ID associated with the credentials used to sign the request. If you use an account ID, do not include any hyphens ('-') in the ID.
            Note: this parameter is set to '-' bydefault if no value is not specified.

    :type vaultName: string
    :param vaultName: [REQUIRED]
            The name of the vault.

    :rtype: dict
    :return: {
        'policy': {
            'Policy': 'string'
        }
    }

    """
    pass


def append_gene_summary(main_curr, chunk_db):
    """
    Append the gene_summary from a chunk_db
    to the main database.
    """
    cmd = 'attach ? as toMerge'
    main_curr.execute(cmd, (chunk_db,))
    cmd = 'INSERT INTO gene_summary SELECT * FROM toMerge.gene_summary'
    main_curr.execute(cmd)
    cmd = 'detach toMerge'
    main_curr.execute(cmd)


def maybe_extract_tuple(t):
    """Returns a tuple of Variables."""
    values = t.data
    if len(values) > 1:
        return t,
    v, = values
    if not v.isinstance_Tuple():
        return t,
    return v.pyval


def get_status():
    """Return the version status.
        """


@classmethod
def disable(cls):
    """Disables tracking security state changes.
        """
    return cls.build_send_payload('disable', {}), None


def escape_for_query(query_part: str) ->str:
    """Escapes all characters reserved by jriver in a natural string.

    Do not put a complete query in here - this method is used to escape
    reserved characters in a natural string that will be used as a query fragment.
    This is usually the content of a field (e.g. an album or artist name).
    """
    query_part = query_part.replace('"', '/"')
    query_part = query_part.replace('^', '/^')
    query_part = query_part.replace('[', '/[')
    query_part = query_part.replace(']', '/]')
    return query_part


@staticmethod
def _compare_relative_path(path_main, path_other):
    """Returns path from path_main to path_other.

        Example:
            path_main = 'some_folder\\file1.html'
            path_other = 'some_folder\\sub_folder\\file2.html'

            returns 'sub_folder\\file2.html'
        """
    if '\\' in path_main:
        main_p = path_main.split('\\')
    else:
        main_p = [path_main]
    if '\\' in path_other:
        other_p = path_other.split('\\')
    else:
        other_p = [path_other]
    min_path_len = min([len(main_p), len(other_p)])
    path_overlap = 0
    for i in range(min_path_len):
        if main_p[i] == other_p[i] and path_overlap == i:
            path_overlap += 1
    return '..\\' * (len(main_p) - 1 - path_overlap) + '\\'.join(other_p[
        path_overlap:])


def get_tag_params(tag_model):
    """Load param strs and n_header based on model of tag model"""
    tag_model = tag_model.replace('-', '')
    tags = dict()
    tags['W190PD3GT'] = ['Acceleration-X', 'Acceleration-Y',
        'Acceleration-Z', 'Depth', 'Propeller', 'Temperature']
    if tag_model in tags:
        return tags[tag_model]
    else:
        raise KeyError('{} not found in tag dictionary'.format(tag_model))


@classmethod
def parse(cls, name: str) ->'PerformanceMetric':
    """
        Converts JSON string into enum value.

        Parameters
        ----------
        name : str
            JSON string.

        Returns
        -------
        PerformanceMetric
            Enum value.
        """
    return cls.get_map()[name]


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

    Like 'git describe --tags --dirty --always -long'.
    The distance/hash is unconditional.

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


def init():
    """This function is a no-op, and exists only to match the native hidapi
	implementation.

	:returns: ``True``.
	"""
    return True


def get_route_doc_string(routes, route, method):
    """Returns doc string for embedded route functions."""
    try:
        doc = routes[route][0].handlers[method].__doc__
    except AttributeError:
        doc = routes[route][0].__doc__
    return doc


def esc(text: str) ->str:
    """ Simple XML text escape """
    return text.replace('&', '&').replace('<', '<').replace('>', '>')


def instanceof(classobj, p=[]):
    """ given a class object, let there be one of that with a name that is randomly selected """
    syb = 'i' + str(1)
    syb = type.__new__(classobj, syb, (), {})
    return syb


def gcd(a, b):
    """Calculate the Greatest Common Divisor of a and b.

    Unless b==0, the result will have the same sign as b (so that when
    b is divided by it, the result comes out positive).
    """
    while b:
        a, b = b, a % b
    return a


def humanize(with_defaults=False, censored=True):
    """Return a human readable string showing changes
        to the configuration.
        """


def p_argument_list(p):
    """argument_list : argument
                     | argument COMMA argument_list"""
    if len(p) == 2:
        p[0] = p[1]
    else:
        p[0] = p[1][0] + p[3][0], {**p[1][1], **p[3][1]}


def revert_annotation(gc, annotation_id=None, annotation=None, version=None,
    revert_to_nonempty_elements=False, only_revert_if_empty=True):
    """Revert an annotation to a previous version.

    Parameters
    ----------
    gc : girder_client.GirderClient
        authenticated girder client
    annotation_id : str
        girder id of annotation
    annotation : dict
        overrides annotation_id if given
    version : int
        versoin number for annotation. If None, and
        not revert_to_nonempty_elements
        the default behavior of the endpoint is evoked, which reverts the
        annotation if it was deleted and if not, reverts to the last version.
    revert_to_nonempty_elements : bool
        if true, reverts to the most recent version of the annotation
        with non-empty elements.
    only_revert_if_empty : bool
        if true, only reverts annotation if it contains an empty element list

    Returns
    -------
    dict
        server response

    """
    if annotation is not None:
        annotation_id = annotation['_id']
    elif annotation_id is None:
        raise Exception(
            'You must provide either the annotation or its girder id.')
    history = gc.get('/annotation/%s/history' % annotation_id)
    if only_revert_if_empty and len(history[0]['groups']) > 0:
        return dict()
    if len(history) < 2:
        return dict()
    if version is None and revert_to_nonempty_elements:
        for ver in history:
            if len(ver['groups']) > 0:
                version = ver['_version']
                break
    ver = '' if version is None else '?version=%d' % version
    return gc.put('/annotation/%s/history/revert%s' % (annotation_id, ver))


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


@staticmethod
def aggregate(converteds):
    """aggregate the list of converted items"""
    return dict(converteds)


def scan_spectrum_file(filename):
    """
    go over mgf file and return list with all spectrum titles
    """
    titles = []
    f = open(filename)
    while 1:
        rows = f.readlines(10000)
        if not rows:
            break
        for row in rows:
            if row[0] == 'T':
                if row[:5] == 'TITLE':
                    titles.append(row.rstrip()[6:])
    f.close()
    return titles


def __ne__(A, other):
    """Returns true if both objects are not equal"""
    return not A == other


def wf_sig(wf):
    """
	Compute a signature of a Compiler.Waveform that identifies the relevant properties for
	two Waveforms to be considered "equal" in the waveform library. For example, we ignore
	length of TA waveforms.
	"""
    if wf.isZero or wf.isTimeAmp and wf.frequency == 0:
        return wf.amp, wf.phase
    else:
        return wf.key, wf.amp, round(wf.phase * 2 ** 13
            ), wf.length, wf.frequency


def get_keyring():
    """ Try to import and return optional keyring dependency. """
    try:
        import keyring
    except ImportError:
        raise ImportError(
            'Extra dependencies must be installed to use the keyring feature. Install them with `pip install bugwarrior[keyring]`.'
            )
    return keyring


def normalize_job_id(job_id):
    """Convert the job id into job_id, array_id."""
    if '_' in job_id:
        job_id, array_id = job_id.split('_')
        job_id = job_id.strip()
        array_id = array_id.strip()
    else:
        array_id = None
    return job_id, array_id


@classmethod
def advice_dcv_method(cls, csr, package, altnames, dcv_method, cert_id=None):
    """ Display dcv_method information. """
    params = {'csr': csr, 'package': package, 'dcv_method': dcv_method}
    if cert_id:
        params['cert_id'] = cert_id
    result = cls.call('cert.get_dcv_params', params)
    if dcv_method == 'dns':
        cls.echo('You have to add these records in your domain zone :')
    cls.echo('\n'.join(result['message']))


@staticmethod
def in_bbox(point, a, b):
    """Return True if `point` is in the bounding box defined by `a`
        and `b`.

        >>> bmin = (0, 0)
        >>> bmax = (100, 100)
        >>> Vector.in_bbox((50, 50), bmin, bmax)
        True
        >>> Vector.in_bbox((647, -10), bmin, bmax)
        False

        """
    return (point[0] <= a[0] and point[0] >= b[0] or point[0] <= b[0] and
        point[0] >= a[0]) and (point[1] <= a[1] and point[1] >= b[1] or
        point[1] <= b[1] and point[1] >= a[1])


@classmethod
def find_supported_devices(cls, **kwargs):
    """Find and bind to compatible devices.

        Returns a list of bound driver instances.
        """
    raise NotImplementedError()


def _check_preload(inst, msg):
    """Ensure data are preloaded."""
    from ..epochs import BaseEpochs
    from ..evoked import Evoked
    from ..time_frequency import _BaseTFR
    if isinstance(inst, (_BaseTFR, Evoked)):
        pass
    else:
        name = 'epochs' if isinstance(inst, BaseEpochs) else 'raw'
        if not inst.preload:
            raise RuntimeError(
                'By default, MNE does not load data into main memory to conserve resources. '
                 + msg +
                ' requires %s data to be loaded. Use preload=True (or string) in the constructor or %s.load_data().'
                 % (name, name))


def annotate_axes(index, labels, points, offset_points, size, ax, **kwargs):
    """
    Annotate Axes with labels, points, offset_points according to the
    given index.
    """
    for i in index:
        label = labels[i]
        point = points[i]
        offset = offset_points[i]
        ax.annotate(label, point, xytext=offset, textcoords='offset points',
            size=size, **kwargs)
    return ax


@classmethod
def _check_add_constraints(cls, state):
    """
        Obnoxious way to handle this, should ONLY be called from crash monitor.
        """
    state.inspect.address_concretization_add_constraints = (cls.
        _should_add_constraints(state))


def merge_dict(*dicts):
    """Merge dicts and return a dictionnary mapping key to list of values.

    Order of the values corresponds to the order of the original dicts.
    """
    ret = dict()
    for dict_ in dicts:
        for key, val in dict_.items():
            ret.setdefault(key, []).append(val)
    return ret


def addBranchNamesToFile(fileSection, branchNames):
    """
    _addBranchNamesToFile_

    Given a list of branch names add them to the file section in the FWJR.
    """
    setattr(fileSection, 'branches', branchNames)
    return


def merge_schedules(schedules, how='outer'):
    """
    Given a list of schedules will return a merged schedule. The merge method (how) will either return the superset
    of any datetime when any schedule is open (outer) or only the datetime where all markets are open (inner)

    :param schedules: list of schedules
    :param how: outer or inner
    :return: schedule DataFrame
    """
    result = schedules[0]
    for schedule in schedules[1:]:
        result = result.merge(schedule, how=how, right_index=True,
            left_index=True)
        if how == 'outer':
            result['market_open'] = result.apply(lambda x: min(x.
                market_open_x, x.market_open_y), axis=1)
            result['market_close'] = result.apply(lambda x: max(x.
                market_close_x, x.market_close_y), axis=1)
        elif how == 'inner':
            result['market_open'] = result.apply(lambda x: max(x.
                market_open_x, x.market_open_y), axis=1)
            result['market_close'] = result.apply(lambda x: min(x.
                market_close_x, x.market_close_y), axis=1)
        else:
            raise ValueError('how argument must be "inner" or "outer"')
        result = result[['market_open', 'market_close']]
    return result


def duration_to_dt(duration):
    """
    Given a time duration, returns back the sampling rate of timeseries
    such that a maximum of 1000 points are plotted at a given time.

    This is used as a default if the user doesn't specify a dt explicitly.

    >>> duration_to_dt(900)
    1
    >>> duration_to_dt(11000)
    100

    """
    if duration <= 1000:
        dt = 1
    elif duration <= 10000:
        dt = 10
    elif duration <= 100000:
        dt = 100
    elif duration <= 1000000:
        dt = 1000
    elif duration <= 10000000:
        dt = 10000
    else:
        dt = 100000
    return dt


def setup_pressureview(ax):
    """Builds the simulation instantaneous pressure visualisation pane.

    Parameters
    ----------
    ax: Axes object
        The axes position that the pane should be placed in.
    """
    ax.plot([0], color='#34a5daff')
    ax.set_ylabel('Pressure/$\\times10^6$Pa m$^{-1}$', fontsize=16)
    ax.set_xlabel('Time/s', fontsize=16)


def fast_exponentiation(base, exponent, modulus):
    """
    Applies a fast exponentiation algorithm to the
    given value retrieving the exponentiation result.
    The calculus may be defined by: base ^ exponent % modulus.

    :type base: int
    :param base: The base value for the exponentiation.
    :type exponent: int
    :param exponent: The exponent value for the exponentiation.
    :type modulus: int
    :param modulus: The modulus value for the exponentiation.
    :rtype: int
    :return: The result of the exponentiation.
    """
    result = base % modulus
    remainders = []
    while not exponent == 1:
        remainders.append(exponent & 1)
        exponent >>= 1
    while remainders:
        remainder = remainders.pop()
        result = base ** remainder * result ** 2 % modulus
    return result


def _clean_suffix(string, suffix):
    """
    If string endswith the suffix, remove it. Else leave it alone.
    """
    suffix_len = len(suffix)
    if len(string) < suffix_len:
        raise ValueError('A suffix can not be bigger than string argument.')
    if string.endswith(suffix):
        return string[0:-suffix_len]
    else:
        return string


def matrix_scalar(m, sc):
    """ Matrix multiplication by a scalar value (iterative algorithm).

    The running time of the iterative matrix multiplication algorithm is :math:`O(n^{2})`.

    :param m: input matrix
    :type m: list, tuple
    :param sc: scalar value
    :type sc: int, float
    :return: resultant matrix
    :rtype: list
    """
    mm = [[(0.0) for _ in range(len(m[0]))] for _ in range(len(m))]
    for i in range(len(m)):
        for j in range(len(m[0])):
            mm[i][j] = float(m[i][j] * sc)
    return mm


def complex_to_seq(z):
    """Transform a complex number into a 4-element sequence

    :arg z: a number

    If ``z = x + yj``, then an array of the form ``[[x,-y],[y,x]]``
    can be used to represent ``z`` in matrix computations.

    **Examples**::
        >>> import numpy
        >>> z = 1 + 2j
        >>> function.complex_to_seq(z)
        (1.0, -2.0, 2.0, 1.0)

        >>> m = numpy.array( function.complex_to_seq(z) )
        >>> m.shape = (2,2)
        >>> print( m )
        [[ 1. -2.]
         [ 2.  1.]]

    """
    z = complex(z)
    return z.real, -z.imag, z.imag, z.real


@staticmethod
def _apply_data_oper(v, oper_name, *oper_args, delete_props=False, **
    oper_kwargs):
    """Define a data array operation and delete some properties.

    :Parameters:

        v: the data array to apply the operations to (possibly in-place)

        oper_name: the string name for the desired operation, as it is
            defined (its method name) under the Data class, e.g.
            `sin` to apply `Data.sin`.

            Note: there is no (easy) way to determine the name of a
            function/method within itself, without e.g. inspecting the stack
            (see rejected PEP 3130), so even though functions are named
            identically to those call in Data (e.g. both `sin`) the same
            name must be typed and passed into this method in each case.

            TODO: is there a way to prevent/bypass the above?

        oper_args, oper_kwargs: all of the arguments for *oper_name*.

        delete_props: whether or not to delete name properties.

        """
    if not oper_kwargs.get('inplace'):
        oper_kwargs['inplace'] = True
    data = v.get_data(None)
    if data is not None:
        getattr(data, oper_name)(*oper_args, **oper_kwargs)
    if delete_props:
        v.del_property('standard_name', None)
        v.del_property('long_name', None)
    return v


def boolean_setting(settings, key, default=None):
    """
    Given a setting from a .ini file and returns a boolean interpretation of it.
    - Treats an actual python boolean as itself
    - Using case-insensitive comparison, treats the string 'true' as True and both 'false' and '' as False.
    - If an element is missing,
    - Treats None the same as the option being missing, so returns the given default.
    - Raises an error for any non-standard value. This is harsh, but it should not happen.
    """
    if key not in settings:
        return default
    setting = settings[key]
    if isinstance(setting, str):
        setting_lower = setting.lower()
        if setting_lower in ('', 'false'):
            return False
        elif setting_lower == 'true':
            return True
        else:
            return setting
    else:
        return setting


def impossible_label(n, amended_labels):
    """ Return True if n is not in the same family as amended_labels. """
    test = n.label_id().startswith
    return not any(filter(test, amended_labels))


def filter_stubs(tracks, threshold=100):
    """Filter out trajectories with few points. They are often spurious.

    Parameters
    ----------
    tracks : DataFrame
        must include columns named 'frame' and 'particle'
    threshold : integer, default 100
        minimum number of points (video frames) to survive

    Returns
    -------
    a subset of tracks
    """
    try:
        tracks['frame']
        tracks['particle']
    except KeyError:
        raise ValueError("Tracks must contain columns 'frame' and 'particle'.")
    grouped = tracks.reset_index(drop=True).groupby('particle')
    filtered = grouped.filter(lambda x: x.frame.count() >= threshold)
    return filtered.set_index('frame', drop=False)


def split_by_pred(pred, iterable, constructor=list):
    """Sort elements of `iterable` into two lists based on predicate `pred`.

    Returns a tuple (l1, l2), where
     * l1: list of elements in `iterable` for which pred(elem) == True
     * l2: list of elements in `iterable` for which pred(elem) == False
    """
    pred_true = constructor()
    pred_false = constructor()
    for item in iterable:
        if pred(item):
            pred_true.append(item)
        else:
            pred_false.append(item)
    return pred_true, pred_false


def clear_predef_parse_reply():
    """Revert _parse to standard behaviour"""
    global _predef_parse_reply
    _predef_parse_reply = None


@staticmethod
def get_elastic_mappings(es_major):
    """Get Elasticsearch mapping.

        :param es_major: major version of Elasticsearch, as string
        :returns:        dictionary with a key, 'items', with the mapping
        """
    mapping = """
        {
            "properties": {
                 "Subject_analyzed": {
                   "type": "text",
                   "fielddata": true,
                   "index": true
                 },
                 "body": {
                   "type": "text",
                   "index": true
                 }
           }
        } """
    return {'items': mapping}


def add_outbound_message(msg, batch_ids=()):
    """
        Add an outbound mesage to the message store.

        :param msg:
            The TransportUserMessage to add.
        :param batch_ids:
            Sequence of batch identifiers to add the message to.

        :returns:
            ``None``.
            If async, a Deferred is returned instead.
        """


def force_fmg(mass, gravitational_field_strength):
    """Usage: Find force of gravity using mass and a gravitational constant """
    return mass * gravitational_field_strength


def debug_menu(debug_value: int=0):
    """Open a popup to set the debug level

    :param debug_value: Debug Value
    :type debug_value: int
    """
    pass


def median():
    """median of all incoming things"""


def UInt64(value):
    """Encode a 64-bit integer value"""
    return value.to_bytes(8, 'big')


def scan_module(module, interface):
    """Return all the items in a module that conform to an interface.

    Scan every item named in the module's `__all__`.  If that item conforms to
    the given interface, *and* the item is not declared as an
    `@abstract_component`, then return the item.

    :param module: A module object.
    :type module: module
    :param interface: The interface that returned objects must conform to.
    :type interface: `Interface`
    :return: The sequence of matching components.
    :rtype: items implementing `interface`
    """
    missing = object()
    for name in module.__all__:
        component = getattr(module, name, missing)
        assert component is not missing, '%s has bad __all__: %s' % (module,
            name)
        if interface.implementedBy(component
            ) and '__abstract_component__' not in component.__dict__:
            yield component


def getSets():
    """Returns a list of ISet in this cube."""