def ZhangJohnson(tokens, index, history):
    """
    These features were taken from Zhang and Johnson (2003). They correspond
    to the combination B+D+E+F in their paper.

    Feature 'C' was not included, since
    CRFsuite cannot handle 2nd order CRFS (which can use the i-1 and (i-2)th
    labels) or features of the form label_(i-1) & tok_i.

    Feature 'G' (part-of-speech tags), feature 'H' (chunking tags) and
    features 'I' & 'J' (dictionaries and gazetteers specific to the CONLL 2003
    shared task) are not included.

    References
    ----------

    - Turian J, Rativ L, Bengio Y. Word representations: a simple and general
    method for semi-supervised learning. Proceedings of the 48th annual meeting
    of the association for computational linguistics. Association for
    Computational Linguistics, 2010.

    - Zhang, T. and Johnson D. A robust risk minimization based named entity
    recognition system. Proceedings of the seventh conference on natural
    language learning at HLT-NAACL 2003-Volume 4, Association for Computational
    Linguistics, 2003.

    """

    start_pad2 = ('[START2]', '[START2]','[START2]')
    start_pad1 = ('[START1]', '[START1]','[START1]')
    end_pad2 = ('[END2]', '[END2]','[END2]')
    end_pad1 = ('[END1]', '[END1]','[END1]')
    tokens = [start_pad2, start_pad1] + list(tokens) + [end_pad1, end_pad2]
    history = ['[START2]', '[START1]'] + history
    index += 2 # Shift index to accommodate padding in front of list.

    # Feature set 'B': Tokens in a window of 2
    word = tokens[index][0]
    prevword = tokens[index - 1][0]
    prev2word = tokens[index - 2][0]
    nextword = tokens[index + 1][0]
    next2word = tokens[index + 2][0]

    # Feature set 'D': Initial capitalization of tokens in a window of 2
    capitalized = word[0] == word.capitalize()[0]
    prevcapitalized = prevword[0] == prevword.capitalize()[0]
    prev2capitalized = prev2word[0] == prev2word.capitalize()[0]
    nextcapitalized = nextword[0] == nextword.capitalize()[0]
    next2capitalized = next2word[0] == next2word.capitalize()[0]

    # Feature set 'E': All capitalization, all digitals, or digitals containing
    # punctuation (for center word only).
    allcaps = word.isupper() #word == word.upper()
    all_digits = word.isdigit()
    all_letters = word.isalpha()
    # NOTE: Zhang and Johnson use say "digitals containing punctuations"; we
    # interpret this in the same way as Turian, Ratinov and Bengio (2010)
    # to mean "all non-letters"

    # Feature set 'F': Token prefix (lengths 3 & 4), and suffix (1 - 4)
    prefix3 = word[:3]
    prefix4 = word[:4]
    suffix1 = word[-1:]
    suffix2 = word[-2:]
    suffix3 = word[-3:]
    suffix4 = word[-4:]

    features = {
        'word': word,
        'prevword': prevword,
        'prev2word': prev2word,
        'nextword': nextword,
        'next2word': next2word,
        'capitalized': capitalized,
        'prevcapitalized': prevcapitalized,
        'prev2capitalized': prev2capitalized,
        'nextcapitalized': nextcapitalized,
        'next2capitalized': next2capitalized,
        'allcaps': allcaps,
        'all_digits': all_digits,
        'all_letters': all_letters,
        'prefix3': prefix3,
        'prefix4': prefix4,
        'suffix1': suffix1,
        'suffix2': suffix2,
        'suffix3': suffix3,
        'suffix4': suffix4,
                }

    return features