def _get_zone_letter(latitude):
    """
    Calculate the UTM zone letter from the given latitude. Shamelessly lifted
    from the utm.latitude_to_zone_letter function.

    Parameters
    ----------
    lat : float
        Latitude

    Returns
    -------
    zone_letter : str
        Zone letter

    """
    ZONE_LETTERS = 'CDEFGHJKLMNPQRSTUVWXX'
    if -80 <= latitude <= 84:
        return ZONE_LETTERS[int(latitude + 80) >> 3]
    else:
        return None


def PreciseTime():
    """Return the time string for the object."""


def tamper(payload, **kwargs):
    """
    Replaces instances of UNION ALL SELECT with UNION SELECT counterpart

    >>> tamper('-1 UNION ALL SELECT')
    '-1 UNION SELECT'
    """
    return payload.replace('UNION ALL SELECT', 'UNION SELECT'
        ) if payload else payload


def atom_is_in_ring(atom):
    """Get whether the atom is in ring.

    Parameters
    ----------
    atom : rdkit.Chem.rdchem.Atom
        RDKit atom instance.

    Returns
    -------
    list
        List containing one bool only.

    See Also
    --------
    atom_is_in_ring_one_hot
    """
    return [atom.IsInRing()]


def p_abs_location_path_3(p):
    """AbsoluteLocationPath : AbbreviatedAbsoluteLocationPath"""
    p[0] = p[1]


def __imul__(left, right):
    """
        Pose multiplication

        :arg left: left multiplicand
        :arg right: right multiplicand
        :return: product
        :raises: ValueError

        - ``X *= Y`` compounds the poses X and Y and places the result in X
        - ``X *= s`` performs elementwise multiplication of the elements of ``X``

        Any other input combinations result in a ValueError.

        Note that left and right can have a length greater than 1 in which case

        ====   =====   ====  ================================
        left   right   len     operation
        ====   =====   ====  ================================
         1      1       1    ``prod = left * right``
         1      M       M    ``prod[i] = left * right[i]``
         N      1       M    ``prod[i] = left[i] * right``
         M      M       M    ``prod[i] = left[i] * right[i]``
        ====   =====   ====  ================================

        A scalar of length M is list, tuple or numpy array.
        An N-vector of length M is a NxM numpy array, where each column is an N-vector.
        """
    return left.__mul__(right)


def format_baseline_list(baseline_list):
    """Format the list of baseline information from the loaded files into a
    cohesive, informative string

    Parameters
    ------------
    baseline_list : (list)
        List of strings specifying the baseline information for each
        SuperMAG file

    Returns
    ---------
    base_string : (str)
        Single string containing the relevent data

    """
    uniq_base = dict()
    uniq_delta = dict()
    for bline in baseline_list:
        bsplit = bline.split()
        bdate = ' '.join(bsplit[2:])
        if bsplit[0] not in uniq_base.keys():
            uniq_base[bsplit[0]] = ''
        if bsplit[1] not in uniq_delta.keys():
            uniq_delta[bsplit[1]] = ''
        uniq_base[bsplit[0]] += '{:s}, '.format(bdate)
        uniq_delta[bsplit[1]] += '{:s}, '.format(bdate)
    if len(uniq_base.items()) == 1:
        base_string = 'Baseline {:s}'.format(list(uniq_base.keys())[0])
    else:
        base_string = 'Baseline '
        for i, kk in enumerate(uniq_base.keys()):
            if i == 1:
                base_string += '{:s}: {:s}'.format(kk, uniq_base[kk][:-2])
            else:
                base_string += '         {:s}: {:s}'.format(kk, uniq_base[
                    kk][:-2])
        else:
            base_string += 'unknown'
    if len(uniq_delta.items()) == 1:
        base_string += '\nDelta    {:s}'.format(list(uniq_delta.keys())[0])
    else:
        base_string += '\nDelta    '
        for i, kk in enumerate(uniq_delta.keys()):
            if i == 1:
                base_string += '{:s}: {:s}'.format(kk, uniq_delta[kk][:-2])
            else:
                base_string += '         {:s}: {:s}'.format(kk, uniq_delta[
                    kk][:-2])
        else:
            base_string += 'unknown'
    return base_string


def partial_subset_of_range(range1, range2):
    """ Asks whether range1 is a subset of range2. Returns True or False respectively. """
    if not range1:
        raise ValueError('{} is empty'.format(range1))
    if not range2:
        raise ValueError('{} is empty'.format(range2))
    if len(range1) > 1 and range1.step % range2.step:
        return False
    return range1.start in range2 or range1[-1] in range2


def resetstate(repo):
    """remove any bisect state from the repository"""
    if repo.vfs.exists(b'bisect.state'):
        repo.vfs.unlink(b'bisect.state')


@staticmethod
def is_unsure():
    """
        Verify if the interface state is Unsure
        """
    return True


def intersect_point_quad_2d(pt: 'mathutils.Vector', quad_p1:
    'mathutils.Vector', quad_p2: 'mathutils.Vector', quad_p3:
    'mathutils.Vector', quad_p4: 'mathutils.Vector') ->int:
    """Takes 5 vectors (using only the x and y coordinates): one is the point and the next 4 define the quad, only the x and y are used from the vectors. Returns 1 if the point is within the quad, otherwise 0. Works only with convex quads without singular edges.

    :param pt: Point
    :type pt: 'mathutils.Vector'
    :param quad_p1: First point of the quad
    :type quad_p1: 'mathutils.Vector'
    :param quad_p2: Second point of the quad
    :type quad_p2: 'mathutils.Vector'
    :param quad_p3: Third point of the quad
    :type quad_p3: 'mathutils.Vector'
    :param quad_p4: Fourth point of the quad
    :type quad_p4: 'mathutils.Vector'
    """
    pass


def sort_2_lists(list1, list2):
    """Sort list1 in increasing order and list2 occordingly.

    :param list1: the first list.
    :param list2: the second list.

    :Example:

    >>> from pygtftk.utils import sort_2_lists
    >>> a = ["c", "a", "b"]
    >>> b = ["A", "B", "C"]
    >>> c = sort_2_lists(a, b)
    >>> assert c == [('a', 'b', 'c'), ('B', 'C', 'A')]

    """
    tups = sorted(zip(list1, list2))
    return list(zip(*sorted(tups)))


def _a_encode_tuple(values, mapping):
    """
    (1,2) --> ['2', 't', '1', 'i', '1', '1', 'i', '2']
    """
    assert isinstance(values, tuple), 'VALUE has invalid type: %s' % type(
        values)
    encoded = [str(len(values)).encode('UTF-8'), b't']
    extend = encoded.extend
    for value in values:
        extend(mapping[type(value).__name__](value, mapping))
    return encoded


@classmethod
def construct(cls, system, data):
    """
        Template method to enable customizing the object instantiation process.

        This enables system components to be cached rather than re-fetched every time
        """
    return cls(system, data)


def describe_index_fields(DomainName=None, FieldNames=None, Deployed=None):
    """
    Gets information about the index fields configured for the search domain. Can be limited to specific fields by name. By default, shows all fields and includes any pending changes to the configuration. Set the Deployed option to true to show the active configuration and exclude pending changes. For more information, see Getting Domain Information in the Amazon CloudSearch Developer Guide .
    See also: AWS API Documentation

    :example: response = client.describe_index_fields(
        DomainName='string',
        FieldNames=[
            'string',
        ],
        Deployed=True|False
    )

    :type DomainName: string
    :param DomainName: [REQUIRED]
            The name of the domain you want to describe.

    :type FieldNames: list
    :param FieldNames: A list of the index fields you want to describe. If not specified, information is returned for all configured index fields.
            (string) --

    :type Deployed: boolean
    :param Deployed: Whether to display the deployed configuration (true ) or include any pending changes (false ). Defaults to false .

    :rtype: dict
    :return: {
        'IndexFields': [
            {
                'Options': {
                    'IndexFieldName': 'string',
                    'IndexFieldType': 'int'|'double'|'literal'|'text'|'date'|'latlon'|'int-array'|'double-array'|'literal-array'|'text-array'|'date-array',
                    'IntOptions': {
                        'DefaultValue': 123,
                        'SourceField': 'string',
                        'FacetEnabled': True|False,
                        'SearchEnabled': True|False,
                        'ReturnEnabled': True|False,
                        'SortEnabled': True|False
                    },
                    'DoubleOptions': {
                        'DefaultValue': 123.0,
                        'SourceField': 'string',
                        'FacetEnabled': True|False,
                        'SearchEnabled': True|False,
                        'ReturnEnabled': True|False,
                        'SortEnabled': True|False
                    },
                    'LiteralOptions': {
                        'DefaultValue': 'string',
                        'SourceField': 'string',
                        'FacetEnabled': True|False,
                        'SearchEnabled': True|False,
                        'ReturnEnabled': True|False,
                        'SortEnabled': True|False
                    },
                    'TextOptions': {
                        'DefaultValue': 'string',
                        'SourceField': 'string',
                        'ReturnEnabled': True|False,
                        'SortEnabled': True|False,
                        'HighlightEnabled': True|False,
                        'AnalysisScheme': 'string'
                    },
                    'DateOptions': {
                        'DefaultValue': 'string',
                        'SourceField': 'string',
                        'FacetEnabled': True|False,
                        'SearchEnabled': True|False,
                        'ReturnEnabled': True|False,
                        'SortEnabled': True|False
                    },
                    'LatLonOptions': {
                        'DefaultValue': 'string',
                        'SourceField': 'string',
                        'FacetEnabled': True|False,
                        'SearchEnabled': True|False,
                        'ReturnEnabled': True|False,
                        'SortEnabled': True|False
                    },
                    'IntArrayOptions': {
                        'DefaultValue': 123,
                        'SourceFields': 'string',
                        'FacetEnabled': True|False,
                        'SearchEnabled': True|False,
                        'ReturnEnabled': True|False
                    },
                    'DoubleArrayOptions': {
                        'DefaultValue': 123.0,
                        'SourceFields': 'string',
                        'FacetEnabled': True|False,
                        'SearchEnabled': True|False,
                        'ReturnEnabled': True|False
                    },
                    'LiteralArrayOptions': {
                        'DefaultValue': 'string',
                        'SourceFields': 'string',
                        'FacetEnabled': True|False,
                        'SearchEnabled': True|False,
                        'ReturnEnabled': True|False
                    },
                    'TextArrayOptions': {
                        'DefaultValue': 'string',
                        'SourceFields': 'string',
                        'ReturnEnabled': True|False,
                        'HighlightEnabled': True|False,
                        'AnalysisScheme': 'string'
                    },
                    'DateArrayOptions': {
                        'DefaultValue': 'string',
                        'SourceFields': 'string',
                        'FacetEnabled': True|False,
                        'SearchEnabled': True|False,
                        'ReturnEnabled': True|False
                    }
                },
                'Status': {
                    'CreationDate': datetime(2015, 1, 1),
                    'UpdateDate': datetime(2015, 1, 1),
                    'UpdateVersion': 123,
                    'State': 'RequiresIndexDocuments'|'Processing'|'Active'|'FailedToValidate',
                    'PendingDeletion': True|False
                }
            },
        ]
    }

    :returns:
    RequiresIndexDocuments : the option's latest value will not be deployed until  IndexDocuments has been called and indexing is complete.
    Processing : the option's latest value is in the process of being activated.
    Active : the option's latest value is completely deployed.
    FailedToValidate : the option value is not compatible with the domain's data and cannot be used to index the data. You must either modify the option value or update or remove the incompatible documents.

    """
    pass


