def getrefnames(idf, objname):
    """get the reference names for this object"""
    iddinfo = idf.idd_info
    dtls = idf.model.dtls
    index = dtls.index(objname)
    fieldidds = iddinfo[index]
    for fieldidd in fieldidds:
        if 'field' in fieldidd:
            if fieldidd['field'][0].endswith('Name'):
                if 'reference' in fieldidd:
                    return fieldidd['reference']
                else:
                    return []


def normalize(position):
    """ Accepts `position` of arbitrary precision and returns the block
    containing that position.

    Parameters
    ----------
    position : tuple of len 3

    Returns
    -------
    block_position : tuple of ints of len 3

    """
    x, y, z = position
    x, y, z = int(round(x)), int(round(y)), int(round(z))
    return x, y, z


def rect(x, a, y0):
    """
    yep, that's a rect!
    """
    y = a * x + y0
    return y


def ask(prompt: str='', default: str='') ->str:
    """Print the ``prompt``, get user's answer, return it -- or a default."""
    if prompt:
        if default:
            prompt = prompt + ' [' + default + ']'
        prompt = prompt + ' '
    answer = None
    while not answer:
        answer = input(prompt)
        if default and not answer:
            return default
    return answer


def display_to_paper(x, y, layout):
    """Convert mpl display coordinates to plotly paper coordinates.

    Plotly references object positions with an (x, y) coordinate pair in either
    'data' or 'paper' coordinates which reference actual data in a plot or
    the entire plotly axes space where the bottom-left of the bottom-left
    plot has the location (x, y) = (0, 0) and the top-right of the top-right
    plot has the location (x, y) = (1, 1). Display coordinates in mpl reference
    objects with an (x, y) pair in pixel coordinates, where the bottom-left
    corner is at the location (x, y) = (0, 0) and the top-right corner is at
    the location (x, y) = (figwidth*dpi, figheight*dpi). Here, figwidth and
    figheight are in inches and dpi are the dots per inch resolution.

    Positional agruments:
    x -- x coordinate in pixels
    y -- y coordinate in pixels
    layout -- layout for plotly rendering, required for non-zero margins

    Returns:
    x_paper, y_paper -- display coords converted to plotly's papaer coords

    """
    num_x = x - layout['margin']['l']
    den_x = layout['width'] - (layout['margin']['l'] + layout['margin']['r'])
    num_y = y - layout['margin']['b']
    den_y = layout['height'] - (layout['margin']['b'] + layout['margin']['t'])
    return num_x / den_x, num_y / den_y


def p_and_test(p):
    """and_test : not_test
                 | and_test AND not_test
                 | and_test BADAND not_test"""
    if len(p) == 2:
        p[0] = p[1]
    else:
        p[0] = ['MATHOP', 'and', p[1], p[3]]


@staticmethod
def get_table_name(aliased_class):
    """ Returns the table name given an Aliased class"""
    return aliased_class.__tablename__


@classmethod
def get_data(cls, name, default=None):
    """
        Retrieve the desired attribute from the thread local object or the given default value
        """
    data = getattr(cls.__locals, name, default)
    return data


def get_cache(cache_item, config):
    """ returns cached item  """
    dpath = config.get('cache', 'cache_dir')
    inv = {}
    try:
        cache = open('/'.join([dpath, 'scaleway_ansible_inventory.json']), 'r')
        inv = cache.read()
        cache.close()
    except IOError as e:
        pass
    return inv


def get_E(data, keys):
    """
    Retrive the E from a dataset
    """
    try:
        Ei = keys.index('Ekine')
    except:
        try:
            Ei = keys.index('E')
        except:
            raise RuntimeError(
                "Error, cannot find key 'Ekine' nor 'E'. Keys are: ", keys)
    E = data[:, (Ei)]
    return E, Ei


@staticmethod
def split_line(line):
    """
		Split line using ; as separator char
		considering single quotes as a way to delimit
		tokens. (in particular to enable using char ; inside a token)
		"""
    tokens = []
    token = ''
    in_qoutes = False
    in_dqoutes = False
    for char in line:
        if char == '"' and not in_qoutes:
            in_dqoutes = not in_dqoutes
        elif char == "'" and not in_dqoutes:
            in_qoutes = not in_qoutes
        elif char == ';' and not in_qoutes and not in_dqoutes:
            tokens.append(token)
            token = ''
        else:
            token += char
    if token.strip() != '':
        tokens.append(token)
    return tokens


@staticmethod
def create_event_list(ll_ref, ll_hyp, time_threshold=0.01):
    """
        Create an event list of all labels.

        Arguments:
            ll_ref (LabelList): Reference labels.
            ll_hyp (LabelList): Hypothesis labels.
            time_threshold (float): If two event times are closer than this threshold the time of the
                                    earlier event is used for both events.

        Returns:
            list: List of list of tuples. Every tuple contains a time, type (start or end), ll_index (ref/hyp) and
            the label which is responsible for the event. It is sorted ascending by time.
        """
    events = []
    for label in ll_ref:
        events.append((label.start, 'S', 0, label))
        events.append((label.end, 'E', 0, label))
    for label in ll_hyp:
        events.append((label.start, 'S', 1, label))
        events.append((label.end, 'E', 1, label))
    events = sorted(events, key=lambda x: x[0])
    time_grouped = []
    current_group = events[0][0], [events[0]]
    for i in range(1, len(events)):
        if abs(events[i][0] - events[i - 1][0]) < time_threshold:
            current_group[1].append(events[i])
        else:
            time_grouped.append(current_group)
            current_group = events[i][0], [events[i]]
    time_grouped.append(current_group)
    return time_grouped


def methods_of(obj):
    """Get all callable methods of an object that don't start with underscore

    returns a list of tuples of the form (method_name, method)
    """
    result = []
    for i in dir(obj):
        if callable(getattr(obj, i)) and not i.startswith('_'):
            result.append((i, getattr(obj, i)))
    return result


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


def write_gct(df, file_path):
    """
    Writes the provided DataFrame to a GCT file.

    Assumes that the DataFrame matches the structure of those produced
    by the GCT() function in this library

    :param df:
    :param file_path:
    :return:
    """
    with open(file_path, 'w') as file:
        file.write('#1.2\n' + str(len(df.index)) + '\t' + str(len(df.
            columns)) + '\n')
        df.to_csv(file, sep='\t', mode='w+')


