code: func (dl *downloader) rateLimit(ctx context.Context, f func() error) error {
  	const (
  		msgRateLimitExceeded          = "Rate Limit Exceeded"
  		msgUserRateLimitExceeded      = "User Rate Limit Exceeded"
  		msgUserRateLimitExceededShort = "userRateLimitExceeded"
  	)
  
  	// Ensure a 1 minute try limit.
  	ctx, cancel := context.WithTimeout(ctx, time.Minute)
  	defer cancel()
  	for {
  		if err := dl.rate.Wait(ctx); err != nil {
  			log.Printf("gphotos: rate limit failure: %v", err)
  			return err
  		}
  		err := f()
  		if err == nil {
  			return nil
  		}
  		ge, ok := err.(*googleapi.Error)
  		if !ok || ge.Code != 403 {
  			return err
  		}
  		if ge.Message == "" {
  			var ok bool
  			for _, e := range ge.Errors {
  				if ok = e.Reason == msgUserRateLimitExceededShort; ok {
  					break
  				}
  			}
  			// For some cases, googleapi does not parse the returned JSON
  			// properly, so we have to fall back to check the original text.
  			//
  			// Usually this is a "User Rate Limit Exceeded", but that's
  			// also a "Rate Limit Exceeded", and we're interested just in the
  			// fact, not the cause.
  			if !ok && !strings.Contains(ge.Body, msgRateLimitExceeded) {
  				return err
  			}
  		}
  		// Some arbitrary sleep.
  		log.Printf("gphotos: sleeping for 5s after 403 error, presumably due to a rate limit")
  		time.Sleep(5 * time.Second)
  		log.Printf("gphotos: retrying after sleep...")
  	}
  }
docs: // rateLimit calls f obeying the global Rate limit.
  // On "Rate Limit Exceeded" error, it sleeps and tries later.