@staticmethod
def get_frozen(f):
    """Returns a string interpretation of the number of frozen/unfrozen layers in tuple `f`"""
    if f[0] == 0:
        return 'Unfrozen'
    elif f[1] == 0:
        return 'Frozen'
    else:
        return f'{f[0]}/{f[0] + f[1]} layers frozen'


def _ipv6_host(host):
    """
    Process IPv6 address literals
    """
    if host.startswith('[') and host.endswith(']'):
        host = host.replace('%25', '%').strip('[]')
    return host


def add_subcommands(parser, commands):
    """Add commands to a parser"""
    subps = parser.add_subparsers()
    for cmd, cls in commands:
        subp = subps.add_parser(cmd, help=cls.__doc__)
        add_args = getattr(cls, 'add_arguments', None)
        if add_args:
            add_args(subp)
        handler = getattr(cls, 'handle', None)
        if handler:
            subp.set_defaults(handler=handler)


def removeDuplicates(inFileName, outFileName):
    """removes duplicated lines from a 'inFileName' CSV file, the results are witten in 'outFileName'"""
    f = open(inFileName)
    legend = f.readline()
    data = ''
    h = {}
    h[legend] = 0
    lines = f.readlines()
    for l in lines:
        if l not in h:
            h[l] = 0
            data += l
    f.flush()
    f.close()
    f = open(outFileName, 'w')
    f.write(legend + data)
    f.flush()
    f.close()


@staticmethod
def p_function_list_optional_list(p):
    """function_list_optional_list : function_list_optional
                                       | function_list_optional function_list_optional_list"""
    try:
        p[0] = [p[1]] + p[2]
    except IndexError:
        p[0] = [p[1]]


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

        :param UserLogInfo val:
        :rtype: ParticipantLogInfo
        """
    return cls('user', val)


def simple_features(tag, token_index, len_tags, beginning_context,
    ending_context):
    """Return simple features from token"""
    token, postag, _, _ = tag
    features = ['bias', 'token.lower=%s' % token.lower(),
        'token.suffix[-3:]=%s' % token[-3:], 'token.suffix[-2:]=%s' % token
        [-2:], 'token.isupper=%s' % token.isupper(), 'token.istitle=%s' %
        token.istitle(), 'token.isdigit=%s' % token.isdigit(), 'postag=%s' %
        postag, 'postag[:2]=%s' % postag[:2]]
    if token_index == 0:
        features.append('BOS')
    elif token_index == len_tags - 1:
        features.append('EOS')
    len_context = len(beginning_context)
    for i, (token, postag, _, _) in enumerate(beginning_context):
        context_index = len_context - i
        features.extend(['-%d:token.lower=%s' % (context_index, token.lower
            ()), '-%d:token.istitle=%s' % (context_index, token.istitle()),
            '-%d:token.isupper=%s' % (context_index, token.isupper()),
            '-%d:postag=%s' % (context_index, postag), '-%d:postag[:2]=%s' %
            (context_index, postag[:2])])
    for context_index, (token, postag, _, _) in enumerate(ending_context, 1):
        features.extend(['+%d:token.lower=%s' % (context_index, token.lower
            ()), '+%d:token.istitle=%s' % (context_index, token.istitle()),
            '+%d:token.isupper=%s' % (context_index, token.isupper()),
            '+%d:postag=%s' % (context_index, postag), '+%d:postag[:2]=%s' %
            (context_index, postag[:2])])
    return features


def upload_ssh_public_key(UserName=None, SSHPublicKeyBody=None):
    """
    Uploads an SSH public key and associates it with the specified IAM user.
    The SSH public key uploaded by this action can be used only for authenticating the associated IAM user to an AWS CodeCommit repository. For more information about using SSH keys to authenticate to an AWS CodeCommit repository, see Set up AWS CodeCommit for SSH Connections in the AWS CodeCommit User Guide .
    See also: AWS API Documentation

    :example: response = client.upload_ssh_public_key(
        UserName='string',
        SSHPublicKeyBody='string'
    )

    :type UserName: string
    :param UserName: [REQUIRED]
            The name of the IAM user to associate the SSH public key with.
            This parameter allows (per its regex pattern ) a string of characters consisting of upper and lowercase alphanumeric characters with no spaces. You can also include any of the following characters: =,.@-

    :type SSHPublicKeyBody: string
    :param SSHPublicKeyBody: [REQUIRED]
            The SSH public key. The public key must be encoded in ssh-rsa format or PEM format.
            The regex pattern used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through u00FF). It also includes the special characters tab (u0009), line feed (u000A), and carriage return (u000D).

    :rtype: dict
    :return: {
        'SSHPublicKey': {
            'UserName': 'string',
            'SSHPublicKeyId': 'string',
            'Fingerprint': 'string',
            'SSHPublicKeyBody': 'string',
            'Status': 'Active'|'Inactive',
            'UploadDate': datetime(2015, 1, 1)
        }
    }

    """
    pass


def regnames_to_ranges(dev, regs):
    """Convert a list of register names to a register-ranges string.

    """
    indices = []
    for name in regs:
        indices.append(dev.reg_idx(name))
    indices = sorted(indices)
    ranges = []
    idx = 0
    while idx < len(indices):
        start = stop = indices[idx]
        idx += 1
        while idx < len(indices) and indices[idx] == stop + 1:
            stop = indices[idx]
            idx += 1
        if start == stop:
            ranges.append('%s' % start)
        else:
            ranges.append('%s:%s' % (start, stop))
    return ','.join(ranges)


def create_from_rsat_feature_names(dfile, key_transforms=None):
    """Uses a feature_names.tab file from RSAT to create a Thesaurus,
    represented as a dictionary.
    key_transforms is an optional list of key modifiers that are applied in
    sequence to the key before it is added to the dictionary
    a key_transform is a function from string -> [string], so multiple
    results can be returned from the transformer
    e.g. the feature_names.tab file stores VNG names with a modification
    suffix that can be removed
    """
    result = {}
    for line in dfile.lines:
        key = line[1]
        alternative = line[0]
        if key_transforms:
            for transform in key_transforms:
                for transform_key in transform(key):
                    result[transform_key] = alternative
        else:
            result[key] = alternative
    return result


def _encode_superdense(message, q):
    """
    Encode qubit q with the 2 bit message.

    Args:
        message: the message to encode
        q: the qubit to encode the message
    """
    if message == '00':
        pass
    elif message == '01':
        q.X()
    elif message == '10':
        q.Z()
    elif message == '11':
        q.X()
        q.Z()
    else:
        raise Exception('Not possible to encode this message')


def rangeFrameLocator(tickLocs, axisRange):
    """
	Convert axis tick positions for a Tufte style range frame. Takes existing tick locations, places a tick at the min and max of the data, and drops existing ticks that fall outside of this range or too close to the margins.

	TODO: Convert to a true axis artist that also sets spines

	:param list tickLocs: List of current tick locations on the axis
	:param tuple axisRange: Tuple of (min, max) value on the axis
	:returns: List of tick locations
	:rtype: list
	"""
    newTicks = [axisRange[0]]
    for tick in tickLocs:
        if tick <= axisRange[0]:
            pass
        elif tick >= axisRange[1]:
            pass
        else:
            newTicks.append(tick)
    newTicks.append(axisRange[1])
    return newTicks


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

        :param ResellerSupportSessionStartDetails val:
        :rtype: EventDetails
        """
    return cls('reseller_support_session_start_details', val)


def sort_df_for_grid(df, params):
    """
    Sort dataframe based on 'sort' property in parameter dictionary. Sort
    configuration is of the following shape:
    {
        sort: [
            [col1, ASC],
            [col2, DESC],
            ...
        ]
    }

    :param df: dataframe
    :type df: :class:`pandas:pandas.DataFrame`
    :param params: arguments from :attr:`flask:flask.request`
    :type params: dict
    :return: sorted dataframe
    :rtype: :class:`pandas:pandas.DataFrame`
    """
    if 'sort' in params:
        cols, dirs = [], []
        for col, dir in params['sort']:
            cols.append(col)
            dirs.append(dir == 'ASC')
        return df.sort_values(cols, ascending=dirs)
    return df.sort_index()


def constraints_clear():
    """Clear all the constraints for the selected bones

    """
    pass


def generator_updater(data_gen, **kwargs):
    """
    Update each item in a generator with kwargs.
    Expects the generator to be yielding dictionaries.
    """
    for item in data_gen:
        item.update(**kwargs)
        yield item


@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


@classmethod
def bringToFront(cls):
    """Brings page to front (activates tab).
        """
    return cls.build_send_payload('bringToFront', {}), None


def minreal(sys, tol=None, verbose=True):
    """
    Eliminates uncontrollable or unobservable states in state-space
    models or cancelling pole-zero pairs in transfer functions. The
    output sysr has minimal order and the same response
    characteristics as the original model sys.

    Parameters
    ----------
    sys: StateSpace or TransferFunction
        Original system
    tol: real
        Tolerance
    verbose: bool
        Print results if True

    Returns
    -------
    rsys: StateSpace or TransferFunction
        Cleaned model
    """
    sysr = sys.minreal(tol)
    if verbose:
        print('{nstates} states have been removed from the model'.format(
            nstates=len(sys.pole()) - len(sysr.pole())))
    return sysr


def is_math(value):
    """must be a valid math operator"""
    valid_maths = ['__add__', '__radd__', '__sub__', '__rsub__', '__mul__',
        '__rmul__', '__div__', '__rdiv__']
    valid_maths += ['sin', 'cos', 'tan']
    valid_maths += ['__and__', '__or__']
    return value in valid_maths, value


def reload_placeholder(update):
    """
    This function successfully does nothing.

    It serves as a placeholder so that we can attach an abort function to a
    specific point in the update pipeline.
    """
    pass


@classmethod
def get_actions_hotkeys(cls):
    """
        Return or yield a list of hotkeys to be linked to named actions.

        [{'key': key, 'ctrl': Bool, 'shift': Bool, 'ba': action_name}]

        """


@staticmethod
def _setup_topic(model):
    """
        This method is needed to setup the topic.
        model = {
            'connection_type': str,
            ...
        }
        """
    opt_args = model.get('optional_creation_arguments', {})
    return opt_args.get('topic', '')


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 lowpass(s, fc, tbw=0.01):
    """
    Lowpass filter of 1D object s.

    Parameters
    ----------

    s : Iterable or Generator
        Input signal
    fc : float
        Cutoff frequency as a fraction of the sampling rate (in (0, 0.5)).
    tbw : float, optional
        Transition band width, as a fraction of the cutoff frequency (in (0, 1), the default is 0.01).

    Return
    ------
    s_out : ndarray
        Low-pass version of input signal s.
    """
    from numpy import arange, cos, sinc, ceil, convolve, pi
    b = tbw * fc
    fc = fc - b
    N = int(ceil(4 / b))
    if not N % 2:
        N += 1
    n = arange(N)
    h = sinc(2 * fc * (n - (N - 1) / 2.0))
    w = 0.42 - 0.5 * cos(2 * pi * n / (N - 1)) + 0.08 * cos(4 * pi * n / (N -
        1))
    h = h * w
    h = h / sum(h)
    return convolve(s, h, 'same')