@staticmethod
def make_json(raw_json, prettyprint=False):
    """Turn the string copied from the Inspect->Network window into a Dict."""
    json = eval(raw_json.replace('null', 'None').replace('false', 'False').
        replace('true', 'True'))
    if prettyprint:
        import pprint
        pprint.pprint(json)
    return json


@classmethod
def model_type(cls):
    """
        get the model type name
        :return: the model type name
        """
    return cls.__name__


@staticmethod
def get_status(instance):
    """
        Returns the status of a VM instance
        provisioning | staging | running | stopping |
        stopped | suspending | suspended | terminated
        """
    return instance['status'].lower()


def count_chains(structure):
    """
    Uses Biopython to obtain the number of chains.
    Called by: OligoSum.py:main()
    """
    nchains = 0
    for model in structure:
        if model.id == 0:
            for chain in model:
                nres = 0
                nchains += 1
                for residue in chain:
                    nres += 1
    return nchains, nres


def chunks(l, n):
    """Yield successive n-size chunks from l."""
    for i in range(0, len(l), n):
        yield l[i:i + n]


def parse_float(arg, name, parser):
    """
    Tries to parse a string as a float.

    :param arg:    The arg to parse as a float
    :param name:   A description of the argument used for error messages
    :param parser: The parser used to report an error message
    :return: The parsed float if succeeds or the original argument if fails
    """
    if arg == 'None' or arg is None:
        return None
    else:
        try:
            arg = float(arg)
            return arg
        except ValueError:
            parser.error("'" + arg + "' is not a valid " + name)
            return None


def skeletonModuleName(mname):
    """Convert a scoped name string into the corresponding skeleton
module name. e.g. M1.M2.I -> M1__POA.M2.I"""
    l = mname.split('.')
    l[0] = l[0] + '__POA'
    return '.'.join(l)


def _gather_channels(x, indexes, **kwargs):
    """Slice tensor along channels axis by given indexes"""
    backend = kwargs['backend']
    if backend.image_data_format() == 'channels_last':
        x = backend.permute_dimensions(x, (3, 0, 1, 2))
        x = backend.gather(x, indexes)
        x = backend.permute_dimensions(x, (1, 2, 3, 0))
    else:
        x = backend.permute_dimensions(x, (1, 0, 2, 3))
        x = backend.gather(x, indexes)
        x = backend.permute_dimensions(x, (1, 0, 2, 3))
    return x


def feedfolder_created_handler(feedfolder, event):
    """Update feed folder after its creation"""
    feedfolder.restrictedTraverse('update_feed_items')()


def move_col_to_beginning_of_df(df_in, colname):
    """
    Small helper to move a column to the beginning of the DataFrame
    """
    cols = df_in.columns.tolist()
    cols.insert(0, cols.pop(cols.index(colname)))
    return df_in.reindex(columns=cols)


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

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


def ltrim(text, char):
    """
    Delete the specified character on the left
    :param text: str
    :param char: character
    :return:
    """
    length = len(char)
    if length > len(text):
        return text
    if char == text[:length]:
        text = text[length:]
    return text


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 connected_pair(dmrs, first_id, second_id):
    """
    Check if a pair of nodes are connected to each other
    """
    cover = set()
    queue = {first_id}
    while queue:
        new = queue.pop()
        cover.add(new)
        for adjacent in dmrs.get_neighbours(new, nodeids=True, itr=True):
            if adjacent == second_id:
                return True
            elif adjacent not in cover:
                queue.add(adjacent)
    return False


def str_find_between_tags(string, start='', end='', case=True):
    """ Returns a substring between two string tags """
    if not case:
        string_orig = string
        string = string.lower()
        start = start.lower()
        end = end.lower()
    if start:
        s = string.find(start)
    else:
        s = 0
    if end:
        e = string.find(end, s + len(start))
    else:
        e = len(string)
    if s < 0 or e < 0:
        return ''
    if not case:
        return string_orig[s + len(start):e]
    return string[s + len(start):e]


def provider_parser(subparser):
    """Generate a subparser for Google Cloud DNS"""
    subparser.description = """
        The Google Cloud DNS provider requires the JSON file which contains the service account info to connect to the API.
        This service account must own the project role DNS > DNS administrator for the project associated to the DNS zone.
        You can create a new service account, associate a private key, and download its info through this url:
        https://console.cloud.google.com/iam-admin/serviceaccounts?authuser=2"""
    subparser.add_argument('--auth-service-account-info', help=
        """
        specify the service account info in the Google JSON format:
        can be either the path of a file prefixed by 'file::' (eg. file::/tmp/service_account_info.json)
        or the base64 encoded content of this file prefixed by 'base64::'
        (eg. base64::eyJhbGciOyJ...)"""
        )


@staticmethod
def requiredSizeLimit():
    """
		Returns the minimum required image size limit (in GB) for Windows containers
		"""
    return 200.0


def assemble_multivalue_arguments(argument):
    """Assemble single string or list of strings into string."""
    if isinstance(argument, (list, tuple)):
        argument = ' '.join(argument)
    return argument


def _is_string_like(obj):
    """
    Check whether obj behaves like a string.
    """
    try:
        obj + ''
    except (TypeError, ValueError):
        return False
    return True


def _is_escaped(c):
    """Queries whether a character ordinal or code point was part of an escape sequence."""
    try:
        return c.is_escaped
    except AttributeError:
        return False


def wei_to_ether(wei):
    """
    Convert wei to ether
    """
    return 1.0 * wei / 10 ** 18


def unmangle_name(s: str) ->str:
    """
    Convert a name with ``$uXXXX`` character runs into their original forms, which may not
    necessarily be safe DAML identifiers.

    :param s: The string to interpret.
    :return: A new string with the appropriate substitutions.
    """
    return s.replace('$u002b', '+').replace('$u005b', '[').replace('$u005d',
        ']').replace('$u003c', '<').replace('$u003e', '>').replace('$u003a',
        ':').replace('$u0022', '"').replace('$u0028', '(').replace('$u0029',
        ')').replace('$u002f', '/').replace('$u002c', ',').replace('$u003d',
        '=')


def _update_contentmodel(page, pagedict):
    """Update page content model."""
    page._contentmodel = pagedict.get('contentmodel')
    if (page._contentmodel and page._contentmodel == 'proofread-page' and
        'proofread' in pagedict):
        page._quality = pagedict['proofread']['quality']
        page._quality_text = pagedict['proofread']['quality_text']


