<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def retryable(a_func, retry_options, **kwargs):
 """Creates a function equivalent to a_func, but that retries on certain exceptions. Args: a_func (callable):
 A callable. retry_options (RetryOptions):
 Configures the exceptions upon which the callable should retry, and the parameters to the exponential backoff retry algorithm. kwargs: Addtional arguments passed through to the callable. Returns: Callable: A function that will retry on exception. """

    delay_mult = retry_options.backoff_settings.retry_delay_multiplier
    max_delay_millis = retry_options.backoff_settings.max_retry_delay_millis
    has_timeout_settings = _has_timeout_settings(retry_options.backoff_settings)

    if has_timeout_settings:
        timeout_mult = retry_options.backoff_settings.rpc_timeout_multiplier
        max_timeout = (retry_options.backoff_settings.max_rpc_timeout_millis /
                       _MILLIS_PER_SECOND)
        total_timeout = (retry_options.backoff_settings.total_timeout_millis /
                         _MILLIS_PER_SECOND)

    def inner(*args):
        """Equivalent to ``a_func``, but retries upon transient failure.

        Retrying is done through an exponential backoff algorithm configured
        by the options in ``retry``.
        """
        delay = retry_options.backoff_settings.initial_retry_delay_millis
        exc = errors.RetryError('Retry total timeout exceeded before any'
                                'response was received')
        if has_timeout_settings:
            timeout = (
                retry_options.backoff_settings.initial_rpc_timeout_millis /
                _MILLIS_PER_SECOND)

            now = time.time()
            deadline = now + total_timeout
        else:
            timeout = None
            deadline = None

        while deadline is None or now < deadline:
            try:
                to_call = add_timeout_arg(a_func, timeout, **kwargs)
                return to_call(*args)
            except Exception as exception:  # pylint: disable=broad-except
                code = config.exc_to_code(exception)
                if code not in retry_options.retry_codes:
                    raise errors.RetryError(
                        'Exception occurred in retry method that was not'
                        ' classified as transient', exception)

                exc = errors.RetryError(
                    'Retry total timeout exceeded with exception', exception)

                # Sleep a random number which will, on average, equal the
                # expected delay.
                to_sleep = random.uniform(0, delay * 2)
                time.sleep(to_sleep / _MILLIS_PER_SECOND)
                delay = min(delay * delay_mult, max_delay_millis)

                if has_timeout_settings:
                    now = time.time()
                    timeout = min(
                        timeout * timeout_mult, max_timeout, deadline - now)

        raise exc

    return inner