def _convert_stringval(value):
    """Converts a value to, hopefully, a more appropriate Python object."""
    value = str(value)
    try:
        value = int(value)
    except (ValueError, TypeError):
        pass
    return value


def write_vis(xds, outfile='vis.zarr', ddi=0, append=True):
    """
    Write xarray Visibility Dataset to zarr format on disk

    Parameters
    ----------
    xds : xarray.core.dataset.Dataset
        Visibility Dataset to write to disk
    outfile : str
        output filename, generally ends in .zarr
    int : ddi
        Data Description ID of Visibility data to write. Defaults to 0
    append : bool
        Append this DDI in to an existing zarr directory. False will erase old zarr directory. Default=True

    Returns
    -------
    """
    import os
    from numcodecs import Blosc
    from itertools import cycle
    outfile = os.path.expanduser(outfile)
    if not append:
        tmp = os.system('rm -fr ' + outfile)
    else:
        tmp = os.system('rm -fr ' + outfile + '/' + str(ddi))
    tmp = os.system('mkdir ' + outfile)
    compressor = Blosc(cname='zstd', clevel=2, shuffle=0)
    encoding = dict(zip(list(xds.data_vars), cycle([{'compressor':
        compressor}])))
    xds.to_zarr(outfile + '/' + str(ddi), mode='w', encoding=encoding)


def fileiterator(f, chunksize=8192):
    """Yield the content of a file by chunks of a given size at a time."""
    while True:
        chunk = f.read(chunksize)
        if not chunk:
            break
        yield chunk


def send_xmpp(to, sender, subject, body_text, body_html):
    """Send a message as a xmpp."""
    raise NotImplemented()


@staticmethod
def getReprArabicNumberFullWidth(number):
    """
                HLevel.getReprArabicNumberFullWidth

                number  : (int)
        """
    strnumber = str(number)
    res = []
    digit_to_fullwidthdigit = {'-': '-', '0': '０', '1': '１', '2': '２', '3':
        '３', '4': '４', '5': '５', '6': '６', '7': '７', '8': '８', '9': '９'}
    for digit in str(strnumber):
        res.append(digit_to_fullwidthdigit[digit])
    return ''.join(res)


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

        :param IntegrationDisconnectedDetails val:
        :rtype: EventDetails
        """
    return cls('integration_disconnected_details', val)


def explode_refresh(modifier: str=''):
    """Refresh data in the Explode modifier

    :param modifier: Modifier, Name of the modifier to edit
    :type modifier: str
    """
    pass


def split_target_value(field, value):
    """Split the reference value into target and value"""
    assert field['type'] == 'reference'
    target = None
    if isinstance(value, str):
        for key, text in field['selection']:
            if value.lower().startswith(text.lower() + ','):
                target = key
                value = value[len(text) + 1:]
                break
    return target, value


def _delta_te(in_values, te1=None, te2=None):
    """Read :math:`\\Delta_\\text{TE}` from BIDS metadata dict."""
    if isinstance(in_values, float):
        te2 = in_values
        te1 = 0.0
    if isinstance(in_values, dict):
        te1 = in_values.get('EchoTime1')
        te2 = in_values.get('EchoTime2')
        if not all((te1, te2)):
            te2 = in_values.get('EchoTimeDifference')
            te1 = 0
    if isinstance(in_values, list):
        te2, te1 = in_values
        if isinstance(te1, list):
            te1 = te1[1]
        if isinstance(te2, list):
            te2 = te2[1]
    if te1 is None and te2 is None:
        raise RuntimeError(
            'EchoTime1 and EchoTime2 metadata fields not found. Please consult the BIDS specification.'
            )
    if te1 is None:
        raise RuntimeError(
            'EchoTime1 metadata field not found. Please consult the BIDS specification.'
            )
    if te2 is None:
        raise RuntimeError(
            'EchoTime2 metadata field not found. Please consult the BIDS specification.'
            )
    return abs(float(te2) - float(te1))


@staticmethod
def accepted_ct():
    """Return a list of content types accepted by the tile."""
    return ['Audio']


def id_or_none(obj):
    """Returns None if the object is None, obj.ufl_id() if available, or id(obj) if not.

    This allows external libraries to implement an alternative
    to id(obj) in the ufl_id() function, such that ufl can identify
    objects as the same without knowing about their types.
    """
    if obj is None:
        return None
    elif hasattr(obj, 'ufl_id'):
        return obj.ufl_id()
    else:
        return id(obj)


@staticmethod
def get_jenkins_plugin_name():
    """Gets the name of the Jenkins plugin associated with this PyJen plugin

        This static method is used by the PyJen plugin API to associate this
        class with a specific Jenkins plugin, as it is encoded in the config.xml

        :rtype: :class:`str`
        """
    return 'hudson.model.MyView'


@staticmethod
def size(n):
    """
        Test if size of an array-like field is n.

        Example::

            filters = {"cart.items": Array.size(3)}
        """
    return {'$size': n}


def include_up_hosts(nmap_host):
    """
        Includes only hosts that have the status 'up'
    """
    if nmap_host.status == 'up':
        return True
    return False


def evaluate(value, *args, **kwargs):
    """
    This is a helper function used for lazy evaluation.

        1. If value is a callable it's called with given parameters
        2. If value is an iterable is converted to a tuple

    :param value: value to evluate
    :param args: positional arguments that are passed if value is a callable
    :param kwargs: key word arguments that are passed if value is a callable
    :return: evaluate value
    """
    if callable(value):
        value = value(*args, **kwargs)
    try:
        return tuple(value)
    except TypeError:
        return value


def resolve_pattern(pattern, args):
    """
    returns a string in which slots have been resolved with args, if the string has slots anyway,
    else returns the strng itself (no copy, should we??)
    :param pattern:
    :param args:
    :return:
    """
    if args is None or len(args) == 0:
        return pattern
    elif pattern.find('%') >= 0:
        return pattern % args
    elif pattern.find('{') >= 0:
        return pattern.format(*args)
    else:
        return pattern


def enable_endpoint_for_tenant(tenant_id, template_id):
    """
        Enable an endpoint for a specific tenant.

        :param six.text_type tenant_id: tenant id to operate on
        :param six.text_type template_id: endpoint template id to enable
        :raises: ValueError if the template id is not found
        """


def filter_select_columns_ratio(df, columns):
    """
    Filter dataframe to include specified columns, retaining Ratio columns.
    """
    return df.filter(regex='^(Ratio ./. normalized.*|%s)$' % '|'.join(columns))


def afterhgrcload(ui, wdirvfs, hgvfs, requirements):
    """Perform additional actions after .hg/hgrc is loaded.

    This function is called during repository loading immediately after
    the .hg/hgrc file is loaded and before per-repo extensions are loaded.

    The function can be used to validate configs, automatically add
    options (including extensions) based on requirements, etc.
    """
    autoextensions = {b'git': [b'git'], b'largefiles': [b'largefiles'],
        b'lfs': [b'lfs']}
    for requirement, names in sorted(autoextensions.items()):
        if requirement not in requirements:
            continue
        for name in names:
            if not ui.hasconfig(b'extensions', name):
                ui.setconfig(b'extensions', name, b'', source=b'autoload')


def gather_row(data, row_index):
    """Slice out the data given the row index.

    Parameters
    ----------
    data : Tensor
        The data tensor
    row_index : Tensor
        A 1-D integer tensor containing which rows to be sliced out.

    Returns
    -------
    Tensor
        The sliced data. The first dimension should equal to ``len(row_index)``.
    """
    pass


def has_ipynb_shell():
    """Check if IPython shell is available"""
    try:
        from IPython import get_ipython
        cls = get_ipython().__class__.__name__
        return cls == 'ZMQInteractiveShell'
    except:
        return False


def check_status_and_pickle(task):
    """Check the status of the task and update the pickle database."""
    task.flow.check_status()
    task.flow.pickle_dump()


def is_jupyter():
    """This Method is not foolprof and might fail with any given jupyter release
    :return: True if we believe to be running in a Jupyter Notebook or Lab
    """
    from IPython import get_ipython
    from os import environ
    force = environ.get('PYMOR_FORCE_JUPYTER', None)
    if force is not None:
        return bool(force)
    return type(get_ipython()).__module__.startswith('ipykernel.')


def _fix_frameshift_deletion(antibody, segment, s, e):
    """
    Fixes (removes) frameshift deletions.

    Input is a BlastResult object, the starting postion of the deletion (s) and the
    ending position of the deletion (e).

    Output is a modified BlastResult object.
    """
    segment.query_alignment = segment.query_alignment[:s
        ] + segment.germline_alignment[s:e] + segment.query_alignment[e:]
    segment.alignment_midline = segment.alignment_midline[:s] + ''.join([
        '|'] * (e - s)) + segment.alignment_midline[e:]
    oi_firsthalf = antibody.oriented_input.sequence[:s + segment.query_start]
    middle = segment.germline_alignment[s:e]
    oi_secondhalf = antibody.oriented_input.sequence[s + segment.query_start:]
    antibody.oriented_input.sequence = oi_firsthalf + middle + oi_secondhalf
    segment.query_end += e - s


@staticmethod
def convert_flag_to_name(s):
    """Try to convert str to legal Python identifier."""
    s = s.strip().lstrip('-').replace('-', '_')
    return s


def iter_distance_from_camera(stroke, range_min, range_max, normfac):
    """
    Yields the distance to the camera relative to the maximum
    possible distance for every stroke vertex, constrained by
    given minimum and maximum values.
    """
    for svert in stroke:
        distance = svert.point_3d.length
        if range_min < distance < range_max:
            yield svert, (distance - range_min) / normfac
        else:
            yield (svert, 0.0) if range_min > distance else (svert, 1.0)


def es_clickable_link(c, p, line_number, message):
    """Write a clickable message to the given line number of p.b."""
    log = c.frame.log
    unl = p.get_UNL(with_proto=True, with_count=True)
    if unl:
        nodeLink = f'{unl},{line_number}'
        log.put(message, nodeLink=nodeLink)
    else:
        log.put(message)


def getSkinSelections():
    """ Get the sorted list of available skin names.

        o Permission:  Public
        """


def get_set_intersection(list_i, list_j):
    """ Get the intersection set
    Parameters
    ----------
    list_i, list_j: list
        two generic lists

    Returns
    -------
    intersection_set: set
        the intersection of list_i and list_j
    """
    set_i = set(list_i)
    set_j = set(list_j)
    intersection_set = set_i.intersection(set_j)
    return intersection_set


def patch_prior_1_0(plotter_d, versions):
    """Patch psy_maps plotters for versions smaller than 1.0

    Before psyplot 1.0.0, the plotters in the psy_maps package where part of
    the psyplot.plotter.maps module. This has to be corrected"""
    plotter_d['cls'] = 'psy_maps.plotters', plotter_d['cls'][1]


def validate(email):
    """Validate an email address.

        :param email: A text email address.
        :type email: str
        :raise InvalidEmailAddressError: when `email` is deemed invalid.
        """


def extract_alzip(archive, compression, cmd, verbosity, interactive, outdir):
    """Extract a ALZIP archive."""
    return [cmd, '-d', outdir, archive]


def _is_preferred_to_delete(cl_del, cl) ->bool:
    """
    Compares two classifiers `cl_del` (marked for deletion) with `cl` to
    check whether `cl` should be deleted instead.

    Parameters
    ----------
    cl_del: Classifier marked for deletion
    cl: Examined classifier

    Returns
    -------
    bool
        True if `cl` is "worse" than `cl_del`. False otherwise
    """
    if cl.q - cl_del.q < -0.1:
        return True
    if abs(cl.q - cl_del.q) <= 0.1:
        if cl.is_marked() and not cl_del.is_marked():
            return True
        elif cl.is_marked or not cl_del.is_marked():
            if cl.tav > cl_del.tav:
                return True
    return False


def bool_to_tuple(input):
    """Converts a single :class:`bool <python:bool>` value to a
    :class:`tuple <python:tuple>` of form ``(bool, bool)``.

    :param input: Value that should be converted.
    :type input: :class:`bool <python:bool>` / 2-member :class:`tuple <python:tuple>`

    :returns: :class:`tuple <python:tuple>` of form (:class:`bool <python:bool>`,
      :class:`bool <python:bool>`)
    :rtype: :class:`tuple <python:tuple>`

    :raises ValueError: if ``input`` is not a :class:`bool <python:bool>` or
      2-member :class:`tuple <python:tuple>`
    """
    if input is True:
        input = True, True
    elif not input:
        input = False, False
    elif not isinstance(input, tuple) or len(input) > 2:
        raise ValueError('input was neither a bool nor a 2-member tuple')
    return input


def configure(conf):
    """
	Detects the program gdbus-codegen and sets ``conf.env.GDBUS_CODEGEN``
	"""
    conf.find_program('gdbus-codegen', var='GDBUS_CODEGEN')


def is_downgrades_https(domain):
    """
    Domain downgrades if HTTPS is supported in some way, but
    its canonical HTTPS endpoint immediately redirects internally to HTTP.
    """
    canonical, https, httpswww = (domain.canonical, domain.https, domain.
        httpswww)
    supports_https = (https.live and not https.https_bad_hostname or
        httpswww.live and not httpswww.https_bad_hostname)
    if canonical.host == 'www':
        canonical_https = httpswww
    else:
        canonical_https = https
    return bool(supports_https and canonical_https.
        redirect_immediately_to_http and not canonical_https.
        redirect_immediately_to_external)


@classmethod
def undecorate(cls, function):
    """
        Remove validator decoration from a function.

        The `function` argument is the function to be cleaned from
        the validator decorator.
        """
    if cls.is_function_validated(function):
        return cls.get_function_validator(function).function
    return function


def _validate_timeout(timeout):
    """
    Raises an exception if the given timeout is an invalid value.
    """
    if not (timeout is None or type(timeout) == int and timeout > 0):
        raise ValueError('timeout must be a positive integer')


def url_flask_to_swagger(source):
    """Convert Flask URL to swagger path."""
    return source.replace('<', '{').replace('>', '}')


def close_event(event):
    """
    Closes an event retrieved from Pilatus files.

    Since an event corresponds to a CBF data file, which does not need to be closed,
    this function actually does nothing.

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

    Arguments:

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