def add_on_store_opened(f):
    """
        Add a callable(cursor, restart=bool) for when a store connection
        is opened.

        .. versionadded:: 2.1a1
        """


def _sort_reports(reports: list) ->tuple:
    """Sorts the reports into published and not published"""
    published = []
    not_published = []
    for report in reports:
        if report['status'] == 'COMPLETED':
            published.append(report)
        else:
            not_published.append(report)
    return published, not_published


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


@staticmethod
def clean_data(star_schema_df, measures):
    """measure like this: 1 349 is not numeric so we try to transform it to
        1349.

        :param star_schema_df: start schema dataframe
        :param measures: list of measures columns names

        :return: cleaned columns
        """
    if measures:
        for measure in measures:
            if star_schema_df.select(measure).dtypes[0][1] == 'string':
                star_schema_df[measure] = star_schema_df[measure].str.replace(
                    ' ', '')
                star_schema_df[measure] = star_schema_df[measure].astype(
                    'float')
    return star_schema_df


def primitive_plane_add(radius: float=1.0, calc_uvs: bool=False, view_align:
    bool=False, enter_editmode: bool=False, location: float=(0.0, 0.0, 0.0),
    rotation: float=(0.0, 0.0, 0.0), layers: bool=(False, False, False,
    False, False, False, False, False, False, False, False, False, False,
    False, False, False, False, False, False, False)):
    """Construct a filled planar mesh with 4 vertices

    :param radius: Radius
    :type radius: float
    :param calc_uvs: Generate UVs, Generate a default UV map
    :type calc_uvs: bool
    :param view_align: Align to View, Align the new object to the view
    :type view_align: bool
    :param enter_editmode: Enter Editmode, Enter editmode when adding this object
    :type enter_editmode: bool
    :param location: Location, Location for the newly added object
    :type location: float
    :param rotation: Rotation, Rotation for the newly added object
    :type rotation: float
    :param layers: Layer
    :type layers: bool
    """
    pass


def get_name():
    """Return the name of this backend."""


def optional_string(value):
    """Raise an exception if a value isn't a string, or None."""
    if not isinstance(value, (str, type(None))):
        raise ValueError('Expected a string value or None, received %s.' %
            value)
    return value


def is_multiclass_classifier(clf):
    """
    Return True if a classifier is multiclass or False if it is binary.
    """
    return clf.coef_.shape[0] > 1


def _matches(params, **kwargs):
    """ See if keyword arguments are a subset of `params` """
    for key, value in kwargs.items():
        if value is None:
            continue
        if key not in params:
            continue
        if params.get(key) != value:
            return False
    return True


def round_channels(channels, divisor=8):
    """
    Round weighted channel number (make divisible operation).

    Parameters:
    ----------
    channels : int or float
        Original number of channels.
    divisor : int, default 8
        Alignment value.

    Returns
    -------
    int
        Weighted number of channels.
    """
    rounded_channels = max(int(channels + divisor / 2.0) // divisor *
        divisor, divisor)
    if float(rounded_channels) < 0.9 * channels:
        rounded_channels += divisor
    return rounded_channels


def wang_ryzin(h, Xi, x):
    """
    The Wang-Ryzin kernel, used for ordered discrete random variables.

    Parameters
    ----------
    h : scalar or 1-D ndarray, shape (K,)
        The bandwidths used to estimate the value of the kernel function.
    Xi : ndarray of ints, shape (nobs, K)
        The value of the training set.
    x : scalar or 1-D ndarray of shape (K,)
        The value at which the kernel density is being estimated.

    Returns
    -------
    kernel_value : ndarray, shape (nobs, K)
        The value of the kernel function at each training point for each var.

    Notes
    -----
    See p. 19 in [1]_ for details.  The value of the kernel L if
    :math:`X_{i}=x` is :math:`1-\\lambda`, otherwise it is
    :math:`\\frac{1-\\lambda}{2}\\lambda^{|X_{i}-x|}`, where :math:`\\lambda` is
    the bandwidth.

    References
    ----------
    .. [*] Racine, Jeff. "Nonparametric Econometrics: A Primer," Foundation
           and Trends in Econometrics: Vol 3: No 1, pp1-88., 2008.
           http://dx.doi.org/10.1561/0800000009
    .. [*] M.-C. Wang and J. van Ryzin, "A class of smooth estimators for
           discrete distributions", Biometrika, vol. 68, pp. 301-309, 1981.
    """
    Xi = Xi.reshape(Xi.size)
    kernel_value = 0.5 * (1 - h) * h ** abs(Xi - x)
    idx = Xi == x
    kernel_value[idx] = (idx * (1 - h))[idx]
    return kernel_value


def ndim(input):
    """Return the number of dimensions of the tensor.

    Parameters
    ----------
    input : Tensor
        The input tensor.

    Returns
    -------
    int
        The number of dimensions
    """
    pass


@classmethod
def _pre_build(cls, data: dict) ->dict:
    """Run data modification before building."""
    return data


def rawidf2str(rawidf, order=None):
    """string rep of rawidf"""
    lst = []
    if order:
        keys = order
    else:
        keys = rawidf.keys()
    for key in keys:
        try:
            for vals in rawidf[key]:
                lst.append('{},'.format(key))
                for val in vals[1:]:
                    lst.append('     {},'.format(val))
                lst.pop(-1)
                lst.append('    {};'.format(val))
                lst.append('')
        except KeyError as e:
            continue
    return '\n'.join(lst)


@staticmethod
def _get_name_from_dn(dn):
    """
        Get the instance name from the dn

        :param dn: string containing the distinguished name URL
        :return: string containing the name
        """
    name = dn.split('/sys/arp/inst')[1].split('/')[0]
    return name


def outputMarkdown(markdown_cont, output_file):
    """
    Writes to an output file if `outfile` is a valid path.

    """
    if output_file:
        with open(output_file, 'w') as out:
            out.write(markdown_cont)


def delete_comp(mgr, comp):
    """Delete the component from the manager."""
    mgr.deleteComponent(comp=comp)


def fill_in_name_and_ver(template_string, name, version):
    """
    TODO: Rename this?
    """
    return template_string.replace('DX_APP_WIZARD_NAME', name).replace(
        'DX_APP_WIZARD_VERSION', version)


def serialize_resource(resource, ctx):
    """
    Serialize resource by schema.

    :param resource: Resource instance
    :param ctx: Request context
    :return: Serialized resource
    """
    schema_cls, _ = ctx.registry[resource]
    return schema_cls(ctx).serialize_resource(resource)


