func (s *Slack) do(path string, params url.Values, result interface{}) error {
	appendNotEmpty("token", s.token, params)
	var t time.Time
	if s.tracelog != nil {
		t = time.Now()
		s.tracef("Start request %s at %v", path, t)
	}
	resp, err := s.c.PostForm(s.url+path, params)
	if s.tracelog != nil {
		s.tracef("End request %s at %v - took %v", path, time.Now(), time.Since(t))
	}
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if err = s.handleError(resp); err != nil {
		return err
	}
	s.dumpResponse(resp)
	if result != nil {
		switch result := result.(type) {
		case io.Writer:
			if _, err = io.Copy(result, resp.Body); err != nil {
				return err
			}
		case Response:
			if err = json.NewDecoder(resp.Body).Decode(result); err != nil {
				return err
			}
			if !result.IsOK() {
				s.errorf("%s\n", result.Error())
				return result
			}
		default:
			if err = json.NewDecoder(resp.Body).Decode(result); err != nil {
				return err
			}
		}
	}
	return nil
}
do executes the API request.
Returns the response if the status code is between 200 and 299
package slack
import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
	"sync"
	"time"
	"github.com/gorilla/websocket"
)
const (
	DefaultURL = "https://slack.com/api/"
)
type Error struct {
	ID     string `json:"id"`
	Detail string `json:"detail"`
}
func newError(code, format string, args ...interface{}) *Error {
	return &Error{code, fmt.Sprintf(format, args...)}
}
func (e *Error) Error() string {
	return fmt.Sprintf("%s: %s", e.ID, e.Detail)
}
var (
	ErrBadToken = &Error{"bad_token", "Bad token was provided to the API"}
	ErrNoToken = &Error{"no_token", "You must provide a Slack token to use the API"}
	ErrBadOAuth = &Error{"bad_oauth", "Bad OAuth credentials provided"}
)
type Slack struct {
	token    string           
	url      string           
	errorlog *log.Logger      
	tracelog *log.Logger      
	c        *http.Client     
	ws       *websocket.Conn  
	mid      int              
	mutex    sync.Mutex       
}
type OptionFunc func(*Slack) error
func (s *Slack) errorf(format string, args ...interface{}) {
	if s.errorlog != nil {
		s.errorlog.Printf(format, args...)
	}
}
func (s *Slack) tracef(format string, args ...interface{}) {
	if s.tracelog != nil {
		s.tracelog.Printf(format, args...)
	}
}
func New(options ...OptionFunc) (*Slack, error) {
	s := &Slack{
		url: "",
		c:   http.DefaultClient,
	}
	for _, option := range options {
		if err := option(s); err != nil {
			return nil, err
		}
	}
	if s.url == "" {
		s.url = DefaultURL
	}
	s.tracef("Using URL [%s]\n", s.url)
	if s.token == "" {
		s.errorf("%s\n", ErrNoToken.Error())
		return nil, ErrNoToken
	}
	return s, nil
}
func SetToken(token string) OptionFunc {
	return func(s *Slack) error {
		if token == "" {
			s.errorf("%s\n", ErrBadToken.Error())
			return ErrBadToken
		}
		s.token = token
		return nil
	}
}
func SetHTTPClient(httpClient *http.Client) OptionFunc {
	return func(s *Slack) error {
		if httpClient != nil {
			s.c = httpClient
		} else {
			s.c = http.DefaultClient
		}
		return nil
	}
}
func SetURL(rawurl string) OptionFunc {
	return func(s *Slack) error {
		if rawurl == "" {
			rawurl = DefaultURL
		}
		u, err := url.Parse(rawurl)
		if err != nil {
			e := newError("bad_url", "Invalid URL [%s] - %v\n", rawurl, err.Error())
			s.errorf("%s\n", e.Error())
			return e
		}
		if u.Scheme != "http" && u.Scheme != "https" {
			err = newError("bad_url", "Invalid schema specified [%s]", rawurl)
			s.errorf("%v", err)
			return err
		}
		s.url = rawurl
		if !strings.HasSuffix(s.url, "/") {
			s.url += "/"
		}
		return nil
	}
}
func SetErrorLog(logger *log.Logger) func(*Slack) error {
	return func(s *Slack) error {
		s.errorlog = logger
		return nil
	}
}
func SetTraceLog(logger *log.Logger) func(*Slack) error {
	return func(s *Slack) error {
		s.tracelog = logger
		return nil
	}
}
func (s *Slack) dumpRequest(req *http.Request) {
	if s.tracelog != nil {
		out, err := httputil.DumpRequestOut(req, true)
		if err == nil {
			s.tracef("%s\n", string(out))
		}
	}
}
func (s *Slack) dumpResponse(resp *http.Response) {
	if s.tracelog != nil {
		out, err := httputil.DumpResponse(resp, true)
		if err == nil {
			s.tracef("%s\n", string(out))
		}
	}
}
func (s *Slack) handleError(resp *http.Response) error {
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		if s.errorlog != nil {
			out, err := httputil.DumpResponse(resp, true)
			if err == nil {
				s.errorf("%s\n", string(out))
			}
		}
		e := newError("http_error", "Unexpected status code: %d (%s)", resp.StatusCode, http.StatusText(resp.StatusCode))
		s.errorf("%s\n", e.Error())
		return e
	}
	return nil
}