if (<EOL>(<EOL>(self._tp + self._fp)<EOL>* (self._tp + self._fn)<EOL>* (self._tn + self._fp)<EOL>* (self._tn + self._fn)<EOL>)<EOL>) == <NUM_LIT:0>:<EOL><INDENT>return float('<STR_LIT>')<EOL><DEDENT>return ((self._tp * self._tn) - (self._fp * self._fn)) / math.sqrt(<EOL>(self._tp + self._fp)<EOL>* (self._tp + self._fn)<EOL>* (self._tn + self._fp)<EOL>* (self._tn + self._fn)<EOL>)<EOL>

r"""Return Matthews correlation coefficient (MCC).

        The Matthews correlation coefficient is defined in
        :cite:`Matthews:1975` as:
        :math:`\frac{(tp \cdot tn) - (fp \cdot fn)}
        {\sqrt{(tp + fp)(tp + fn)(tn + fp)(tn + fn)}}`

        This is equivalent to the geometric mean of informedness and
        markedness, defined above.

        Cf. https://en.wikipedia.org/wiki/Matthews_correlation_coefficient

        Returns
        -------
        float
            The Matthews correlation coefficient of the confusion table

        Example
        -------
        >>> ct = ConfusionTable(120, 60, 20, 30)
        >>> ct.mcc()
        0.5367450401216932


if (<EOL>(<EOL>(self._tp + self._fp)<EOL>* (self._tp + self._fn)<EOL>* (self._tn + self._fp)<EOL>* (self._tn + self._fn)<EOL>)<EOL>) == <NUM_LIT:0>:<EOL><INDENT>return float('<STR_LIT>')<EOL><DEDENT>return (<EOL>(self._tp * self._tn - self._fp * self._fn) ** <NUM_LIT:2><EOL>* (self._tp + self._tn + self._fp + self._fn)<EOL>) / (<EOL>(self._tp + self._fp)<EOL>* (self._tp + self._fn)<EOL>* (self._tn + self._fp)<EOL>* (self._tn + self._fn)<EOL>)<EOL>

r"""Return the significance, :math:`\chi^{2}`.

        Significance is defined as:
        :math:`\chi^{2} =
        \frac{(tp \cdot tn - fp \cdot fn)^{2} (tp + tn + fp + fn)}
        {((tp + fp)(tp + fn)(tn + fp)(tn + fn)}`

        Also: :math:`\chi^{2} = MCC^{2} \cdot n`

        Cf. https://en.wikipedia.org/wiki/Pearson%27s_chi-square_test

        Returns
        -------
        float
            The significance of the confusion table

        Example
        -------
        >>> ct = ConfusionTable(120, 60, 20, 30)
        >>> ct.significance()
        66.26190476190476


if self.population() == <NUM_LIT:0>:<EOL><INDENT>return float('<STR_LIT>')<EOL><DEDENT>random_accuracy = (<EOL>(self._tn + self._fp) * (self._tn + self._fn)<EOL>+ (self._fn + self._tp) * (self._fp + self._tp)<EOL>) / self.population() ** <NUM_LIT:2><EOL>return (self.accuracy() - random_accuracy) / (<NUM_LIT:1> - random_accuracy)<EOL>

r"""Return κ statistic.

        The κ statistic is defined as:
        :math:`\kappa = \frac{accuracy - random~ accuracy}
        {1 - random~ accuracy}`

        The κ statistic compares the performance of the classifier relative to
        the performance of a random classifier. :math:`\kappa` = 0 indicates
        performance identical to random. :math:`\kappa` = 1 indicates perfect
        predictive success. :math:`\kappa` = -1 indicates perfect predictive
        failure.

        Returns
        -------
        float
            The κ statistic of the confusion table

        Example
        -------
        >>> ct = ConfusionTable(120, 60, 20, 30)
        >>> ct.kappa_statistic()
        0.5344129554655871


return sum(nums) / len(nums)<EOL>

r"""Return arithmetic mean.

    The arithmetic mean is defined as:
    :math:`\frac{\sum{nums}}{|nums|}`

    Cf. https://en.wikipedia.org/wiki/Arithmetic_mean

    Parameters
    ----------
    nums : list
        A series of numbers

    Returns
    -------
    float
        The arithmetric mean of nums

    Examples
    --------
    >>> amean([1, 2, 3, 4])
    2.5
    >>> amean([1, 2])
    1.5
    >>> amean([0, 5, 1000])
    335.0


return _prod(nums) ** (<NUM_LIT:1> / len(nums))<EOL>

r"""Return geometric mean.

    The geometric mean is defined as:
    :math:`\sqrt[|nums|]{\prod\limits_{i} nums_{i}}`

    Cf. https://en.wikipedia.org/wiki/Geometric_mean

    Parameters
    ----------
    nums : list
        A series of numbers

    Returns
    -------
    float
        The geometric mean of nums

    Examples
    --------
    >>> gmean([1, 2, 3, 4])
    2.213363839400643
    >>> gmean([1, 2])
    1.4142135623730951
    >>> gmean([0, 5, 1000])
    0.0


if len(nums) < <NUM_LIT:1>:<EOL><INDENT>raise AttributeError('<STR_LIT>')<EOL><DEDENT>elif len(nums) == <NUM_LIT:1>:<EOL><INDENT>return nums[<NUM_LIT:0>]<EOL><DEDENT>else:<EOL><INDENT>for i in range(<NUM_LIT:1>, len(nums)):<EOL><INDENT>if nums[<NUM_LIT:0>] != nums[i]:<EOL><INDENT>break<EOL><DEDENT><DEDENT>else:<EOL><INDENT>return nums[<NUM_LIT:0>]<EOL><DEDENT><DEDENT>if <NUM_LIT:0> in nums:<EOL><INDENT>if nums.count(<NUM_LIT:0>) > <NUM_LIT:1>:<EOL><INDENT>return float('<STR_LIT>')<EOL><DEDENT>return <NUM_LIT:0><EOL><DEDENT>return len(nums) / sum(<NUM_LIT:1> / i for i in nums)<EOL>

r"""Return harmonic mean.

    The harmonic mean is defined as:
    :math:`\frac{|nums|}{\sum\limits_{i}\frac{1}{nums_i}}`

    Following the behavior of Wolfram|Alpha:
    - If one of the values in nums is 0, return 0.
    - If more than one value in nums is 0, return NaN.

    Cf. https://en.wikipedia.org/wiki/Harmonic_mean

    Parameters
    ----------
    nums : list
        A series of numbers

    Returns
    -------
    float
        The harmonic mean of nums

    Raises
    ------
    AttributeError
        hmean requires at least one value

    Examples
    --------
    >>> hmean([1, 2, 3, 4])
    1.9200000000000004
    >>> hmean([1, 2])
    1.3333333333333333
    >>> hmean([0, 5, 1000])
    0


return (sum(i ** <NUM_LIT:2> for i in nums) / len(nums)) ** <NUM_LIT:0.5><EOL>

r"""Return quadratic mean.

    The quadratic mean of precision and recall is defined as:
    :math:`\sqrt{\sum\limits_{i} \frac{num_i^2}{|nums|}}`

    Cf. https://en.wikipedia.org/wiki/Quadratic_mean

    Parameters
    ----------
    nums : list
        A series of numbers

    Returns
    -------
    float
        The quadratic mean of nums

    Examples
    --------
    >>> qmean([1, 2, 3, 4])
    2.7386127875258306
    >>> qmean([1, 2])
    1.5811388300841898
    >>> qmean([0, 5, 1000])
    577.3574860228857


return sum(x ** <NUM_LIT:2> for x in nums) / sum(nums)<EOL>

r"""Return contraharmonic mean.

    The contraharmonic mean is:
    :math:`\frac{\sum\limits_i x_i^2}{\sum\limits_i x_i}`

    Cf. https://en.wikipedia.org/wiki/Contraharmonic_mean

    Parameters
    ----------
    nums : list
        A series of numbers

    Returns
    -------
    float
        The contraharmonic mean of nums

    Examples
    --------
    >>> cmean([1, 2, 3, 4])
    3.0
    >>> cmean([1, 2])
    1.6666666666666667
    >>> cmean([0, 5, 1000])
    995.0497512437811


if len(nums) != len(set(nums)):<EOL><INDENT>raise AttributeError('<STR_LIT>')<EOL><DEDENT>rolling_sum = <NUM_LIT:0><EOL>for i in range(len(nums)):<EOL><INDENT>rolling_prod = <NUM_LIT:1><EOL>for j in range(len(nums)):<EOL><INDENT>if i != j:<EOL><INDENT>rolling_prod *= math.log(nums[i] / nums[j])<EOL><DEDENT><DEDENT>rolling_sum += nums[i] / rolling_prod<EOL><DEDENT>return math.factorial(len(nums) - <NUM_LIT:1>) * rolling_sum<EOL>

r"""Return logarithmic mean.

    The logarithmic mean of an arbitrarily long series is defined by
    http://www.survo.fi/papers/logmean.pdf
    as:
    :math:`L(x_1, x_2, ..., x_n) =
    (n-1)! \sum\limits_{i=1}^n \frac{x_i}
    {\prod\limits_{\substack{j = 1\\j \ne i}}^n
    ln \frac{x_i}{x_j}}`

    Cf. https://en.wikipedia.org/wiki/Logarithmic_mean

    Parameters
    ----------
    nums : list
        A series of numbers

    Returns
    -------
    float
        The logarithmic mean of nums

    Raises
    ------
    AttributeError
        No two values in the nums list may be equal

    Examples
    --------
    >>> lmean([1, 2, 3, 4])
    2.2724242417489258
    >>> lmean([1, 2])
    1.4426950408889634


if len(nums) == <NUM_LIT:1>:<EOL><INDENT>return nums[<NUM_LIT:0>]<EOL><DEDENT>if len(nums) > <NUM_LIT:2>:<EOL><INDENT>raise AttributeError('<STR_LIT>')<EOL><DEDENT>if nums[<NUM_LIT:0>] <= <NUM_LIT:0> or nums[<NUM_LIT:1>] <= <NUM_LIT:0>:<EOL><INDENT>return float('<STR_LIT>')<EOL><DEDENT>elif nums[<NUM_LIT:0>] == nums[<NUM_LIT:1>]:<EOL><INDENT>return nums[<NUM_LIT:0>]<EOL><DEDENT>return (<NUM_LIT:1> / math.e) * (nums[<NUM_LIT:0>] ** nums[<NUM_LIT:0>] / nums[<NUM_LIT:1>] ** nums[<NUM_LIT:1>]) ** (<EOL><NUM_LIT:1> / (nums[<NUM_LIT:0>] - nums[<NUM_LIT:1>])<EOL>)<EOL>

r"""Return identric (exponential) mean.

    The identric mean of two numbers x and y is:
    x if x = y
    otherwise :math:`\frac{1}{e} \sqrt[x-y]{\frac{x^x}{y^y}}`

    Cf. https://en.wikipedia.org/wiki/Identric_mean

    Parameters
    ----------
    nums : list
        A series of numbers

    Returns
    -------
    float
        The identric mean of nums

    Raises
    ------
    AttributeError
        imean supports no more than two values

    Examples
    --------
    >>> imean([1, 2])
    1.4715177646857693
    >>> imean([1, 0])
    nan
    >>> imean([2, 4])
    2.9430355293715387


if len(nums) == <NUM_LIT:1>:<EOL><INDENT>return nums[<NUM_LIT:0>]<EOL><DEDENT>if len(nums) > <NUM_LIT:2>:<EOL><INDENT>raise AttributeError('<STR_LIT>')<EOL><DEDENT>if nums[<NUM_LIT:0>] + nums[<NUM_LIT:1>] == <NUM_LIT:0> or nums[<NUM_LIT:0>] - nums[<NUM_LIT:1>] == <NUM_LIT:0>:<EOL><INDENT>return float('<STR_LIT>')<EOL><DEDENT>return (nums[<NUM_LIT:0>] - nums[<NUM_LIT:1>]) / (<EOL><NUM_LIT:2> * math.asin((nums[<NUM_LIT:0>] - nums[<NUM_LIT:1>]) / (nums[<NUM_LIT:0>] + nums[<NUM_LIT:1>]))<EOL>)<EOL>

r"""Return Seiffert's mean.

    Seiffert's mean of two numbers x and y is:
    :math:`\frac{x - y}{4 \cdot arctan \sqrt{\frac{x}{y}} - \pi}`

    It is defined in :cite:`Seiffert:1993`.

    Parameters
    ----------
    nums : list
        A series of numbers

    Returns
    -------
    float
        Sieffert's mean of nums

    Raises
    ------
    AttributeError
        seiffert_mean supports no more than two values

    Examples
    --------
    >>> seiffert_mean([1, 2])
    1.4712939827611637
    >>> seiffert_mean([1, 0])
    0.3183098861837907
    >>> seiffert_mean([2, 4])
    2.9425879655223275
    >>> seiffert_mean([2, 1000])
    336.84053300118825


return sum(x ** exp for x in nums) / sum(x ** (exp - <NUM_LIT:1>) for x in nums)<EOL>

r"""Return Lehmer mean.

    The Lehmer mean is:
    :math:`\frac{\sum\limits_i{x_i^p}}{\sum\limits_i{x_i^(p-1)}}`

    Cf. https://en.wikipedia.org/wiki/Lehmer_mean

    Parameters
    ----------
    nums : list
        A series of numbers
    exp : numeric
        The exponent of the Lehmer mean

    Returns
    -------
    float
        The Lehmer mean of nums for the given exponent

    Examples
    --------
    >>> lehmer_mean([1, 2, 3, 4])
    3.0
    >>> lehmer_mean([1, 2])
    1.6666666666666667
    >>> lehmer_mean([0, 5, 1000])
    995.0497512437811


mag = len(nums)<EOL>rolling_sum = <NUM_LIT:0><EOL>for i in range(mag):<EOL><INDENT>for j in range(i, mag):<EOL><INDENT>if nums[i] == nums[j]:<EOL><INDENT>rolling_sum += nums[i]<EOL><DEDENT>else:<EOL><INDENT>rolling_sum += (nums[i] * nums[j]) ** <NUM_LIT:0.5><EOL><DEDENT><DEDENT><DEDENT>return rolling_sum * <NUM_LIT:2> / (mag * (mag + <NUM_LIT:1>))<EOL>

r"""Return Heronian mean.

    The Heronian mean is:
    :math:`\frac{\sum\limits_{i, j}\sqrt{{x_i \cdot x_j}}}
    {|nums| \cdot \frac{|nums| + 1}{2}}`
    for :math:`j \ge i`

    Cf. https://en.wikipedia.org/wiki/Heronian_mean

    Parameters
    ----------
    nums : list
        A series of numbers

    Returns
    -------
    float
        The Heronian mean of nums

    Examples
    --------
    >>> heronian_mean([1, 2, 3, 4])
    2.3888282852609093
    >>> heronian_mean([1, 2])
    1.4714045207910316
    >>> heronian_mean([0, 5, 1000])
    179.28511301977582


if exp == <NUM_LIT:0>:<EOL><INDENT>return gmean(nums)<EOL><DEDENT>return ((<NUM_LIT:1> / len(nums)) * sum(i ** exp for i in nums)) ** (<NUM_LIT:1> / exp)<EOL>

r"""Return Hölder (power/generalized) mean.

    The Hölder mean is defined as:
    :math:`\sqrt[p]{\frac{1}{|nums|} \cdot \sum\limits_i{x_i^p}}`
    for :math:`p \ne 0`, and the geometric mean for :math:`p = 0`

    Cf. https://en.wikipedia.org/wiki/Generalized_mean

    Parameters
    ----------
    nums : list
        A series of numbers
    exp : numeric
        The exponent of the Hölder mean

    Returns
    -------
    float
        The Hölder mean of nums for the given exponent

    Examples
    --------
    >>> hoelder_mean([1, 2, 3, 4])
    2.7386127875258306
    >>> hoelder_mean([1, 2])
    1.5811388300841898
    >>> hoelder_mean([0, 5, 1000])
    577.3574860228857