def read_words(path):
    """
    From a TIMIT file, reads the word info

    Parameters
    ----------
    path : str
        path to file

    Returns
    -------
    list of dicts
        each dict has spelling, begin, end

    """
    output = []
    sr = 16000
    prev = None
    with open(path, 'r') as file_handle:
        for line in file_handle:
            l = line.strip().split(' ')
            begin = float(l[0]) / sr
            end = float(l[1]) / sr
            word = l[2]
            if prev is not None and begin != prev:
                output.append({'spelling': '<SIL>', 'begin': prev, 'end':
                    begin})
            elif prev is None and begin != 0:
                output.append({'spelling': '<SIL>', 'begin': 0, 'end': begin})
            output.append({'spelling': word, 'begin': begin, 'end': end})
            prev = end
    return output


def Metatype():
    """ Return the Zope 'meta_type' for this content object.

        o Deprecated (not all objects of a given type may even share
          the same meta_type).
        """


@classmethod
def value_of(cls, string: str) ->'DataType':
    """
        Gets the enum constant with the given name.

        :param string:  The name of the enum member.
        :return:        The enum instance.
        """
    return cls[string]


def text_value(node):
    """
    Retrieves the text/xml string value for the provided
    node, this is a recursive approach and the child nodes
    are used as the entry point.

    :type node: Element
    :param node: The base element node from which the values
    are going to be retrieved.
    :rtype: String
    :return: The string/textual part of the xml element node
    provided.
    """
    nodes = node.childNodes
    data = []
    for node in nodes:
        if not node.nodeType == node.TEXT_NODE:
            continue
        data.append(node.data)
    return ''.join(data)


def query_yes_no(question: str):
    """Ask the user a yes/no question"""
    yes = {'yes', 'y', 'ye'}
    no = {'no', 'n'}
    while True:
        choice = input(question).lower()
        if choice in yes:
            return True
        elif choice in no:
            return False
        else:
            print("Please respond with 'yes' or 'no'\n")


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

        :param TeamFolderCreateType val:
        :rtype: EventType
        """
    return cls('team_folder_create', val)


def update(key, body, *args, **kwargs):
    """Updates (patches) a entry"""
    pass


def smooth():
    """Apply weighted moving means to make selected F-Curves less bumpy

    """
    pass


@classmethod
def clean_data(cls, error, key=None, parent=None):
    """Clean empty errors."""
    if isinstance(error, dict):
        items = error.copy().items()
        for _key, _value in items:
            cls.clean_data(_value, _key, error)
    elif isinstance(error, list):
        aux = len(error)
        while aux > 0:
            aux -= 1
            cls.clean_data(error[aux], aux, error)
    if not error and parent:
        if isinstance(parent, dict):
            del parent[key]
        else:
            parent.pop(key)


def convert_py_to_cpp_namespace(python_namespace):
    """Convert a Python namespace name to a C++ namespace.

    Parameters
    ----------
    python_namespace : `str`
        A string describing a Python namespace. For example,
        ``'lsst.example'``.

    Returns
    -------
    cpp_namespace : `str`
        A C++ namespace. For example: ``'lsst::example'``.
    """
    return python_namespace.replace('.', '::')


def build_no_log_generator(container, log_args):
    """Return a generator that prints a warning about logs and waits for
    container to exit.
    """
    yield "WARNING: no logs are available with the '{}' log driver\n".format(
        container.log_driver)


def add_kernel_arrays_1D(array_1, array_2):
    """
    Add two 1D kernel arrays of different size.

    The arrays are added with the centers lying upon each other.
    """
    if array_1.size > array_2.size:
        new_array = array_1.copy()
        center = array_1.size // 2
        slice_ = slice(center - array_2.size // 2, center + array_2.size //
            2 + 1)
        new_array[slice_] += array_2
        return new_array
    elif array_2.size > array_1.size:
        new_array = array_2.copy()
        center = array_2.size // 2
        slice_ = slice(center - array_1.size // 2, center + array_1.size //
            2 + 1)
        new_array[slice_] += array_1
        return new_array
    return array_2 + array_1


@classmethod
def sync_from_stripe_data(cls, data):
    """
        Syncs this object from the stripe data provided.

        Foreign keys will also be retrieved and synced recursively.

        :param data: stripe object
        :type data: dict
        :rtype: cls
        """
    current_ids = set()
    data_id = data.get('id')
    if data_id:
        current_ids.add(data_id)
    instance, created = cls._get_or_create_from_stripe_object(data,
        current_ids=current_ids)
    if not created:
        instance._sync(cls._stripe_object_to_record(data))
        instance._attach_objects_hook(cls, data)
        instance.save()
        instance._attach_objects_post_save_hook(cls, data)
    return instance


def day_of_month(datetimes):
    """Return the day of the month of given dates."""
    return (datetimes.astype('datetime64[D]', copy=False) - datetimes.
        astype('datetime64[M]', copy=False) + 1).astype(int)


def update(*args, **kwds):
    """od.update(E, **F) -> None.  Update od from dict/iterable E and F.

        If E is a dict instance, does:           for k in E: od[k] = E[k]
        If E has a .keys() method, does:         for k in E.keys(): od[k] = E[k]
        Or if E is an iterable of items, does:   for k, v in E: od[k] = v
        In either case, this is followed by:     for k, v in F.items(): od[k] = v

        """
    if len(args) > 2:
        raise TypeError(
            'update() takes at most 2 positional arguments (%d given)' % (
            len(args),))
    elif not args:
        raise TypeError('update() takes at least 1 argument (0 given)')
    self = args[0]
    other = ()
    if len(args) == 2:
        other = args[1]
    if isinstance(other, dict):
        for key in other:
            self[key] = other[key]
    elif hasattr(other, 'keys'):
        for key in other.keys():
            self[key] = other[key]
    else:
        for key, value in other:
            self[key] = value
    for key, value in kwds.items():
        self[key] = value


def name_version_fn(fn):
    """
    Given the filename of a package, returns a tuple(name, version).
    """
    if fn.endswith('.egg'):
        fn = fn[:-4]
    if '-' in fn:
        return tuple(fn.split('-', 1))
    else:
        return fn, ''


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


def _remove_context(exc):
    """Python3: remove context from chained exceptions to prevent leaking API keys in tracebacks."""
    exc.__cause__ = None
    return exc


def string_contains(string: str, query: str) ->bool:
    """Return True if string contains query."""
    return string.find(query) != -1


def cname(s):
    """ make name s C-friendly """
    for c in '-+.':
        s = s.replace(c, '_')
    return s.upper()


def list_difference(left, right):
    """
    Take the not-in-place difference of two lists (left - right), similar to sets but preserving order.
    """
    blocked = set(right)
    difference = []
    for item in left:
        if item not in blocked:
            blocked.add(item)
            difference.append(item)
    return difference


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

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

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

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

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


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

    The ".dev0" means dirty.

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


def is_valid_match(match, text):
    """True unless the match starts or ends in the middle of a word."""
    end, phrase_mapping = match
    start = end - phrase_mapping.phrase_length + 1
    return (end + 1 == len(text) or not text[end + 1].isalnum() or not text
        [end].isalnum()) and (start == 0 or not text[start].isalnum() or
        not text[start - 1].isalnum())


def limbs_for_int(v):
    """
    Return the number of bytes required to represent this integer.
    """
    return v.bit_length() + 7 >> 3


def _print_summary_instrument_components(instance):
    """ Print summary information about an instrument_components file """
    print(f'FORMAT_VERSION: {instance.format_version}')
    print(f'REVISION: {instance.revision}')
    print(10 * '=')
    print('DATALOGGERS:')
    instance.print_elements('datalogger')
    print(10 * '=')
    print('PREAMPLIFIERS:')
    instance.print_elements('preamplifier')
    print(10 * '=')
    print('SENSORS:')
    instance.print_elements('sensor')
    print(10 * '=')
    if instance.verify_individuals():
        print('All specific components have a generic counterpart')
    print(10 * '=')
    n_files, n_found, n_cites = instance.verify_source_files(print_names=True)
    if n_files == n_found:
        print('Found all {:d} specified source files ({:d} total citations)'
            .format(n_files, n_cites))
    else:
        print('MISSING {:d} of {:d} specified source files'.format(n_files -
            n_found, n_files))


def ensure_one_opt(opt, parser, opt_list):
    """  Check that one and only one in the opt_list is defined in opt

    Parameters
    ----------
    opt : object
        Result of option parsing
    parser : object
        OptionParser instance.
    opt_list : list of strings
    """
    the_one = None
    for name in opt_list:
        attr = name[2:].replace('-', '_')
        if hasattr(opt, attr) and getattr(opt, attr) is not None:
            if the_one is None:
                the_one = name
            else:
                parser.error('%s and %s are mutually exculsive' % (the_one,
                    name))
    if the_one is None:
        parser.error('you must supply one of the following %s' % ', '.join(
            opt_list))


def get_relates_to_info():
    """Retrieves the relatesTo header. This is used for callbacks"""
    from soaplib.wsgi_soap import request
    headerElement = request.header
    if headerElement:
        headers = headerElement.getchildren()
        for header in headers:
            if header.tag.lower().find('relatesto') != -1:
                return header.text


def register(name, policy, priority=0.0):
    """Register a new policy. Name should content meta_type.
        """


def unassign(username):
    """Unassign a user (login) name from a group"""


def WWMA(df, n, price='Close'):
    """
    Welles Wilder Moving Average
    Returns: list of floats = jhta.WWMA(df, n, price='Close')
    Source: https://www.fmlabs.com/reference/default.htm?url=WellesMA.htm
    """
    wwma_list = []
    for i in range(len(df[price])):
        if i + 1 < n:
            wwma = float('NaN')
            wwma_list.append(wwma)
            wwma = df[price][i]
        else:
            wwma = (wwma * (n - 1) + df[price][i]) / n
            wwma_list.append(wwma)
    return wwma_list


def int_to_bytes_32(k: int) ->bytes:
    """Serialize an integer to the corresponding big endian bytes."""
    assert 0 <= k < 2 ** 256
    return k.to_bytes(32, byteorder='big')


def generate_file(file, geomtype, geom, commsec, jobsec):
    """Construct input file from options of all jobs.
    file: input file path
    geomtype: absolute or incremental
    geom: geometry points
    commsec: common section settings
    jobsec: list of job settings"""
    B = {(True): '.T.', (False): '.F.', None: '', 'Absolute': '##',
        'Incremental': '@@'}
    try:
        with open(file, 'w') as f:
            f.write(
                f""" &FILE LSAV={B[commsec['gensec']['LSAV']]}, ITEST={commsec['gensec']['ITEST']}, LREC={B[commsec['gensec']['LSAV']]}, LCPUTM={B[commsec['gensec']['LSAV']]}, TSOS={commsec['gensec']['TSOS']}, TMAX={commsec['gensec']['TMAX']} &END