def execute_fetch(connection, query):
    """Execute SELECT sql"""
    sql = str(query)
    with connection.cursor() as cursor:
        row = cursor.execute(sql)
        result = cursor.fetchall()
    return result, row


def line_number():
    """The current line number

    """
    pass


def subpositions(G):
    """
        Return an iterator over all subpositions of G.

        Yields
        ------
        g : Game
            A subposition of G.
        """
    for g in (G._left | G._right):
        yield g
        yield from g.subpositions()


def _create_ansi_color_dict(color_cls):
    """ Create a table that maps the 16 named ansi colors to their Windows code. """
    return {'ansidefault': color_cls.BLACK, 'ansiblack': color_cls.BLACK,
        'ansidarkgray': color_cls.BLACK | color_cls.INTENSITY,
        'ansilightgray': color_cls.GRAY, 'ansiwhite': color_cls.GRAY |
        color_cls.INTENSITY, 'ansidarkred': color_cls.RED, 'ansidarkgreen':
        color_cls.GREEN, 'ansibrown': color_cls.YELLOW, 'ansidarkblue':
        color_cls.BLUE, 'ansipurple': color_cls.MAGENTA, 'ansiteal':
        color_cls.CYAN, 'ansired': color_cls.RED | color_cls.INTENSITY,
        'ansigreen': color_cls.GREEN | color_cls.INTENSITY, 'ansiyellow':
        color_cls.YELLOW | color_cls.INTENSITY, 'ansiblue': color_cls.BLUE |
        color_cls.INTENSITY, 'ansifuchsia': color_cls.MAGENTA | color_cls.
        INTENSITY, 'ansiturquoise': color_cls.CYAN | color_cls.INTENSITY}


def perm_conjugate(p1, p2, n=None):
    """
    Conjugate ``p1`` by ``p2``.

    Let call ``res`` the output of this function. If ``p1`` was
    mapping ``a`` to ``b`` then ``res`` will map ``p2[a]``
    to ``p2[b]``.

    EXAMPLES::

        sage: from surface_dynamics.misc.permutation import perm_random, perm_conjugate

        sage: p1 = perm_random(23)
        sage: p2 = perm_random(23)
        sage: res = perm_conjugate(p1, p2)
        sage: res[p2[14]] == p2[p1[14]]
        True
        sage: res[p2[19]] == p2[p1[19]]
        True
    """
    if n is None:
        n = len(p1)
    res = [-1] * n
    for i in range(n):
        res[p2[i]] = p2[p1[i]]
    return res


@classmethod
def get(cls, project_id, model_id):
    """ Retrieve model parameters.

        Parameters
        ----------
        project_id : str
            The project's id.
        model_id : str
            Id of model parameters we requested.

        Returns
        -------
        ModelParameters
            The queried model parameters.
        """
    url = 'projects/{}/models/{}/parameters/'.format(project_id, model_id)
    return cls.from_location(url)


def convert_uuid(*args, **kwargs):
    """
    Handle converter type "uuid"

    :param args:
    :param kwargs:
    :return: return schema dict
    """
    schema = {'type': 'string', 'format': 'uuid'}
    return schema


def hide(unselected: bool=False):
    """Hide (un)selected UV vertices

    :param unselected: Unselected, Hide unselected rather than selected
    :type unselected: bool
    """
    pass


def cloudwatch_dimension(name: str, value: (str, int)):
    """ Structure for forming aCloudwatch dimension """
    return {'Name': str(name), 'Value': str(value)}


def reshape_fortran(tensor, shape):
    """The missing Fortran reshape for mx.NDArray

    Parameters
    ----------
    tensor : NDArray
        source tensor
    shape : NDArray
        desired shape

    Returns
    -------
    output : NDArray
        reordered result
    """
    return tensor.T.reshape(tuple(reversed(shape))).T


def p_first(p):
    """
    const_expr : STRING_LIT
               | FLOAT_LIT
               | INTEGER_LIT
               | BOOLEAN_LIT
    expr : primary
    primary : simple_primary
    native_element : primary
                   | NATIVE_STRING_LIT
    type : simple_type
    statement : simple_statement newlines
              | dlt
    actions : action
    parameter_types_list : parameter_types_list1
    opmode_type : AUTONOMOUS
                | TELEOP
    """
    p[0] = p[1]


@staticmethod
def add_cmdline_args(argparser):
    """Add command-line arguments specifically for this agent."""
    agent = argparser.add_argument_group('RetrieverReader Arguments')
    agent.add_argument('--retriever-model-file', type=str, default=None)
    agent.add_argument('--reader-model-file', type=str, default=None)
    agent.add_argument('--num-retrieved', type=int, default=5, help=
        'how many passages to retrieve')
    agent.add_argument('--split-paragraphs', type='bool', default=True,
        help='Whether to split the retrieved passages into paragraphs')
    return agent


def compute_empty_cells_score(stats, columns, col_name):
    """
    # Creates a quality socre based on the percentage of empty cells (empty_percentage)

    :param stats: The stats extracted up until this point for all columns
    :param columns: All the columns
    :param col_name: The name of the column we should compute the new stats for
    :return: Dictioanry containing:
        empty_cells_score: A quality score based on the nr of empty cells, ranges from 1 to 0, where 1 is lowest quality and 0 is highest quality.
    """
    return {'empty_cells_score': round(10 * (1 - stats[col_name][
        'empty_percentage'] / 100)), 'empty_cells_score_description':
        'This score is computed as the % of empty values / 100. Empty values in a column are always bad for training correctly on that data.'
        }


def get_loging_level(level):
    """
    Find corresponding logging level related to BitDust log level:

        0 : CRITICAL
        1-2 : FATAL
        3-4 : ERROR
        5-6 : WARNING
        7-8 : INFO
        9-10 : DEBUG
        11... : NOTSET
    """
    import logging
    if level == 0:
        return logging.CRITICAL
    if level <= 2:
        return logging.FATAL
    if level <= 4:
        return logging.ERROR
    if level <= 6:
        return logging.WARNING
    if level <= 8:
        return logging.INFO
    if level <= 10:
        return logging.DEBUG
    return logging.NOTSET


def get_preferred_sparse_format():
    """Get the preferred sparse matrix format supported by the backend.

    Different backends have their preferred backend. This info is useful when
    constructing a sparse matrix.
    """
    return 'csr'


def register_serialization_lazy(toplevel, func):
    """Register a registration function to be called if *toplevel*
    module is ever loaded.
    """
    raise Exception('Serialization registration has changed. See documentation'
        )


def resize_aspect(width, height, wanted_width=None, wanted_height=None):
    """ resize_aspect(width, height, wanted_width=None, wanted_height = None)

    resizes to either the width or height, and keeps the other one with
    the given aspect ratio.

    >>> resize_aspect(100, 120, None, 60)
    (50, 60)
    >>> resize_aspect(100, 120, 200, None)
    (200, 240)
    >>> resize_aspect(100, 120, 200, 200)
    Traceback (most recent call last):
    ...
    ValueError: must give either a wanted_width or wanted_height
    """
    if wanted_width is None and wanted_height is None:
        raise ValueError('must give either a wanted_width or wanted_height')
    if wanted_width is not None and wanted_height is not None:
        raise ValueError('must give either a wanted_width or wanted_height')
    if wanted_height is not None:
        the_width = width / (float(height) / wanted_height)
        the_height = wanted_height
    else:
        the_width = wanted_width
        the_height = height / (float(width) / wanted_width)
    return int(the_width), int(the_height)


