def char2features(sentence, i):
    '''
    Returns features of char at position `i` in given sentence
    When it possible, result features list also includes features for 2 characters
    ahead and behind current position (like bigrams, or something like it)
    Currently, used features is:
    1. lower-cased value of character
    2. result of calling `character.isupper()` method
    3. result of calling `character.isnumeric()` method
    '''
    char = sentence[i]
    length = len(sentence)

    features = [
        'lower={0}'.format(char.lower()),
        'isupper={0}'.format(char.isupper()),
        'isnumeric={0}'.format(char.isnumeric()),
    ]

    if i == 0:
        features.extend(['BOS'])

    if i > 0:
        char = sentence[i - 1]
        features.extend([
            '-1:lower={0}'.format(char.lower()),
            '-1:isupper={0}'.format(char.isupper()),
            '-1:isnumeric={0}'.format(char.isnumeric()),
        ])

    if i > 1:
        char = sentence[i - 2]
        features.extend([
            '-2:lower={0}'.format(char.lower()),
            '-2:isupper={0}'.format(char.isupper()),
            '-2:isnumeric={0}'.format(char.isnumeric()),
        ])

    if i < length - 1:
        char = sentence[i + 1]
        features.extend([
            '+1:lower={0}'.format(char.lower()),
            '+1:isupper={0}'.format(char.isupper()),
            '+1:isnumeric={0}'.format(char.isnumeric()),
        ])

    if i < length - 2:
        char = sentence[i + 2]
        features.extend([
            '+2:lower={0}'.format(char.lower()),
            '+2:isupper={0}'.format(char.isupper()),
            '+2:isnumeric={0}'.format(char.isnumeric()),
        ])

    if i == length - 1:
        features.extend(['EOS'])

    return features