"""
                )
            f.write(f" {commsec['gensec']['TITLE']}\n")
            f.write(' &BOUN IZL=3, IZR=3 &END\n')
            f.write(f" &MESH DDZ={jobsec[0]['meshsec']['DDZ']}")
            if jobsec[0]['meshsec']['DDR'] is not None:
                f.write(f", DDR={jobsec[0]['meshsec']['DDR']}")
            if jobsec[0]['meshsec']['NR'] is not None:
                f.write(f", NR={jobsec[0]['meshsec']['NR']}")
            if jobsec[0]['meshsec']['NZ'] is not None:
                f.write(f", NZ={jobsec[0]['meshsec']['NZ']}")
            if jobsec[0]['meshsec']['RMARK'] is not None:
                f.write(f", RMARK={jobsec[0]['meshsec']['RMARK']}")
            if jobsec[0]['meshsec']['RZ'] is not None:
                f.write(f", RZ={jobsec[0]['meshsec']['RZ']}")
            f.write(' &END\n')
            f.write(f' {B[geomtype]}CAVITYSHAPE\n')
            f.write('0.\n')
            for r, z in geom:
                f.write(f'{r} {z}\n')
            f.write('9999. 9999.\n')
            firstpass = True
            for j in jobsec:
                if not firstpass:
                    f.write('CONTINUE\n')
                    f.write(f' &MESH')
                    if j['meshsec']['DDZ'] is not None:
                        f.write(f" DDZ={j['meshsec']['DDZ']}")
                    else:
                        f.write(f' DDZ=0.001')
                    if j['meshsec']['DDR'] is not None:
                        f.write(f", DDR={j['meshsec']['DDR']}")
                    else:
                        f.write(f', DDR=0.001')
                    if j['meshsec']['NR'] is not None:
                        f.write(f", NR={j['meshsec']['NR']}")
                    if j['meshsec']['NZ'] is not None:
                        f.write(f", NZ={j['meshsec']['NZ']}")
                    if j['meshsec']['RMARK'] is not None:
                        f.write(f", RMARK={j['meshsec']['RMARK']}")
                    if j['meshsec']['RZ'] is not None:
                        f.write(f", RZ={j['meshsec']['RZ']}")
                    f.write(' &END\n')
                f.write(
                    f" &BEAM MROT={j['beamsec']['MROT']}, ISIG={j['beamsec']['ISIG']}, NBUNCH={j['beamsec']['NBUNCH']}, BSEP={j['beamsec']['BSEP']}"
                    )
                if j['beamsec']['SIG'] is not None:
                    f.write(f", SIG={j['beamsec']['SIG']}")
                if j['beamsec']['RDRIVE'] is not None:
                    f.write(f", RDRIVE={j['beamsec']['RDRIVE']}")
                f.write(' &END\n')
                if firstpass:
                    f.write(
                        f" &TIME MT={commsec['timesec']['MT']}, NSHOT={commsec['timesec']['NSHOT']}"
                        )
                    if commsec['timesec']['TPS'] is not None:
                        f.write(f", TPS={commsec['timesec']['TSP']}")
                    f.write(' &END\n')
                f.write(
                    f" &WAKE LCFRON={j['wakesec']['LCFRON']}, LCBACK={j['wakesec']['LCBACK']}, LCHIN={j['wakesec']['LCHIN']}, LNAPOLY={j['wakesec']['LNAPOLY']}, LNONAP={j['wakesec']['LNONAP']}, LCRBW={j['wakesec']['LCRBW']}, ZSEP={j['wakesec']['ZSEP']}"
                    )
                if j['wakesec']['UBT'] is not None:
                    f.write(f", UBT={j['wakesec']['UBT']}")
                if j['wakesec']['ZCF'] is not None:
                    f.write(f", ZCF={j['wakesec']['ZCF']}")
                if j['wakesec']['ZCT'] is not None:
                    f.write(f", ZCT={j['wakesec']['ZCT']}")
                if j['wakesec']['RWAK'] is not None:
                    f.write(f", RWAK={j['wakesec']['RWAK']}")
                f.write(' &END\n')
                f.write(
                    f""" &PLOT LCAVIN={j['plotsec']['LCAVIN']}, LCAVUS={j['plotsec']['LCAVUS']}, LPATH={j['plotsec']['LPATH']}, LPLW={j['plotsec']['LPLW']}, LPLWL={j['plotsec']['LPLWL']}, LPLWA={j['plotsec']['LPLWA']}, LPLWT={j['plotsec']['LPLWT']}, LFFT={j['plotsec']['LFFT']}, LFFTA={j['plotsec']['LFFTA']}, LFFTA={j['plotsec']['LFFTA']}, LFFTT={j['plotsec']['LFFTT']}, LINTZ={j['plotsec']['LINTZ']}, LWNDW={j['plotsec']['LWNDW']}, NWFUN={j['plotsec']['NWFUN']}, ALPHA={j['plotsec']['ALPHA']}, CUTOFF={j['plotsec']['CUTOFF']}, EXPFAC={j['plotsec']['EXPFAC']}, LPLE={j['plotsec']['LPLE']}, LPLC={j['plotsec']['LPLC']}, NPLOT={j['plotsec']['NPLOT']}, LPALL={j['plotsec']['LPALL']} &END