@staticmethod
def int(value):
    """Make sure the value is an integer, or None."""
    try:
        return int(value)
    except ValueError:
        return None


def jsName(path, name):
    """Returns a name string without \\, -, and . so that
    the string will play nicely with javascript."""
    shortPath = path.replace('C:\\Users\\scheinerbock\\Desktop\\' +
        'ideogram\\scrapeSource\\test\\', '')
    noDash = shortPath.replace('-', '_dash_')
    jsPath = noDash.replace('\\', '_slash_').replace('.', '_dot_')
    jsName = jsPath + '_slash_' + name
    return jsName


def d(value: bytes) ->str:
    """
    Decode a bytestring for interpolating into an error message.

    """
    return value.decode(errors='backslashreplace')


def is_multiple(a: float, b: float, tolerance: float=tolerance) ->bool:
    """
    is_multiple - Check whether a%b is 0 within some tolerance.
    :param a: float The number that may be multiple of b
    :param b: float The number a may be a multiple of
    :param tolerance: float Relative tolerance
    :return bool: True if a is a multiple of b within some tolerance
    """
    min_remainder = min(a % b, b - a % b)
    return min_remainder < tolerance * b


def set_prefs(prefs):
    """This function is called before opening the project"""
    prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject', '.hg',
        '.svn', '_svn', '.git']
    prefs['save_objectdb'] = True
    prefs['compress_objectdb'] = False
    prefs['automatic_soa'] = True
    prefs['soa_followed_calls'] = 0
    prefs['perform_doa'] = True
    prefs['validate_objectdb'] = True
    prefs['max_history_items'] = 32
    prefs['save_history'] = True
    prefs['compress_history'] = False
    prefs['indent_size'] = 4
    prefs['extension_modules'] = []
    prefs['import_dynload_stdmods'] = True
    prefs['ignore_syntax_errors'] = False
    prefs['ignore_bad_imports'] = False


@classmethod
def from_sqla(cls, sqla_obj):
    """ Create a yalchemy CheckConstraint from a sqlalchemy CheckConstraint """
    if sqla_obj.name is None or str(sqla_obj.name) == '_unnamed_':
        name = None
    else:
        name = str(sqla_obj.name)
    return cls(name, str(sqla_obj.sqltext))


def create_literal(val, datatype=None, lang=None):
    """
    Put the value in unicode escaping new special characters to keep canonical form
    From NT specification at 'https://www.w3.org/TR/n-triples/#canonical-ntriples':
    "Within STRING_LITERAL_QUOTE, only the characters U+0022, U+005C, U+000A, U+000D are
    encoded using ECHAR. ECHAR must not be used for characters that are allowed directly
    in STRING_LITERAL_QUOTE."
    """
    escape_pairs = [(u'\\', '\\\\'), (u'"', '\\"'), (u'\n', '\\n'), (u'\r',
        '\\r')]
    for orig, rep in escape_pairs:
        val = val.replace(orig, rep)
    lit_value = u'"{}"'.format(val)
    if datatype is not None:
        lit_value += '^^<{}>'.format(datatype)
    elif lang is not None:
        lit_value += '@{}'.format(lang)
    return lit_value


def serialize(obj):
    """JSON serializer for objects not serializable by default json code
    """
    if getattr(obj, '__dict__', False):
        return obj.__dict__
    return str(obj)


def registeredAdapters():
    """Return an iterable of IAdapterRegistration instances.

        These registrations describe the current adapter registrations
        in the object.
        """


def register_job_definition(jobDefinitionName=None, type=None, parameters=
    None, containerProperties=None, retryStrategy=None):
    """
    Registers an AWS Batch job definition.
    See also: AWS API Documentation

    Examples
    This example registers a job definition for a simple container job.
    Expected Output:

    :example: response = client.register_job_definition(
        jobDefinitionName='string',
        type='container',
        parameters={
            'string': 'string'
        },
        containerProperties={
            'image': 'string',
            'vcpus': 123,
            'memory': 123,
            'command': [
                'string',
            ],
            'jobRoleArn': 'string',
            'volumes': [
                {
                    'host': {
                        'sourcePath': 'string'
                    },
                    'name': 'string'
                },
            ],
            'environment': [
                {
                    'name': 'string',
                    'value': 'string'
                },
            ],
            'mountPoints': [
                {
                    'containerPath': 'string',
                    'readOnly': True|False,
                    'sourceVolume': 'string'
                },
            ],
            'readonlyRootFilesystem': True|False,
            'privileged': True|False,
            'ulimits': [
                {
                    'hardLimit': 123,
                    'name': 'string',
                    'softLimit': 123
                },
            ],
            'user': 'string'
        },
        retryStrategy={
            'attempts': 123
        }
    )

    :type jobDefinitionName: string
    :param jobDefinitionName: [REQUIRED]
            The name of the job definition to register.

    :type type: string
    :param type: [REQUIRED]
            The type of job definition.

    :type parameters: dict
    :param parameters: Default parameter substitution placeholders to set in the job definition. Parameters are specified as a key-value pair mapping. Parameters in a SubmitJob request override any corresponding parameter defaults from the job definition.
            (string) --
            (string) --

    :type containerProperties: dict
    :param containerProperties: An object with various properties specific for container-based jobs. This parameter is required if the type parameter is container .
            image (string) -- [REQUIRED]The image used to start a container. This string is passed directly to the Docker daemon. Images in the Docker Hub registry are available by default. Other repositories are specified with `` repository-url /image :tag `` . Up to 255 letters (uppercase and lowercase), numbers, hyphens, underscores, colons, periods, forward slashes, and number signs are allowed. This parameter maps to Image in the Create a container section of the Docker Remote API and the IMAGE parameter of docker run .
            Images in Amazon ECR repositories use the full registry and repository URI (for example, 012345678910.dkr.ecr.region-name.amazonaws.com/repository-name ).
            Images in official repositories on Docker Hub use a single name (for example, ubuntu or mongo ).
            Images in other repositories on Docker Hub are qualified with an organization name (for example, amazon/amazon-ecs-agent ).
            Images in other online repositories are qualified further by a domain name (for example, quay.io/assemblyline/ubuntu ).
            vcpus (integer) -- [REQUIRED]The number of vCPUs reserved for the container. This parameter maps to CpuShares in the Create a container section of the Docker Remote API and the --cpu-shares option to docker run . Each vCPU is equivalent to 1,024 CPU shares.
            memory (integer) -- [REQUIRED]The hard limit (in MiB) of memory to present to the container. If your container attempts to exceed the memory specified here, the container is killed. This parameter maps to Memory in the Create a container section of the Docker Remote API and the --memory option to docker run .
            command (list) --The command that is passed to the container. This parameter maps to Cmd in the Create a container section of the Docker Remote API and the COMMAND parameter to docker run . For more information, see https://docs.docker.com/engine/reference/builder/#cmd .
            (string) --
            jobRoleArn (string) --The Amazon Resource Name (ARN) of the IAM role that the container can assume for AWS permissions.
            volumes (list) --A list of data volumes used in a job.
            (dict) --A data volume used in a job's container properties.
            host (dict) --The contents of the host parameter determine whether your data volume persists on the host container instance and where it is stored. If the host parameter is empty, then the Docker daemon assigns a host path for your data volume, but the data is not guaranteed to persist after the containers associated with it stop running.
            sourcePath (string) --The path on the host container instance that is presented to the container. If this parameter is empty, then the Docker daemon has assigned a host path for you. If the host parameter contains a sourcePath file location, then the data volume persists at the specified location on the host container instance until you delete it manually. If the sourcePath value does not exist on the host container instance, the Docker daemon creates it. If the location does exist, the contents of the source path folder are exported.
            name (string) --The name of the volume. Up to 255 letters (uppercase and lowercase), numbers, hyphens, and underscores are allowed. This name is referenced in the sourceVolume parameter of container definition mountPoints .

            environment (list) --The environment variables to pass to a container. This parameter maps to Env in the Create a container section of the Docker Remote API and the --env option to docker run .
            Warning
            We do not recommend using plain text environment variables for sensitive information, such as credential data.
            (dict) --A key-value pair object.
            name (string) --The name of the key value pair. For environment variables, this is the name of the environment variable.
            value (string) --The value of the key value pair. For environment variables, this is the value of the environment variable.

            mountPoints (list) --The mount points for data volumes in your container. This parameter maps to Volumes in the Create a container section of the Docker Remote API and the --volume option to docker run .
            (dict) --Details on a Docker volume mount point that is used in a job's container properties.
            containerPath (string) --The path on the container at which to mount the host volume.
            readOnly (boolean) --If this value is true , the container has read-only access to the volume; otherwise, the container can write to the volume. The default value is false .
            sourceVolume (string) --The name of the volume to mount.

            readonlyRootFilesystem (boolean) --When this parameter is true, the container is given read-only access to its root file system. This parameter maps to ReadonlyRootfs in the Create a container section of the Docker Remote API and the --read-only option to docker run .
            privileged (boolean) --When this parameter is true, the container is given elevated privileges on the host container instance (similar to the root user). This parameter maps to Privileged in the Create a container section of the Docker Remote API and the --privileged option to docker run .
            ulimits (list) --A list of ulimits to set in the container. This parameter maps to Ulimits in the Create a container section of the Docker Remote API and the --ulimit option to docker run .
            (dict) --The ulimit settings to pass to the container.
            hardLimit (integer) -- [REQUIRED]The hard limit for the ulimit type.
            name (string) -- [REQUIRED]The type of the ulimit .
            softLimit (integer) -- [REQUIRED]The soft limit for the ulimit type.

            user (string) --The user name to use inside the container. This parameter maps to User in the Create a container section of the Docker Remote API and the --user option to docker run .

    :type retryStrategy: dict
    :param retryStrategy: The retry strategy to use for failed jobs that are submitted with this job definition. Any retry strategy that is specified during a SubmitJob operation overrides the retry strategy defined here.
            attempts (integer) --The number of times to move a job to the RUNNABLE status. You may specify between 1 and 10 attempts. If attempts is greater than one, the job is retried if it fails until it has moved to RUNNABLE that many times.

    :rtype: dict
    :return: {
        'jobDefinitionName': 'string',
        'jobDefinitionArn': 'string',
        'revision': 123
    }

    """
    pass


def shortest_path_pick():
    """Select shortest path between two bones

    """
    pass


def get_config_str(config, section, option, default_value=None):
    """tries to retrieve a str value from config or returns the default"""
    try:
        return config.get(section, option)
    except:
        return default_value


def group(nb, digits=0):
    """Transforms a number into a string with a thousand separator.

    .. code-block:: python

        pycof.group(nb, digits=0)

    :Parameters:
        * **nb** (:obj:`float`): Number to be transformed.
        * **digits** (:obj:`int`): Number of digits to round.

    :Example:
        >>> pycof.group(12345)
        ... '12,345'
        >>> pycof.group(12345.54321, digits=3)
        ... '12,345.543'

    :Returns:
        * :obj:`str`: Transformed number.
    """
    s = '%d' % nb
    groups = []
    if digits > 0:
        dig = '.' + str(nb).split('.')[1][:digits]
    else:
        dig = ''
    while s and s[-1].isdigit():
        groups.append(s[-3:])
        s = s[:-3]
    return s + ','.join(reversed(groups)) + dig


