func PrepareUpload(media io.Reader, chunkSize int) (r io.Reader, mb *MediaBuffer, singleChunk bool) {
	if chunkSize == 0 {  
		return media, nil, true
	}
	mb = NewMediaBuffer(media, chunkSize)
	_, _, _, err := mb.Chunk()
	return nil, mb, err == io.EOF
}
PrepareUpload determines whether the data in the supplied reader should be
uploaded in a single request, or in sequential chunks.
chunkSize is the size of the chunk that media should be split into.

If chunkSize is zero, media is returned as the first value, and the other
two return values are nil, true.

Otherwise, a MediaBuffer is returned, along with a bool indicating whether the
contents of media fit in a single chunk.

After PrepareUpload has been called, media should no longer be used: the
media content should be accessed via one of the return values.
package gensupport
import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"mime"
	"mime/multipart"
	"net/http"
	"net/textproto"
	"strings"
	"sync"
	"google.golang.org/api/googleapi"
)
const sniffBuffSize = 512
func newContentSniffer(r io.Reader) *contentSniffer {
	return &contentSniffer{r: r}
}
type contentSniffer struct {
	r     io.Reader
	start []byte  
	err   error   
	ctype   string  
	sniffed bool    
}
func (cs *contentSniffer) Read(p []byte) (n int, err error) {
	_, _ = cs.ContentType()
	if len(cs.start) > 0 {
		n := copy(p, cs.start)
		cs.start = cs.start[n:]
		return n, nil
	}
	if cs.err != nil {
		return 0, cs.err
	}
	return cs.r.Read(p)
}
func (cs *contentSniffer) ContentType() (string, bool) {
	if cs.sniffed {
		return cs.ctype, cs.ctype != ""
	}
	cs.sniffed = true
	cs.start, cs.err = ioutil.ReadAll(io.LimitReader(cs.r, sniffBuffSize))
	if cs.err != nil {
		return "", false
	}
	cs.ctype = http.DetectContentType(cs.start)
	return cs.ctype, true
}
func DetermineContentType(media io.Reader, ctype string) (io.Reader, string) {
	if ctype != "" {
		return media, ctype
	}
	if typer, ok := media.(googleapi.ContentTyper); ok {
		return media, typer.ContentType()
	}
	sniffer := newContentSniffer(media)
	if ctype, ok := sniffer.ContentType(); ok {
		return sniffer, ctype
	}
	return sniffer, ""
}
type typeReader struct {
	io.Reader
	typ string
}
type multipartReader struct {
	pr       *io.PipeReader
	ctype    string
	mu       sync.Mutex
	pipeOpen bool
}
func newMultipartReader(parts []typeReader, boundary string) *multipartReader {
	mp := &multipartReader{pipeOpen: true}
	var pw *io.PipeWriter
	mp.pr, pw = io.Pipe()
	mpw := multipart.NewWriter(pw)
	if boundary != "" {
		mpw.SetBoundary(boundary)
	}
	mp.ctype = "multipart/related; boundary=" + mpw.Boundary()
	go func() {
		for _, part := range parts {
			w, err := mpw.CreatePart(typeHeader(part.typ))
			if err != nil {
				mpw.Close()
				pw.CloseWithError(fmt.Errorf("googleapi: CreatePart failed: %v", err))
				return
			}
			_, err = io.Copy(w, part.Reader)
			if err != nil {
				mpw.Close()
				pw.CloseWithError(fmt.Errorf("googleapi: Copy failed: %v", err))
				return
			}
		}
		mpw.Close()
		pw.Close()
	}()
	return mp
}
func (mp *multipartReader) Read(data []byte) (n int, err error) {
	return mp.pr.Read(data)
}
func (mp *multipartReader) Close() error {
	mp.mu.Lock()
	if !mp.pipeOpen {
		mp.mu.Unlock()
		return nil
	}
	mp.pipeOpen = false
	mp.mu.Unlock()
	return mp.pr.Close()
}
func CombineBodyMedia(body io.Reader, bodyContentType string, media io.Reader, mediaContentType string) (io.ReadCloser, string) {
	return combineBodyMedia(body, bodyContentType, media, mediaContentType, "")
}
func combineBodyMedia(body io.Reader, bodyContentType string, media io.Reader, mediaContentType, mimeBoundary string) (io.ReadCloser, string) {
	mp := newMultipartReader([]typeReader{
		{body, bodyContentType},
		{media, mediaContentType},
	}, mimeBoundary)
	return mp, mp.ctype
}
func typeHeader(contentType string) textproto.MIMEHeader {
	h := make(textproto.MIMEHeader)
	if contentType != "" {
		h.Set("Content-Type", contentType)
	}
	return h
}