"""
                    )
                f.write(
                    f""" &PRIN LPRW={j['printsec']['LPRW']}, LMATPR={j['printsec']['LMATPR']}, LSVW={j['printsec']['LSVW']}, LSVWL={j['printsec']['LSVWL']}, LSVWA={j['printsec']['LSVWA']}, LSVWT={j['printsec']['LSVWT']}, LSVF={j['printsec']['LSVF']} &END
"""
                    )
                firstpass = False
            f.write('STOP\n')
    except PermissionError:
        pass


def get(isamAppliance, resource_id, check_mode=False, force=False):
    """
    Retrieving a list of stanzas - Runtime Environment
    """
    return isamAppliance.invoke_get(
        'Retrieving a list of stanzas - Runtime Environment',
        '/isam/runtime/{0}/configuration/stanza'.format(resource_id))


def cache_property(key, empty, type):
    """Return a new property object for a cache header.  Useful if you
    want to add support for a cache extension in a subclass."""
    return property(lambda x: x._get_cache_value(key, empty, type), lambda
        x, v: x._set_cache_value(key, v, type), lambda x: x.
        _del_cache_value(key), 'accessor for %r' % key)


def remove_site():
    """Remove a site either by name or by id
    """
    pass


@classmethod
def _get_um_dm(cls, df):
    """ Up move and down move

        initialize up move and down move
        :param df: data
        """
    hd = df['high_delta']
    df['um'] = (hd + hd.abs()) / 2
    ld = -df['low_delta']
    df['dm'] = (ld + ld.abs()) / 2


def join(iterable, sep=' ', end='\n'):
    """Return a string which is the concatenation of string
    representations of objects in the iterable, separated by sep.

    end is appended to the resulting string.
    """
    return sep.join(map(str, iterable)) + end


def copy(wave_in, wave_out, sample_count, sample_bytes):
    """Copy samples between WAV objects."""
    b_size = 65536 // sample_bytes
    while sample_count:
        b = wave_in.readframes(min(b_size, sample_count))
        b_samples = len(b) // sample_bytes
        sample_count -= b_samples
        wave_out.writeframes(b)


def set_pass_code():
    """
    Set and validate the password
    :return: string
    """
    pass_code = input('Enter your Oracle Commerce Cloud backend pass-code: ')
    while True:
        if len(pass_code) >= 5:
            return pass_code
        else:
            pass_code = input(
                'Enter your Oracle Commerce Cloud backend pass-code: ')


def p_scheme_type_element_def(p):
    """schema_type_element_def : LBRACE field_decl_list RBRACE
    """
    p[0] = p[2]


def seconds_to_months(seconds):
    """Convert seconds to months"""
    return seconds / 2592000.0


def _add_default_fields(ds, fields):
    """
    Add some default fields to rays to assure they can be processed correctly.
    """
    if ('gas', 'temperature') in ds.derived_field_list:
        fields.append(('gas', 'temperature'))
    if ('gas', 'H_nuclei_density') in ds.derived_field_list:
        fields.append(('gas', 'H_nuclei_density'))
    return fields


def astrix_line(qty: int=80) ->str:
    """Return break line of astrix characters.

    :param int qty: number of * characters to be returned
    :returns: * characters and a line break
    :rtype: str
    """
    return '*' * int(qty) + '\n'


def get_key(chem):
    """
    Turns a chemical object into (mz, rt, intensity) tuples for equal comparison
    :param chem: A chemical object
    :return: a tuple of the three values
    """
    return tuple(chem.isotopes), chem.rt, chem.max_intensity


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

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


def p_AttributeOrOperation(p):
    """AttributeOrOperation : Attribute
                          | Operation
  """
    p[0] = p[1]


def is_float(f):
    """return True if input is a float.
    """
    return isinstance(f, float)


def sequence_termnum(nth, first_term, common_difference):
    """Usage: Find the term number in a sequence"""
    return (nth - first_term) / common_difference + 1


def p_subpackages(t):
    """subpackages : empty
                   | subpackage subpackages"""
    if len(t) == 2:
        t[0] = []
    elif len(t) == 3:
        t[0] = [t[1]] + t[2]
    else:
        assert False


def contion(response, bean):
    """
    判断是单品还是组合and两者活动以什么满足是
    :param response:
    :return:
    """
    condition1 = None
    condition2 = None
    if response[-1] == 2:
        condition1 = None
        condition2 = None
        if response[0] != None:
            condition1 = response[0]
        if response[1] != 'qtty' and response[1] != 2:
            condition2 = response[1]
    else:
        condition1 = None
        if response[0] != None:
            condition1 = response[0]
        if bean.target_type.lower() == 'amt_list':
            condition1 = 'amt_list'
        elif bean.target_type.lower() == 'amt_retail':
            condition1 = 'amt_retail'
        elif bean.target_type.lower() == 'amt_receivable':
            condition1 = 'amt_receivable'
    return condition1, condition2


def isAlphanum(c):
    """return true if the character is a letter, digit, underscore,
           dollar sign, or non-ASCII character.
    """
    return (c >= 'a' and c <= 'z' or c >= '0' and c <= '9' or c >= 'A' and
        c <= 'Z' or c == '_' or c == '$' or c == '\\' or c is not None and
        ord(c) > 126)


def format_duration(duration):
    """
    Format duration from seconds to hours, minutes and seconds.

    Parameters:
    - duration : duration in seconds
    """
    if type(duration) not in (float, int) or duration < 0:
        return 'unknown'
    duration = round(duration)
    seconds = int(duration % 60)
    duration = duration / 60
    format_string = '{:d}s'.format(seconds)
    if duration >= 1:
        minutes = int(duration % 60)
        duration = duration / 60
        format_string = '{:d}m {:s}'.format(minutes, format_string)
        if duration >= 1:
            hours = int(duration % 60)
            format_string = '{:d}h {:s}'.format(hours, format_string)
    return format_string


@staticmethod
def is_pmml_format(data):
    """
        Determine whether the data format is PMML.

        Parameters
        ----------

        data : String

            Tree model data.

        Returns
        -------

        True or False

        """
    return data.endswith('</PMML>')


def _expand_dict_attr(collection, attr):
    """Expand item attribute whose value is a dict.

    Take a collection of items where the named attribute is known to have a
    dictionary value and replace the named attribute with multiple attributes
    whose names are the keys of the dictionary namespaced with the original
    attribute name.
    """
    for item in collection:
        field = getattr(item, attr)
        delattr(item, attr)
        for subkey in field.keys():
            setattr(item, attr + ':' + subkey, field[subkey])
            item.set_info(attr + ':' + subkey, field[subkey])


def _normalize_image_location_for_db(image_data):
    """
    This function takes the legacy locations field and the newly added
    location_data field from the image_data values dictionary which flows
    over the wire between the registry and API servers and converts it
    into the location_data format only which is then consumable by the
    Image object.

    :param image_data: a dict of values representing information in the image
    :returns: a new image data dict
    """
    if 'locations' not in image_data and 'location_data' not in image_data:
        image_data['locations'] = None
        return image_data
    locations = image_data.pop('locations', [])
    location_data = image_data.pop('location_data', [])
    location_data_dict = {}
    for l in locations:
        location_data_dict[l] = {}
    for l in location_data:
        location_data_dict[l['url']] = {'metadata': l['metadata'], 'status':
            l['status'], 'id': l['id'] if 'id' in l else None}
    ordered_keys = locations[:]
    for ld in location_data:
        if ld['url'] not in ordered_keys:
            ordered_keys.append(ld['url'])
    location_data = []
    for loc in ordered_keys:
        data = location_data_dict[loc]
        if data:
            location_data.append({'url': loc, 'metadata': data['metadata'],
                'status': data['status'], 'id': data['id']})
        else:
            location_data.append({'url': loc, 'metadata': {}, 'status':
                'active', 'id': None})
    image_data['locations'] = location_data
    return image_data


@classmethod
def fromkeys(cls, iterable, value=None):
    """OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
        and values equal to v (which defaults to None).

        """
    d = cls()
    for key in iterable:
        d[key] = value
    return d


def cut_prefix(value, prefix):
    """Removes the leading `prefix` if exists, else return `value`
    unchanged.

    """
    from xotl.tools.future.codecs import safe_encode, safe_decode
    if isinstance(value, str) and isinstance(prefix, bytes):
        prefix = safe_decode(prefix)
    elif isinstance(value, bytes) and isinstance(prefix, str):
        prefix = safe_encode(prefix)
    return value[len(prefix):] if value.startswith(prefix) else value


def _get_arr_same_size_object(same_arr_size_list, size):
    """
    This function, for a given list of ArraysSameSize objects, returns
    the object that represents arrays of the size passed as argument
    """
    for elem in same_arr_size_list:
        if elem.size == size:
            return elem
    return None


def get_window_data(conn, analysis_type, temp_file):
    """
    Create a temp file of the requested statistic for each variant.

    Execute a query against the variants table
    that extracts the requested column for each variant.
    save the results to '.temp.pid', which will be loaded
    into a pybedtools BedTool for use with the bedtools map
    function.  This will compute the requested statistic
    for each variant in the variants table
    """
    if analysis_type == 'hwe':
        column = 'hwe'
    elif analysis_type == 'nucl_div':
        column = 'pi'
    t = open(temp_file, 'w')
    query = ('SELECT chrom,start,end,' + column +
        ' FROM variants ORDER BY chrom,start')
    for row in conn.execute(query):
        if row[column] is not None:
            t.write('%s\t%d\t%d\t%f\n' % (str(row['chrom']), int(row[
                'start']), int(row['end']), float(row[column])))
    t.close()
    return 4


def extract_field_names(dict_list):
    """ Returns a sorted list of field names from a dictionary list
    > extract_field_names([{'a': 1, 'b': 2}, {'a': 3, 'c': 4}])
    ['a', 'b', 'c']
    """
    field_names = []
    for row_dict in dict_list:
        field_names += row_dict.keys()
    field_names = list(set(field_names))
    return sorted(field_names)


def _is_task_visible(context, task):
    """Return True if the task is visible in this context."""
    if context.is_admin:
        return True
    if task['owner'] is None:
        return True
    if context.owner is not None:
        if context.owner == task['owner']:
            return True
    return False


def _init_chain_type(chain_type):
    """Validation of chain type on initialization

    Parameters
    ----------
    `chain_type` : { "heavy", "h", "light", "kappa", "k", "lambda", "l", "alpha", "a", "beta", "b" }
        word / letter representing the chain_type .
        NOTE: "l" is representing the chain type "lambda", NOT "light".

    Returns
    -------
    String
        Returns a string representing the chain type if validation is successfull

    Raises
    ------
    ValueError
        If the `chain_type` is not part of valid chain types
    """
    if chain_type:
        valid_chain_types = ['heavy', 'h', 'light', 'l', 'kappa', 'lambda',
            'alpha', 'beta', 'a', 'b', 'k']
        if not chain_type.lower() in valid_chain_types:
            raise ValueError(
                f'Please select a valid chain type! {valid_chain_types}')
        return chain_type.lower()
    else:
        return None


def get_extra_metadata(domain='llc', nx=90):
    """
    Return the extra_metadata dictionay for selected domains

    PARAMETERS
    ----------
    domain : str
        domain can be llc, aste, cs
    nx : int
        size of the face in the x direction

    RETURNS
    -------
    extra_metadata : dict
        all extra_metadata to handle multi-faceted grids
    """
    available_domains = ['llc', 'aste', 'cs']
    if domain not in available_domains:
        raise ValueError('not an available domain')
    llc = {'has_faces': True, 'ny': 13 * nx, 'nx': nx, 'ny_facets': [3 * nx,
        3 * nx, nx, 3 * nx, 3 * nx], 'face_facets': [0, 0, 0, 1, 1, 1, 2, 3,
        3, 3, 4, 4, 4], 'facet_orders': ['C', 'C', 'C', 'F', 'F'],
        'face_offsets': [0, 1, 2, 0, 1, 2, 0, 0, 1, 2, 0, 1, 2],
        'transpose_face': [False, False, False, False, False, False, False,
        True, True, True, True, True, True]}
    aste = {'has_faces': True, 'ny': 5 * nx, 'nx': nx, 'ny_facets': [int(5 *
        nx / 3.0), 0, nx, int(2 * nx / 3.0), int(5 * nx / 3.0)],
        'pad_before_y': [int(1 * nx / 3.0), 0, 0, 0, 0], 'pad_after_y': [0,
        0, 0, int(1 * nx / 3.0), int(1 * nx / 3.0)], 'face_facets': [0, 0,
        2, 3, 4, 4], 'facet_orders': ['C', 'C', 'C', 'F', 'F'],
        'face_offsets': [0, 1, 0, 0, 0, 1], 'transpose_face': [False, False,
        False, True, True, True]}
    cs = {'has_faces': True, 'ny': nx, 'nx': nx, 'ny_facets': [nx, nx, nx,
        nx, nx, nx], 'face_facets': [0, 1, 2, 3, 4, 5], 'facet_orders': [
        'F', 'F', 'F', 'F', 'F', 'F'], 'face_offsets': [0, 0, 0, 0, 0, 0],
        'transpose_face': [False, False, False, False, False, False]}
    if domain == 'llc':
        extra_metadata = llc
    elif domain == 'aste':
        extra_metadata = aste
    elif domain == 'cs':
        extra_metadata = cs
    return extra_metadata


def isBuildConfChanged(buildconf, buildroot):
    """
    Try to detect if current buildconf file is changed.
    Returns True if it's changed or file just doesn't exist.
    """
    raise NotImplementedError


@classmethod
def retrieve(cls, location, project_path):
    """
        Retrieves a TidyPy configuration from the specified location.

        :param location:
            a URI indicating where to retrieve the TidyPy configuration from
        :type location: str
        :param project_path: the full path to the project's base
        :type project_path: str
        :rtype: dict
        """
    raise NotImplementedError()


def set_hooks(app, hook_setters=None):
    """Set hooks on a Flask application

    Example: Adding a hook

    .. doctest::
        >>> from flask import Flask, request, current_app

        >>> app = Flask(__name__)

        >>> def set_log_request_hook(app):
        ...     @app.before_request
        ...     def log_request():
        ...         current_app.logger.debug(request)

        >>> my_hook_setters = [set_log_request_hook]

        >>> set_hooks(app, my_hook_setters)

    :param app: Flask application
    :type app: :class:`flask.Flask`
    :param hook_setters: Hooks to set on the application.
        Expects a list of functions that takes a :class:`flask.Flask` as argument
    :type hook_setters: list
    """
    hook_setters = hook_setters or []
    for set_hook in hook_setters:
        set_hook(app)


def _is_number(x):
    """"Test if a string or other is a number

    Examples
    --------
    >>> _is_number('3')
    True
    >>> _is_number(3.)
    True
    >>> _is_number('a')
    False
    """
    try:
        float(x)
        return True
    except (ValueError, TypeError):
        return False


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


def is_num(num):
    """Return whether num can be an int"""
    try:
        num = int(num)
        return True
    except ValueError:
        return False


@classmethod
def strptime(cls, date_string, format):
    """string, format -> new datetime parsed from a string (like time.strptime())."""
    import _strptime
    return _strptime._strptime_datetime(cls, date_string, format)


def varLen(value):
    """
    Returns the the number of bytes an integer will be when
    converted to varlength
    """
    if value <= 127:
        return 1
    elif value <= 16383:
        return 2
    elif value <= 2097151:
        return 3
    else:
        return 4


def insert(obj, id=None):
    """Insert an object into PostGreSQL.

        The correct collection is determined by object type.

        If `id` is provided, object will be inserted under that id. Otherwise,
        a new unique id will be generated.
        """