func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Response, error) {
	req = withContext(ctx, req)
	rateLimitCategory := category(req.URL.Path)
	if err := c.checkRateLimitBeforeDo(req, rateLimitCategory); err != nil {
		return &Response{
			Response: err.Response,
			Rate:     err.Rate,
		}, err
	}
	resp, err := c.client.Do(req)
	if err != nil {
		select {
		case <-ctx.Done():
			return nil, ctx.Err()
		default:
		}
		if e, ok := err.(*url.Error); ok {
			if url, err := url.Parse(e.URL); err == nil {
				e.URL = sanitizeURL(url).String()
				return nil, e
			}
		}
		return nil, err
	}
	defer resp.Body.Close()
	response := newResponse(resp)
	c.rateMu.Lock()
	c.rateLimits[rateLimitCategory] = response.Rate
	c.rateMu.Unlock()
	err = CheckResponse(resp)
	if err != nil {
		if _, ok := err.(*AcceptedError); !ok {
			return response, err
		}
	}
	if v != nil {
		if w, ok := v.(io.Writer); ok {
			io.Copy(w, resp.Body)
		} else {
			decErr := json.NewDecoder(resp.Body).Decode(v)
			if decErr == io.EOF {
				decErr = nil  
			}
			if decErr != nil {
				err = decErr
			}
		}
	}
	return response, err
}
Do sends an API request and returns the API response. The API response is
JSON decoded and stored in the value pointed to by v, or returned as an
error if an API error has occurred. If v implements the io.Writer
interface, the raw response body will be written to v, without attempting to
first decode it. If rate limit is exceeded and reset time is in the future,
Do returns *RateLimitError immediately without making a network API call.

