def METHOD_NAME(
    value: IntegerLike,
    flags: Iterable[Tuple[str, int]],
    bit_numbers: bool = True,
) -> str:
    """
    Get a human-readable representation of a bitmask of flags.
    By default, flags are specified by their bit number:
    >>> decode_flags(2, [("BOLD", 0), ("ITALIC", 1), ("UNDERLINE", 2)])
    'ITALIC'
    They can also be specified by their value:
    >>> decode_flags(2, [("BOLD", 1), ("ITALIC", 2), ("UNDERLINE", 4)],
    ...              bit_numbers=False)
    'ITALIC'
    Multiple flags are combined with "|":
    >>> decode_flags(5, [("BOLD", 0), ("ITALIC", 1), ("UNDERLINE", 2)])
    'BOLD|UNDERLINE'
    If there are multiple names for the same bit, they are all included:
    >>> decode_flags(2, [("SMALL", 0), ("BIG", 1), ("LARGE", 1)])
    'BIG|LARGE'
    If there are any unknown bits, their raw value is included:
    >>> decode_flags(27, [("BOLD", 0), ("ITALIC", 1), ("UNDERLINE", 2)])
    'BOLD|ITALIC|0x18'
    Zero is returned verbatim:
    >>> decode_flags(0, [("BOLD", 0), ("ITALIC", 1), ("UNDERLINE", 2)])
    '0'
    :param value: Bitmask to decode.
    :param flags: List of flag names and their bit numbers or values.
    :param bit_numbers: Whether *flags* specifies the bit numbers (where 0 is
        the least significant bit) or values of the flags.
    """
    value = value.__index__()
    if value == 0:
        return "0"
    parts = []
    mask = 0
    for name, flag in flags:
        if bit_numbers:
            flag = 1 << flag
        if value & flag:
            parts.append(name)
            mask |= flag
    if value & ~mask:
        parts.append(hex(value & ~mask))
    return "|".join(parts)