def convert_offsets(offsets, offset_sets):
    """ Convert offset indices to world values for any number of offsets. """
    world_offsets = []
    for offset, offset_set in zip(offsets, offset_sets):
        world_offsets.append(offset_set.index_to_world(offset))
    return world_offsets


def _parse_template(cf_client, template):
    """Parse and validate the cloudformation template file.

    Parameters
    ----------
    cf_client : object
        Cloudformation client for performing stack operations.
    template : str
        Filename of the cloudformation template.

    Returns
    -------
    str
        Cloudformation template data.
    """
    with open(template) as template_fileobj:
        template_data = template_fileobj.read()
    cf_client.validate_template(TemplateBody=template_data)
    return template_data


def preffiletype(preffile):
    """ Infer type from first uncommented line in preffile
    """
    with open(preffile, 'r') as fp:
        while True:
            line = fp.readline().split('#')[0]
            if line:
                break
    if '=' in line:
        return 'old'
    elif ':' in line:
        return 'yaml'
    else:
        return None


def _convert_remove_append(options):
    """Convert append and remove dicts read from .yaml file.

    :param options: {'section.key': 'value1,value2', ...}
    :type options: dict
    :return: ['section.key=value1,value2', ...]
    :rtype: list
    """
    converted = []
    for key in options:
        v = options[key]
        if isinstance(v, list):
            v = ','.join(v)
        converted.append(key + '=' + v)
    return converted


@classmethod
def find(cls, db, token):
    """Find a token object by value.

        Returns None if not found.

        `kind='user'` only returns API tokens for users
        `kind='service'` only returns API tokens for services
        """
    prefix_match = cls.find_prefix(db, token)
    for orm_token in prefix_match:
        if orm_token.match(token):
            return orm_token


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

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


@staticmethod
def is_batch():
    """
        Returns whether DCC is being executed in batch mode or not
        :return: bool
        """
    return False


def insert_derived_spline(spline_dictionary, spline_keys, derived_quantity,
    log=print):
    """Inserts a spline into a dictionary of horizon splines

    Derived from Horizons.h5.  Note: spline_keys is a vector of key
    names (should be length 1 for scalars, length 3 for vectors), where
    each key is the name of a group that will be written in the LVC
    file, such as Omega-vs-time or LNhatx-vs-time; and derived_quantity
    is the quantity to be splined.  The derived_quantity should be
    computed using derived_horizon_quantities_from_sxs().

    """
    from . import LVCDataset
    log('Computing ' + str(spline_keys))
    times_AH = derived_quantity[:, (0)]
    quantity_AH = derived_quantity[:, 1:]
    for i, spline_key in enumerate(spline_keys):
        spline_dictionary[spline_key] = LVCDataset.from_data(times_AH,
            quantity_AH[:, (i)], tol=1e-06)


def range_overlap(a_min, a_max, b_min, b_max):
    """
    Neither range is completely greater than the other.
    """
    return a_min < b_max and b_min < a_max


@classmethod
def close(cls, stream):
    """
        Close a stream. Typically use :py:func:`Stream.close` instead.

        :param stream: An instance of the :py:class:`Stream` object.
        :raises ValueError: if stream does not exist.
        """
    if stream not in cls._streams:
        raise ValueError("Stream `%s' not found" % str(stream))
    stream.close()


def check_distribusi_index(args, index):
    """
    check whether a index.html file is generated by distribusi
    """
    if not args.force:
        with open(index, 'r') as f:
            if '<meta name="generator" content="distribusi" />' in f.read():
                return True
            else:
                if args.verbose:
                    print(index, 'not generated by distribusi, skipping')
                return False
    elif args.force:
        return True


def strip_words(text):
    """
    When multiple words (separated by '|') are
    used to describe emojis, we need to remove the
    '|' in order to create edges for each word.
    This function takes out the '|' and puts all
    the words into a list.
    """
    return text.split(' | ')


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

        :param UserDeleteEmailsResult val:
        :rtype: UserDeleteResult
        """
    return cls('success', val)


def Day_():
    """Compatibility: see pDay"""


@classmethod
def normalize(cls, obj):
    """Normalize an object, if possible, to conform to this type.

        Args:
            obj (object): Object to normalize.

        Returns:
            object: Normalized object.

        """
    try:
        obj = int(obj)
    except BaseException:
        pass
    return obj


@staticmethod
def concat_url(endpoint, url):
    """Concatenate endpoint and final URL.

        E.g., "http://keystone/v2.0/" and "/tokens" are concatenated to
        "http://keystone/v2.0/tokens".

        :param endpoint: the base URL
        :param url: the final URL
        """
    return '%s/%s' % (endpoint.rstrip('/'), url.strip('/'))


def wave_overtone_relative_amplitude(wavetype='saw', overtone=2):
    """
    Return the relative amplitude of the overtone given the wavetype

    Available wavetypes are: saw, sine, square, and tri (triangle)
    """
    if overtone <= 0:
        raise ValueError('Overtone should be >= 1 (f0 = overtone 1)')
    if wavetype == 'saw':
        return 1 / overtone
    elif wavetype == 'square':
        return 1 / overtone * (overtone % 2)
    elif wavetype == 'sine':
        return 1 if overtone == 1 else 0
    elif wavetype == 'tri':
        return 1 / overtone ** 2 * (overtone % 2)
    else:
        raise KeyError(
            'wavetype not known, should be one of saw, square, sine or tri')


@classmethod
def _size_from_header(cls, header):
    """
        Get the size of each columns from the header.

        :param dict header:
            The header template we have to get the size from.

        :return: The maximal size of the each data to print.
        :rtype: list
        """
    result = []
    for data in header:
        result.append(header[data])
    return result


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


def sql_flush(style, connection, only_django=False, reset_sequences=True,
    allow_cascade=False):
    """
    Return a list of the SQL statements used to flush the database.

    If only_django is True, only include the table names that have associated
    Django models and are in INSTALLED_APPS .
    """
    if only_django:
        tables = connection.introspection.django_table_names(only_existing=
            True, include_views=False)
    else:
        tables = connection.introspection.table_names(include_views=False)
    seqs = connection.introspection.sequence_list() if reset_sequences else ()
    statements = connection.ops.sql_flush(style, tables, seqs, allow_cascade)
    return statements


def as_cpx(arr):
    """
    interpret arr as a complex array
    useful to move between complex and real arrays (see as_float)

    >>> print as_cpx(np.arange(4.0))
    [ 0.+1.j  2.+3.j]

    """
    return arr.view(dtype='complex')


def save_model(model, fname):
    """Save a Model to a file.

    Parameters
    ----------
    model : model instance
        Model to be saved.
    fname : str
        Name of file for saved Model.

    """
    with open(fname, 'w') as fout:
        model.dump(fout)


def size_to_kb_mb_string(data_size: int, as_additional_info: bool=False) ->str:
    """Returns human-readable string with kilobytes or megabytes depending on the data_size range.

		:param data_size: data size in bytes to convert
		:param as_additional_info:
		if True, the dynamic data appear in round bracket after the number in bytes. e.g. '12345678 bytes (11.7 MB)'
		if False, only the dynamic data is returned e.g. '11.7 MB' """
    if data_size < 1024:
        as_additional_info = False
        dynamic = f'{data_size} bytes'
    elif data_size < 1048576:
        dynamic = f'{data_size / 1024:0.1f} kB'
    else:
        dynamic = f'{data_size / 1048576:0.1f} MB'
    if as_additional_info:
        return f'{data_size} bytes ({dynamic})'
    else:
        return dynamic


def brush_copy():
    """Copy current Grease Pencil drawing brush

    """
    pass


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

        :param SfAddGroupDetails val:
        :rtype: EventDetails
        """
    return cls('sf_add_group_details', val)


def calculate_r_dynamic(r_wheels, tyre_dynamic_rolling_coefficient):
    """
    Calculates the dynamic radius of the wheels [m].

    :param r_wheels:
        Radius of the wheels [m].
    :type r_wheels: float

    :param tyre_dynamic_rolling_coefficient:
        Dynamic rolling coefficient [-].
    :type tyre_dynamic_rolling_coefficient: float

    :return:
        Dynamic radius of the wheels [m].
    :rtype: float
    """
    return tyre_dynamic_rolling_coefficient * r_wheels


def unpack(pyramid, backend='numpy'):
    """ Unpacks a pyramid give back the constituent parts.

    :param pyramid: The Pyramid of DTCWT transforms you wish to unpack
    :param str backend: A string from 'numpy', 'opencl', or 'tf' indicating
        which attributes you want to unpack from the pyramid.

    :returns: returns a generator which can be unpacked into the Yl, Yh and
        Yscale components of the pyramid. The generator will only return 2
        values if the pyramid was created with the include_scale parameter set
        to false.

    .. note::

        You can still unpack a tf or opencl pyramid as if it were created by a
        numpy. In this case it will return a numpy array, rather than the
        backend specific array type.
    """
    backend = backend.lower()
    if backend == 'numpy':
        yield pyramid.lowpass
        yield pyramid.highpasses
        if pyramid.scales is not None:
            yield pyramid.scales
    elif backend == 'opencl':
        yield pyramid.cl_lowpass
        yield pyramid.cl_highpasses
        if pyramid.cl_scales is not None:
            yield pyramid.cl_scales
    elif backend == 'tf':
        yield pyramid.lowpass_op
        yield pyramid.highpasses_ops
        if pyramid.scales_ops is not None:
            yield pyramid.scales_ops


@classmethod
def get_number_of_electrons(cls, calc, **kwargs):
    """Return the number of electrons."""
    parameters = calc.outputs.output_parameters
    if 'number_of_electrons' not in parameters.attrs():
        return None
    return parameters.get_attr('number_of_electrons')


@classmethod
def line_intersection(cls, line0, line1):
    """ Returns True if line0 intersects line1, else False.
        Returns -1 if line0 and line1 are collinear and intersect.

        cls.test_intersection(np.arr[float(x4)], np.arr[float(x4)]) -> int

        """
    p0, q0 = line0.reshape((2, 2))
    p1, q1 = line1.reshape((2, 2))
    ori_0p1 = cls.cross_orientation(p0, q0, p1)
    ori_0q1 = cls.cross_orientation(p0, q0, q1)
    ori_1p0 = cls.cross_orientation(p1, q1, p0)
    ori_1q0 = cls.cross_orientation(p1, q1, q0)
    if ori_0p1 == ori_0q1 == 0 or ori_1p0 == ori_1q0 == 0:
        return -1
    return ori_0p1 != ori_0q1 and ori_1p0 != ori_1q0


