<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def WithLimitedCallFrequency(min_time_between_calls):
 """Function call rate-limiting decorator. This decorator ensures that the wrapped function will be called at most once in min_time_between_calls time for the same set of arguments. For all excessive calls a previous cached return value will be returned. Suppose we use the decorator like this: @cache.WithLimitedCallFrequency(rdfvalue.Duration("30s")) def Foo(id):
 If Foo(42) is called and then Foo(42) is called again within 30 seconds, then the second call will simply return the cached return value of the first. If Foo(42) is called and then Foo(43) is called within 30 seconds, the wrapped function will be properly called in both cases, since these Foo calls have different arguments sets. If Foo(42) is called and takes a long time to finish, and another Foo(42) call is done in another thread, then the latter call will wait for the first one to finish and then return the cached result value. I.e. the wrapped function will be called just once, thus keeping the guarantee of at most 1 run in min_time_between_calls. NOTE 1: this function becomes a trivial pass-through and does no caching if module-level WITH_LIMITED_CALL_FREQUENCY_PASS_THROUGH variable is set to True. This is used in testing. NOTE 2: all decorated functions' arguments have to be hashable. Args: min_time_between_calls: An rdfvalue.Duration specifying the minimal time to pass between 2 consecutive function calls with same arguments. Returns: A Python function decorator. """


  def Decorated(f):
    """Actual decorator implementation."""

    lock = threading.RLock()
    prev_times = {}
    prev_results = {}
    result_locks = {}

    @functools.wraps(f)
    def Fn(*args, **kwargs):
      """Wrapper around the decorated function."""

      if WITH_LIMITED_CALL_FREQUENCY_PASS_THROUGH:
        # This effectively turns off the caching.
        min_time = rdfvalue.Duration(0)
      else:
        min_time = min_time_between_calls

      key = (args, tuple(sorted(kwargs.items())))
      now = rdfvalue.RDFDatetime.Now()

      with lock:
        for k, prev_time in list(prev_times.items()):
          if now - prev_time >= min_time:
            prev_times.pop(k)
            prev_results.pop(k, None)
            result_locks.pop(k, None)

        try:
          # We eliminated all the old entries, so if the key is present
          # in the cache, it means that the data is fresh enough to be used.
          prev_time = prev_times[key]
          return prev_results[key]
        except KeyError:
          prev_time = None
          should_call = True

        if not should_call:
          return prev_results[key]

        try:
          result_lock = result_locks[key]
        except KeyError:
          result_lock = threading.RLock()
          result_locks[key] = result_lock

      with result_lock:
        t = prev_times.get(key)

        if t == prev_time:
          result = f(*args, **kwargs)
          with lock:
            prev_times[key] = rdfvalue.RDFDatetime.Now()
            prev_results[key] = result

          return result
        else:
          return prev_results[key]

    return Fn

  return Decorated