m_a = amean(nums)<EOL>m_g = gmean(nums)<EOL>if math.isnan(m_a) or math.isnan(m_g):<EOL><INDENT>return float('<STR_LIT>')<EOL><DEDENT>while round(m_a, <NUM_LIT:12>) != round(m_g, <NUM_LIT:12>):<EOL><INDENT>m_a, m_g = (m_a + m_g) / <NUM_LIT:2>, (m_a * m_g) ** (<NUM_LIT:1> / <NUM_LIT:2>)<EOL><DEDENT>return m_a<EOL>

Return arithmetic-geometric mean.

    Iterates between arithmetic & geometric means until they converge to
    a single value (rounded to 12 digits).

    Cf. https://en.wikipedia.org/wiki/Arithmetic-geometric_mean

    Parameters
    ----------
    nums : list
        A series of numbers

    Returns
    -------
    float
        The arithmetic-geometric mean of nums

    Examples
    --------
    >>> agmean([1, 2, 3, 4])
    2.3545004777751077
    >>> agmean([1, 2])
    1.4567910310469068
    >>> agmean([0, 5, 1000])
    2.9753977059954195e-13


m_g = gmean(nums)<EOL>m_h = hmean(nums)<EOL>if math.isnan(m_g) or math.isnan(m_h):<EOL><INDENT>return float('<STR_LIT>')<EOL><DEDENT>while round(m_h, <NUM_LIT:12>) != round(m_g, <NUM_LIT:12>):<EOL><INDENT>m_g, m_h = (m_g * m_h) ** (<NUM_LIT:1> / <NUM_LIT:2>), (<NUM_LIT:2> * m_g * m_h) / (m_g + m_h)<EOL><DEDENT>return m_g<EOL>

Return geometric-harmonic mean.

    Iterates between geometric & harmonic means until they converge to
    a single value (rounded to 12 digits).

    Cf. https://en.wikipedia.org/wiki/Geometric-harmonic_mean

    Parameters
    ----------
    nums : list
        A series of numbers

    Returns
    -------
    float
        The geometric-harmonic mean of nums

    Examples
    --------
    >>> ghmean([1, 2, 3, 4])
    2.058868154613003
    >>> ghmean([1, 2])
    1.3728805006183502
    >>> ghmean([0, 5, 1000])
    0.0

    >>> ghmean([0, 0])
    0.0
    >>> ghmean([0, 0, 5])
    nan


m_a = amean(nums)<EOL>m_g = gmean(nums)<EOL>m_h = hmean(nums)<EOL>if math.isnan(m_a) or math.isnan(m_g) or math.isnan(m_h):<EOL><INDENT>return float('<STR_LIT>')<EOL><DEDENT>while round(m_a, <NUM_LIT:12>) != round(m_g, <NUM_LIT:12>) and round(m_g, <NUM_LIT:12>) != round(<EOL>m_h, <NUM_LIT:12><EOL>):<EOL><INDENT>m_a, m_g, m_h = (<EOL>(m_a + m_g + m_h) / <NUM_LIT:3>,<EOL>(m_a * m_g * m_h) ** (<NUM_LIT:1> / <NUM_LIT:3>),<EOL><NUM_LIT:3> / (<NUM_LIT:1> / m_a + <NUM_LIT:1> / m_g + <NUM_LIT:1> / m_h),<EOL>)<EOL><DEDENT>return m_a<EOL>

Return arithmetic-geometric-harmonic mean.

    Iterates over arithmetic, geometric, & harmonic means until they
    converge to a single value (rounded to 12 digits), following the
    method described in :cite:`Raissouli:2009`.

    Parameters
    ----------
    nums : list
        A series of numbers

    Returns
    -------
    float
        The arithmetic-geometric-harmonic mean of nums

    Examples
    --------
    >>> aghmean([1, 2, 3, 4])
    2.198327159900212
    >>> aghmean([1, 2])
    1.4142135623731884
    >>> aghmean([0, 5, 1000])
    335.0


return <NUM_LIT:0.5> * (max(nums) + min(nums))<EOL>

Return midrange.

    The midrange is the arithmetic mean of the maximum & minimum of a series.

    Cf. https://en.wikipedia.org/wiki/Midrange

    Parameters
    ----------
    nums : list
        A series of numbers

    Returns
    -------
    float
        The midrange of nums

    Examples
    --------
    >>> midrange([1, 2, 3])
    2.0
    >>> midrange([1, 2, 2, 3])
    2.0
    >>> midrange([1, 2, 1000, 3])
    500.5


nums = sorted(nums)<EOL>mag = len(nums)<EOL>if mag % <NUM_LIT:2>:<EOL><INDENT>mag = int((mag - <NUM_LIT:1>) / <NUM_LIT:2>)<EOL>return nums[mag]<EOL><DEDENT>mag = int(mag / <NUM_LIT:2>)<EOL>med = (nums[mag - <NUM_LIT:1>] + nums[mag]) / <NUM_LIT:2><EOL>return med if not med.is_integer() else int(med)<EOL>

Return median.

    With numbers sorted by value, the median is the middle value (if there is
    an odd number of values) or the arithmetic mean of the two middle values
    (if there is an even number of values).

    Cf. https://en.wikipedia.org/wiki/Median

    Parameters
    ----------
    nums : list
        A series of numbers

    Returns
    -------
    int or float
        The median of nums

    Examples
    --------
    >>> median([1, 2, 3])
    2
    >>> median([1, 2, 3, 4])
    2.5
    >>> median([1, 2, 2, 4])
    2


return Counter(nums).most_common(<NUM_LIT:1>)[<NUM_LIT:0>][<NUM_LIT:0>]<EOL>

Return the mode.

    The mode of a series is the most common element of that series

    Cf. https://en.wikipedia.org/wiki/Mode_(statistics)

    Parameters
    ----------
    nums : list
        A series of numbers

    Returns
    -------
    int or float
        The mode of nums

    Example
    -------
    >>> mode([1, 2, 2, 3])
    2


def var(nums, mean_func=amean, ddof=<NUM_LIT:0>):

x_bar = mean_func(nums)<EOL>return sum((x - x_bar) ** <NUM_LIT:2> for x in nums) / (len(nums) - ddof)<EOL>