def describe_ca_certificate(certificateId=None):
    """
    Describes a registered CA certificate.
    See also: AWS API Documentation

    :example: response = client.describe_ca_certificate(
        certificateId='string'
    )

    :type certificateId: string
    :param certificateId: [REQUIRED]
            The CA certificate identifier.

    :rtype: dict
    :return: {
        'certificateDescription': {
            'certificateArn': 'string',
            'certificateId': 'string',
            'status': 'ACTIVE'|'INACTIVE',
            'certificatePem': 'string',
            'ownedBy': 'string',
            'creationDate': datetime(2015, 1, 1),
            'autoRegistrationStatus': 'ENABLE'|'DISABLE'
        }
    }

    """
    pass


def to_offset(page_num, per_page):
    """
    Convert a page_num and per_page to offset.

    :param page_num: The current page number
    :type page_num: int
    :param per_page: The maximum number of results per page
    :type per_page: int
    :rtype: int

    """
    if page_num and per_page:
        return (page_num - 1) * per_page
    else:
        return None


def square(x):
    """
	Squares each value of an array
	"""
    series = []
    for i in range(0, len(x)):
        series.append(x[i] ** 2)
    return series


@classmethod
def info(cls):
    """Display information about a Contact."""
    return cls.call('contact.info')


def hash_iterable(it):
    """Perform a O(1) memory hash of an iterable of arbitrary length.

	hash(tuple(it)) creates a temporary tuple containing all values from it
	which could be a problem if it is large.

	See discussion at:
	https://groups.google.com/forum/#!msg/python-ideas/XcuC01a8SYs/e-doB9TbDwAJ
	"""
    hash_value = hash(type(it))
    for value in it:
        hash_value = hash((hash_value, value))
    return hash_value


def unique(L):
    """Return a list of unhashable elements in s, but without duplicates.
    [[1, 2], [2, 3], [1, 2]] >>> [[1, 2], [2, 3]]"""
    nDupli = 0
    nZcolinear = 0
    L.sort()
    last = L[-1]
    for i in range(len(L) - 2, -1, -1):
        if last[:2] == L[i][:2]:
            if last[2] == L[i][2]:
                nDupli += 1
            else:
                nZcolinear += 1
            del L[i]
        else:
            last = L[i]
    return nDupli, nZcolinear


@classmethod
def param_spec_names(cls):
    """Lists the names of all param_specs defined in the study"""
    return iter(cls._param_specs.keys())


@staticmethod
def strategy_override(config, path, base, nxt):
    """ overrides the new object over the old object """
    return nxt


def break_connection(module, array, target_array):
    """Break connection between arrays"""
    changed = True
    if not module.check_mode:
        source_array = array.get()['array_name']
        try:
            array.disconnect_array(target_array['array_name'])
        except Exception:
            module.fail_json(msg='Failed to disconnect {0} from {1}.'.
                format(target_array['array_name'], source_array))
    module.exit_json(changed=changed)


def parseQueryEx(query):
    """Parse a query string.

        Return a tuple (tree, ignored) where 'tree' is the parse tree
        as returned by parseQuery(), and 'ignored' is a list of
        ignored terms as returned by getIgnored().

        May raise ParseTree.ParseError.
        """


def p_simple_stmt(p):
    """ simple_stmt : small_stmt
                    | simple_stmt ";" small_stmt """
    if len(p) == 2:
        p[0] = ['STATEMENTS', [p[1]]]
    else:
        p[0] = ['STATEMENTS', p[1][1] + [p[3]]]


@classmethod
def get_current(cls, app, tag):
    """
        Given an app and a tag, look for a build that matches both, and was
        successfully built (or is currently building).  If not found, return
        None.
        """
    builds = cls.objects.filter(app=app, tag=tag).exclude(status='expired'
        ).exclude(status='failed').order_by('-id')
    if not builds:
        return None
    return builds[0]


def parse_attributes(attribute_string):
    """Returns region of attribute string between first pair of double quotes"""
    attribute_string = attribute_string[attribute_string.find('"') + 1:]
    if '"' in attribute_string:
        attribute_string = attribute_string[:attribute_string.find('"')]
    return attribute_string


def load(project_id):
    """
        Google API Project Client Secrets를 적재한다.

        :param project_id:
            Google API 프로젝트 식별자
        :returns: client_type, client_info
        :raises KeyError:
            주어진 프로젝트 식별자에 해당하는 Client Secrets가 없음
        """


@staticmethod
def _build_mac(fields, data):
    """Build MAC string. Length is in bytes instead of symbols."""
    f = lambda x: data.get('VK_%s' % x).encode('latin', 'ignore')
    return ''.join(map(lambda k: '%03d%s' % (len(f(k)), f(k)), fields))


@property
def __abstract__(cls):
    """
        Whether this model class is abstract or not.
        """
    return cls._abstract


def tex(text, env=None):
    """Create html code for any object with a string representation

    Parameters
    ----------
    text : any
        Object to be converted to HTML. If the object has a ``.get_html()``
        method the result of this method is returned, otherwise ``str(text)``.
    env : dict
        Environment for FMTXT compilation.
    """
    if hasattr(text, 'get_tex'):
        if env is None:
            env = {'math': False}
        elif 'math' not in env:
            env['math'] = False
        return text.get_tex(env)
    else:
        return str(text)


@classmethod
def from_config(cls, config, **kwargs):
    """Instantiate this class from (inner) config."""
    return cls._from_config(config, **kwargs)


def view_center_lock():
    """Center the view lock offset

    """
    pass


def delete_run(run):
    """Delete a run from paragraph."""
    r = run._r
    r.getparent().remove(r)


def accuracy_efficiency(rk1, parallel=False, mode='float', tol=1e-14, p=None):
    """
    Compute the accuracy efficiency of method rk1.

    The accuracy efficiency is

    `\\eta = \\frac{1}{s_1} \\left(\\frac{1}{A_1}\\right)^{1/p+1}`

    where `s_1` are the number of stages of the the method and
    `A_1` is its principal error norms.

    **Examples**::

        Accuracy efficiency of Dormand-Prince
        >>> from nodepy import rk
        >>> dp5 = rk.loadRKM('DP5')
        >>> rk.accuracy_efficiency(dp5) # doctest: +ELLIPSIS
        0.5264921944121...
    """
    if p is None:
        p = rk1.order(mode=mode, tol=tol)
    A1 = rk1.principal_error_norm(mode=mode, tol=tol)
    if parallel:
        return 1.0 / rk1.num_seq_dep_stages() * (1.0 / A1) ** (1.0 / (p + 1))
    else:
        return 1.0 / len(rk1) * (1.0 / A1) ** (1.0 / (p + 1))


@staticmethod
def all_which(entity):
    """
        Select all pipelines.
        """
    return True


def parse_color(color):
    """Parse a color value.

    I've decided not to expect a leading '#' because it's a comment character
    in some shells.

        >>> parse_color('4bf') == (0x44, 0xbb, 0xff, 0xff)
        True
        >>> parse_color('ccce') == (0xcc, 0xcc, 0xcc, 0xee)
        True
        >>> parse_color('d8b4a2') == (0xd8, 0xb4, 0xa2, 0xff)
        True
        >>> parse_color('12345678') == (0x12, 0x34, 0x56, 0x78)
        True

    Raises ValueError on errors.
    """
    if len(color) not in (3, 4, 6, 8):
        raise ValueError('bad color %s' % repr(color))
    if len(color) in (3, 4):
        r = int(color[0], 16) * 17
        g = int(color[1], 16) * 17
        b = int(color[2], 16) * 17
    elif len(color) in (6, 8):
        r = int(color[0:2], 16)
        g = int(color[2:4], 16)
        b = int(color[4:6], 16)
    if len(color) == 4:
        a = int(color[3], 16) * 17
    elif len(color) == 8:
        a = int(color[6:8], 16)
    else:
        a = 255
    return r, g, b, a


def t_php_DOC_COMMENT(t):
    """/\\*\\*(.|\\n)*?\\*/"""
    t.lexer.lineno += t.value.count('\n')
    return t


def decodedir(path):
    """
    >>> decodedir(b'data/foo.i')
    'data/foo.i'
    >>> decodedir(b'data/foo.i.hg/bla.i')
    'data/foo.i/bla.i'
    >>> decodedir(b'data/foo.i.hg.hg/bla.i')
    'data/foo.i.hg/bla.i'
    """
    if b'.hg/' not in path:
        return path
    return path.replace(b'.d.hg/', b'.d/').replace(b'.i.hg/', b'.i/').replace(
        b'.hg.hg/', b'.hg/')


def solution(func):
    """Attach the `func` a solution marker
    """
    func.__dict__['solution'] = True
    return func


def ResultIter(cursor, arraysize=1000000):
    """An iterator that uses fetchmany to keep memory usage down"""
    while True:
        results = cursor.fetchmany(arraysize)
        if not results:
            break
        for result in results:
            yield result


@classmethod
def slope_of_last_term(cls, f, h, *args, **kwargs):
    """Get the slope (up to a constant) of the last term of the series with h.

        Parameters
        ----------
        f : callable
            The function to integrate/transform
        h : float
            The resolution parameter of the hankel integration

        Other Parameters
        ----------------
        args, kwargs :
            All other parameters are passed through to :func:`final_term_amplitude`.

        Returns
        -------
        float :
            The derivative of the last term of the series with h.
        """
    return cls.final_term_amplitude(f, h, *args, **kwargs
        ) - cls.final_term_amplitude(f, h / 1.1, *args, **kwargs)


@classmethod
def from_api_data(cls, data):
    """Creates a new Seat object from API data from ticketswitch.

        Args:
            data (dict): the part of the response from a ticketswitch API call
                that concerns a seat.

        Returns:
            :class:`Seat <pyticketswitch.seat.Seat>`: a new
            :class:`Seat <pyticketswitch.seat.Seat>` object
            populated with the data from the api.

        """
    kwargs = {'id_': data.get('full_id'), 'column': data.get('col_id'),
        'row': data.get('row_id'), 'is_restricted': data.get(
        'is_restricted_view', False), 'seat_text_code': data.get(
        'seat_text_code'), 'seat_text': data.get('seat_text'), 'separator':
        data.get('separator', ''), 'barcode': data.get('barcode')}
    return cls(**kwargs)


def get_atomic_number_symbol(Z=None, symbol=None):
    """This function returns a tuple of matching arrays of atomic numbers
    (Z) and chemical symbols (symbol).

    :param Z: atomic numbers
    :type Z: int, array like object of int's
    :param symbol: chemical symbols
    :type symbol: str, array like object of str
    :return: arrays of atomic numbers and chemical symbols
    :rtype: tuple of :class:`numpy.ndarray`

    Note: If both Z and symbol are provided the symbol will win out and
    change the Z to match.

    :examples:

    >>> Z, symbol = get_atomic_number_symbol(Z=[12, 24, 26, 48])
    >>> print(Z)
    [12 24 26 48]
    >>> print(symbol[0])
    Mg
    >>> print(symbol[1])
    Cr
    >>> print(symbol[2])
    Fe
    >>> print(symbol[3])
    Cd

    >>> Z, symbol = get_atomic_number_symbol(symbol=['C', 'H', 'N', 'O'])
    >>> print(Z)
    [6 1 7 8]
    >>> print(symbol)
    ['C' 'H' 'N' 'O']
    """
    import numpy as np
    from periodictable import elements
    if isinstance(Z, int):
        Z = [Z]
    if isinstance(symbol, str):
        symbol = [symbol]
    if np.count_nonzero(symbol) == 0:
        if np.count_nonzero(Z) == 0:
            raise ValueError("Need to provide list of either Z's or symbols.")
        else:
            Z = np.asarray(Z)
            length = len(Z)
            symbol = np.empty(length, dtype='<U2')
            for i in range(length):
                symbol[i] = elements[Z[i]].symbol
    else:
        symbol = np.asarray(symbol)
        length = len(symbol)
        Z = np.empty(length, dtype=np.int64)
        for i in range(length):
            symbol[i] = symbol[i].capitalize()
            Z[i] = elements.symbol(symbol[i]).number
    return Z, symbol


