<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def about_time(fn=None, it=None):
 """Measures the execution time of a block of code, and even counts iterations and the throughput of them, always with a beautiful "human" representation. There's three modes of operation: context manager, callable handler and iterator metrics. 1. Use it like a context manager: The actual duration in seconds is available in: 2. You can also use it like a callable handler: Use the field `result` to get the outcome of the function. Or you mix and match both: 3. And you can count and, since we have duration, also measure the throughput of an iterator block, specially useful in generators, which do not have length, but you can use with any iterables: """


    # has to be here to be mockable.
    if sys.version_info >= (3, 3):
        timer = time.perf_counter
    else:  # pragma: no cover
        timer = time.time

    @contextmanager
    def context():
        timings[0] = timer()
        yield handle
        timings[1] = timer()

    timings = [0.0, 0.0]
    handle = Handle(timings)

    if it is None:
        # use as context manager.
        if fn is None:
            return context()

        # use as callable handler.
        with context():
            result = fn()
        return HandleResult(timings, result)

    # use as counter/throughput iterator.
    if fn is None or not callable(fn):  # handles inversion of parameters.
        raise UserWarning('use as about_time(callback, iterable) in counter/throughput mode.')

    def counter():
        i = -1
        with context():
            for i, elem in enumerate(it):
                yield elem
        fn(HandleStats(timings, i + 1))

    return counter()