def ngrams_of(sequence, ngram_size, ngram_behaviour="exact"):
    """Produce n-grams of a sequence of tokens. The n-gram behaviour can either
    be "exact", meaning that only n-grams of exactly size n are produced,
    or "subgrams" meaning that all n-grams of size less than or equal to n are
    produced.

    Parameters
    ----------
    sequence: Iterable
        The sequence of tokens to produce n-grams of.

    ngram_size: int
        The size of n-grams to use.

    ngram_behaviour: string (optional, default="exact")
        The n-gram behaviour. Should be one of:
            * "exact"
            * "subgrams"

    Returns
    -------
    ngrams: list
        A list of the n-grams of the sequence.
    """
    result = []
    for i in range(len(sequence)):
        if ngram_behaviour == "exact":
            if i + ngram_size <= len(sequence):
                result.append(sequence[i : i + ngram_size])
        elif ngram_behaviour == "subgrams":
            for j in range(1, ngram_size + 1):
                if i + j <= len(sequence):
                    result.append(sequence[i : i + j])
        else:
            raise ValueError("Unrecognized ngram_behaviour!")
    return result