def props(b: bytes, i: int):
    '''
    ``props`` is a little-endian 64 bit value that represents informal properties about the resolver. It is a logical OR
    combination of the following values:

    - ``1``: the server supports DNSSEC
    - ``2``: the server doesn’t keep logs
    - ``4``: the server doesn’t intentionally block domains

    For example, a server that supports DNSSEC, stores logs, but doesn’t block anything on its own should set ``props``
    as the following 8 bytes sequence: ``[ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]``.
    '''
    props = b[i]
    dnssec = not not ((props >> 0) & 1)
    nolog = not not ((props >> 1) & 1)
    nofilter = not not ((props >> 2) & 1)
    i = i + 8
    return i, dnssec, nolog, nofilter


def LP(b: bytes, i: int):
    '''
    ``a || b`` is the concatenation of ``a`` and ``b``

    ``len(x)`` is a single byte representation of the length of ``x``, in bytes. Strings don’t have to be zero-terminated
    and do not require invidual encoding.

    ``LP(x)`` is ``len(x) || x``, i.e ``x`` prefixed by its length.
    '''
    x_len = b[i]
    i = i + 1
    x = b[i:i + x_len]
    i = i + x_len
    return i, x


def LP_decode(b: bytes, i: int, encoding='utf-8'):
    i, x = LP(b, i)
    return i, x.decode(encoding)


def LP_pk(b: bytes, i: int):
    i, x = LP(b, i)
    if len(x) != 32:
        raise ValueError("LP(pk)")
    hpk = x.hex().upper()
    hpks = []
    for j in range(0, 16):
        hpks.append(hpk[j * 4: j * 4 + 4])
    pk = ":".join(hpks)
    return i, pk


def VLP(b: bytes, i: int):
    '''
    ``a | b`` is the result of the logical ``OR`` operation between ``a`` and ``b``.

    ``vlen(x)`` is equal to ``len(x)`` if ``x`` is the last element of a set, and ``0x80 | len(x)`` if there are more
    elements in the set.

    ``VLP(x1, x2, ...xn)`` encodes a set, as ``vlen(x1) || x1 || vlen(x2) || x2 ... || vlen(xn) || xn``.
    Since ``vlen(xn) == len(xn)`` (length of the last element doesn’t have the high bit set), for a set with a single
    element, we have ``VLP(x) == LP(x)``.
    '''
    xx = []
    last_element = False
    while True:
        if b[i] & 0x80 == 0:
            last_element = True
            x_len = b[i]
        else:
            x_len = b[i] ^ 0x80
        i = i + 1
        if x_len > 0:
            x = b[i:i + x_len]
            xx.append(x)
            i = i + x_len
        if last_element:
            return i, xx


def VLP_hashs(b: bytes, i: int):
    i, xx = VLP(b, i)
    hashs = list(map(lambda x: x.hex(), xx))
    return i, hashs


def VLP_bootstrap_ipi(b: bytes, i: int):
    i, xx = VLP(b, i)
    bootstrap_ipi = list(map(lambda x: x.decode("utf-8"), xx))
    return i, bootstrap_ipi