r"""
    Return a hexdump-dump of a string as a generator of lines.  Unless you have
    massive amounts of data you probably want to use :meth:`hexdump`.

    Arguments:
        logger(FastLogger): Logger object
        fd(file): File object to dump.  Use :meth:`StringIO.StringIO` or :meth:`hexdump` to dump a string.
        width(int): The number of characters per line
        skip(bool): Set to True, if repeated lines should be replaced by a "*"
        hexii(bool): Set to True, if a hexii-dump should be returned instead of a hexdump.
        begin(int):  Offset of the first byte to print in the left column
        highlight(iterable): Byte values to highlight.

    Returns:
        A generator producing the hexdump-dump one line at a time.

def hexdump_iter(logger, fd, width=16, skip=True, hexii=False, begin=0, highlight=None):
    r"""
    Return a hexdump-dump of a string as a generator of lines.  Unless you have
    massive amounts of data you probably want to use :meth:`hexdump`.

    Arguments:
        logger(FastLogger): Logger object
        fd(file): File object to dump.  Use :meth:`StringIO.StringIO` or :meth:`hexdump` to dump a string.
        width(int): The number of characters per line
        skip(bool): Set to True, if repeated lines should be replaced by a "*"
        hexii(bool): Set to True, if a hexii-dump should be returned instead of a hexdump.
        begin(int):  Offset of the first byte to print in the left column
        highlight(iterable): Byte values to highlight.

    Returns:
        A generator producing the hexdump-dump one line at a time.
    """
    style     = logger.style.hexdump.copy()
    highlight = highlight or []

    for b in highlight:
        if isinstance(b, str):
            b = ord(b)
        style['%02x' % b] = style['highlight']

    _style = style

    skipping    = False
    lines       = []
    last_unique = ''
    byte_width  = len('00 ')
    column_sep  = '  '
    line_fmt    = '%%(offset)08x  %%(hexbytes)-%is │%%(printable)s│' % (len(column_sep)+(width*byte_width))
    spacer      = ' '
    marker      = (style.get('marker') or (lambda s:s))('│')

    if hexii:
        column_sep = ''
        line_fmt   = '%%(offset)08x  %%(hexbytes)-%is│' % (len(column_sep)+(width*byte_width))
    else:
        def style_byte(b):
            hbyte = '%02x' % ord(b)
            abyte = b if isprint(b) else '·'
            if hbyte in style:
                st = style[hbyte]
            elif isprint(b):
                st = style.get('printable')
            else:
                st = style.get('nonprintable')
            if st:
                hbyte = st(hbyte)
                abyte = st(abyte)
            return hbyte, abyte
        cache = [style_byte(chr(b)) for b in range(256)]

    numb = 0
    while True:
        offset = begin + numb

        # If a tube is passed in as fd, it will raise EOFError when it runs
        # out of data, unlike a file or StringIO object, which return an empty
        # string.
        try:
            chunk = fd.read(width)
        except EOFError:
            chunk = ''

        # We have run out of data, exit the loop
        if chunk == '':
            break

        # Advance the cursor by the number of bytes we actually read
        numb += len(chunk)

        # If this chunk is the same as the last unique chunk,
        # use a '*' instead.
        if skip and last_unique:
            same_as_last_line = (last_unique == chunk)
            lines_are_sequential = False
            last_unique = chunk

            if same_as_last_line or lines_are_sequential:

                # If we have not already printed a "*", do so
                if not skipping:
                    yield '*'
                    skipping = True

                # Move on to the next chunk
                continue

        # Chunk is unique, no longer skipping
        skipping = False
        last_unique = chunk

        # Generate contents for line
        hexbytes = ''
        printable = ''
        for i, b in enumerate(chunk):
            if not hexii:
                hbyte, abyte = cache[ord(b)]
            else:
                hbyte, abyte = _hexiichar(b), ''

            if i % 4 == 3 and i < width - 1:
                hbyte += spacer
                abyte += marker

            hexbytes += hbyte + ' '
            printable += abyte

        if i + 1 < width:
            delta = width - i - 1

            # How many hex-bytes would we have printed?
            count = byte_width * delta

            # How many dividers do we need to fill out the line?
            dividers_per_line = (width // 4) - (1 if width % 4 == 0 else 0)
            dividers_printed = (i // 4) + (1 if i % 4 == 3 else 0)
            count += dividers_per_line - dividers_printed

            hexbytes += ' ' * count

        # Python2 -> 3 wew
        if isinstance(line_fmt, six.binary_type):
            line_fmt = line_fmt.decode('utf-8')
        if isinstance(offset, six.binary_type):
            offset = printable.decode('utf-8')
        
        line = line_fmt % {'offset': offset, 'hexbytes': hexbytes, 'printable': printable}
        yield line

    line = "%08x" % (begin + numb)
    yield line