pun not intended

        # TODO: record iteration times for analysis
        # TODO Incorporate this better
        # FIXME; pad_stdout into subfunctions

        import dis
        dis.dis(ut.ProgressIter.iter_rate)

def iter_rate(self):
        """
        pun not intended

        # TODO: record iteration times for analysis
        # TODO Incorporate this better
        # FIXME; pad_stdout into subfunctions

        import dis
        dis.dis(ut.ProgressIter.iter_rate)
        """
        #class IterState(object):
        #    def __init__(state):
        #        state.freq = 1
        #        state.freq = 1
        #        pass
        adjust = self.autoadjust
        self._cursor_at_newline = not self.backspace
        # SETUP VARIABLES
        # HACK: reaquire logging print funcs in case they have changed
        if self.stream is None:
            self.write = util_logging._utool_write()
            self.flush = util_logging._utool_flush()
        else:
            self.write = lambda msg: self.stream.write(msg)  # NOQA
            self.flush = lambda: self.stream.flush()  # NOQA

        length        = self.length * self.parent_length  # hack
        freq          = self.freq
        self.count    = 0
        between_count = 0
        last_count    = 0

        # how long iterations should be before a flush
        # (used for freq adjustment)
        time_thresh = (self._get_timethresh_heuristics()
                       if self.time_thresh is None else
                       self.time_thresh)
        time_thresh_growth = self.time_thresh_growth
        if time_thresh_growth > 1:
            # time_thresh_growth is specified for very long processes
            # print out the starting timestamp in that case
            timestamp = time.strftime('%Y-%m-%d %H:%M:%S') + ' ' + time.tzname[0]
            print('Start progress lbl= %s at %s' % (self.lbl, timestamp,))
        #time_thresh = 0.5
        max_between_time = -1.0
        max_between_count = -1.0  # why is this different? # because frequency varies

        # TODO: should be kept as a statistic that uses the max time from a
        # list of iterations divided by the size of that list that will account
        # for buffering issues
        iters_per_second = 0
        self.iters_per_second = float('nan')
        self.est_seconds_left = 0
        self.total_seconds = 0

        # Write initial message
        #force_newlines = not self.backspace
        start_msg_fmt = ''.join(self.build_msg_fmtstr_head_cols(length, self.lbl))
        self.msg_fmtstr = self.build_msg_fmtstr2(self.lbl, length,
                                                 self.invert_rate,
                                                 self.backspace)

        try:
            util_logging._utool_flush()()
        except IOError as ex:
            # There is some weird error when doing progress in IPython notebook
            if util_arg.VERBOSE:
                print('IOError flushing %s' % (ex,))
        if not self.prehack:
            if self.backspace:
                self.display_message()
            elif self.verbose:
                start_msg = start_msg_fmt.format(count=self.parent_offset)
                util_logging._utool_write()(start_msg + '\n')

            self._cursor_at_newline = not self.backspace

            try:
                util_logging._utool_flush()()
            except IOError as ex:
                # There is some weird error when doing progress in IPython notebook
                if util_arg.VERBOSE:
                    print('IOError flushing %s' % (ex,))
        else:
            self._cursor_at_newline = True

        if self.prog_hook is not None:
            self.prog_hook(self.count, length)

        # TODO: on windows is time.clock better?
        # http://exnumerus.blogspot.com/2011/02/how-to-quickly-plot-multiple-line.html
        start_time    = default_timer()
        last_time     = start_time

        start = 1 + self.parent_offset

        if self.freq_est_strat == 'between':
            FREQ_EST = 0
        elif self.freq_est_strat == 'absolute':
            FREQ_EST = 1
        else:
            FREQ_EST = 1

        USE_RECORD = True

        # use last 64 times to compute a more stable average rate
        measure_between_time = collections.deque([], maxlen=self.est_window)

        # Wrap the for loop with a generator
        for self.count, item in enumerate(self.iterable, start=start):
            if self.prehack:
                # hack to print before yeilding
                # so much for efficiency
                self.set_extra((self.lbl + '=' + self.prehack) % item)
                self.display_message()
                self.ensure_newline()

            # GENERATE
            yield item

            if self.prehack or (self.count) % freq == 0:
                now_time          = default_timer()
                between_time      = (now_time - last_time)
                between_count     = self.count - last_count
                total_seconds     = (now_time - start_time)
                self.total_seconds = total_seconds
                if FREQ_EST == 0:
                    if USE_RECORD:
                        measure_between_time.append(between_count / (float(between_time) + 1E-9))
                        iters_per_second = sum(measure_between_time) / len(measure_between_time)
                    else:
                        iters_per_second = between_count / (float(between_time) + 1E-9)
                elif FREQ_EST == 1:
                    iters_per_second = (now_time - start_time) / self.count

                self.iters_per_second = iters_per_second
                # If the future is known
                if length is None:
                    est_seconds_left = -1
                else:
                    iters_left = length - self.count
                    est_seconds_left = iters_left / (iters_per_second + 1E-9)
                self.est_seconds_left = est_seconds_left

                # /future
                last_count        = self.count
                last_time         = now_time
                # ADJUST FREQ IF NEEDED
                # Adjust frequency if printing too quickly
                # so progress doesnt slow down actual function
                # TODO: better adjust algorithm
                time_thresh *= time_thresh_growth
                if adjust and (between_time < time_thresh or between_time > time_thresh * 2.0):
                    max_between_time = max(max(max_between_time, between_time),
                                           1E-9)
                    max_between_count = max(max_between_count, between_count)
                    # If progress was uniform and all time estimates were
                    # perfect this would be the new freq to achieve time_thresh
                    new_freq = max(int(time_thresh * max_between_count /
                                       max_between_time), 1)
                    if DEBUG_FREQ_ADJUST:
                        print('\n+---')
                        print('[prog] between_count = %r' % between_count)
                        print('[prog] between_time = %.8r' % between_time)
                        print('[prog] time_thresh = %r' % time_thresh)
                        print('[prog] max_between_count = %r' % max_between_count)
                        print('[prog] max_between_time = %.8r' % max_between_time)
                        print('[prog] Adusting frequency from: %r' % freq)
                        print('[prog] Adusting frequency to: %r' % new_freq)
                        print('L___')
                    # But things are not perfect. So, don't make drastic changes
                    max_freq_change_up = max(256, freq * 2)
                    max_freq_change_down = freq // 2
                    if (new_freq - freq) > max_freq_change_up:
                        freq += max_freq_change_up
                    elif (freq - new_freq) > max_freq_change_down:
                        freq -= max_freq_change_down
                    else:
                        freq = new_freq

                if not self.prehack:
                    self.display_message()

                # DO PROGRESS INFO
                if self.prog_hook is not None:
                    # From the point of view of the progress iter, we are about
                    # to enter the body of a for loop. (But we may have
                    # executed the body implicitly in the yeild....  so it is
                    # ambiguous. In the second case 0 will be executed twice.
                    self.prog_hook(self.count, length)

        if self.prehack:
            self.set_extra('')

        # --- end of main loop
        # cleanup
        if (self.count) % freq != 0:
            # If the final line of progress was not written in the loop, write
            # it here
            self.est_seconds_left = 0
            self.total_seconds = (default_timer() - start_time)
            self.display_message()
            if self.prog_hook is not None:
                # From the point of view of the progress iter, we are about to
                # enter the body of a for loop. (But we may have executed the
                # body implicitly in the yeild....  so it is ambiguous. In the
                # second case 0 will be executed twice.
                self.prog_hook(self.count, length)

        self.ensure_newline()