The provided ctx must be non-nil. If it is canceled or times out,
ctx.Err() will be returned.
package github
import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"
	"github.com/google/go-querystring/query"
)
const (
	defaultBaseURL = "https://api.github.com/"
	uploadBaseURL  = "https://uploads.github.com/"
	userAgent      = "go-github"
	headerRateLimit     = "X-RateLimit-Limit"
	headerRateRemaining = "X-RateLimit-Remaining"
	headerRateReset     = "X-RateLimit-Reset"
	headerOTP           = "X-GitHub-OTP"
	mediaTypeV3                = "application/vnd.github.v3+json"
	defaultMediaType           = "application/octet-stream"
	mediaTypeV3SHA             = "application/vnd.github.v3.sha"
	mediaTypeV3Diff            = "application/vnd.github.v3.diff"
	mediaTypeV3Patch           = "application/vnd.github.v3.patch"
	mediaTypeOrgPermissionRepo = "application/vnd.github.v3.repository+json"
	mediaTypeStarringPreview = "application/vnd.github.v3.star+json"
	mediaTypeMigrationsPreview = "application/vnd.github.wyandotte-preview+json"
	mediaTypeDeploymentStatusPreview = "application/vnd.github.ant-man-preview+json"
	mediaTypeImportPreview = "application/vnd.github.barred-rock-preview"
	mediaTypeReactionsPreview = "application/vnd.github.squirrel-girl-preview"
	mediaTypeGitSigningPreview = "application/vnd.github.cryptographer-preview+json"
	mediaTypeTimelinePreview = "application/vnd.github.mockingbird-preview+json"
	mediaTypeRepositoryInvitationsPreview = "application/vnd.github.swamp-thing-preview+json"
	mediaTypePagesPreview = "application/vnd.github.mister-fantastic-preview+json"
	mediaTypeProjectsPreview = "application/vnd.github.inertia-preview+json"
	mediaTypeIntegrationPreview = "application/vnd.github.machine-man-preview+json"
	mediaTypeCommitSearchPreview = "application/vnd.github.cloak-preview+json"
	mediaTypeBlockUsersPreview = "application/vnd.github.giant-sentry-fist-preview+json"
	mediaTypeRepositoryCommunityHealthMetricsPreview = "application/vnd.github.black-panther-preview+json"
	mediaTypeCodesOfConductPreview = "application/vnd.github.scarlet-witch-preview+json"
	mediaTypeTopicsPreview = "application/vnd.github.mercy-preview+json"
	mediaTypeNestedTeamsPreview = "application/vnd.github.hellcat-preview+json"
	mediaTypeRepositoryTransferPreview = "application/vnd.github.nightshade-preview+json"
	mediaTypeOrganizationInvitationPreview = "application/vnd.github.dazzler-preview+json"
	mediaTypeRequiredApprovingReviewsPreview = "application/vnd.github.luke-cage-preview+json"
	mediaTypeLabelDescriptionSearchPreview = "application/vnd.github.symmetra-preview+json"
	mediaTypeTeamDiscussionsPreview = "application/vnd.github.echo-preview+json"
	mediaTypeHovercardPreview = "application/vnd.github.hagar-preview+json"
	mediaTypeLockReasonPreview = "application/vnd.github.sailor-v-preview+json"
	mediaTypeCheckRunsPreview = "application/vnd.github.antiope-preview+json"
	mediaTypePreReceiveHooksPreview = "application/vnd.github.eye-scream-preview"
)
type Client struct {
	clientMu sync.Mutex    
	client   *http.Client  
	BaseURL *url.URL
	UploadURL *url.URL
	UserAgent string
	rateMu     sync.Mutex
	rateLimits [categories]Rate  
	common service  
	Activity       *ActivityService
	Admin          *AdminService
	Apps           *AppsService
	Authorizations *AuthorizationsService
	Checks         *ChecksService
	Gists          *GistsService
	Git            *GitService
	Gitignores     *GitignoresService
	Issues         *IssuesService
	Licenses       *LicensesService
	Marketplace    *MarketplaceService
	Migrations     *MigrationService
	Organizations  *OrganizationsService
	Projects       *ProjectsService
	PullRequests   *PullRequestsService
	Reactions      *ReactionsService
	Repositories   *RepositoriesService
	Search         *SearchService
	Teams          *TeamsService
	Users          *UsersService
}
type service struct {
	client *Client
}
type ListOptions struct {
	Page int `url:"page,omitempty"`
	PerPage int `url:"per_page,omitempty"`
}
type UploadOptions struct {
	Name string `url:"name,omitempty"`
}
type RawType uint8
const (
	Diff RawType = 1 + iota
	Patch
)
type RawOptions struct {
	Type RawType
}
func addOptions(s string, opt interface{}) (string, error) {
	v := reflect.ValueOf(opt)
	if v.Kind() == reflect.Ptr && v.IsNil() {
		return s, nil
	}
	u, err := url.Parse(s)
	if err != nil {
		return s, err
	}
	qs, err := query.Values(opt)
	if err != nil {
		return s, err
	}
	u.RawQuery = qs.Encode()
	return u.String(), nil
}
func NewClient(httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}
	baseURL, _ := url.Parse(defaultBaseURL)
	uploadURL, _ := url.Parse(uploadBaseURL)
	c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: userAgent, UploadURL: uploadURL}
	c.common.client = c
	c.Activity = (*ActivityService)(&c.common)
	c.Admin = (*AdminService)(&c.common)
	c.Apps = (*AppsService)(&c.common)
	c.Authorizations = (*AuthorizationsService)(&c.common)
	c.Checks = (*ChecksService)(&c.common)
	c.Gists = (*GistsService)(&c.common)
	c.Git = (*GitService)(&c.common)
	c.Gitignores = (*GitignoresService)(&c.common)
	c.Issues = (*IssuesService)(&c.common)
	c.Licenses = (*LicensesService)(&c.common)
	c.Marketplace = &MarketplaceService{client: c}
	c.Migrations = (*MigrationService)(&c.common)
	c.Organizations = (*OrganizationsService)(&c.common)
	c.Projects = (*ProjectsService)(&c.common)
	c.PullRequests = (*PullRequestsService)(&c.common)
	c.Reactions = (*ReactionsService)(&c.common)
	c.Repositories = (*RepositoriesService)(&c.common)
	c.Search = (*SearchService)(&c.common)
	c.Teams = (*TeamsService)(&c.common)
	c.Users = (*UsersService)(&c.common)
	return c
}
func NewEnterpriseClient(baseURL, uploadURL string, httpClient *http.Client) (*Client, error) {
	baseEndpoint, err := url.Parse(baseURL)
	if err != nil {
		return nil, err
	}
	if !strings.HasSuffix(baseEndpoint.Path, "/") {
		baseEndpoint.Path += "/"
	}
	uploadEndpoint, err := url.Parse(uploadURL)
	if err != nil {
		return nil, err
	}
	if !strings.HasSuffix(uploadEndpoint.Path, "/") {
		uploadEndpoint.Path += "/"
	}
	c := NewClient(httpClient)
	c.BaseURL = baseEndpoint
	c.UploadURL = uploadEndpoint
	return c, nil
}
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
	if !strings.HasSuffix(c.BaseURL.Path, "/") {
		return nil, fmt.Errorf("BaseURL must have a trailing slash, but %q does not", c.BaseURL)
	}
	u, err := c.BaseURL.Parse(urlStr)
	if err != nil {
		return nil, err
	}
	var buf io.ReadWriter
	if body != nil {
		buf = new(bytes.Buffer)
		enc := json.NewEncoder(buf)
		enc.SetEscapeHTML(false)
		err := enc.Encode(body)
		if err != nil {
			return nil, err
		}
	}
	req, err := http.NewRequest(method, u.String(), buf)
	if err != nil {
		return nil, err
	}
	if body != nil {
		req.Header.Set("Content-Type", "application/json")
	}
	req.Header.Set("Accept", mediaTypeV3)
	if c.UserAgent != "" {
		req.Header.Set("User-Agent", c.UserAgent)
	}
	return req, nil
}
func (c *Client) NewUploadRequest(urlStr string, reader io.Reader, size int64, mediaType string) (*http.Request, error) {
	if !strings.HasSuffix(c.UploadURL.Path, "/") {
		return nil, fmt.Errorf("UploadURL must have a trailing slash, but %q does not", c.UploadURL)
	}
	u, err := c.UploadURL.Parse(urlStr)
	if err != nil {
		return nil, err
	}
	req, err := http.NewRequest("POST", u.String(), reader)
	if err != nil {
		return nil, err
	}
	req.ContentLength = size
	if mediaType == "" {
		mediaType = defaultMediaType
	}
	req.Header.Set("Content-Type", mediaType)
	req.Header.Set("Accept", mediaTypeV3)
	req.Header.Set("User-Agent", c.UserAgent)
	return req, nil
}
type Response struct {
	*http.Response
	NextPage  int
	PrevPage  int
	FirstPage int
	LastPage  int
	Rate Rate
}
func newResponse(r *http.Response) *Response {
	response := &Response{Response: r}
	response.populatePageValues()
	response.Rate = parseRate(r)
	return response
}
func (r *Response) populatePageValues() {
	if links, ok := r.Response.Header["Link"]; ok && len(links) > 0 {
		for _, link := range strings.Split(links[0], ",") {
			segments := strings.Split(strings.TrimSpace(link), ";")
			if len(segments) < 2 {
				continue
			}
			if !strings.HasPrefix(segments[0], "<") || !strings.HasSuffix(segments[0], ">") {
				continue
			}
			url, err := url.Parse(segments[0][1 : len(segments[0])-1])
			if err != nil {
				continue
			}
			page := url.Query().Get("page")
			if page == "" {
				continue
			}
			for _, segment := range segments[1:] {
				switch strings.TrimSpace(segment) {
				case `rel="next"`:
					r.NextPage, _ = strconv.Atoi(page)
				case `rel="prev"`:
					r.PrevPage, _ = strconv.Atoi(page)
				case `rel="first"`:
					r.FirstPage, _ = strconv.Atoi(page)
				case `rel="last"`:
					r.LastPage, _ = strconv.Atoi(page)
				}
			}
		}
	}
}
func parseRate(r *http.Response) Rate {
	var rate Rate
	if limit := r.Header.Get(headerRateLimit); limit != "" {
		rate.Limit, _ = strconv.Atoi(limit)
	}
	if remaining := r.Header.Get(headerRateRemaining); remaining != "" {
		rate.Remaining, _ = strconv.Atoi(remaining)
	}
	if reset := r.Header.Get(headerRateReset); reset != "" {
		if v, _ := strconv.ParseInt(reset, 10, 64); v != 0 {
			rate.Reset = Timestamp{time.Unix(v, 0)}
		}
	}
	return rate
}