def contains_bias(layer):
    """
    Check whether the layer contains a bias.
    """
    if hasattr(layer, 'bias'):
        return True
    else:
        return False


def kwargs_repr(kwargs, **options):
    """Format positional arguments to use in exception handling.

    :params kwargs: dict as obtained in arguments when declared as
           ``**kwargs``.

    :param options: some extra options are used in this function.

           - count: maximum amount of actual parameters to process; after
             reached that amount a tail item is appended with the remainder
             number.  If None is given -the default- the value ``3`` is used.

           - cast: must be a function to convert the value into the
             representation; when no value is given -the default- it's assumed
             ``λ arg: type(arg).__name__``.

           - item_format: the format for each argument type, if no value is
             given the value "{}:{}" is used.  Each item value is
             obtained as with the "cast" function.

           - tail_format: a format string for the tail with the remainder (not
             processed arguments) specification; must contain a positional
             (like "{}") format specifier if obtaining the remainder count is
             desired; when no value is given -the default- the value "..." is
             used; another valid example could be "and {} more".

           - joiner: could be a function or a string to join all parts
             including the tail; if no value is given -the default- the value
             ", " is used (thed equivalent to ``', '.join``).

    For example::

      >>> kwargs_repr({'x': 1, 'y': 2.0, 'z': '3', 'zz': {}})
      'x:int, y:float, z:str, ...'

    """
    count = options.get('count', 3)
    cast = options.get('cast', lambda arg: type(arg).__name__)
    item_format = options.get('item_format', '{}:{}')
    tail_format = options.get('tail_format', '...')
    joiner = options.get('joiner', ', ')
    if isinstance(joiner, str):
        joiner = str(joiner).join
    parts = []
    keys = list(kwargs)
    keys.sort()
    i = 0
    while i < min(count, len(keys)):
        key = keys[i]
        value = kwargs[key]
        parts.append(item_format.format(key, cast(value)))
        i += 1
    rem = len(keys) - i
    if rem > 0:
        parts.append(tail_format.format(rem))
    return joiner(parts)


def _terminal_settings(spawn, prompt, timeout):
    """Run commands for terminal settings
    :param spawn: a Spawn object
    :param prompt: a string representing a pattern to match against the content of the buffer
    :param timeout: in seconds
    :return:
    """
    initcommands = """
        top
        terminal length 0
        terminal width 511
    """
    for cmd in initcommands.split('\n'):
        cmd = cmd.strip()
        spawn.sendline(cmd)
        spawn.expect(prompt, timeout=timeout)


@classmethod
def get(cls, object_id, feature_name, bin_limit=None, key_name=None):
    """Retrieve a single feature histogram

        Parameters
        ----------
        object_id : str
            The ID of the object the feature is associated with.
        feature_name : str
            The name of the feature to retrieve
        bin_limit : int or None
            Desired max number of histogram bins. If omitted, by default
            endpoint will use 60.
        key_name: string or None
            (Only required for summarized categorical feature)
            Name of the top 50 keys for which plot to be retrieved

        Returns
        -------
        featureHistogram : FeatureHistogram
            The queried instance with `plot` attribute in it.
        """
    path = cls._build_url(object_id, feature_name, bin_limit, key_name)
    return cls.from_location(path)


@staticmethod
def p_mod_common_optional_parameter_list(p):
    """mod_common_optional_list : mod_common_optional
                                    | mod_common_optional mod_common_optional_list"""
    try:
        p[0] = [p[1]] + p[2]
    except IndexError:
        p[0] = [p[1]]


def auto_type(string):
    """
    Try and convert a string to an integer or float
    """
    try:
        return int(string)
    except:
        try:
            return float(string)
        except:
            return string


def count_tup(tupl, value, start=None, end=None):
    """
    Counts the number of times ``value`` occurs in ``tupl[start:end]``.

    Optional arguments start and end are interpreted as in slice notation.

    :param tupl: The tuple to search
    :type tupl:  ``tuple``

    :param value: The value to count
    :type value:  ``any``

    :param start: The start of the search range
    :type start:  ``int``

    :param end: The end of the search range
    :type end:  ``int``

    :return: The number of times ``value`` occurs in ``tupl[start:end]``.
    :rtype:  ``int``
    """
    assert type(tupl) == tuple, '%s is not a tuple' % tupl
    return tupl[start:end].count(value)


@staticmethod
def strip_textpad(text):
    """
        Attempt to intelligently strip excess whitespace from the output of a
        curses textpad.
        """
    if text is None:
        return text
    if '\n' not in text:
        return text.rstrip()
    stack, current_line = [], ''
    for line in text.split('\n'):
        if line.endswith('  ') or not line:
            stack.append(current_line + line.rstrip())
            current_line = ''
        else:
            current_line += line
    stack.append(current_line)
    for item in stack[::-1]:
        if not item:
            stack.pop()
        else:
            break
    out = '\n'.join(stack)
    return out


def router_from_id(routerid):
    """
        Note that this method MUST always return a Router instance --
        if you ask for a router ID that didn't yet exist, it is
        created (although without IP addresses and such because it
        wasn't in the consensus). You may find out if a Router came
        from the 'GETINFO ns/all' list by checking the from_consensus
        attribute. This is to simplify code like in Circuit.update()
        that needs to handle the case where an EXTENDED circuit event
        is the only time we've seen a Router -- it's possible for Tor
        to do things with routers not in the consensus (like extend
        circuits to them).

        :return: a router by its ID.
        """


def parse_range(spec):
    """
    Return minimum, maximum, and stepping value for a range.

    Argument `spec` must be a string of the form `LOW:HIGH:STEP`,
    where LOW, HIGH and STEP are (integer or floating-point) numbers.
    Example::

      >>> parse_range('1:10:2')
      (1, 10, 2)

      >>> parse_range('1.0:3.5:0.5')
      (1.0, 3.5, 0.5)

    Note that, as soon as *any* one of LOW, HIGH, STEP is not an
    integer, *all* of them are parsed as Python floats::

      >>> parse_range('1:3:0.5')
      (1.0, 3.0, 0.5)

      >>> parse_range('1.0:3:1')
      (1.0, 3.0, 1.0)

      >>> parse_range('1:3.0:1')
      (1.0, 3.0, 1.0)

    The final part `:STEP` can be omitted if the step is `1`::

      >>> parse_range('2:5')
      (2, 5, 1)

      >>> parse_range('1.0:3.0')
      (1.0, 3.0, 1.0)

    Finally, note that `parse_range` does not perform any kind of
    check on the validity of the resulting range; so it is possible to
    parse a string into an empty range or range specification with
    stepping 0::

      >>> parse_range('1:-5:10')
      (1, -5, 10)

      >>> parse_range('1:2:0')
      (1, 2, 0)

    As a special case to simplify user interfaces, a single number is
    accepted as a *degenerate* range: it will be parsed as a range
    whose content is just the given number::

      >>> parse_range('42')
      (42, 43, 1)
    """
    colons = spec.count(':')
    if colons == 2:
        low, high, step = spec.split(':')
    elif colons == 1:
        low, high = spec.split(':')
        step = '1'
    elif colons == 0:
        low = spec
        if '.' in low:
            high = str(float(low) + 1)
        else:
            high = str(int(low) + 1)
        step = '1'
    else:
        raise ValueError(
            "Argument `spec` must have the form 'LOW:HIGH:STEP', where LOW, HIGH and STEP are (integer or floating-point) numbers."
            )
    if '.' in low or '.' in high or '.' in step:
        low = float(low)
        high = float(high)
        step = float(step)
    else:
        low = int(low)
        high = int(high)
        step = int(step)
    return low, high, step


@classmethod
def cast_from_kw(cls, kw, grid, default_value=0):
    """Will convert a normal EclKW to a Ecl3DKW.

        The method will convert a normal EclKW instance to Ecl3DKw
        instance with an attached grid and a default value.

        The method will check that size of the keyword is compatible
        with the grid dimensions, i.e. the keyword must have either
        nactive or nx*ny*nz elements. If the size of the keyword is
        not compatible with the grid dimensions a ValueError exception
        is raised.

        Example:

          1. Load the poro keyword from a grdecl formatted file.
          2. Convert the keyword to a 3D keyword.

        from ecl.ecl import EclGrid,EclKW,Ecl3DKW

        grid = EclGrid("ECLIPSE.EGRID")
        poro = EclKW.read_grdecl(open("poro.grdecl") , "PORO")
        Ecl3DKW.castFromKW( poro , grid )

        print('Porosity in cell (10,11,12):%g' % poro[10,11,12])
        """
    if len(kw) == grid.getGlobalSize():
        kw.global_active = True
    elif len(kw) == grid.getNumActive():
        kw.global_active = False
    else:
        raise ValueError(
            'Size mismatch - must have size matching global/active size of grid'
            )
    kw.__class__ = cls
    kw.default_value = default_value
    kw.grid = grid
    if len(kw) == grid.getGlobalSize():
        kw.global_active = True
    else:
        kw.global_active = False
    kw.setDefault(default_value)
    return kw


def g_to_oz(g):
    """
    Convert grams to ounces
    """
    return g / 28.34952


@classmethod
def get_balance(cls, address):
    """Gets the balance of an address in satoshi.

        :param address: The address in question.
        :type address: ``str``
        :raises ConnectionError: If all API services fail.
        :rtype: ``int``
        """
    for api_call in cls.GET_BALANCE_MAIN:
        try:
            return api_call(address)
        except cls.IGNORED_ERRORS:
            pass
    raise ConnectionError('All APIs are unreachable.')


def and_filter(filter_predicate_one, filter_predicate_two):
    """Combine two filter predicates with the logical AND."""
    return lambda properties: filter_predicate_one(properties
        ) and filter_predicate_two(properties)


@classmethod
def filter_params(cls, ref):
    """Remove unspecified parameters from the dictionary.

        This function removes unspecified parameters from the dictionary.
        This method checks only root-level keys from a ref dictionary.

        :param ref: a dictionary representing deserialized response to be
                    serialized
        """
    if cls._public_parameters:
        ref_keys = set(ref.keys())
        blocked_keys = ref_keys - cls._public_parameters
        for blocked_param in blocked_keys:
            del ref[blocked_param]
    return ref


def fix_edge_betweennesses(G):
    """
    Given a graph G, makes sure that every edge has a betweenness
    score assigned to it.
    """
    for e in G.es:
        if e['eb'] is None:
            e['eb'] = 0