r"""Calculate the variance.

    The variance (:math:`\sigma^2`) of a series of numbers (:math:`x_i`) with
    mean :math:`\mu` and population :math:`N` is:

    :math:`\sigma^2 = \frac{1}{N}\sum_{i=1}^{N}(x_i-\mu)^2`.

    Cf. https://en.wikipedia.org/wiki/Variance

    Parameters
    ----------
    nums : list
        A series of numbers
    mean_func : function
        A mean function (amean by default)
    ddof : int
        The degrees of freedom (0 by default)

    Returns
    -------
    float
        The variance of the values in the series

    Examples
    --------
    >>> var([1, 1, 1, 1])
    0.0
    >>> var([1, 2, 3, 4])
    1.25
    >>> round(var([1, 2, 3, 4], ddof=1), 12)
    1.666666666667


def std(nums, mean_func=amean, ddof=<NUM_LIT:0>):

return var(nums, mean_func, ddof) ** <NUM_LIT:0.5><EOL>

Return the standard deviation.

    The standard deviation of a series of values is the square root of the
    variance.

    Cf. https://en.wikipedia.org/wiki/Standard_deviation

    Parameters
    ----------
    nums : list
        A series of numbers
    mean_func : function
        A mean function (amean by default)
    ddof : int
        The degrees of freedom (0 by default)

    Returns
    -------
    float
        The standard deviation of the values in the series

    Examples
    --------
    >>> std([1, 1, 1, 1])
    0.0
    >>> round(std([1, 2, 3, 4]), 12)
    1.11803398875
    >>> round(std([1, 2, 3, 4], ddof=1), 12)
    1.290994448736


def mean_pairwise_similarity(<EOL>collection, metric=sim, mean_func=hmean, symmetric=False<EOL>):

if not callable(mean_func):<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>if not callable(metric):<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>if hasattr(collection, '<STR_LIT>'):<EOL><INDENT>collection = collection.split()<EOL><DEDENT>if not hasattr(collection, '<STR_LIT>'):<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>elif len(collection) < <NUM_LIT:2>:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>collection = list(collection)<EOL>pairwise_values = []<EOL>for i in range(len(collection)):<EOL><INDENT>for j in range(i + <NUM_LIT:1>, len(collection)):<EOL><INDENT>pairwise_values.append(metric(collection[i], collection[j]))<EOL>if symmetric:<EOL><INDENT>pairwise_values.append(metric(collection[j], collection[i]))<EOL><DEDENT><DEDENT><DEDENT>return mean_func(pairwise_values)<EOL>

Calculate the mean pairwise similarity of a collection of strings.

    Takes the mean of the pairwise similarity between each member of a
    collection, optionally in both directions (for asymmetric similarity
    metrics.

    Parameters
    ----------
    collection : list
        A collection of terms or a string that can be split
    metric : function
        A similarity metric function
    mean_func : function
        A mean function that takes a list of values and returns a float
    symmetric : bool
        Set to True if all pairwise similarities should be calculated in both
        directions

    Returns
    -------
    float
        The mean pairwise similarity of a collection of strings

    Raises
    ------
    ValueError
        mean_func must be a function
    ValueError
        metric must be a function
    ValueError
        collection is neither a string nor iterable type
    ValueError
        collection has fewer than two members

    Examples
    --------
    >>> round(mean_pairwise_similarity(['Christopher', 'Kristof',
    ... 'Christobal']), 12)
    0.519801980198
    >>> round(mean_pairwise_similarity(['Niall', 'Neal', 'Neil']), 12)
    0.545454545455


if not callable(mean_func):<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>if not callable(metric):<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>if hasattr(src_collection, '<STR_LIT>'):<EOL><INDENT>src_collection = src_collection.split()<EOL><DEDENT>if not hasattr(src_collection, '<STR_LIT>'):<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>if hasattr(tar_collection, '<STR_LIT>'):<EOL><INDENT>tar_collection = tar_collection.split()<EOL><DEDENT>if not hasattr(tar_collection, '<STR_LIT>'):<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>src_collection = list(src_collection)<EOL>tar_collection = list(tar_collection)<EOL>pairwise_values = []<EOL>for src in src_collection:<EOL><INDENT>for tar in tar_collection:<EOL><INDENT>pairwise_values.append(metric(src, tar))<EOL>if symmetric:<EOL><INDENT>pairwise_values.append(metric(tar, src))<EOL><DEDENT><DEDENT><DEDENT>return (<EOL>max(pairwise_values),<EOL>min(pairwise_values),<EOL>mean_func(pairwise_values),<EOL>std(pairwise_values, mean_func, <NUM_LIT:0>),<EOL>)<EOL>

Calculate the pairwise similarity statistics a collection of strings.

    Calculate pairwise similarities among members of two collections,
    returning the maximum, minimum, mean (according to a supplied function,
    arithmetic mean, by default), and (population) standard deviation
    of those similarities.

    Parameters
    ----------
    src_collection : list
        A collection of terms or a string that can be split
    tar_collection : list
        A collection of terms or a string that can be split
    metric : function
        A similarity metric function
    mean_func : function
        A mean function that takes a list of values and returns a float
    symmetric : bool
        Set to True if all pairwise similarities should be calculated in both
        directions

    Returns
    -------
    tuple
        The max, min, mean, and standard deviation of similarities

    Raises
    ------
    ValueError
        mean_func must be a function
    ValueError
        metric must be a function
    ValueError
        src_collection is neither a string nor iterable
    ValueError
        tar_collection is neither a string nor iterable

    Example
    -------
    >>> tuple(round(_, 12) for _ in pairwise_similarity_statistics(
    ... ['Christopher', 'Kristof', 'Christobal'], ['Niall', 'Neal', 'Neil']))
    (0.2, 0.0, 0.118614718615, 0.075070477184)


return OmissionKey().fingerprint(word)<EOL>

Return the omission key.

    This is a wrapper for :py:meth:`OmissionKey.fingerprint`.

    Parameters
    ----------
    word : str
        The word to transform into its omission key

    Returns
    -------
    str
        The omission key

    Examples
    --------
    >>> omission_key('The quick brown fox jumped over the lazy dog.')
    'JKQXZVWYBFMGPDHCLNTREUIOA'
    >>> omission_key('Christopher')
    'PHCTSRIOE'
    >>> omission_key('Niall')
    'LNIA'


word = unicode_normalize('<STR_LIT>', text_type(word.upper()))<EOL>word = '<STR_LIT>'.join(c for c in word if c in self._letters)<EOL>key = '<STR_LIT>'<EOL>for char in self._consonants:<EOL><INDENT>if char in word:<EOL><INDENT>key += char<EOL><DEDENT><DEDENT>for char in word:<EOL><INDENT>if char not in self._consonants and char not in key:<EOL><INDENT>key += char<EOL><DEDENT><DEDENT>return key<EOL>

Return the omission key.

        Parameters
        ----------
        word : str
            The word to transform into its omission key

        Returns
        -------
        str
            The omission key

        Examples
        --------
        >>> ok = OmissionKey()
        >>> ok.fingerprint('The quick brown fox jumped over the lazy dog.')
        'JKQXZVWYBFMGPDHCLNTREUIOA'
        >>> ok.fingerprint('Christopher')
        'PHCTSRIOE'
        >>> ok.fingerprint('Niall')
        'LNIA'


def count_fingerprint(word, n_bits=<NUM_LIT:16>, most_common=MOST_COMMON_LETTERS_CG):

return Count().fingerprint(word, n_bits, most_common)<EOL>

Return the count fingerprint.

    This is a wrapper for :py:meth:`Count.fingerprint`.

    Parameters
    ----------
    word : str
        The word to fingerprint
    n_bits : int
        Number of bits in the fingerprint returned
    most_common : list
        The most common tokens in the target language, ordered by frequency

    Returns
    -------
    int
        The count fingerprint

    Examples
    --------
    >>> bin(count_fingerprint('hat'))
    '0b1010000000001'
    >>> bin(count_fingerprint('niall'))
    '0b10001010000'
    >>> bin(count_fingerprint('colin'))
    '0b101010000'
    >>> bin(count_fingerprint('atcg'))
    '0b1010000000000'
    >>> bin(count_fingerprint('entreatment'))
    '0b1111010000100000'


def fingerprint(self, word, n_bits=<NUM_LIT:16>, most_common=MOST_COMMON_LETTERS_CG):

if n_bits % <NUM_LIT:2>:<EOL><INDENT>n_bits += <NUM_LIT:1><EOL><DEDENT>word = Counter(word)<EOL>fingerprint = <NUM_LIT:0><EOL>for letter in most_common:<EOL><INDENT>if n_bits:<EOL><INDENT>fingerprint <<= <NUM_LIT:2><EOL>fingerprint += word[letter] & <NUM_LIT:3><EOL>n_bits -= <NUM_LIT:2><EOL><DEDENT>else:<EOL><INDENT>break<EOL><DEDENT><DEDENT>if n_bits:<EOL><INDENT>fingerprint <<= n_bits<EOL><DEDENT>return fingerprint<EOL>

Return the count fingerprint.

        Parameters
        ----------
        word : str
            The word to fingerprint
        n_bits : int
            Number of bits in the fingerprint returned
        most_common : list
            The most common tokens in the target language, ordered by frequency

        Returns
        -------
        int
            The count fingerprint

        Examples
        --------
        >>> cf = Count()
        >>> bin(cf.fingerprint('hat'))
        '0b1010000000001'
        >>> bin(cf.fingerprint('niall'))
        '0b10001010000'
        >>> bin(cf.fingerprint('colin'))
        '0b101010000'
        >>> bin(cf.fingerprint('atcg'))
        '0b1010000000000'
        >>> bin(cf.fingerprint('entreatment'))
        '0b1111010000100000'


def position_fingerprint(<EOL>word, n_bits=<NUM_LIT:16>, most_common=MOST_COMMON_LETTERS_CG, bits_per_letter=<NUM_LIT:3><EOL>):

return Position().fingerprint(word, n_bits, most_common, bits_per_letter)<EOL>

Return the position fingerprint.

    This is a wrapper for :py:meth:`Position.fingerprint`.

    Parameters
    ----------
    word : str
        The word to fingerprint
    n_bits : int
        Number of bits in the fingerprint returned
    most_common : list
        The most common tokens in the target language, ordered by frequency
    bits_per_letter : int
        The bits to assign for letter position

    Returns
    -------
    int
        The position fingerprint

    Examples
    --------
    >>> bin(position_fingerprint('hat'))
    '0b1110100011111111'
    >>> bin(position_fingerprint('niall'))
    '0b1111110101110010'
    >>> bin(position_fingerprint('colin'))
    '0b1111111110010111'
    >>> bin(position_fingerprint('atcg'))
    '0b1110010001111111'
    >>> bin(position_fingerprint('entreatment'))
    '0b101011111111'


position = {}<EOL>for pos, letter in enumerate(word):<EOL><INDENT>if letter not in position and letter in most_common:<EOL><INDENT>position[letter] = min(pos, <NUM_LIT:2> ** bits_per_letter - <NUM_LIT:1>)<EOL><DEDENT><DEDENT>fingerprint = <NUM_LIT:0><EOL>for letter in most_common:<EOL><INDENT>if n_bits:<EOL><INDENT>fingerprint <<= min(bits_per_letter, n_bits)<EOL>if letter in position:<EOL><INDENT>fingerprint += min(position[letter], <NUM_LIT:2> ** n_bits - <NUM_LIT:1>)<EOL><DEDENT>else:<EOL><INDENT>fingerprint += min(<EOL><NUM_LIT:2> ** bits_per_letter - <NUM_LIT:1>, <NUM_LIT:2> ** n_bits - <NUM_LIT:1><EOL>)<EOL><DEDENT>n_bits -= min(bits_per_letter, n_bits)<EOL><DEDENT>else:<EOL><INDENT>break<EOL><DEDENT><DEDENT>for _ in range(n_bits):<EOL><INDENT>fingerprint <<= <NUM_LIT:1><EOL>fingerprint += <NUM_LIT:1><EOL><DEDENT>return fingerprint<EOL>

Return the position fingerprint.

        Parameters
        ----------
        word : str
            The word to fingerprint
        n_bits : int
            Number of bits in the fingerprint returned
        most_common : list
            The most common tokens in the target language, ordered by frequency
        bits_per_letter : int
            The bits to assign for letter position

        Returns
        -------
        int
            The position fingerprint

        Examples
        --------
        >>> bin(position_fingerprint('hat'))
        '0b1110100011111111'
        >>> bin(position_fingerprint('niall'))
        '0b1111110101110010'
        >>> bin(position_fingerprint('colin'))
        '0b1111111110010111'
        >>> bin(position_fingerprint('atcg'))
        '0b1110010001111111'
        >>> bin(position_fingerprint('entreatment'))
        '0b101011111111'


return String().fingerprint(phrase, joiner)<EOL>

Return string fingerprint.

    This is a wrapper for :py:meth:`String.fingerprint`.

    Parameters
    ----------
    phrase : str
        The string from which to calculate the fingerprint
    joiner : str
        The string that will be placed between each word

    Returns
    -------
    str
        The fingerprint of the phrase

    Example
    -------
    >>> str_fingerprint('The quick brown fox jumped over the lazy dog.')
    'brown dog fox jumped lazy over quick the'


def fingerprint(self, phrase, joiner='<STR_LIT:U+0020>'):

phrase = unicode_normalize('<STR_LIT>', text_type(phrase.strip().lower()))<EOL>phrase = '<STR_LIT>'.join([c for c in phrase if c.isalnum() or c.isspace()])<EOL>phrase = joiner.join(sorted(list(set(phrase.split()))))<EOL>return phrase<EOL>

Return string fingerprint.

        Parameters
        ----------
        phrase : str
            The string from which to calculate the fingerprint
        joiner : str
            The string that will be placed between each word

        Returns
        -------
        str
            The fingerprint of the phrase

        Example
        -------
        >>> sf = String()
        >>> sf.fingerprint('The quick brown fox jumped over the lazy dog.')
        'brown dog fox jumped lazy over quick the'


def occurrence_fingerprint(<EOL>word, n_bits=<NUM_LIT:16>, most_common=MOST_COMMON_LETTERS_CG<EOL>):

return Occurrence().fingerprint(word, n_bits, most_common)<EOL>

Return the occurrence fingerprint.

    This is a wrapper for :py:meth:`Occurrence.fingerprint`.

    Parameters
    ----------
    word : str
        The word to fingerprint
    n_bits : int
        Number of bits in the fingerprint returned
    most_common : list
        The most common tokens in the target language, ordered by frequency

    Returns
    -------
    int
        The occurrence fingerprint

    Examples
    --------
    >>> bin(occurrence_fingerprint('hat'))
    '0b110000100000000'
    >>> bin(occurrence_fingerprint('niall'))
    '0b10110000100000'
    >>> bin(occurrence_fingerprint('colin'))
    '0b1110000110000'
    >>> bin(occurrence_fingerprint('atcg'))
    '0b110000000010000'
    >>> bin(occurrence_fingerprint('entreatment'))
    '0b1110010010000100'


word = set(word)<EOL>fingerprint = <NUM_LIT:0><EOL>for letter in most_common:<EOL><INDENT>if letter in word:<EOL><INDENT>fingerprint += <NUM_LIT:1><EOL><DEDENT>n_bits -= <NUM_LIT:1><EOL>if n_bits:<EOL><INDENT>fingerprint <<= <NUM_LIT:1><EOL><DEDENT>else:<EOL><INDENT>break<EOL><DEDENT><DEDENT>n_bits -= <NUM_LIT:1><EOL>if n_bits > <NUM_LIT:0>:<EOL><INDENT>fingerprint <<= n_bits<EOL><DEDENT>return fingerprint<EOL>

Return the occurrence fingerprint.

        Parameters
        ----------
        word : str
            The word to fingerprint
        n_bits : int
            Number of bits in the fingerprint returned
        most_common : list
            The most common tokens in the target language, ordered by frequency

        Returns
        -------
        int
            The occurrence fingerprint

        Examples
        --------
        >>> of = Occurrence()
        >>> bin(of.fingerprint('hat'))
        '0b110000100000000'
        >>> bin(of.fingerprint('niall'))
        '0b10110000100000'
        >>> bin(of.fingerprint('colin'))
        '0b1110000110000'
        >>> bin(of.fingerprint('atcg'))
        '0b110000000010000'
        >>> bin(of.fingerprint('entreatment'))
        '0b1110010010000100'


def occurrence_halved_fingerprint(<EOL>word, n_bits=<NUM_LIT:16>, most_common=MOST_COMMON_LETTERS_CG<EOL>):

return OccurrenceHalved().fingerprint(word, n_bits, most_common)<EOL>

Return the occurrence halved fingerprint.

    This is a wrapper for :py:meth:`OccurrenceHalved.fingerprint`.

    Parameters
    ----------
    word : str
        The word to fingerprint
    n_bits : int
        Number of bits in the fingerprint returned
    most_common : list
        The most common tokens in the target language, ordered by frequency

    Returns
    -------
    int
        The occurrence halved fingerprint

    Examples
    --------
    >>> bin(occurrence_halved_fingerprint('hat'))
    '0b1010000000010'
    >>> bin(occurrence_halved_fingerprint('niall'))
    '0b10010100000'
    >>> bin(occurrence_halved_fingerprint('colin'))
    '0b1001010000'
    >>> bin(occurrence_halved_fingerprint('atcg'))
    '0b10100000000000'
    >>> bin(occurrence_halved_fingerprint('entreatment'))
    '0b1111010000110000'


if n_bits % <NUM_LIT:2>:<EOL><INDENT>n_bits += <NUM_LIT:1><EOL><DEDENT>w_len = len(word) // <NUM_LIT:2><EOL>w_1 = set(word[:w_len])<EOL>w_2 = set(word[w_len:])<EOL>fingerprint = <NUM_LIT:0><EOL>for letter in most_common:<EOL><INDENT>if n_bits:<EOL><INDENT>fingerprint <<= <NUM_LIT:1><EOL>if letter in w_1:<EOL><INDENT>fingerprint += <NUM_LIT:1><EOL><DEDENT>fingerprint <<= <NUM_LIT:1><EOL>if letter in w_2:<EOL><INDENT>fingerprint += <NUM_LIT:1><EOL><DEDENT>n_bits -= <NUM_LIT:2><EOL><DEDENT>else:<EOL><INDENT>break<EOL><DEDENT><DEDENT>if n_bits > <NUM_LIT:0>:<EOL><INDENT>fingerprint <<= n_bits<EOL><DEDENT>return fingerprint<EOL>

Return the occurrence halved fingerprint.

        Based on the occurrence halved fingerprint from :cite:`Cislak:2017`.

        Parameters
        ----------
        word : str
            The word to fingerprint
        n_bits : int
            Number of bits in the fingerprint returned
        most_common : list
            The most common tokens in the target language, ordered by frequency

        Returns
        -------
        int
            The occurrence halved fingerprint

        Examples
        --------
        >>> ohf = OccurrenceHalved()
        >>> bin(ohf.fingerprint('hat'))
        '0b1010000000010'
        >>> bin(ohf.fingerprint('niall'))
        '0b10010100000'
        >>> bin(ohf.fingerprint('colin'))
        '0b1001010000'
        >>> bin(ohf.fingerprint('atcg'))
        '0b10100000000000'
        >>> bin(ohf.fingerprint('entreatment'))
        '0b1111010000110000'


def phonetic_fingerprint(<EOL>phrase, phonetic_algorithm=double_metaphone, joiner='<STR_LIT:U+0020>', *args, **kwargs<EOL>):

return Phonetic().fingerprint(<EOL>phrase, phonetic_algorithm, joiner, *args, **kwargs<EOL>)<EOL>

Return the phonetic fingerprint of a phrase.

    This is a wrapper for :py:meth:`Phonetic.fingerprint`.

    Parameters
    ----------
    phrase : str
        The string from which to calculate the phonetic fingerprint
    phonetic_algorithm : function
        A phonetic algorithm that takes a string and returns a string
        (presumably a phonetic representation of the original string). By
        default, this function uses :py:func:`.double_metaphone`.
    joiner : str
        The string that will be placed between each word
    *args
        Variable length argument list
    **kwargs
        Arbitrary keyword arguments

    Returns
    -------
    str
        The phonetic fingerprint of the phrase

    Examples
    --------
    >>> phonetic_fingerprint('The quick brown fox jumped over the lazy dog.')
    '0 afr fks jmpt kk ls prn tk'
    >>> from abydos.phonetic import soundex
    >>> phonetic_fingerprint('The quick brown fox jumped over the lazy dog.',
    ... phonetic_algorithm=soundex)
    'b650 d200 f200 j513 l200 o160 q200 t000'


phonetic = '<STR_LIT>'<EOL>for word in phrase.split():<EOL><INDENT>word = phonetic_algorithm(word, *args, **kwargs)<EOL>if not isinstance(word, text_type) and hasattr(word, '<STR_LIT>'):<EOL><INDENT>word = word[<NUM_LIT:0>]<EOL><DEDENT>phonetic += word + joiner<EOL><DEDENT>phonetic = phonetic[: -len(joiner)]<EOL>return super(self.__class__, self).fingerprint(phonetic)<EOL>

Return the phonetic fingerprint of a phrase.

        Parameters
        ----------
        phrase : str
            The string from which to calculate the phonetic fingerprint
        phonetic_algorithm : function
            A phonetic algorithm that takes a string and returns a string
            (presumably a phonetic representation of the original string). By
            default, this function uses :py:func:`.double_metaphone`.
        joiner : str
            The string that will be placed between each word
        *args
            Variable length argument list
        **kwargs
            Arbitrary keyword arguments

        Returns
        -------
        str
            The phonetic fingerprint of the phrase

        Examples
        --------
        >>> pf = Phonetic()
        >>> pf.fingerprint('The quick brown fox jumped over the lazy dog.')
        '0 afr fks jmpt kk ls prn tk'
        >>> from abydos.phonetic import soundex
        >>> pf.fingerprint('The quick brown fox jumped over the lazy dog.',
        ... phonetic_algorithm=soundex)
        'b650 d200 f200 j513 l200 o160 q200 t000'


def qgram_fingerprint(phrase, qval=<NUM_LIT:2>, start_stop='<STR_LIT>', joiner='<STR_LIT>'):

return QGram().fingerprint(phrase, qval, start_stop, joiner)<EOL>

Return Q-Gram fingerprint.

    This is a wrapper for :py:meth:`QGram.fingerprint`.

    Parameters
    ----------
    phrase : str
        The string from which to calculate the q-gram fingerprint
    qval : int
        The length of each q-gram (by default 2)
    start_stop : str
        The start & stop symbol(s) to concatenate on either end of the phrase,
        as defined in :py:class:`tokenizer.QGrams`
    joiner : str
        The string that will be placed between each word

    Returns
    -------
    str
        The q-gram fingerprint of the phrase

    Examples
    --------
    >>> qgram_fingerprint('The quick brown fox jumped over the lazy dog.')
    'azbrckdoedeleqerfoheicjukblampnfogovowoxpequrortthuiumvewnxjydzy'
    >>> qgram_fingerprint('Christopher')
    'cherhehrisopphristto'
    >>> qgram_fingerprint('Niall')
    'aliallni'


def fingerprint(self, phrase, qval=<NUM_LIT:2>, start_stop='<STR_LIT>', joiner='<STR_LIT>'):

phrase = unicode_normalize('<STR_LIT>', text_type(phrase.strip().lower()))<EOL>phrase = '<STR_LIT>'.join(c for c in phrase if c.isalnum())<EOL>phrase = QGrams(phrase, qval, start_stop)<EOL>phrase = joiner.join(sorted(phrase))<EOL>return phrase<EOL>

Return Q-Gram fingerprint.

        Parameters
        ----------
        phrase : str
            The string from which to calculate the q-gram fingerprint
        qval : int
            The length of each q-gram (by default 2)
        start_stop : str
            The start & stop symbol(s) to concatenate on either end of the
            phrase, as defined in :py:class:`tokenizer.QGrams`
        joiner : str
            The string that will be placed between each word

        Returns
        -------
        str
            The q-gram fingerprint of the phrase

        Examples
        --------
        >>> qf = QGram()
        >>> qf.fingerprint('The quick brown fox jumped over the lazy dog.')
        'azbrckdoedeleqerfoheicjukblampnfogovowoxpequrortthuiumvewnxjydzy'
        >>> qf.fingerprint('Christopher')
        'cherhehrisopphristto'
        >>> qf.fingerprint('Niall')
        'aliallni'


return SkeletonKey().fingerprint(word)<EOL>

Return the skeleton key.

    This is a wrapper for :py:meth:`SkeletonKey.fingerprint`.

    Parameters
    ----------
    word : str
        The word to transform into its skeleton key

    Returns
    -------
    str
        The skeleton key

    Examples
    --------
    >>> skeleton_key('The quick brown fox jumped over the lazy dog.')
    'THQCKBRWNFXJMPDVLZYGEUIOA'
    >>> skeleton_key('Christopher')
    'CHRSTPIOE'
    >>> skeleton_key('Niall')
    'NLIA'


word = unicode_normalize('<STR_LIT>', text_type(word.upper()))<EOL>word = '<STR_LIT>'.join(c for c in word if c in self._letters)<EOL>start = word[<NUM_LIT:0>:<NUM_LIT:1>]<EOL>consonant_part = '<STR_LIT>'<EOL>vowel_part = '<STR_LIT>'<EOL>for char in word[<NUM_LIT:1>:]:<EOL><INDENT>if char != start:<EOL><INDENT>if char in self._vowels:<EOL><INDENT>if char not in vowel_part:<EOL><INDENT>vowel_part += char<EOL><DEDENT><DEDENT>elif char not in consonant_part:<EOL><INDENT>consonant_part += char<EOL><DEDENT><DEDENT><DEDENT>return start + consonant_part + vowel_part<EOL>

Return the skeleton key.

        Parameters
        ----------
        word : str
            The word to transform into its skeleton key

        Returns
        -------
        str
            The skeleton key

        Examples
        --------
        >>> sk = SkeletonKey()
        >>> sk.fingerprint('The quick brown fox jumped over the lazy dog.')
        'THQCKBRWNFXJMPDVLZYGEUIOA'
        >>> sk.fingerprint('Christopher')
        'CHRSTPIOE'
        >>> sk.fingerprint('Niall')
        'NLIA'


pass<EOL>

Fingerprint string.

        Parameters
        ----------
        word : str
            Word to fingerprint


def synoname_toolcode(lname, fname='<STR_LIT>', qual='<STR_LIT>', normalize=<NUM_LIT:0>):

return SynonameToolcode().fingerprint(lname, fname, qual, normalize)<EOL>

Build the Synoname toolcode.

    This is a wrapper for :py:meth:`SynonameToolcode.fingerprint`.

    Parameters
    ----------
    lname : str
        Last name
    fname : str
        First name (can be blank)
    qual : str
        Qualifier
    normalize : int
        Normalization mode (0, 1, or 2)

    Returns
    -------
    tuple
        The transformed names and the synoname toolcode

    Examples
    --------
    >>> synoname_toolcode('hat')
    ('hat', '', '0000000003$$h')
    >>> synoname_toolcode('niall')
    ('niall', '', '0000000005$$n')
    >>> synoname_toolcode('colin')
    ('colin', '', '0000000005$$c')
    >>> synoname_toolcode('atcg')
    ('atcg', '', '0000000004$$a')
    >>> synoname_toolcode('entreatment')
    ('entreatment', '', '0000000011$$e')

    >>> synoname_toolcode('Ste.-Marie', 'Count John II', normalize=2)
    ('ste.-marie ii', 'count john', '0200491310$015b049a127c$smcji')
    >>> synoname_toolcode('Michelangelo IV', '', 'Workshop of')
    ('michelangelo iv', '', '3000550015$055b$mi')


def fingerprint(self, lname, fname='<STR_LIT>', qual='<STR_LIT>', normalize=<NUM_LIT:0>):

lname = lname.lower()<EOL>fname = fname.lower()<EOL>qual = qual.lower()<EOL>toolcode = ['<STR_LIT:0>', '<STR_LIT:0>', '<STR_LIT:0>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT:$>', '<STR_LIT>', '<STR_LIT:$>', '<STR_LIT>']<EOL>full_name = '<STR_LIT:U+0020>'.join((lname, fname))<EOL>if qual in self._qual_3:<EOL><INDENT>toolcode[<NUM_LIT:0>] = '<STR_LIT:3>'<EOL><DEDENT>elif qual in self._qual_2:<EOL><INDENT>toolcode[<NUM_LIT:0>] = '<STR_LIT:2>'<EOL><DEDENT>elif qual in self._qual_1:<EOL><INDENT>toolcode[<NUM_LIT:0>] = '<STR_LIT:1>'<EOL><DEDENT>if '<STR_LIT:.>' in full_name:<EOL><INDENT>toolcode[<NUM_LIT:1>] = '<STR_LIT:2>'<EOL><DEDENT>else:<EOL><INDENT>for punct in '<STR_LIT>':<EOL><INDENT>if punct in full_name:<EOL><INDENT>toolcode[<NUM_LIT:1>] = '<STR_LIT:1>'<EOL>break<EOL><DEDENT><DEDENT><DEDENT>elderyounger = '<STR_LIT>'  <EOL>for gen in self._gen_1:<EOL><INDENT>if gen in full_name:<EOL><INDENT>toolcode[<NUM_LIT:2>] = '<STR_LIT:1>'<EOL>elderyounger = gen<EOL>break<EOL><DEDENT><DEDENT>else:<EOL><INDENT>for gen in self._gen_2:<EOL><INDENT>if gen in full_name:<EOL><INDENT>toolcode[<NUM_LIT:2>] = '<STR_LIT:2>'<EOL>elderyounger = gen<EOL>break<EOL><DEDENT><DEDENT><DEDENT>if normalize:<EOL><INDENT>comma = lname.find('<STR_LIT:U+002C>')<EOL>if comma != -<NUM_LIT:1>:<EOL><INDENT>lname_end = lname[comma + <NUM_LIT:1> :]<EOL>while lname_end[<NUM_LIT:0>] in {'<STR_LIT:U+0020>', '<STR_LIT:U+002C>'}:<EOL><INDENT>lname_end = lname_end[<NUM_LIT:1>:]<EOL><DEDENT>fname = lname_end + '<STR_LIT:U+0020>' + fname<EOL>lname = lname[:comma].strip()<EOL><DEDENT><DEDENT>if normalize == <NUM_LIT:2> and elderyounger:<EOL><INDENT>elderyounger_loc = fname.find(elderyounger)<EOL>if elderyounger_loc != -<NUM_LIT:1>:<EOL><INDENT>lname = '<STR_LIT:U+0020>'.join((lname, elderyounger.strip()))<EOL>fname = '<STR_LIT:U+0020>'.join(<EOL>(<EOL>fname[:elderyounger_loc].strip(),<EOL>fname[elderyounger_loc + len(elderyounger) :],<EOL>)<EOL>).strip()<EOL><DEDENT><DEDENT>toolcode[<NUM_LIT:4>] = '<STR_LIT>'.format(len(fname))<EOL>toolcode[<NUM_LIT:5>] = '<STR_LIT>'.format(len(lname))<EOL>for char in '<STR_LIT>':<EOL><INDENT>full_name = full_name.replace(char, '<STR_LIT>')<EOL><DEDENT>for pos, char in enumerate(full_name):<EOL><INDENT>if char == '<STR_LIT:->' and full_name[pos - <NUM_LIT:1> : pos + <NUM_LIT:2>] != '<STR_LIT>':<EOL><INDENT>full_name = full_name[:pos] + '<STR_LIT:U+0020>' + full_name[pos + <NUM_LIT:1> :]<EOL><DEDENT><DEDENT>for letter in [_[<NUM_LIT:0>] for _ in full_name.split()]:<EOL><INDENT>if letter not in toolcode[<NUM_LIT:9>]:<EOL><INDENT>toolcode[<NUM_LIT:9>] += letter<EOL><DEDENT>if len(toolcode[<NUM_LIT:9>]) == <NUM_LIT:15>:<EOL><INDENT>break<EOL><DEDENT><DEDENT>def roman_check(numeral, fname, lname):<EOL><INDENT>"""<STR_LIT>"""<EOL>loc = fname.find(numeral)<EOL>if fname and (<EOL>loc != -<NUM_LIT:1><EOL>and (len(fname[loc:]) == len(numeral))<EOL>or fname[loc + len(numeral)] in {'<STR_LIT:U+0020>', '<STR_LIT:U+002C>'}<EOL>):<EOL><INDENT>lname = '<STR_LIT:U+0020>'.join((lname, numeral))<EOL>fname = '<STR_LIT:U+0020>'.join(<EOL>(<EOL>fname[:loc].strip(),<EOL>fname[loc + len(numeral) :].lstrip('<STR_LIT>'),<EOL>)<EOL>)<EOL><DEDENT>return fname.strip(), lname.strip()<EOL><DEDENT>for num, special in enumerate(self._synoname_special_table):<EOL><INDENT>roman, match, extra, method = special<EOL>if method & self._method_dict['<STR_LIT:end>']:<EOL><INDENT>match_context = '<STR_LIT:U+0020>' + match<EOL>loc = full_name.find(match_context)<EOL>if (len(full_name) > len(match_context)) and (<EOL>loc == len(full_name) - len(match_context)<EOL>):<EOL><INDENT>if roman:<EOL><INDENT>if not any(<EOL>abbr in fname for abbr in ('<STR_LIT>', '<STR_LIT>', '<STR_LIT>')<EOL>):<EOL><INDENT>full_name = full_name[:loc]<EOL>toolcode[<NUM_LIT:7>] += '<STR_LIT>'.format(num) + '<STR_LIT:a>'<EOL>if toolcode[<NUM_LIT:3>] == '<STR_LIT>':<EOL><INDENT>toolcode[<NUM_LIT:3>] = '<STR_LIT>'.format(num)<EOL><DEDENT>if normalize == <NUM_LIT:2>:<EOL><INDENT>fname, lname = roman_check(match, fname, lname)<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>full_name = full_name[:loc]<EOL>toolcode[<NUM_LIT:7>] += '<STR_LIT>'.format(num) + '<STR_LIT:a>'<EOL><DEDENT><DEDENT><DEDENT>if method & self._method_dict['<STR_LIT>']:<EOL><INDENT>match_context = '<STR_LIT:U+0020>' + match + '<STR_LIT:U+0020>'<EOL>loc = <NUM_LIT:0><EOL>while loc != -<NUM_LIT:1>:<EOL><INDENT>loc = full_name.find(match_context, loc + <NUM_LIT:1>)<EOL>if loc > <NUM_LIT:0>:<EOL><INDENT>if roman:<EOL><INDENT>if not any(<EOL>abbr in fname for abbr in ('<STR_LIT>', '<STR_LIT>', '<STR_LIT>')<EOL>):<EOL><INDENT>full_name = (<EOL>full_name[:loc]<EOL>+ full_name[loc + len(match) + <NUM_LIT:1> :]<EOL>)<EOL>toolcode[<NUM_LIT:7>] += '<STR_LIT>'.format(num) + '<STR_LIT:b>'<EOL>if toolcode[<NUM_LIT:3>] == '<STR_LIT>':<EOL><INDENT>toolcode[<NUM_LIT:3>] = '<STR_LIT>'.format(num)<EOL><DEDENT>if normalize == <NUM_LIT:2>:<EOL><INDENT>fname, lname = roman_check(<EOL>match, fname, lname<EOL>)<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>full_name = (<EOL>full_name[:loc]<EOL>+ full_name[loc + len(match) + <NUM_LIT:1> :]<EOL>)<EOL>toolcode[<NUM_LIT:7>] += '<STR_LIT>'.format(num) + '<STR_LIT:b>'<EOL><DEDENT><DEDENT><DEDENT><DEDENT>if method & self._method_dict['<STR_LIT>']:<EOL><INDENT>match_context = match + '<STR_LIT:U+0020>'<EOL>loc = full_name.find(match_context)<EOL>if loc == <NUM_LIT:0>:<EOL><INDENT>full_name = full_name[len(match) + <NUM_LIT:1> :]<EOL>toolcode[<NUM_LIT:7>] += '<STR_LIT>'.format(num) + '<STR_LIT:c>'<EOL><DEDENT><DEDENT>if method & self._method_dict['<STR_LIT>']:<EOL><INDENT>loc = full_name.find(match)<EOL>if loc == <NUM_LIT:0>:<EOL><INDENT>toolcode[<NUM_LIT:7>] += '<STR_LIT>'.format(num) + '<STR_LIT:d>'<EOL>if full_name[: len(match)] not in toolcode[<NUM_LIT:9>]:<EOL><INDENT>toolcode[<NUM_LIT:9>] += full_name[: len(match)]<EOL><DEDENT><DEDENT><DEDENT>if extra:<EOL><INDENT>loc = full_name.find(extra)<EOL>if loc != -<NUM_LIT:1>:<EOL><INDENT>toolcode[<NUM_LIT:7>] += '<STR_LIT>'.format(num) + '<STR_LIT:X>'<EOL>toolcode[<NUM_LIT:9>] += full_name[loc : loc + len(match)]<EOL><DEDENT><DEDENT><DEDENT>return lname, fname, '<STR_LIT>'.join(toolcode)<EOL>

Build the Synoname toolcode.

        Parameters
        ----------
        lname : str
            Last name
        fname : str
            First name (can be blank)
        qual : str
            Qualifier
        normalize : int
            Normalization mode (0, 1, or 2)

        Returns
        -------
        tuple
            The transformed names and the synoname toolcode

        Examples
        --------
        >>> st = SynonameToolcode()
        >>> st.fingerprint('hat')
        ('hat', '', '0000000003$$h')
        >>> st.fingerprint('niall')
        ('niall', '', '0000000005$$n')
        >>> st.fingerprint('colin')
        ('colin', '', '0000000005$$c')
        >>> st.fingerprint('atcg')
        ('atcg', '', '0000000004$$a')
        >>> st.fingerprint('entreatment')
        ('entreatment', '', '0000000011$$e')

        >>> st.fingerprint('Ste.-Marie', 'Count John II', normalize=2)
        ('ste.-marie ii', 'count john', '0200491310$015b049a127c$smcji')
        >>> st.fingerprint('Michelangelo IV', '', 'Workshop of')
        ('michelangelo iv', '', '3000550015$055b$mi')


return _super_corpus_file(name, corpora_dir)<EOL>

Return the path to a corpus file.

    Parameters
    ----------
    name : str
        Corpus file
    corpora_dir : str
        The directory containing the corpora

    Returns
    -------
    str
        The path to the corpus file


while True:<EOL><INDENT>char = unichr(randint(<NUM_LIT:0>, below))  <EOL>try:<EOL><INDENT>name = unicodedata.name(char)<EOL>if must_be is None or must_be in name:<EOL><INDENT>return char<EOL><DEDENT><DEDENT>except ValueError:<EOL><INDENT>pass<EOL><DEDENT><DEDENT>

Generate a random Unicode character below U+{below}.

    Parameters
    ----------
    below : int
        Maximum Unicode value
    must_be : str
        A required part of the character name

    Returns
    -------
    str
        A character

    Raises
    ------
    ValueError


while True:<EOL><INDENT>new_word = []<EOL>for ch in word:<EOL><INDENT>if random() > fuzziness:  <EOL><INDENT>new_word.append(ch)<EOL><DEDENT>else:<EOL><INDENT>if random() > <NUM_LIT:0.5>:  <EOL><INDENT>new_word.append(choice(printable))  <EOL><DEDENT>elif random() > <NUM_LIT>:  <EOL><INDENT>new_word.append(unichr(randint(<NUM_LIT:0>, <NUM_LIT>)))  <EOL><DEDENT>else:<EOL><INDENT>new_word.append(unichr(randint(<NUM_LIT:0>, <NUM_LIT>)))  <EOL><DEDENT>if random() > <NUM_LIT:0.5>:  <EOL><INDENT>new_word.append(ch)<EOL><DEDENT><DEDENT><DEDENT>new_word = '<STR_LIT>'.join(new_word)<EOL>if new_word != word:<EOL><INDENT>return new_word<EOL><DEDENT><DEDENT>

Fuzz a word with noise.

    Parameters
    ----------
    word : str
        A word to fuzz
    fuzziness : float
        How fuzzy to make the word

    Returns
    -------
    str
        A fuzzed word


return os.path.join(corpora_dir, name)<EOL>

Return the path to a corpus file.

    Parameters
    ----------
    name : str
        Corpus file
        corpora_dir : str
        The directory containing the corpora

    Returns
    -------
    str: The full path to the corpus file


if EXTREME_TEST:<EOL><INDENT>return True<EOL><DEDENT>elif ALLOW_RANDOM and random() * inverse_probability < <NUM_LIT:1>:  <EOL><INDENT>return True<EOL><DEDENT>else:<EOL><INDENT>return False<EOL><DEDENT>

Return whether to run a test.

    Return True if:
        EXTREME_TEST is True
        OR
        (ALLOW_RANDOM is True
        AND
        random.random() * inverse_probability < 1)
    Otherwise return False

    Parameters
    ----------
    inverse_probability : int
        The inverse of the probability

    Returns
    -------
    bool: Whether to run a test


nw_matrix = {<EOL>('<STR_LIT:A>', '<STR_LIT:A>'): <NUM_LIT:10>,<EOL>('<STR_LIT>', '<STR_LIT>'): <NUM_LIT:7>,<EOL>('<STR_LIT:C>', '<STR_LIT:C>'): <NUM_LIT:9>,<EOL>('<STR_LIT:T>', '<STR_LIT:T>'): <NUM_LIT:8>,<EOL>('<STR_LIT:A>', '<STR_LIT>'): -<NUM_LIT:1>,<EOL>('<STR_LIT:A>', '<STR_LIT:C>'): -<NUM_LIT:3>,<EOL>('<STR_LIT:A>', '<STR_LIT:T>'): -<NUM_LIT:4>,<EOL>('<STR_LIT>', '<STR_LIT:C>'): -<NUM_LIT:5>,<EOL>('<STR_LIT>', '<STR_LIT:T>'): -<NUM_LIT:3>,<EOL>('<STR_LIT:C>', '<STR_LIT:T>'): <NUM_LIT:0>,<EOL>}<EOL>return NeedlemanWunsch.sim_matrix(<EOL>src, tar, nw_matrix, symmetric=True, alphabet='<STR_LIT>'<EOL>)<EOL>

Return a similarity score for two DNA base pairs.

    Values copied from:
    https://en.wikipedia.org/wiki/Needleman%E2%80%93Wunsch_algorithm

    Parameters
    ----------
    src : str
        Source string for comparison
        tar : str
        Target string for comparison

    Returns
    -------
    int: similarity of two DNA base pairs


return <NUM_LIT:2> * int(src is tar) - <NUM_LIT:1><EOL>

Return 1 if src is tar, otherwise -1.

    Parameters
    ----------
    src : str
        Source string for comparison
        tar : str
        Target string for comparison

    Returns
    -------
    int: nw similarity


s1 = re.sub('<STR_LIT>', r'<STR_LIT>', name)<EOL>s1 = re.sub('<STR_LIT>', r'<STR_LIT>', s1).lower()<EOL>return s1<EOL>

Convert camelCase (used in PHP) to Python-standard snake_case.

    Src:
    https://stackoverflow.com/questions/1175208/elegant-python-function-to-convert-camelcase-to-snake-case

    Parameters
    ----------
    name: A function or variable name in camelCase

    Returns
    -------
    str: The name in snake_case


def pythonize(line, fn='<STR_LIT>', subdir='<STR_LIT>'):

global array_seen, nl, sd<EOL>if '<STR_LIT>' in line:<EOL><INDENT>return '<STR_LIT>'<EOL><DEDENT>if '<STR_LIT>' in line:<EOL><INDENT>return '<STR_LIT>'<EOL><DEDENT>line = line.strip()<EOL>if '<STR_LIT>' in line and not line.startswith('<STR_LIT>'):<EOL><INDENT>array_seen = True<EOL><DEDENT>line = re.sub('<STR_LIT>', '<STR_LIT:#>', line)<EOL>if line and re.search(r'<STR_LIT>', line):<EOL><INDENT>line = '<STR_LIT>'<EOL><DEDENT>line = line.replace('<STR_LIT>', '<STR_LIT>')<EOL>line = re.sub(r'<STR_LIT>', '<STR_LIT>', line)<EOL>line = re.sub('<STR_LIT>', '<STR_LIT>', line)<EOL>line = re.sub('<STR_LIT>', '<STR_LIT>', line)<EOL>line = re.sub(<EOL>r'<STR_LIT>'<EOL>+ r'<STR_LIT>',<EOL>lambda m: (<EOL>"<STR_LIT>"<EOL>+ subdir<EOL>+ "<STR_LIT>"<EOL>+ m.group(<NUM_LIT:1>)<EOL>+ "<STR_LIT>"<EOL>+ m.group(<NUM_LIT:2>).upper()<EOL>+ '<STR_LIT>'<EOL>+ subdir.upper()<EOL>+ '<STR_LIT:_>'<EOL>+ c2u(m.group(<NUM_LIT:3>)).upper()<EOL>),<EOL>line,<EOL>)<EOL>line = re.sub(<EOL>r'<STR_LIT>'<EOL>+ r'<STR_LIT>',<EOL>lambda m: (<EOL>"<STR_LIT>"<EOL>+ subdir<EOL>+ "<STR_LIT>"<EOL>+ m.group(<NUM_LIT:1>)<EOL>+ "<STR_LIT>"<EOL>+ c2u(m.group(<NUM_LIT:2>)).upper()<EOL>+ '<STR_LIT>'<EOL>+ subdir.upper()<EOL>+ '<STR_LIT:_>'<EOL>+ c2u(m.group(<NUM_LIT:3>)).upper()<EOL>+ '<STR_LIT>'<EOL>+ subdir.upper()<EOL>+ '<STR_LIT:_>'<EOL>+ c2u(m.group(<NUM_LIT:4>)).upper()<EOL>),<EOL>line,<EOL>)<EOL>line = re.sub(<EOL>r'<STR_LIT>'<EOL>+ r'<STR_LIT>',<EOL>lambda m: (<EOL>"<STR_LIT>"<EOL>+ subdir<EOL>+ "<STR_LIT>"<EOL>+ m.group(<NUM_LIT:1>)<EOL>+ "<STR_LIT>"<EOL>+ c2u(m.group(<NUM_LIT:2>)).upper()<EOL>+ '<STR_LIT>'<EOL>+ subdir.upper()<EOL>+ '<STR_LIT:_>'<EOL>+ c2u(m.group(<NUM_LIT:3>)).upper()<EOL>+ '<STR_LIT>'<EOL>+ subdir.upper()<EOL>+ '<STR_LIT:_>'<EOL>+ c2u(m.group(<NUM_LIT:4>)).upper()<EOL>),<EOL>line,<EOL>)<EOL>line = re.sub(<EOL>r'<STR_LIT>',<EOL>lambda m: '<STR_LIT:_>' + sd.upper() + '<STR_LIT:_>' + c2u(m.group(<NUM_LIT:1>)).upper(),<EOL>line,<EOL>)<EOL>for _ in range(len(lang_tuple)):<EOL><INDENT>line = re.sub(r'<STR_LIT>', r'<STR_LIT>', line)<EOL><DEDENT>line = re.sub(<EOL>r'<STR_LIT>',<EOL>lambda m: (<EOL>'<STR_LIT>' + m.group(<NUM_LIT:1>).upper()<EOL>if m.group(<NUM_LIT:1>) in lang_dict<EOL>else '<STR_LIT:$>' + m.group(<NUM_LIT:1>)<EOL>),<EOL>line,<EOL>)<EOL>line = re.sub(r'<STR_LIT>', r'<STR_LIT>', line)<EOL>line = re.sub(<EOL>'<STR_LIT>', lambda m: str(lang_dict[m.group(<NUM_LIT:1>).lower()]), line<EOL>)<EOL>for _ in range(<NUM_LIT:4>):<EOL><INDENT>line = re.sub(<EOL>r'<STR_LIT>',<EOL>lambda m: str(int(m.group(<NUM_LIT:1>)) + int(m.group(<NUM_LIT:2>))),<EOL>line,<EOL>)<EOL><DEDENT>if fn == '<STR_LIT>':<EOL><INDENT>if len(line.split('<STR_LIT:U+002C>')) >= <NUM_LIT:3>:<EOL><INDENT>parts = line.split('<STR_LIT:U+002C>')<EOL>parts[<NUM_LIT:0>] = re.sub('<STR_LIT>', r'<STR_LIT>', parts[<NUM_LIT:0>])<EOL>parts[<NUM_LIT:2>] = parts[<NUM_LIT:2>].title()<EOL>line = '<STR_LIT:U+002C>'.join(parts)<EOL><DEDENT><DEDENT>if '<STR_LIT>' in fn:<EOL><INDENT>line = line.replace('<STR_LIT:">', "<STR_LIT:'>")<EOL>line = line.replace("<STR_LIT>", "<STR_LIT>")<EOL>if line and line[<NUM_LIT:0>] == "<STR_LIT:'>":<EOL><INDENT>line = '<STR_LIT:U+0020>' * <NUM_LIT> + line<EOL><DEDENT><DEDENT>comment = '<STR_LIT>'<EOL>if '<STR_LIT:#>' in line:<EOL><INDENT>hashsign = line.find('<STR_LIT:#>')<EOL>comment = line[hashsign:]<EOL>code = line[:hashsign]<EOL><DEDENT>else:<EOL><INDENT>code = line<EOL><DEDENT>code = code.rstrip()<EOL>comment = comment.strip()<EOL>if not re.match(r'<STR_LIT>', code):<EOL><INDENT>comment = '<STR_LIT:U+0020>' + comment<EOL><DEDENT>if '<STR_LIT:(>' in code and '<STR_LIT:)>' in code:<EOL><INDENT>prefix = code[: code.find('<STR_LIT:(>') + <NUM_LIT:1>]<EOL>suffix = code[code.rfind('<STR_LIT:)>') :]<EOL>tuplecontent = code[len(prefix) : len(code) - len(suffix)]<EOL>elts = tuplecontent.split('<STR_LIT:U+002C>')<EOL>for i in range(len(elts)):<EOL><INDENT>elts[i] = elts[i].strip()<EOL>if elts[i][<NUM_LIT:0>] == '<STR_LIT:">' and elts[i][-<NUM_LIT:1>] == '<STR_LIT:">':<EOL><INDENT>elts[i] = "<STR_LIT:'>" + elts[i][<NUM_LIT:1>:-<NUM_LIT:1>].replace("<STR_LIT:'>", "<STR_LIT>") + "<STR_LIT:'>"<EOL><DEDENT><DEDENT>tuplecontent = '<STR_LIT:U+002CU+0020>'.join(elts)<EOL>code = prefix + tuplecontent + suffix<EOL><DEDENT>line = code + comment<EOL>line = re.sub('<STR_LIT>', '<STR_LIT>', line)<EOL>if line:<EOL><INDENT>nl = False<EOL>if array_seen and not (line[<NUM_LIT:0>] == '<STR_LIT:_>' or line.startswith('<STR_LIT>')):<EOL><INDENT>line = '<STR_LIT:U+0020>' * <NUM_LIT:4> + line<EOL><DEDENT>return line + '<STR_LIT:\n>'<EOL><DEDENT>elif not nl:<EOL><INDENT>nl = True<EOL>return '<STR_LIT:\n>'<EOL><DEDENT>else:<EOL><INDENT>return '<STR_LIT>'<EOL><DEDENT>

Convert a line of BMPM code from PHP to Python.

    Parameters
    ----------
    line : str
        A line of code
        fn : str
        A filename
        subdir : str
        The file's subdirectory

    Returns
    -------
    The code in Python


<EOL>score_cutoffs = (<NUM_LIT:10>, <NUM_LIT>, <NUM_LIT>, <NUM_LIT>, <NUM_LIT:5>)<EOL>for i in range(len(score_cutoffs)):<EOL><INDENT>if score >= score_cutoffs[i]:<EOL><INDENT>return BADGE_COLORS[i]<EOL><DEDENT><DEDENT>return BADGE_COLORS[-<NUM_LIT:1>]<EOL>

Return Pylint badge color.

    Parameters
    ----------
    score : float
        A Pylint score

    Returns
    -------
    str
        Badge color


<EOL>score_cutoffs = (<NUM_LIT:0>, <NUM_LIT:10>, <NUM_LIT>, <NUM_LIT:50>, <NUM_LIT:100>)<EOL>for i in range(len(score_cutoffs)):<EOL><INDENT>if score <= score_cutoffs[i]:<EOL><INDENT>return BADGE_COLORS[i]<EOL><DEDENT><DEDENT>return BADGE_COLORS[-<NUM_LIT:1>]<EOL>

Return pydocstyle badge color.

    Parameters
    ----------
    score : float
        A pydocstyle score

    Returns
    -------
    str
        Badge color


<EOL>score_cutoffs = (<NUM_LIT:0>, <NUM_LIT:20>, <NUM_LIT:50>, <NUM_LIT:100>, <NUM_LIT:200>)<EOL>for i in range(len(score_cutoffs)):<EOL><INDENT>if score <= score_cutoffs[i]:<EOL><INDENT>return BADGE_COLORS[i]<EOL><DEDENT><DEDENT>return BADGE_COLORS[-<NUM_LIT:1>]<EOL>

Return flake8 badge color.

    Parameters
    ----------
    score : float
        A flake8 score

    Returns
    -------
    str
        Badge color


with open(path.join(HERE, fn), '<STR_LIT:r>', encoding='<STR_LIT:utf-8>') as f:<EOL><INDENT>return f.read()<EOL><DEDENT>

Read fn and return the contents.

    Parameters
    ----------
    fn : str
        A filename

    Returns
    -------
    str
        The content of the file


first_col = <NUM_LIT:3><EOL>last_col = -<NUM_LIT:1><EOL>def print_usage():<EOL><INDENT>"""<STR_LIT>"""<EOL>sys.stdout.write(<EOL>'<STR_LIT>' + '<STR_LIT>'<EOL>)<EOL>sys.exit(<NUM_LIT:2>)<EOL><DEDENT>def binarize(num):<EOL><INDENT>"""<STR_LIT>"""<EOL>if num == '<STR_LIT:0>':  <EOL><INDENT>return '<STR_LIT>'<EOL><DEDENT>elif num == '<STR_LIT>':  <EOL><INDENT>return '<STR_LIT>'<EOL><DEDENT>elif num == '<STR_LIT:1>':  <EOL><INDENT>return '<STR_LIT>'<EOL><DEDENT>elif num == '<STR_LIT:2>':  <EOL><INDENT>return '<STR_LIT>'<EOL><DEDENT><DEDENT>def init_termdicts():<EOL><INDENT>"""<STR_LIT>"""<EOL>ifile = codecs.open('<STR_LIT>', '<STR_LIT:r>', '<STR_LIT:utf-8>')<EOL>feature_mask = {}<EOL>keyline = ifile.readline().strip().split('<STR_LIT:U+002C>')[first_col:last_col]<EOL>mag = len(keyline)<EOL>for i in range(len(keyline)):<EOL><INDENT>features = '<STR_LIT>' + ('<STR_LIT>' * i) + '<STR_LIT>' + ('<STR_LIT>' * (mag - i - <NUM_LIT:1>))<EOL>feature_mask[keyline[i]] = int(features, <NUM_LIT:2>)<EOL><DEDENT>termdict = {}<EOL>for line in ifile:<EOL><INDENT>line = line.strip().rstrip('<STR_LIT:U+002C>')<EOL>if '<STR_LIT:#>' in line:<EOL><INDENT>line = line[: line.find('<STR_LIT:#>')].strip()<EOL><DEDENT>if line:<EOL><INDENT>line = line.split('<STR_LIT:U+002C>')<EOL>term = line[last_col]<EOL>features = '<STR_LIT>' + '<STR_LIT>'.join(<EOL>[binarize(val) for val in line[first_col:last_col]]<EOL>)<EOL>termdict[term] = int(features, <NUM_LIT:2>)<EOL><DEDENT><DEDENT>return termdict, feature_mask<EOL><DEDENT>def check_terms(sym, features, name, termdict):<EOL><INDENT>"""<STR_LIT>"""<EOL>if '<STR_LIT:#>' in name:<EOL><INDENT>name = name[: name.find('<STR_LIT:#>')].strip()<EOL><DEDENT>for term in name.split():<EOL><INDENT>if term in termdict:<EOL><INDENT>if termdict[term] & features != termdict[term]:<EOL><INDENT>sys.stdout.write(<EOL>'<STR_LIT>'<EOL>+ term<EOL>+ '<STR_LIT>'<EOL>+ sym<EOL>+ '<STR_LIT:\n>'<EOL>)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>sys.stdout.write(<EOL>'<STR_LIT>'<EOL>+ term<EOL>+ '<STR_LIT>'<EOL>+ name<EOL>+ '<STR_LIT>'<EOL>+ sym<EOL>+ '<STR_LIT:\n>'<EOL>)<EOL><DEDENT><DEDENT><DEDENT>def check_entailments(sym, features, feature_mask):<EOL><INDENT>"""<STR_LIT>"""<EOL>entailments = {<EOL>'<STR_LIT>': ('<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': ('<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': ('<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': ('<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': ('<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': ('<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': ('<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': ('<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': ('<STR_LIT>', '<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': ('<STR_LIT>', '<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': ('<STR_LIT>',),<EOL>'<STR_LIT>': ('<STR_LIT>',),<EOL>}<EOL>for feature in entailments:<EOL><INDENT>fname = feature[<NUM_LIT:1>:]<EOL>if feature[<NUM_LIT:0>] == '<STR_LIT:+>':<EOL><INDENT>fm = (feature_mask[fname] >> <NUM_LIT:1>) & feature_mask[fname]<EOL><DEDENT>else:<EOL><INDENT>fm = (feature_mask[fname] << <NUM_LIT:1>) & feature_mask[fname]<EOL><DEDENT>if (features & fm) == fm:<EOL><INDENT>for ent in entailments[feature]:<EOL><INDENT>ename = ent[<NUM_LIT:1>:]<EOL>if ent[<NUM_LIT:0>] == '<STR_LIT:+>':<EOL><INDENT>efm = (feature_mask[ename] >> <NUM_LIT:1>) & feature_mask[ename]<EOL><DEDENT>elif ent[<NUM_LIT:0>] == '<STR_LIT:->':<EOL><INDENT>efm = (feature_mask[ename] << <NUM_LIT:1>) & feature_mask[ename]<EOL><DEDENT>elif ent[<NUM_LIT:0>] == '<STR_LIT:0>':<EOL><INDENT>efm = <NUM_LIT:0><EOL><DEDENT>elif ent[<NUM_LIT:0>] == '<STR_LIT>':<EOL><INDENT>efm = feature_mask[ename]<EOL><DEDENT>if ent[<NUM_LIT:0>] == '<STR_LIT>':<EOL><INDENT>if (features & efm) == <NUM_LIT:0>:<EOL><INDENT>sys.stdout.write(<EOL>'<STR_LIT>'<EOL>+ sym<EOL>+ '<STR_LIT>'<EOL>+ fname<EOL>+ '<STR_LIT>'<EOL>+ ename<EOL>)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if (features & efm) != efm:<EOL><INDENT>sys.stdout.write(<EOL>'<STR_LIT>'<EOL>+ sym<EOL>+ '<STR_LIT>'<EOL>+ fname<EOL>+ '<STR_LIT>'<EOL>+ ename<EOL>)<EOL><DEDENT><DEDENT><DEDENT><DEDENT><DEDENT><DEDENT>checkdict = {}  <EOL>checkset_s = set()  <EOL>checkset_f = set()  <EOL>termdict, feature_mask = init_termdicts()<EOL>ifile = '<STR_LIT>'<EOL>ofile = '<STR_LIT>'<EOL>try:<EOL><INDENT>opts = getopt.getopt(argv, '<STR_LIT>', ['<STR_LIT>', '<STR_LIT>'])[<NUM_LIT:0>]<EOL><DEDENT>except getopt.GetoptError:<EOL><INDENT>print_usage()<EOL><DEDENT>for opt, arg in opts:<EOL><INDENT>if opt == '<STR_LIT>':<EOL><INDENT>print_usage()<EOL><DEDENT>elif opt in ('<STR_LIT>', '<STR_LIT>'):<EOL><INDENT>ifile = codecs.open(arg, '<STR_LIT:r>', '<STR_LIT:utf-8>')<EOL><DEDENT>elif opt in ('<STR_LIT>', '<STR_LIT>'):<EOL><INDENT>ofile = codecs.open(arg, '<STR_LIT:w>', '<STR_LIT:utf-8>')<EOL><DEDENT><DEDENT>if not ifile:<EOL><INDENT>print_usage()<EOL><DEDENT>oline = '<STR_LIT>'<EOL>if not ofile:<EOL><INDENT>ofile = sys.stdout<EOL><DEDENT>ofile.write(oline + '<STR_LIT:\n>')<EOL>keyline = ifile.readline().strip().split('<STR_LIT:U+002C>')[first_col:last_col]<EOL>for line in ifile:<EOL><INDENT>line = line.strip().rstrip('<STR_LIT:U+002C>')<EOL>if line.startswith('<STR_LIT>'):<EOL><INDENT>break<EOL><DEDENT>line = unicodedata.normalize('<STR_LIT>', line)<EOL>if not line or line.startswith('<STR_LIT:#>'):<EOL><INDENT>oline = '<STR_LIT:U+0020>' + line<EOL><DEDENT>else:<EOL><INDENT>line = line.strip().split('<STR_LIT:U+002C>')<EOL>if '<STR_LIT:#>' in line:<EOL><INDENT>line = line[: line.find('<STR_LIT:#>')]<EOL><DEDENT>symbol = line[<NUM_LIT:0>]<EOL>variant = int(line[<NUM_LIT:1>])<EOL>segmental = bool(line[<NUM_LIT:2>])<EOL>features = '<STR_LIT>' + '<STR_LIT>'.join(<EOL>[binarize(val) for val in line[first_col:last_col]]<EOL>)<EOL>name = line[-<NUM_LIT:1>].strip()<EOL>if not segmental:<EOL><INDENT>features = '<STR_LIT:->' + features<EOL><DEDENT>featint = int(features, <NUM_LIT:2>)<EOL>check_terms(symbol, featint, name, termdict)<EOL>check_entailments(symbol, featint, feature_mask)<EOL>if symbol in checkset_s:<EOL><INDENT>sys.stdout.write(<EOL>'<STR_LIT>' + symbol + '<STR_LIT>'<EOL>)<EOL><DEDENT>else:<EOL><INDENT>checkset_s.add(symbol)<EOL><DEDENT>if variant < <NUM_LIT:2>:<EOL><INDENT>if featint in checkset_f:<EOL><INDENT>sys.stdout.write(<EOL>'<STR_LIT>'<EOL>+ str(featint)<EOL>+ '<STR_LIT>'<EOL>+ '<STR_LIT>'<EOL>+ symbol<EOL>+ '<STR_LIT>'<EOL>+ checkdict[featint]<EOL>)<EOL><DEDENT>else:<EOL><INDENT>checkdict[featint] = symbol<EOL>checkset_f.add(featint)<EOL><DEDENT><DEDENT>if variant < <NUM_LIT:5>:<EOL><INDENT>oline = '<STR_LIT>'.format(<EOL>symbol, featint<EOL>)<EOL><DEDENT>else:<EOL><INDENT>oline = '<STR_LIT>'<EOL><DEDENT><DEDENT>if oline:<EOL><INDENT>ofile.write(oline + '<STR_LIT:\n>')<EOL><DEDENT><DEDENT>ofile.write('<STR_LIT>')<EOL>mag = len(keyline)<EOL>for i in range(len(keyline)):<EOL><INDENT>features = int('<STR_LIT>' + ('<STR_LIT>' * i) + '<STR_LIT>' + ('<STR_LIT>' * (mag - i - <NUM_LIT:1>)), <NUM_LIT:2>)<EOL>oline = '<STR_LIT>'.format(keyline[i], features)<EOL>ofile.write(oline + '<STR_LIT:\n>')<EOL><DEDENT>ofile.write('<STR_LIT>')<EOL>

Read input file and write to output.

    Parameters
    ----------
    argv : list
        Arguments to the script


return dict((resource_basename(fn), resource_filename(__name__, dirname +'<STR_LIT:/>'+fn))<EOL>for fn in resource_listdir(__name__, dirname)<EOL>if not fn.endswith('<STR_LIT>'))<EOL>

Generate a list of included files *and* extract them to a temp space.

    Templates have to be extracted from the egg because they are used
    by external code. All template filenames are stored in
    :data:`config.templates`.


if resource.endswith('<STR_LIT:/>'):<EOL><INDENT>resource = resource[:-<NUM_LIT:1>]<EOL><DEDENT>parts = resource.split('<STR_LIT:/>')<EOL>return parts[-<NUM_LIT:1>]<EOL>

Last component of a resource (which always uses '/' as sep).


templates = [_get_template(s) for s in utilities.asiterable(t)]<EOL>if len(templates) == <NUM_LIT:1>:<EOL><INDENT>return templates[<NUM_LIT:0>]<EOL><DEDENT>return templates<EOL>

Find template file *t* and return its real path.

    *t* can be a single string or a list of strings. A string
    should be one of

    1. a relative or absolute path,
    2. a file in one of the directories listed in :data:`gromacs.config.path`,
    3. a filename in the package template directory (defined in the template dictionary
       :data:`gromacs.config.templates`) or
    4. a key into :data:`~gromacs.config.templates`.

    The first match (in this order) is returned. If the argument is a
    single string then a single string is returned, otherwise a list
    of strings.

    :Arguments: *t* : template file or key (string or list of strings)
    :Returns:   os.path.realpath(*t*) (or a list thereof)
    :Raises:    :exc:`ValueError` if no file can be located.


return [_get_template(s) for s in utilities.asiterable(t)]<EOL>

Find template file(s) *t* and return their real paths.

    *t* can be a single string or a list of strings. A string should
    be one of

    1. a relative or absolute path,
    2. a file in one of the directories listed in :data:`gromacs.config.path`,
    3. a filename in the package template directory (defined in the template dictionary
       :data:`gromacs.config.templates`) or
    4. a key into :data:`~gromacs.config.templates`.

    The first match (in this order) is returned for each input argument.

    :Arguments: *t* : template file or key (string or list of strings)
    :Returns:   list of os.path.realpath(*t*)
    :Raises:    :exc:`ValueError` if no file can be located.


if os.path.exists(t):           <EOL><INDENT>pass<EOL><DEDENT>else:<EOL><INDENT>_t = t<EOL>_t_found = False<EOL>for d in path:              <EOL><INDENT>p = os.path.join(d, _t)<EOL>if os.path.exists(p):<EOL><INDENT>t = p<EOL>_t_found = True<EOL>break<EOL><DEDENT><DEDENT>_t = os.path.basename(t)<EOL>if not _t_found:            <EOL><INDENT>for p in templates.values():<EOL><INDENT>if _t == os.path.basename(p):<EOL><INDENT>t = p<EOL>_t_found = True     <EOL>break               <EOL><DEDENT><DEDENT><DEDENT>if not _t_found:            <EOL><INDENT>try:<EOL><INDENT>t = templates[t]<EOL><DEDENT>except KeyError:<EOL><INDENT>pass<EOL><DEDENT>else:<EOL><INDENT>_t_found = True<EOL><DEDENT><DEDENT>if not _t_found:            <EOL><INDENT>raise ValueError("<STR_LIT>".format(**vars()))<EOL><DEDENT><DEDENT>return os.path.realpath(t)<EOL>


global cfg, configuration    <EOL>cfg = GMXConfigParser(filename=filename)   <EOL>globals().update(cfg.configuration)        <EOL>configuration = cfg.configuration          <EOL>return cfg<EOL>

Reads and parses the configuration file.

    Default values are loaded and then replaced with the values from
    ``~/.gromacswrapper.cfg`` if that file exists. The global
    configuration instance :data:`gromacswrapper.config.cfg` is updated
    as are a number of global variables such as :data:`configdir`,
    :data:`qscriptdir`, :data:`templatesdir`, :data:`logfilename`, ...

    Normally, the configuration is only loaded when the :mod:`gromacs`
    package is imported but a re-reading of the configuration can be forced
    anytime by calling :func:`get_configuration`.

    :Returns: a dict with all updated global configuration variables


<EOL>get_configuration()<EOL>if not os.path.exists(filename):<EOL><INDENT>with open(filename, '<STR_LIT:w>') as configfile:<EOL><INDENT>cfg.write(configfile)  <EOL>msg = "<STR_LIT>""<STR_LIT>" % filename<EOL>print(msg)<EOL><DEDENT><DEDENT>for d in config_directories:<EOL><INDENT>utilities.mkdir_p(d)<EOL><DEDENT>

Prepare a default GromacsWrapper global environment.

    1) Create the global config file.
    2) Create the directories in which the user can store template and config files.

    This function can be run repeatedly without harm.


if "<STR_LIT>" in os.environ:<EOL><INDENT>return True<EOL><DEDENT>missing = [d for d in config_directories if not os.path.exists(d)]<EOL>if len(missing) > <NUM_LIT:0>:<EOL><INDENT>print("<STR_LIT>")<EOL>print("<STR_LIT>".format('<STR_LIT>'.join(missing)))<EOL>print("<STR_LIT>")<EOL>print("<STR_LIT>")<EOL>print("<STR_LIT>")<EOL>return False<EOL><DEDENT>return True<EOL>

Check if templates directories are setup and issue a warning and help.

   Set the environment variable  :envvar:`GROMACSWRAPPER_SUPPRESS_SETUP_CHECK`
   skip the check and make it always return ``True``

   :return ``True`` if directories were found and ``False`` otherwise

    .. versionchanged:: 0.3.1
       Uses :envvar:`GROMACSWRAPPER_SUPPRESS_SETUP_CHECK` to suppress check
       (useful for scripts run on a server)


<EOL>envvars = ['<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>',<EOL>'<STR_LIT>', '<STR_LIT>', '<STR_LIT>',<EOL>'<STR_LIT>',<EOL>'<STR_LIT>', '<STR_LIT>']<EOL>cmdargs = ['<STR_LIT>', '<STR_LIT:-c>', "<STR_LIT>".format(gmxrc,<EOL>'<STR_LIT:U+0020>'.join(['<STR_LIT>'.format(v) for v in envvars]))]<EOL>if not gmxrc:<EOL><INDENT>logger.debug("<STR_LIT>")<EOL>return<EOL><DEDENT>try:<EOL><INDENT>out = subprocess.check_output(cmdargs)<EOL>out = out.strip().split()<EOL>for key, value in zip(envvars, out):<EOL><INDENT>value = str(value.decode('<STR_LIT:ascii>').replace('<STR_LIT>', '<STR_LIT>'))  <EOL>os.environ[key] = value<EOL>logger.debug("<STR_LIT>", key, value)<EOL><DEDENT><DEDENT>except (subprocess.CalledProcessError, OSError):<EOL><INDENT>logger.warning("<STR_LIT>"<EOL>"<STR_LIT>", gmxrc)<EOL><DEDENT>

Set the environment from ``GMXRC`` provided in *gmxrc*.

    Runs ``GMXRC`` in a subprocess and puts environment variables loaded by it
    into this Python environment.

    If *gmxrc* evaluates to ``False`` then nothing is done. If errors occur
    then only a warning will be logged. Thus, it should be safe to just call
    this function.


names = []<EOL>for group in cfg.get('<STR_LIT>', '<STR_LIT>').split():<EOL><INDENT>names.extend(cfg.get('<STR_LIT>', group).split())<EOL><DEDENT>return names<EOL>

Get tool names from all configured groups.

    :return: list of tool names


return cfg.get('<STR_LIT>', '<STR_LIT>').split()<EOL>


self.filename = kwargs.pop('<STR_LIT:filename>', CONFIGNAME)<EOL>super(GMXConfigParser, self).__init__(*args, **kwargs)<EOL>self.set('<STR_LIT>', '<STR_LIT>',<EOL>os.path.join("<STR_LIT>", os.path.basename(defaults['<STR_LIT>'])))<EOL>self.set('<STR_LIT>', '<STR_LIT>',<EOL>os.path.join("<STR_LIT>", os.path.basename(defaults['<STR_LIT>'])))<EOL>self.add_section('<STR_LIT>')<EOL>self.set("<STR_LIT>", "<STR_LIT>", "<STR_LIT>")<EOL>self.set("<STR_LIT>", "<STR_LIT>", "<STR_LIT>")<EOL>self.set("<STR_LIT>", "<STR_LIT>", "<STR_LIT>")<EOL>self.set("<STR_LIT>", "<STR_LIT>", "<STR_LIT>")<EOL>self.set("<STR_LIT>", "<STR_LIT>", "<STR_LIT>")<EOL>self.set("<STR_LIT>", "<STR_LIT>", "<STR_LIT:yes>")<EOL>self.add_section('<STR_LIT>')<EOL>self.set('<STR_LIT>', '<STR_LIT>', defaults['<STR_LIT>'])<EOL>self.set('<STR_LIT>', '<STR_LIT>', defaults['<STR_LIT>'])<EOL>self.set('<STR_LIT>', '<STR_LIT>', defaults['<STR_LIT>'])<EOL>default_cfg = get_template(self.cfg_template)<EOL>self.read_file(open(default_cfg))<EOL>self.read([self.filename])<EOL>

Reads and parses the configuration file.

        Default values are loaded and then replaced with the values from
        ``~/.gromacswrapper.cfg`` if that file exists. The global
        configuration instance :data:`gromacswrapper.config.cfg` is updated
        as are a number of global variables such as :data:`configdir`,
        :data:`qscriptdir`, :data:`templatesdir`, :data:`logfilename`, ...

        Normally, the configuration is only loaded when the :mod:`gromacswrapper`
        package is imported but a re-reading of the configuration can be forced
        anytime by calling :func:`get_configuration`.


configuration = {<EOL>'<STR_LIT>': self.filename,<EOL>'<STR_LIT>': self.getpath('<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': self.getLogLevel('<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': self.getLogLevel('<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': self.getpath('<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': self.getpath('<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': self.getpath('<STR_LIT>', '<STR_LIT>'),<EOL>}<EOL>configuration['<STR_LIT:path>'] = [os.path.curdir,<EOL>configuration['<STR_LIT>'],<EOL>configuration['<STR_LIT>']]<EOL>return configuration<EOL>

Dict of variables that we make available as globals in the module.

        Can be used as ::

           globals().update(GMXConfigParser.configuration)        # update configdir, templatesdir ...


return os.path.expanduser(os.path.expandvars(self.get(section, option)))<EOL>


return logging.getLevelName(self.get(section, option).upper())<EOL>

Return the textual representation of logging level 'option' or the number.

        Note that option is always interpreted as an UPPERCASE string
        and hence integer log levels will not be recognized.

        .. SeeAlso: :mod:`logging` and :func:`logging.getLevelName`


for qs in queuing_systems:<EOL><INDENT>if qs.isMine(scriptfile):<EOL><INDENT>return qs<EOL><DEDENT><DEDENT>return None<EOL>

Return the queuing system for which *scriptfile* was written.


def generate_submit_scripts(templates, prefix=None, deffnm='<STR_LIT>', jobname='<STR_LIT>', budget=None,<EOL>mdrun_opts=None, walltime=<NUM_LIT:1.0>, jobarray_string=None, startdir=None,<EOL>npme=None, **kwargs):

if not jobname[<NUM_LIT:0>].isalpha():<EOL><INDENT>jobname = '<STR_LIT>'+jobname<EOL>wmsg = "<STR_LIT>".format(jobname)<EOL>logger.warn(wmsg)<EOL>warnings.warn(wmsg, category=AutoCorrectionWarning)<EOL><DEDENT>if prefix is None:<EOL><INDENT>prefix = "<STR_LIT>"<EOL><DEDENT>if mdrun_opts is not None:<EOL><INDENT>mdrun_opts = '<STR_LIT:">'+str(mdrun_opts)+'<STR_LIT:">'  <EOL><DEDENT>dirname = kwargs.pop('<STR_LIT>', os.path.curdir)<EOL>wt = Timedelta(hours=walltime)<EOL>walltime = wt.strftime("<STR_LIT>")<EOL>wall_hours = wt.ashours<EOL>def write_script(template):<EOL><INDENT>submitscript = os.path.join(dirname, prefix + os.path.basename(template))<EOL>logger.info("<STR_LIT>".format(**vars()))<EOL>qsystem = detect_queuing_system(template)<EOL>if qsystem is not None and (qsystem.name == '<STR_LIT>'):<EOL><INDENT>cbook.edit_txt(template,<EOL>[('<STR_LIT>','<STR_LIT>', deffnm),<EOL>('<STR_LIT>', '<STR_LIT>', jobname),<EOL>('<STR_LIT>', '<STR_LIT>', budget),<EOL>('<STR_LIT>', '<STR_LIT>', walltime),<EOL>('<STR_LIT>', '<STR_LIT>', wall_hours),<EOL>('<STR_LIT>', '<STR_LIT>', startdir),<EOL>('<STR_LIT>', '<STR_LIT>', npme),<EOL>('<STR_LIT>', '<STR_LIT>', mdrun_opts),  <EOL>('<STR_LIT>', '<STR_LIT>', jobarray_string),<EOL>],<EOL>newname=submitscript)<EOL>ext = os.path.splitext(submitscript)[<NUM_LIT:1>]<EOL><DEDENT>else:<EOL><INDENT>cbook.edit_txt(template,<EOL>[('<STR_LIT>','<STR_LIT>', deffnm),<EOL>('<STR_LIT>', '<STR_LIT>', jobname),<EOL>('<STR_LIT>', '<STR_LIT>', budget),<EOL>('<STR_LIT>', '<STR_LIT>', walltime),<EOL>('<STR_LIT>', '<STR_LIT>', wall_hours),<EOL>('<STR_LIT>', '<STR_LIT>', startdir),<EOL>('<STR_LIT>', '<STR_LIT>', npme),<EOL>('<STR_LIT>', '<STR_LIT>', mdrun_opts),  <EOL>('<STR_LIT>', '<STR_LIT>', jobarray_string),<EOL>],<EOL>newname=submitscript)<EOL>ext = os.path.splitext(submitscript)[<NUM_LIT:1>]<EOL><DEDENT>if ext in ('<STR_LIT>', '<STR_LIT>', '<STR_LIT>'):<EOL><INDENT>os.chmod(submitscript, <NUM_LIT>)<EOL><DEDENT>return submitscript<EOL><DEDENT>return [write_script(template) for template in config.get_templates(templates)]<EOL>

Write scripts for queuing systems.

    This sets up queuing system run scripts with a simple search and replace in
    templates. See :func:`gromacs.cbook.edit_txt` for details. Shell scripts
    are made executable.

    :Arguments:
      *templates*
          Template file or list of template files. The "files" can also be names
          or symbolic names for templates in the templates directory. See
          :mod:`gromacs.config` for details and rules for writing templates.
      *prefix*
          Prefix for the final run script filename; by default the filename will be
          the same as the template. [None]
      *dirname*
          Directory in which to place the submit scripts. [.]
      *deffnm*
          Default filename prefix for :program:`mdrun` ``-deffnm`` [md]
      *jobname*
          Name of the job in the queuing system. [MD]
      *budget*
          Which budget to book the runtime on [None]
      *startdir*
          Explicit path on the remote system (for run scripts that need to `cd`
          into this directory at the beginning of execution) [None]
      *mdrun_opts*
          String of additional options for :program:`mdrun`.
      *walltime*
          Maximum runtime of the job in hours. [1]
      *npme*
          number of PME nodes
      *jobarray_string*
          Multi-line string that is spliced in for job array functionality
          (see :func:`gromacs.qsub.generate_submit_array`; do not use manually)
      *kwargs*
          all other kwargs are ignored

    :Returns: list of generated run scripts


def generate_submit_array(templates, directories, **kwargs):

dirname = kwargs.setdefault('<STR_LIT>', os.path.curdir)<EOL>reldirs = [relpath(p, start=dirname) for p in asiterable(directories)]<EOL>missing = [p for p in (os.path.join(dirname, subdir) for subdir in reldirs)<EOL>if not os.path.exists(p)]<EOL>if len(missing) > <NUM_LIT:0>:<EOL><INDENT>logger.debug("<STR_LIT>", vars())<EOL>logger.error("<STR_LIT>"<EOL>"<STR_LIT>", vars())<EOL><DEDENT>def write_script(template):<EOL><INDENT>qsystem = detect_queuing_system(template)<EOL>if qsystem is None or not qsystem.has_arrays():<EOL><INDENT>logger.warning("<STR_LIT>", vars())<EOL>return None<EOL><DEDENT>kwargs['<STR_LIT>'] = qsystem.array(reldirs)<EOL>return generate_submit_scripts(template, **kwargs)[<NUM_LIT:0>]   <EOL><DEDENT>return [write_script(template) for template in config.get_templates(templates)]<EOL>

Generate a array job.

    For each ``work_dir`` in *directories*, the array job will
     1. cd into ``work_dir``
     2. run the job as detailed in the template
    It will use all the queuing system directives found in the
    template. If more complicated set ups are required, then this
    function cannot be used.

    :Arguments:
       *templates*
          Basic template for a single job; the job array logic is spliced into
          the position of the line ::
              # JOB_ARRAY_PLACEHOLDER
          The appropriate commands for common queuing systems (Sun Gridengine, PBS)
          are hard coded here. The queuing system is detected from the suffix of
          the template.
       *directories*
          List of directories under *dirname*. One task is set up for each
          directory.
       *dirname*
          The array script will be placed in this directory. The *directories*
          **must** be located under *dirname*.
       *kwargs*
          See :func:`gromacs.setup.generate_submit_script` for details.


def __init__(self, name, suffix, qsub_prefix, array_variable=None, array_option=None):

self.name = name<EOL>self.suffix = suffix<EOL>self.qsub_prefix = qsub_prefix<EOL>self.array_variable = array_variable<EOL>self.array_option = array_option<EOL>

Define a queuing system's functionality

        :Arguments:
          *name*
             name of the queuing system, e.g. 'Sun Gridengine'
          *suffix*
             suffix of input files, e.g. 'sge'
          *qsub_prefix*
             prefix string that starts a qsub flag in a script, e.g. '#$'

        :Keywords:
          *array_variable*
             environment variable exported for array jobs, e.g.
             'SGE_TASK_ID'
          *array_option*
             qsub option format string to launch an array (e.g. '-t %d-%d')


return "<STR_LIT:U+0020>".join((self.qsub_prefix,)+args)<EOL>

Return string for qsub flag *args* prefixed with appropriate inscript prefix.


return self.array_variable is not None<EOL>


return self.flag(self.array_option % (<NUM_LIT:1>,len(directories)))<EOL>

Return string to embed the array launching option in the script.


if not self.has_arrays():<EOL><INDENT>raise NotImplementedError('<STR_LIT>'<EOL>'<STR_LIT>' % vars(self))<EOL><DEDENT>hrule = '<STR_LIT:#>'+<NUM_LIT>*'<STR_LIT:->'<EOL>lines = [<EOL>'<STR_LIT>',<EOL>hrule,<EOL>'<STR_LIT>',<EOL>self.array_flag(directories),<EOL>hrule,<EOL>'<STR_LIT>',<EOL>'<STR_LIT>']<EOL>for i,dirname in enumerate(asiterable(directories)):<EOL><INDENT>idx = i+<NUM_LIT:1>   <EOL>lines.append('<STR_LIT>'.format(**vars()))<EOL><DEDENT>lines.extend([<EOL>'<STR_LIT>',<EOL>'<STR_LIT>'.format(**vars(self)),<EOL>'<STR_LIT>',<EOL>hrule,<EOL>'<STR_LIT>'<EOL>])<EOL>return "<STR_LIT:\n>".join(lines)<EOL>

Return multiline string for simple array jobs over *directories*.

        .. Warning:: The string is in ``bash`` and hence the template must also
                     be ``bash`` (and *not* ``csh`` or ``sh``).


suffix = os.path.splitext(scriptname)[<NUM_LIT:1>].lower()<EOL>if suffix.startswith('<STR_LIT:.>'):<EOL><INDENT>suffix = suffix[<NUM_LIT:1>:]<EOL><DEDENT>return self.suffix == suffix<EOL>

Primitive queuing system detection; only looks at suffix at the moment.


cPickle.dump(self, open(self._canonicalize(filename), '<STR_LIT:wb>'), <EOL>protocol=cPickle.HIGHEST_PROTOCOL)<EOL>

Pickle the whole collection to *filename*.

        If no extension is provided, ".collection" is appended.


tmp = cPickle.load(open(self._canonicalize(filename), '<STR_LIT:rb>'))<EOL>if append:<EOL><INDENT>self.extend(tmp)<EOL><DEDENT>else:<EOL><INDENT>self[:] = tmp[:]<EOL><DEDENT>del tmp<EOL>

Load collection from pickled file *filename*.

        *append* determines if the saved collection is added to the current one
        or if it replaces the current content.

        If no extension is provided, ".collection" is appended.


return self[:]<EOL>


path, ext = os.path.splitext(filename)<EOL>if not ext:<EOL><INDENT>ext = "<STR_LIT>"<EOL><DEDENT>return path + ext<EOL>

Use .collection as extension unless provided


def __getnewargs__(self, *args, **kwargs):

return (self.tolist(),)<EOL>

Provide proper initialization to make pickling with protocol 2 work


logger = logging.getLogger(logger_name)<EOL>logger.setLevel(logging.DEBUG)<EOL>logfile = logging.FileHandler(logfile)<EOL>logfile_formatter = logging.Formatter('<STR_LIT>')<EOL>logfile.setFormatter(logfile_formatter)<EOL>logger.addHandler(logfile)<EOL>console = logging.StreamHandler()<EOL>console.setLevel(logging.INFO)<EOL>formatter = logging.Formatter('<STR_LIT>')<EOL>console.setFormatter(formatter)<EOL>logger.addHandler(console)<EOL>return logger<EOL>

Create a top level logger.

    - The file logger logs everything (including DEBUG).
    - The console logger only logs INFO and above.

    Logging to a file and the console.

    See http://docs.python.org/library/logging.html?#logging-to-multiple-destinations

    The top level logger of the library is named 'gromacs'.  Note that
    we are configuring this logger with console output. If the root
    logger also does this then we will get two output lines to the
    console. We'll live with this because this is a simple
    convenience library...


for h in logger.handlers:<EOL><INDENT>logger.removeHandler(h)<EOL><DEDENT>

clean out handlers in the library top level logger

    (only important for reload/debug cycles...)


<EOL>git_refnames = "<STR_LIT>"<EOL>git_full = "<STR_LIT>"<EOL>git_date = "<STR_LIT>"<EOL>keywords = {"<STR_LIT>": git_refnames, "<STR_LIT>": git_full, "<STR_LIT:date>": git_date}<EOL>return keywords<EOL>

Get the keywords needed to look up the version information.


<EOL>cfg = VersioneerConfig()<EOL>cfg.VCS = "<STR_LIT>"<EOL>cfg.style = "<STR_LIT>"<EOL>cfg.tag_prefix = "<STR_LIT>"<EOL>cfg.parentdir_prefix = "<STR_LIT>"<EOL>cfg.versionfile_source = "<STR_LIT>"<EOL>cfg.verbose = False<EOL>return cfg<EOL>

Create, populate and return the VersioneerConfig() object.


def decorate(f):<EOL><INDENT>"""<STR_LIT>"""<EOL>if vcs not in HANDLERS:<EOL><INDENT>HANDLERS[vcs] = {}<EOL><DEDENT>HANDLERS[vcs][method] = f<EOL>return f<EOL><DEDENT>return decorate<EOL>

Decorator to mark a method as the handler for a particular VCS.


def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,<EOL>env=None):

assert isinstance(commands, list)<EOL>p = None<EOL>for c in commands:<EOL><INDENT>try:<EOL><INDENT>dispcmd = str([c] + args)<EOL>p = subprocess.Popen([c] + args, cwd=cwd, env=env,<EOL>stdout=subprocess.PIPE,<EOL>stderr=(subprocess.PIPE if hide_stderr<EOL>else None))<EOL>break<EOL><DEDENT>except EnvironmentError:<EOL><INDENT>e = sys.exc_info()[<NUM_LIT:1>]<EOL>if e.errno == errno.ENOENT:<EOL><INDENT>continue<EOL><DEDENT>if verbose:<EOL><INDENT>print("<STR_LIT>" % dispcmd)<EOL>print(e)<EOL><DEDENT>return None, None<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if verbose:<EOL><INDENT>print("<STR_LIT>" % (commands,))<EOL><DEDENT>return None, None<EOL><DEDENT>stdout = p.communicate()[<NUM_LIT:0>].strip()<EOL>if sys.version_info[<NUM_LIT:0>] >= <NUM_LIT:3>:<EOL><INDENT>stdout = stdout.decode()<EOL><DEDENT>if p.returncode != <NUM_LIT:0>:<EOL><INDENT>if verbose:<EOL><INDENT>print("<STR_LIT>" % dispcmd)<EOL>print("<STR_LIT>" % stdout)<EOL><DEDENT>return None, p.returncode<EOL><DEDENT>return stdout, p.returncode<EOL>


def versions_from_parentdir(parentdir_prefix, root, verbose):

rootdirs = []<EOL>for i in range(<NUM_LIT:3>):<EOL><INDENT>dirname = os.path.basename(root)<EOL>if dirname.startswith(parentdir_prefix):<EOL><INDENT>return {"<STR_LIT:version>": dirname[len(parentdir_prefix):],<EOL>"<STR_LIT>": None,<EOL>"<STR_LIT>": False, "<STR_LIT:error>": None, "<STR_LIT:date>": None}<EOL><DEDENT>else:<EOL><INDENT>rootdirs.append(root)<EOL>root = os.path.dirname(root)  <EOL><DEDENT><DEDENT>if verbose:<EOL><INDENT>print("<STR_LIT>" %<EOL>(str(rootdirs), parentdir_prefix))<EOL><DEDENT>raise NotThisMethod("<STR_LIT>")<EOL>

Try to determine the version from the parent directory name.

    Source tarballs conventionally unpack into a directory that includes both
    the project name and a version string. We will also support searching up
    two directory levels for an appropriately named parent directory


<EOL>keywords = {}<EOL>try:<EOL><INDENT>f = open(versionfile_abs, "<STR_LIT:r>")<EOL>for line in f.readlines():<EOL><INDENT>if line.strip().startswith("<STR_LIT>"):<EOL><INDENT>mo = re.search(r'<STR_LIT>', line)<EOL>if mo:<EOL><INDENT>keywords["<STR_LIT>"] = mo.group(<NUM_LIT:1>)<EOL><DEDENT><DEDENT>if line.strip().startswith("<STR_LIT>"):<EOL><INDENT>mo = re.search(r'<STR_LIT>', line)<EOL>if mo:<EOL><INDENT>keywords["<STR_LIT>"] = mo.group(<NUM_LIT:1>)<EOL><DEDENT><DEDENT>if line.strip().startswith("<STR_LIT>"):<EOL><INDENT>mo = re.search(r'<STR_LIT>', line)<EOL>if mo:<EOL><INDENT>keywords["<STR_LIT:date>"] = mo.group(<NUM_LIT:1>)<EOL><DEDENT><DEDENT><DEDENT>f.close()<EOL><DEDENT>except EnvironmentError:<EOL><INDENT>pass<EOL><DEDENT>return keywords<EOL>

Extract version information from the given file.


@register_vcs_handler("<STR_LIT>", "<STR_LIT>")<EOL>def git_versions_from_keywords(keywords, tag_prefix, verbose):

if not keywords:<EOL><INDENT>raise NotThisMethod("<STR_LIT>")<EOL><DEDENT>date = keywords.get("<STR_LIT:date>")<EOL>if date is not None:<EOL><INDENT>date = date.strip().replace("<STR_LIT:U+0020>", "<STR_LIT:T>", <NUM_LIT:1>).replace("<STR_LIT:U+0020>", "<STR_LIT>", <NUM_LIT:1>)<EOL><DEDENT>refnames = keywords["<STR_LIT>"].strip()<EOL>if refnames.startswith("<STR_LIT>"):<EOL><INDENT>if verbose:<EOL><INDENT>print("<STR_LIT>")<EOL><DEDENT>raise NotThisMethod("<STR_LIT>")<EOL><DEDENT>refs = set([r.strip() for r in refnames.strip("<STR_LIT>").split("<STR_LIT:U+002C>")])<EOL>TAG = "<STR_LIT>"<EOL>tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])<EOL>if not tags:<EOL><INDENT>tags = set([r for r in refs if re.search(r'<STR_LIT>', r)])<EOL>if verbose:<EOL><INDENT>print("<STR_LIT>" % "<STR_LIT:U+002C>".join(refs - tags))<EOL><DEDENT><DEDENT>if verbose:<EOL><INDENT>print("<STR_LIT>" % "<STR_LIT:U+002C>".join(sorted(tags)))<EOL><DEDENT>for ref in sorted(tags):<EOL><INDENT>if ref.startswith(tag_prefix):<EOL><INDENT>r = ref[len(tag_prefix):]<EOL>if verbose:<EOL><INDENT>print("<STR_LIT>" % r)<EOL><DEDENT>return {"<STR_LIT:version>": r,<EOL>"<STR_LIT>": keywords["<STR_LIT>"].strip(),<EOL>"<STR_LIT>": False, "<STR_LIT:error>": None,<EOL>"<STR_LIT:date>": date}<EOL><DEDENT><DEDENT>if verbose:<EOL><INDENT>print("<STR_LIT>")<EOL><DEDENT>return {"<STR_LIT:version>": "<STR_LIT>",<EOL>"<STR_LIT>": keywords["<STR_LIT>"].strip(),<EOL>"<STR_LIT>": False, "<STR_LIT:error>": "<STR_LIT>", "<STR_LIT:date>": None}<EOL>

Get version information from git keywords.


@register_vcs_handler("<STR_LIT>", "<STR_LIT>")<EOL>def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):

GITS = ["<STR_LIT>"]<EOL>if sys.platform == "<STR_LIT:win32>":<EOL><INDENT>GITS = ["<STR_LIT>", "<STR_LIT>"]<EOL><DEDENT>out, rc = run_command(GITS, ["<STR_LIT>", "<STR_LIT>"], cwd=root,<EOL>hide_stderr=True)<EOL>if rc != <NUM_LIT:0>:<EOL><INDENT>if verbose:<EOL><INDENT>print("<STR_LIT>" % root)<EOL><DEDENT>raise NotThisMethod("<STR_LIT>")<EOL><DEDENT>describe_out, rc = run_command(GITS, ["<STR_LIT>", "<STR_LIT>", "<STR_LIT>",<EOL>"<STR_LIT>", "<STR_LIT>",<EOL>"<STR_LIT>", "<STR_LIT>" % tag_prefix],<EOL>cwd=root)<EOL>if describe_out is None:<EOL><INDENT>raise NotThisMethod("<STR_LIT>")<EOL><DEDENT>describe_out = describe_out.strip()<EOL>full_out, rc = run_command(GITS, ["<STR_LIT>", "<STR_LIT>"], cwd=root)<EOL>if full_out is None:<EOL><INDENT>raise NotThisMethod("<STR_LIT>")<EOL><DEDENT>full_out = full_out.strip()<EOL>pieces = {}<EOL>pieces["<STR_LIT>"] = full_out<EOL>pieces["<STR_LIT>"] = full_out[:<NUM_LIT:7>]  <EOL>pieces["<STR_LIT:error>"] = None<EOL>git_describe = describe_out<EOL>dirty = git_describe.endswith("<STR_LIT>")<EOL>pieces["<STR_LIT>"] = dirty<EOL>if dirty:<EOL><INDENT>git_describe = git_describe[:git_describe.rindex("<STR_LIT>")]<EOL><DEDENT>if "<STR_LIT:->" in git_describe:<EOL><INDENT>mo = re.search(r'<STR_LIT>', git_describe)<EOL>if not mo:<EOL><INDENT>pieces["<STR_LIT:error>"] = ("<STR_LIT>"<EOL>% describe_out)<EOL>return pieces<EOL><DEDENT>full_tag = mo.group(<NUM_LIT:1>)<EOL>if not full_tag.startswith(tag_prefix):<EOL><INDENT>if verbose:<EOL><INDENT>fmt = "<STR_LIT>"<EOL>print(fmt % (full_tag, tag_prefix))<EOL><DEDENT>pieces["<STR_LIT:error>"] = ("<STR_LIT>"<EOL>% (full_tag, tag_prefix))<EOL>return pieces<EOL><DEDENT>pieces["<STR_LIT>"] = full_tag[len(tag_prefix):]<EOL>pieces["<STR_LIT>"] = int(mo.group(<NUM_LIT:2>))<EOL>pieces["<STR_LIT>"] = mo.group(<NUM_LIT:3>)<EOL><DEDENT>else:<EOL><INDENT>pieces["<STR_LIT>"] = None<EOL>count_out, rc = run_command(GITS, ["<STR_LIT>", "<STR_LIT>", "<STR_LIT>"],<EOL>cwd=root)<EOL>pieces["<STR_LIT>"] = int(count_out)  <EOL><DEDENT>date = run_command(GITS, ["<STR_LIT>", "<STR_LIT>", "<STR_LIT>", "<STR_LIT>"],<EOL>cwd=root)[<NUM_LIT:0>].strip()<EOL>pieces["<STR_LIT:date>"] = date.strip().replace("<STR_LIT:U+0020>", "<STR_LIT:T>", <NUM_LIT:1>).replace("<STR_LIT:U+0020>", "<STR_LIT>", <NUM_LIT:1>)<EOL>return pieces<EOL>

Get version from 'git describe' in the root of the source tree.

    This only gets called if the git-archive 'subst' keywords were *not*
    expanded, and _version.py hasn't already been rewritten with a short
    version string, meaning we're inside a checked out source tree.


if "<STR_LIT:+>" in pieces.get("<STR_LIT>", "<STR_LIT>"):<EOL><INDENT>return "<STR_LIT:.>"<EOL><DEDENT>return "<STR_LIT:+>"<EOL>

Return a + if we don't already have one, else return a .


if pieces["<STR_LIT>"]:<EOL><INDENT>rendered = pieces["<STR_LIT>"]<EOL>if pieces["<STR_LIT>"] or pieces["<STR_LIT>"]:<EOL><INDENT>rendered += plus_or_dot(pieces)<EOL>rendered += "<STR_LIT>" % (pieces["<STR_LIT>"], pieces["<STR_LIT>"])<EOL>if pieces["<STR_LIT>"]:<EOL><INDENT>rendered += "<STR_LIT>"<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>rendered = "<STR_LIT>" % (pieces["<STR_LIT>"],<EOL>pieces["<STR_LIT>"])<EOL>if pieces["<STR_LIT>"]:<EOL><INDENT>rendered += "<STR_LIT>"<EOL><DEDENT><DEDENT>return rendered<EOL>

Build up version string, with post-release "local version identifier".

    Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
    get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty

    Exceptions:
    1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]


if pieces["<STR_LIT>"]:<EOL><INDENT>rendered = pieces["<STR_LIT>"]<EOL>if pieces["<STR_LIT>"]:<EOL><INDENT>rendered += "<STR_LIT>" % pieces["<STR_LIT>"]<EOL><DEDENT><DEDENT>else:<EOL><INDENT>rendered = "<STR_LIT>" % pieces["<STR_LIT>"]<EOL><DEDENT>return rendered<EOL>

TAG[.post.devDISTANCE] -- No -dirty.

    Exceptions:
    1: no tags. 0.post.devDISTANCE


if pieces["<STR_LIT>"]:<EOL><INDENT>rendered = pieces["<STR_LIT>"]<EOL>if pieces["<STR_LIT>"] or pieces["<STR_LIT>"]:<EOL><INDENT>rendered += "<STR_LIT>" % pieces["<STR_LIT>"]<EOL>if pieces["<STR_LIT>"]:<EOL><INDENT>rendered += "<STR_LIT>"<EOL><DEDENT>rendered += plus_or_dot(pieces)<EOL>rendered += "<STR_LIT>" % pieces["<STR_LIT>"]<EOL><DEDENT><DEDENT>else:<EOL><INDENT>rendered = "<STR_LIT>" % pieces["<STR_LIT>"]<EOL>if pieces["<STR_LIT>"]:<EOL><INDENT>rendered += "<STR_LIT>"<EOL><DEDENT>rendered += "<STR_LIT>" % pieces["<STR_LIT>"]<EOL><DEDENT>return rendered<EOL>

TAG[.postDISTANCE[.dev0]+gHEX] .

    The ".dev0" means dirty. Note that .dev0 sorts backwards
    (a dirty tree will appear "older" than the corresponding clean one),
    but you shouldn't be releasing software with -dirty anyways.

    Exceptions:
    1: no tags. 0.postDISTANCE[.dev0]