func DelayWithRetryAfter(resp *http.Response, cancel <-chan struct{}) bool {
	if resp == nil {
		return false
	}
	var dur time.Duration
	ra := resp.Header.Get("Retry-After")
	if retryAfter, _ := strconv.Atoi(ra); retryAfter > 0 {
		dur = time.Duration(retryAfter) * time.Second
	} else if t, err := time.Parse(time.RFC1123, ra); err == nil {
		dur = t.Sub(time.Now())
	}
	if dur > 0 {
		select {
		case <-time.After(dur):
			return true
		case <-cancel:
			return false
		}
	}
	return false
}
DelayWithRetryAfter invokes time.After for the duration specified in the "Retry-After" header.
The value of Retry-After can be either the number of seconds or a date in RFC1123 format.
The function returns true after successfully waiting for the specified duration.  If there is
no Retry-After header or the wait is cancelled the return value is false.
package autorest
import (
	"context"
	"crypto/tls"
	"fmt"
	"log"
	"math"
	"net/http"
	"net/http/cookiejar"
	"strconv"
	"sync"
	"time"
	"github.com/Azure/go-autorest/tracing"
)
const defaultSendersCount = 3
type defaultSender struct {
	sender Sender
	init   *sync.Once
}
var defaultSenders [defaultSendersCount]defaultSender
func init() {
	for i := 0; i < defaultSendersCount; i++ {
		defaultSenders[i].init = &sync.Once{}
	}
}
type ctxSendDecorators struct{}
func WithSendDecorators(ctx context.Context, sendDecorator []SendDecorator) context.Context {
	if len(sendDecorator) == 0 {
		return ctx
	}
	return context.WithValue(ctx, ctxSendDecorators{}, sendDecorator)
}
func GetSendDecorators(ctx context.Context, defaultSendDecorators ...SendDecorator) []SendDecorator {
	inCtx := ctx.Value(ctxSendDecorators{})
	if sd, ok := inCtx.([]SendDecorator); ok {
		return sd
	}
	return defaultSendDecorators
}
type Sender interface {
	Do(*http.Request) (*http.Response, error)
}
type SenderFunc func(*http.Request) (*http.Response, error)
func (sf SenderFunc) Do(r *http.Request) (*http.Response, error) {
	return sf(r)
}
type SendDecorator func(Sender) Sender
func CreateSender(decorators ...SendDecorator) Sender {
	return DecorateSender(sender(tls.RenegotiateNever), decorators...)
}
func DecorateSender(s Sender, decorators ...SendDecorator) Sender {
	for _, decorate := range decorators {
		s = decorate(s)
	}
	return s
}
func Send(r *http.Request, decorators ...SendDecorator) (*http.Response, error) {
	return SendWithSender(sender(tls.RenegotiateNever), r, decorators...)
}
func SendWithSender(s Sender, r *http.Request, decorators ...SendDecorator) (*http.Response, error) {
	return DecorateSender(s, decorators...).Do(r)
}
func sender(renengotiation tls.RenegotiationSupport) Sender {
	defaultSenders[renengotiation].init.Do(func() {
		defaultTransport := http.DefaultTransport.(*http.Transport)
		transport := &http.Transport{
			Proxy:                 defaultTransport.Proxy,
			DialContext:           defaultTransport.DialContext,
			MaxIdleConns:          defaultTransport.MaxIdleConns,
			IdleConnTimeout:       defaultTransport.IdleConnTimeout,
			TLSHandshakeTimeout:   defaultTransport.TLSHandshakeTimeout,
			ExpectContinueTimeout: defaultTransport.ExpectContinueTimeout,
			TLSClientConfig: &tls.Config{
				MinVersion:    tls.VersionTLS12,
				Renegotiation: renengotiation,
			},
		}
		var roundTripper http.RoundTripper = transport
		if tracing.IsEnabled() {
			roundTripper = tracing.NewTransport(transport)
		}
		j, _ := cookiejar.New(nil)
		defaultSenders[renengotiation].sender = &http.Client{Jar: j, Transport: roundTripper}
	})
	return defaultSenders[renengotiation].sender
}
func AfterDelay(d time.Duration) SendDecorator {
	return func(s Sender) Sender {
		return SenderFunc(func(r *http.Request) (*http.Response, error) {
			if !DelayForBackoff(d, 0, r.Context().Done()) {
				return nil, fmt.Errorf("autorest: AfterDelay canceled before full delay")
			}
			return s.Do(r)
		})
	}
}
func AsIs() SendDecorator {
	return func(s Sender) Sender {
		return SenderFunc(func(r *http.Request) (*http.Response, error) {
			return s.Do(r)
		})
	}
}
func DoCloseIfError() SendDecorator {
	return func(s Sender) Sender {
		return SenderFunc(func(r *http.Request) (*http.Response, error) {
			resp, err := s.Do(r)
			if err != nil {
				Respond(resp, ByDiscardingBody(), ByClosing())
			}
			return resp, err
		})
	}
}
func DoErrorIfStatusCode(codes ...int) SendDecorator {
	return func(s Sender) Sender {
		return SenderFunc(func(r *http.Request) (*http.Response, error) {
			resp, err := s.Do(r)
			if err == nil && ResponseHasStatusCode(resp, codes...) {
				err = NewErrorWithResponse("autorest", "DoErrorIfStatusCode", resp, "%v %v failed with %s",
					resp.Request.Method,
					resp.Request.URL,
					resp.Status)
			}
			return resp, err
		})
	}
}
func DoErrorUnlessStatusCode(codes ...int) SendDecorator {
	return func(s Sender) Sender {
		return SenderFunc(func(r *http.Request) (*http.Response, error) {
			resp, err := s.Do(r)
			if err == nil && !ResponseHasStatusCode(resp, codes...) {
				err = NewErrorWithResponse("autorest", "DoErrorUnlessStatusCode", resp, "%v %v failed with %s",
					resp.Request.Method,
					resp.Request.URL,
					resp.Status)
			}
			return resp, err
		})
	}
}
func DoPollForStatusCodes(duration time.Duration, delay time.Duration, codes ...int) SendDecorator {
	return func(s Sender) Sender {
		return SenderFunc(func(r *http.Request) (resp *http.Response, err error) {
			resp, err = s.Do(r)
			if err == nil && ResponseHasStatusCode(resp, codes...) {
				r, err = NewPollingRequestWithContext(r.Context(), resp)
				for err == nil && ResponseHasStatusCode(resp, codes...) {
					Respond(resp,
						ByDiscardingBody(),
						ByClosing())
					resp, err = SendWithSender(s, r,
						AfterDelay(GetRetryAfter(resp, delay)))
				}
			}
			return resp, err
		})
	}
}
func DoRetryForAttempts(attempts int, backoff time.Duration) SendDecorator {
	return func(s Sender) Sender {
		return SenderFunc(func(r *http.Request) (resp *http.Response, err error) {
			rr := NewRetriableRequest(r)
			for attempt := 0; attempt < attempts; attempt++ {
				err = rr.Prepare()
				if err != nil {
					return resp, err
				}
				DrainResponseBody(resp)
				resp, err = s.Do(rr.Request())
				if err == nil {
					return resp, err
				}
				if !DelayForBackoff(backoff, attempt, r.Context().Done()) {
					return nil, r.Context().Err()
				}
			}
			return resp, err
		})
	}
}
var Count429AsRetry = true
var Max429Delay time.Duration
func DoRetryForStatusCodes(attempts int, backoff time.Duration, codes ...int) SendDecorator {
	return func(s Sender) Sender {
		return SenderFunc(func(r *http.Request) (*http.Response, error) {
			return doRetryForStatusCodesImpl(s, r, Count429AsRetry, attempts, backoff, 0, codes...)
		})
	}
}
func DoRetryForStatusCodesWithCap(attempts int, backoff, cap time.Duration, codes ...int) SendDecorator {
	return func(s Sender) Sender {
		return SenderFunc(func(r *http.Request) (*http.Response, error) {
			return doRetryForStatusCodesImpl(s, r, Count429AsRetry, attempts, backoff, cap, codes...)
		})
	}
}
func doRetryForStatusCodesImpl(s Sender, r *http.Request, count429 bool, attempts int, backoff, cap time.Duration, codes ...int) (resp *http.Response, err error) {
	rr := NewRetriableRequest(r)
	for attempt, delayCount := 0, 0; attempt < attempts+1; {
		err = rr.Prepare()
		if err != nil {
			return
		}
		DrainResponseBody(resp)
		resp, err = s.Do(rr.Request())
		if err == nil && !ResponseHasStatusCode(resp, codes...) || IsTokenRefreshError(err) {
			return resp, err
		}
		delayed := DelayWithRetryAfter(resp, r.Context().Done())
		if resp != nil && resp.StatusCode == http.StatusTooManyRequests {
			cap = Max429Delay
		}
		if !delayed && !DelayForBackoffWithCap(backoff, cap, delayCount, r.Context().Done()) {
			return resp, r.Context().Err()
		}
		if count429 || (resp == nil || resp.StatusCode != http.StatusTooManyRequests) {
			attempt++
		}
		delayCount++
	}
	return resp, err
}