func (cli *Client) NewMonitorUploader() *MonitorUploader {
	return &MonitorUploader{cli: cli}
}
NewMonitorUploader returns a new MonitorUploader.
package vt
import (
	"bytes"
	"compress/gzip"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
)
type Client struct {
	APIKey string
	Agent      string
	httpClient *http.Client
}
type requestOptions struct {
	headers map[string]string
}
type RequestOption func(*requestOptions)
func WithHeader(header, value string) RequestOption {
	return func(opts *requestOptions) {
		if opts.headers == nil {
			opts.headers = make(map[string]string)
		}
		opts.headers[header] = value
	}
}
func opts(opts ...RequestOption) *requestOptions {
	o := &requestOptions{}
	for _, opt := range opts {
		opt(o)
	}
	return o
}
type ClientOption func(*Client)
func WithHTTPClient(httpClient *http.Client) ClientOption {
	return func(c *Client) {
		c.httpClient = httpClient
	}
}
func NewClient(APIKey string, opts ...ClientOption) *Client {
	c := &Client{APIKey: APIKey, httpClient: &http.Client{}}
	for _, o := range opts {
		o(c)
	}
	return c
}
func (cli *Client) sendRequest(method string, url *url.URL, body io.Reader, headers map[string]string) (*http.Response, error) {
	req, err := http.NewRequest(method, url.String(), body)
	if err != nil {
		return nil, err
	}
	agent := cli.Agent
	if agent == "" {
		agent = "unknown"
	}
	req.Header.Set("User-Agent", fmt.Sprintf("%s; vtgo %s; gzip", agent, version))
	req.Header.Set("Accept-Encoding", "gzip")
	req.Header.Set("X-Apikey", cli.APIKey)
	if headers != nil {
		for k, v := range headers {
			req.Header.Set(k, v)
		}
	}
	return (cli.httpClient).Do(req)
}
func (cli *Client) parseResponse(resp *http.Response) (*Response, error) {
	apiresp := &Response{}
	if resp.ContentLength == 0 {
		return apiresp, nil
	}
	if !strings.HasPrefix(resp.Header.Get("Content-Type"), "application/json") {
		return nil, fmt.Errorf("Expecting JSON response from %s %s",
			resp.Request.Method, resp.Request.URL.String())
	}
	ungzipper, err := gzip.NewReader(resp.Body)
	if err != nil {
		return nil, err
	}
	defer ungzipper.Close()
	if err := json.NewDecoder(ungzipper).Decode(apiresp); err != nil {
		return nil, err
	}
	if apiresp.Error.Code != "" {
		return apiresp, apiresp.Error
	}
	return apiresp, nil
}
func (cli *Client) Get(url *url.URL, options ...RequestOption) (*Response, error) {
	o := opts(options...)
	httpResp, err := cli.sendRequest("GET", url, nil, o.headers)
	if err != nil {
		return nil, err
	}
	defer httpResp.Body.Close()
	return cli.parseResponse(httpResp)
}
func (cli *Client) Post(url *url.URL, req *Request, options ...RequestOption) (*Response, error) {
	var b []byte
	var err error
	if req != nil {
		b, err = json.Marshal(req)
		if err != nil {
			return nil, err
		}
	}
	o := opts(options...)
	httpResp, err := cli.sendRequest("POST", url, bytes.NewReader(b), o.headers)
	if err != nil {
		return nil, err
	}
	defer httpResp.Body.Close()
	return cli.parseResponse(httpResp)
}
func (cli *Client) Patch(url *url.URL, req *Request, options ...RequestOption) (*Response, error) {
	var b []byte
	var err error
	if req != nil {
		b, err = json.Marshal(req)
		if err != nil {
			return nil, err
		}
	}
	o := opts(options...)
	httpResp, err := cli.sendRequest("PATCH", url, bytes.NewReader(b), o.headers)
	if err != nil {
		return nil, err
	}
	defer httpResp.Body.Close()
	return cli.parseResponse(httpResp)
}
func (cli *Client) Delete(url *url.URL, options ...RequestOption) (*Response, error) {
	o := opts(options...)
	httpResp, err := cli.sendRequest("DELETE", url, nil, o.headers)
	if err != nil {
		return nil, err
	}
	defer httpResp.Body.Close()
	return cli.parseResponse(httpResp)
}
func (cli *Client) GetData(url *url.URL, target interface{}, options ...RequestOption) (*Response, error) {
	resp, err := cli.Get(url, options...)
	if err != nil {
		return nil, err
	}
	decoder := json.NewDecoder(bytes.NewReader(resp.Data))
	decoder.UseNumber()
	return resp, decoder.Decode(target)
}
func (cli *Client) PostData(url *url.URL, data interface{}, options ...RequestOption) (*Response, error) {
	req := &Request{}
	req.Data = data
	return cli.Post(url, req, options...)
}
func (cli *Client) PostObject(url *url.URL, obj *Object, options ...RequestOption) error {
	req := &Request{}
	req.Data = modifiedObject(*obj)
	resp, err := cli.Post(url, req, options...)
	if err != nil {
		return err
	}
	return json.Unmarshal(resp.Data, obj)
}
func (cli *Client) GetObject(url *url.URL, options ...RequestOption) (*Object, error) {
	obj := &Object{}
	if _, err := cli.GetData(url, obj, options...); err != nil {
		return nil, err
	}
	return obj, nil
}
func (cli *Client) PatchObject(url *url.URL, obj *Object, options ...RequestOption) error {
	req := &Request{}
	req.Data = modifiedObject(*obj)
	resp, err := cli.Patch(url, req, options...)
	if err != nil {
		return err
	}
	return json.Unmarshal(resp.Data, obj)
}
func (cli *Client) DownloadFile(hash string, w io.Writer) (int64, error) {
	u := URL("files/%s/download", hash)
	resp, err := cli.sendRequest("GET", u, nil, nil)
	if err != nil {
		return 0, err
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusOK {
		return io.Copy(w, resp.Body)
	}
	if _, err := cli.parseResponse(resp); err != nil {
		return 0, err
	}
	return 0, fmt.Errorf("Unknown error downloading %q, HTTP response code: %d", hash, resp.StatusCode)
}
func (cli *Client) Iterator(url *url.URL, options ...IteratorOption) (*Iterator, error) {
	return newIterator(cli, url, options...)
}
func (cli *Client) Search(query string, options ...IteratorOption) (*Iterator, error) {
	u := URL("intelligence/search")
	q := u.Query()
	q.Add("query", query)
	u.RawQuery = q.Encode()
	return newIterator(cli, u, options...)
}
type Metadata struct {
	Engines map[string]interface{} `json:"engines" yaml:"engines"`
	Relationships map[string][]RelationshipMeta `json:"relationships" yaml:"relationships"`
	Privileges    []string                      `json:"privileges" yaml:"privileges"`
}
type RelationshipMeta struct {
	Name string `json:"name" yaml:"name"`
	Description string `json:"description" yaml:"description"`
}
func (cli *Client) GetMetadata() (*Metadata, error) {
	metadata := &Metadata{}
	if _, err := cli.GetData(URL("metadata"), metadata); err != nil {
		return nil, err
	}
	return metadata, nil
}
func (cli *Client) NewFileScanner() *FileScanner {
	return &FileScanner{cli: cli}
}
func (cli *Client) NewURLScanner() *URLScanner {
	return &URLScanner{cli: cli}
}