<commit_before>package main

import (
	"encoding/base64"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"time"
)

const (
	CLIENTUUID = "2ea32002-a079-48f4-8020-0badd22939e3"
	FITBITHOST = "https://client.fitbit.com"
	STARTPATH  = "/device/tracker/uploadData"
)

type FitbitConfig struct {
	ResponseInfo Response   `xml:"response"`
	RemoteOps    []RemoteOp `xml:"device>remoteOps>remoteOp"`
}

type FitbitClient struct {
	*FitbitBase
}

type Response struct {
	Body string `xml:",chardata"`
	Host string `xml:"host,attr"`
	Path string `xml:"path,attr"`
}

type RemoteOp struct {
	OpCode      string `xml:"opCode"`
	PayloadData string `xml:"payloadData"`
}

func (c *FitbitClient) UploadData() error {
	//init_tracker_for_transfer
	v := url.Values{}
	weburl := FITBITHOST + STARTPATH
	err := c.InitTrackerForTransfer()
	log.Println("end init----------")
	if err != nil {
		return err
	}
	defer c.CommandSleep()
	client := http.Client{}
	v.Set("beaconType", "standard")
	v.Set("clientMode", "standard")
	v.Set("clientVersion", "1.0")
	v.Set("os", "fitbitd")
	v.Set("clientId", CLIENTUUID)
	for {
		log.Println(weburl, v)
		resp, err := client.PostForm(weburl, v)
		if err != nil {
			return err
		}
		body, err := ioutil.ReadAll(resp.Body)
		config := FitbitConfig{}
		if err == nil {
			err = xml.Unmarshal(body, &config)
		}
		resp.Body.Close()
		log.Println(string(body))
		v, err = url.ParseQuery(config.ResponseInfo.Body)
		if err != nil {
			return err
		}
		for i, op := range config.RemoteOps {
			opcode, err := base64.StdEncoding.DecodeString(op.OpCode)
			payload, err := base64.StdEncoding.DecodeString(op.PayloadData)
			code, err := c.RunOpcode(opcode, payload)
			if err != nil {
				return err
			}
			resp := base64.StdEncoding.EncodeToString(code)
			log.Printf("opCode[%d]: %s, payload: %s, response: %s\n", i, op.OpCode, op.PayloadData, resp)
			v.Set(fmt.Sprintf("opResponse[%d]", i), resp)
			v.Set(fmt.Sprintf("opStatus[%d]", i), "success")
		}
		if config.ResponseInfo.Host == "" {
			break
		}
		v.Set("beaconType", "standard")
		v.Set("clientMode", "standard")
		v.Set("clientVersion", "1.0")
		v.Set("os", "fitbitd")
		v.Set("clientId", CLIENTUUID)
		weburl = "http://" + config.ResponseInfo.Host + config.ResponseInfo.Path
	}
	return err
}

type SyncTask struct {
	exitChannel chan int
}

func (s *SyncTask) Run() {
	ticker := time.Tick(time.Second * 600)
	for {
		fb := FitbitBase{}
		err := fb.Open()
		if err == nil {
			err = fb.SettingUp()
			if err == nil {
				c := FitbitClient{
					FitbitBase: &fb,
				}
				log.Println("start sync")
				err = c.UploadData()
				if err != nil {
					log.Println("sync failed")
				} else {
					log.Println("sync success")
				}
			}
			fb.Close()
		}
		select {
		case <-ticker:
			continue
		case <-s.exitChannel:
			return
		}
	}
}
func (s *SyncTask) Stop() {
	close(s.exitChannel)
}
<commit_msg>code cleanup<commit_after>package main

import (
	"encoding/base64"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"time"
)

const (
	CLIENTUUID = "2ea32002-a079-48f4-8020-0badd22939e3"
	FITBITHOST = "https://client.fitbit.com"
	STARTPATH  = "/device/tracker/uploadData"
)

type FitbitConfig struct {
	ResponseInfo Response   `xml:"response"`
	RemoteOps    []RemoteOp `xml:"device>remoteOps>remoteOp"`
}

type FitbitClient struct {
	*FitbitBase
}

type Response struct {
	Body string `xml:",chardata"`
	Host string `xml:"host,attr"`
	Path string `xml:"path,attr"`
}

type RemoteOp struct {
	OpCode      string `xml:"opCode"`
	PayloadData string `xml:"payloadData"`
}

func (c *FitbitClient) UploadData() error {
	//init_tracker_for_transfer
	v := url.Values{}
	weburl := FITBITHOST + STARTPATH
	err := c.InitTrackerForTransfer()
	log.Println("end init----------")
	if err != nil {
		return err
	}
	defer c.CommandSleep()
	client := http.Client{}
	v.Set("beaconType", "standard")
	v.Set("clientMode", "standard")
	v.Set("clientVersion", "1.0")
	v.Set("os", "fitbitd")
	v.Set("clientId", CLIENTUUID)
	for {
		log.Println(weburl, v)
		resp, err := client.PostForm(weburl, v)
		if err != nil {
			return err
		}
		body, err := ioutil.ReadAll(resp.Body)
		config := FitbitConfig{}
		if err == nil {
			err = xml.Unmarshal(body, &config)
		}
		resp.Body.Close()
		log.Println(string(body))
		v, err = url.ParseQuery(config.ResponseInfo.Body)
		if err != nil {
			return err
		}
		for i, op := range config.RemoteOps {
			opcode, err := base64.StdEncoding.DecodeString(op.OpCode)
			payload, err := base64.StdEncoding.DecodeString(op.PayloadData)
			code, err := c.RunOpcode(opcode, payload)
			if err != nil {
				return err
			}
			resp := base64.StdEncoding.EncodeToString(code)
			log.Printf("opCode[%d]: %s, payload: %s, response: %s\n", i, op.OpCode, op.PayloadData, resp)
			v.Set(fmt.Sprintf("opResponse[%d]", i), resp)
			v.Set(fmt.Sprintf("opStatus[%d]", i), "success")
		}
		if config.ResponseInfo.Host == "" {
			break
		}
		v.Set("beaconType", "standard")
		v.Set("clientMode", "standard")
		v.Set("clientVersion", "1.0")
		v.Set("os", "fitbitd")
		v.Set("clientId", CLIENTUUID)
		weburl = "http://" + config.ResponseInfo.Host + config.ResponseInfo.Path
	}
	return err
}

func (f *FitbitClient) SetBase() error {
	fb := &FitbitBase{}
	err := fb.Open()
	if err == nil {
		f.FitbitBase = fb
	}
	return err
}

type SyncTask struct {
	exitChannel chan int
}

func (s *SyncTask) Run() {
	ticker := time.Tick(time.Second * 600)
	for {
		c := FitbitClient{}
		err := c.SetBase()
		if err != nil {
			continue
		}
		log.Println("start sync")
		err = c.UploadData()
		if err != nil {
			log.Println("sync failed")
		}
		c.Close()
		select {
		case <-ticker:
			continue
		case <-s.exitChannel:
			return
		}
	}
}
func (s *SyncTask) Stop() {
	close(s.exitChannel)
}
<|endoftext|>


<commit_before>package flickr

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

const (
	API_ENDPOINT = "https://api.flickr.com/services/rest"
)

type FlickrClient struct {
	ApiKey           string
	ApiSecret        string
	HTTPClient       *http.Client
	EndpointUrl      string
	HTTPVerb         string
	Args             url.Values
	OAuthToken       string
	OAuthTokenSecret string
}

func NewFlickrClient(apiKey string, apiSecret string) *FlickrClient {
	return &FlickrClient{
		ApiKey:     apiKey,
		ApiSecret:  apiSecret,
		HTTPClient: &http.Client{},
		HTTPVerb:   "GET",
		Args:       url.Values{},
	}
}

func (c *FlickrClient) Sign(tokenSecret string) {
	// the "oauth_signature" param should not be included in the signing process
	c.Args.Del("oauth_signature")
	c.Args.Set("oauth_signature", c.getSignature(tokenSecret))
}

func (c *FlickrClient) GetUrl() string {
	return fmt.Sprintf("%s?%s", c.EndpointUrl, c.Args.Encode())
}

func (c *FlickrClient) ClearArgs() {
	c.Args = url.Values{}
}

func (c *FlickrClient) SetDefaultArgs() {
	c.Args = getDefaultArgs()
}

func (c *FlickrClient) getSigningBaseString() string {
	request_url := url.QueryEscape(c.EndpointUrl)
	query := url.QueryEscape(c.Args.Encode())

	return fmt.Sprintf("%s&%s&%s", c.HTTPVerb, request_url, query)
}

func (c *FlickrClient) getSignature(token_secret string) string {
	key := fmt.Sprintf("%s&%s", url.QueryEscape(c.ApiSecret), url.QueryEscape(token_secret))
	base_string := c.getSigningBaseString()

	mac := hmac.New(sha1.New, []byte(key))
	mac.Write([]byte(base_string))

	ret := base64.StdEncoding.EncodeToString(mac.Sum(nil))

	return ret
}

type FlickrResponse struct {
	XMLName xml.Name `xml:"rsp"`
	Status  string   `xml:"stat,attr"`
	Error   struct {
		XMLName xml.Name `xml:"err"`
		Code    int      `xml:"code,attr"`
		Message string   `xml:"msg,attr"`
	}
}

func (r *FlickrResponse) HasErrors() bool {
	return r.Status == "fail"
}

func (r *FlickrResponse) ErrorCode() int {
	return r.Error.Code
}

func (r *FlickrResponse) ErrorMsg() string {
	return r.Error.Message
}

type RequestToken struct {
	OauthCallbackConfirmed bool
	OauthToken             string
	OauthTokenSecret       string
}

func NewRequestToken(response string) (*RequestToken, error) {
	// TODO parse flickr errors inside the body
	val, err := url.ParseQuery(strings.TrimSpace(response))
	if err != nil {
		return nil, err
	}

	confirmed, _ := strconv.ParseBool(val.Get("oauth_callback_confirmed"))

	return &RequestToken{
		confirmed,
		val.Get("oauth_token"),
		val.Get("oauth_token_secret"),
	}, nil
}

type OAuthToken struct {
	OAuthToken       string
	OAuthTokenSecret string
	UserNsid         string
	Username         string
	Fullname         string
}

func NewOAuthToken(response string) (*OAuthToken, error) {
	// TODO parse flickr errors inside the body
	val, err := url.ParseQuery(strings.TrimSpace(response))
	if err != nil {
		return nil, err
	}

	return &OAuthToken{
		OAuthToken:       val.Get("oauth_token"),
		OAuthTokenSecret: val.Get("oauth_token_secret"),
		Fullname:         val.Get("fullname"),
		UserNsid:         val.Get("user_nsid"),
		Username:         val.Get("username"),
	}, nil
}

func generateNonce() string {
	rand.Seed(time.Now().UTC().UnixNano())
	var letters = []rune("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ")
	b := make([]rune, 8)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func getDefaultArgs() url.Values {
	args := url.Values{}
	args.Add("oauth_version", "1.0")
	args.Add("oauth_signature_method", "HMAC-SHA1")
	args.Add("oauth_nonce", generateNonce())
	args.Add("oauth_timestamp", fmt.Sprintf("%d", time.Now().Unix()))

	return args
}

func GetRequestToken(client *FlickrClient) (*RequestToken, error) {
	client.EndpointUrl = "https://www.flickr.com/services/oauth/request_token"
	client.Args = getDefaultArgs()
	client.Args.Set("oauth_consumer_key", client.ApiKey)
	client.Args.Set("oauth_callback", "oob")

	// we don't have token secret at this stage, pass an empty string
	client.Sign("")

	res, err := client.HTTPClient.Get(client.GetUrl())
	if err != nil {
		return nil, err
	}

	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	return NewRequestToken(string(body))
}

func GetAuthorizeUrl(client *FlickrClient, reqToken *RequestToken) (string, error) {
	client.EndpointUrl = "https://www.flickr.com/services/oauth/authorize"
	client.Args = url.Values{}
	client.Args.Set("oauth_token", reqToken.OauthToken)
	client.Args.Set("perms", "delete")

	return client.GetUrl(), nil
}

func GetAccessToken(client *FlickrClient, reqToken *RequestToken, oauthVerifier string) (*OAuthToken, error) {
	client.EndpointUrl = "https://www.flickr.com/services/oauth/access_token"
	client.Args = getDefaultArgs()
	client.Args.Set("oauth_verifier", oauthVerifier)
	client.Args.Set("oauth_consumer_key", client.ApiKey)
	client.Args.Set("oauth_token", reqToken.OauthToken)
	// use the request token for signing
	client.Sign(reqToken.OauthTokenSecret)

	res, err := client.HTTPClient.Get(client.GetUrl())
	if err != nil {
		return nil, err
	}

	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	return NewOAuthToken(string(body))
}
<commit_msg>call proper method<commit_after>package flickr

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

const (
	API_ENDPOINT = "https://api.flickr.com/services/rest"
)

type FlickrClient struct {
	ApiKey           string
	ApiSecret        string
	HTTPClient       *http.Client
	EndpointUrl      string
	HTTPVerb         string
	Args             url.Values
	OAuthToken       string
	OAuthTokenSecret string
}

func NewFlickrClient(apiKey string, apiSecret string) *FlickrClient {
	return &FlickrClient{
		ApiKey:     apiKey,
		ApiSecret:  apiSecret,
		HTTPClient: &http.Client{},
		HTTPVerb:   "GET",
		Args:       url.Values{},
	}
}

func (c *FlickrClient) Sign(tokenSecret string) {
	// the "oauth_signature" param should not be included in the signing process
	c.Args.Del("oauth_signature")
	c.Args.Set("oauth_signature", c.getSignature(tokenSecret))
}

func (c *FlickrClient) GetUrl() string {
	return fmt.Sprintf("%s?%s", c.EndpointUrl, c.Args.Encode())
}

func (c *FlickrClient) ClearArgs() {
	c.Args = url.Values{}
}

func (c *FlickrClient) SetDefaultArgs() {
	c.Args = getDefaultArgs()
}

func (c *FlickrClient) getSigningBaseString() string {
	request_url := url.QueryEscape(c.EndpointUrl)
	query := url.QueryEscape(c.Args.Encode())

	return fmt.Sprintf("%s&%s&%s", c.HTTPVerb, request_url, query)
}

func (c *FlickrClient) getSignature(token_secret string) string {
	key := fmt.Sprintf("%s&%s", url.QueryEscape(c.ApiSecret), url.QueryEscape(token_secret))
	base_string := c.getSigningBaseString()

	mac := hmac.New(sha1.New, []byte(key))
	mac.Write([]byte(base_string))

	ret := base64.StdEncoding.EncodeToString(mac.Sum(nil))

	return ret
}

type FlickrResponse struct {
	XMLName xml.Name `xml:"rsp"`
	Status  string   `xml:"stat,attr"`
	Error   struct {
		XMLName xml.Name `xml:"err"`
		Code    int      `xml:"code,attr"`
		Message string   `xml:"msg,attr"`
	}
}

func (r *FlickrResponse) HasErrors() bool {
	return r.Status == "fail"
}

func (r *FlickrResponse) ErrorCode() int {
	return r.Error.Code
}

func (r *FlickrResponse) ErrorMsg() string {
	return r.Error.Message
}

type RequestToken struct {
	OauthCallbackConfirmed bool
	OauthToken             string
	OauthTokenSecret       string
}

func NewRequestToken(response string) (*RequestToken, error) {
	// TODO parse flickr errors inside the body
	val, err := url.ParseQuery(strings.TrimSpace(response))
	if err != nil {
		return nil, err
	}

	confirmed, _ := strconv.ParseBool(val.Get("oauth_callback_confirmed"))

	return &RequestToken{
		confirmed,
		val.Get("oauth_token"),
		val.Get("oauth_token_secret"),
	}, nil
}

type OAuthToken struct {
	OAuthToken       string
	OAuthTokenSecret string
	UserNsid         string
	Username         string
	Fullname         string
}

func NewOAuthToken(response string) (*OAuthToken, error) {
	// TODO parse flickr errors inside the body
	val, err := url.ParseQuery(strings.TrimSpace(response))
	if err != nil {
		return nil, err
	}

	return &OAuthToken{
		OAuthToken:       val.Get("oauth_token"),
		OAuthTokenSecret: val.Get("oauth_token_secret"),
		Fullname:         val.Get("fullname"),
		UserNsid:         val.Get("user_nsid"),
		Username:         val.Get("username"),
	}, nil
}

func generateNonce() string {
	rand.Seed(time.Now().UTC().UnixNano())
	var letters = []rune("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ")
	b := make([]rune, 8)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func getDefaultArgs() url.Values {
	args := url.Values{}
	args.Add("oauth_version", "1.0")
	args.Add("oauth_signature_method", "HMAC-SHA1")
	args.Add("oauth_nonce", generateNonce())
	args.Add("oauth_timestamp", fmt.Sprintf("%d", time.Now().Unix()))

	return args
}

func GetRequestToken(client *FlickrClient) (*RequestToken, error) {
	client.EndpointUrl = "https://www.flickr.com/services/oauth/request_token"
	client.SetDefaultArgs()
	client.Args.Set("oauth_consumer_key", client.ApiKey)
	client.Args.Set("oauth_callback", "oob")

	// we don't have token secret at this stage, pass an empty string
	client.Sign("")

	res, err := client.HTTPClient.Get(client.GetUrl())
	if err != nil {
		return nil, err
	}

	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	return NewRequestToken(string(body))
}

func GetAuthorizeUrl(client *FlickrClient, reqToken *RequestToken) (string, error) {
	client.EndpointUrl = "https://www.flickr.com/services/oauth/authorize"
	client.Args = url.Values{}
	client.Args.Set("oauth_token", reqToken.OauthToken)
	client.Args.Set("perms", "delete")

	return client.GetUrl(), nil
}

func GetAccessToken(client *FlickrClient, reqToken *RequestToken, oauthVerifier string) (*OAuthToken, error) {
	client.EndpointUrl = "https://www.flickr.com/services/oauth/access_token"
	client.SetDefaultArgs()
	client.Args.Set("oauth_verifier", oauthVerifier)
	client.Args.Set("oauth_consumer_key", client.ApiKey)
	client.Args.Set("oauth_token", reqToken.OauthToken)
	// use the request token for signing
	client.Sign(reqToken.OauthTokenSecret)

	res, err := client.HTTPClient.Get(client.GetUrl())
	if err != nil {
		return nil, err
	}

	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	return NewOAuthToken(string(body))
}
<|endoftext|>


<commit_before>//prints the text of each line that appears more than once

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	counts := make(map[string]int)
	files := os.Args[1:]
	if len(files) == 0 {
		countLines(os.Stdin, counts)
	} else {
		for _, arg := range files {
			f, err := os.Open(arg)
			if err != nil {
				fmt.Fprintf(os.Stderr, "dup2: %v\n", err)
				continue
			}
			countLines(f, counts)
			f.Close()
		}

	}
	for line, n := range counts {
		if n > 1 {
			fmt.Printf("%d\t%s\n", n, line)
		}
	}
}

func countLines(f *os.File, counts map[string]int) {
	input := bufio.NewScanner(f)
	for input.Scan() {
		counts[input.Text()]++
	}
	//note: ignoring potential errors from input.Err()
}
<commit_msg>First pass at printing file names where duplication occurs<commit_after>//prints the text of each line that appears more than once

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	counts := make(map[string]int)
	filenames := make(map[string]string)

	files := os.Args[1:]
	if len(files) == 0 {
		countLines(os.Stdin, counts, filenames)
	} else {
		for _, arg := range files {
			f, err := os.Open(arg)
			if err != nil {
				fmt.Fprintf(os.Stderr, "dup2: %v\n", err)
				continue
			}
			countLines(f, counts, filenames)
			f.Close()
		}

	}
	for line, n := range counts {
		if n > 1 {
			fmt.Printf("%d\t%s\t%s\n", n, line, filenames[line])
		}
	}
}

func countLines(f *os.File, counts map[string]int, filenames map[string]string) {
	input := bufio.NewScanner(f)
	for input.Scan() {
		counts[input.Text()]++
		filenames[input.Text()] = filenames[input.Text()] + " " + f.Name()
	}
	//note: ignoring potential errors from input.Err()
}
<|endoftext|>


<commit_before>// Package fpaste wraps the basic functions of the Pastebin API and exposes a
// Go API.
package fpaste

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

var (
	ErrPutFailed = errors.New("fpaste Put Failed!")
	ErrGetFailed = errors.New("fpaste Get Failed!")
)

type Fpaste struct{}
type fpasteResponse struct {
	Result struct {
		ID string `json:"id"`
	} `json:"result"`
}

// Function Put uploads text to fpaste.org. It returns the ID of the created
// paste or an error. The title is not used, as the service does not support
// titles.
func (f Fpaste) Put(text, title string) (id string, err error) {
	data := url.Values{}
	// Required values.
	data.Set("paste_data", text)
	data.Set("paste_lang", "text")
	data.Set("api_submit", "true")
	data.Set("mode", "json")        // Get the results back in JSON.
	data.Set("paste_private", "no") // Public paste.
	data.Set("paste_expire", "0")   // Never expire.

	resp, err := http.PostForm("http://fpaste.org", data)
	if err != nil {
		return "", err
	}
	if resp.StatusCode != 200 {
		return "", ErrPutFailed
	}
	defer resp.Body.Close()
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	decresp := &fpasteResponse{}
	err = json.Unmarshal(respBody, decresp)
	if err != nil {
		return "", err
	}
	return decresp.Result.ID, nil
}

// Function Get returns the text inside the paste identified by ID.
func (f Fpaste) Get(id string) (text string, err error) {
	resp, err := http.Get("http://fpaste.org/" + id + "/raw/")
	if err != nil {
		return "", err
	}
	if resp.StatusCode != 200 {
		return "", ErrGetFailed
	}
	defer resp.Body.Close()
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(respBody), nil
}

// Function StripURL returns the paste ID from a fpaste URL.
func (f Fpaste) StripURL(url string) string {
	return strings.Replace(url, "http://fpaste.org/", "", -1)
}

// Function WrapID returns the fpaste URL from a paste ID.
func (f Fpaste) WrapID(id string) string {
	return "http://fpaste.org/" + id
}
<commit_msg>Linted fpaste.<commit_after>// Package fpaste wraps the basic functions of the fpaste.org API and exposes a
// Go API.
package fpaste

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

var (
	// ErrPutFailed is returned when a paste could not be uploaded to fpaste.
	ErrPutFailed = errors.New("fpaste put failed")
	// ErrGetFailed is returned when a paste could not be fetched from fpaste.
	ErrGetFailed = errors.New("fpaste get failed")
)

// Fpaste is an instance of the fpaste service.
type Fpaste struct{}

type fpasteResponse struct {
	Result struct {
		ID string `json:"id"`
	} `json:"result"`
}

// Put uploads text to fpaste.org. It returns the ID of the created paste or an
// error. The title is not used, as the service does not support titles.
func (f Fpaste) Put(text, title string) (id string, err error) {
	data := url.Values{}
	// Required values.
	data.Set("paste_data", text)
	data.Set("paste_lang", "text")
	data.Set("api_submit", "true")
	data.Set("mode", "json")        // Get the results back in JSON.
	data.Set("paste_private", "no") // Public paste.
	data.Set("paste_expire", "0")   // Never expire.

	resp, err := http.PostForm("http://fpaste.org", data)
	if err != nil {
		return "", err
	}
	if resp.StatusCode != 200 {
		return "", ErrPutFailed
	}
	defer resp.Body.Close()
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	decresp := &fpasteResponse{}
	err = json.Unmarshal(respBody, decresp)
	if err != nil {
		return "", err
	}
	return decresp.Result.ID, nil
}

// Get returns the text inside the paste identified by ID.
func (f Fpaste) Get(id string) (text string, err error) {
	resp, err := http.Get("http://fpaste.org/" + id + "/raw/")
	if err != nil {
		return "", err
	}
	if resp.StatusCode != 200 {
		return "", ErrGetFailed
	}
	defer resp.Body.Close()
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(respBody), nil
}

// StripURL returns the paste ID from a fpaste URL.
func (f Fpaste) StripURL(url string) string {
	return strings.Replace(url, "http://fpaste.org/", "", -1)
}

// WrapID returns the fpaste URL from a paste ID.
func (f Fpaste) WrapID(id string) string {
	return "http://fpaste.org/" + id
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"strconv"
	"strings"
)

const (
	toolVersion = "0.1.1"
)

var zfsPool string
var capWarning int64
var capCritical int64
var versionCheck bool

func init() {
	const (
		defaultPool     = "tank"
		poolUsage       = "what ZFS pool to check"
		defaultWarning  = 70
		warningUsage    = "Capacity warning limit"
		defaultCritical = 80
		criticalUsage   = "Capacity critical limit (80% is considered soft limit of ZFS)"
		versionUsage    = "Display current version"
	)
	flag.StringVar(&zfsPool, "pool", defaultPool, poolUsage)
	flag.StringVar(&zfsPool, "p", defaultPool, poolUsage+" (shorthand)")
	flag.Int64Var(&capWarning, "warning", defaultWarning, warningUsage)
	flag.Int64Var(&capWarning, "w", defaultWarning, warningUsage+" (shorthand)")
	flag.Int64Var(&capCritical, "critical", defaultCritical, criticalUsage)
	flag.Int64Var(&capCritical, "c", defaultCritical, criticalUsage+" (shorthand)")
	flag.BoolVar(&versionCheck, "version", false, versionUsage)
	flag.Parse()
}

type zpool struct {
	name     string
	capacity int64
	healthy  bool
	status   string
	faulted  int64
}

func (z *zpool) checkHealth(output string) (err error) {
	output = strings.Trim(output, "\n")
	if output == "ONLINE" {
		z.healthy = true
	} else if output == "DEGRADED" || output == "FAULTED" {
		z.healthy = false
	} else {
		z.healthy = false // just to make sure
		err = errors.New("Unknown status")
	}
	return err
}

func (z *zpool) getCapacity(output string) (err error) {
	s := strings.Split(output, "%")[0]
	z.capacity, err = strconv.ParseInt(s, 0, 8)
	if err != nil {
		return err
	}
	return err
}

func (z *zpool) getFaulted(output string) (err error) {
	lines := strings.Split(output, "\n")
	z.status = strings.Split(lines[1], " ")[2]
	if z.status == "ONLINE" {
		z.faulted = 0 // assume ONLINE means no faulted/unavailable providers
	} else if z.status == "DEGRADED" || z.status == "FAULTED" {
		var count int64
		for _, line := range lines {
			if (strings.Contains(line, "FAULTED") && !strings.Contains(line, "state:")) || strings.Contains(line, "UNAVAIL") {
				count = count + 1
			}
		}
		z.faulted = count
	} else {
		z.faulted = 1 // fake faulted if there is a parsing error
		err = errors.New("Error parsing faulted/unavailable disks")
	}
	return
}

func (z *zpool) getStatus() {
	output := runZpoolCommand([]string{"status", z.name})
	err := z.getFaulted(output)
	if err != nil {
		log.Fatal("Error parsing zpool status")
	}
	output = runZpoolCommand([]string{"list", "-H", "-o", "health", z.name})
	err = z.checkHealth(output)
	if err != nil {
		log.Fatal("Error parsing zpool list -H -o health ", z.name)
	}
	output = runZpoolCommand([]string{"list", "-H", "-o", "cap", z.name})
	err = z.getCapacity(output)
	if err != nil {
		log.Fatal("Error parsing zpool capacity")
	}
}

func checkExistance(pool string) (err error) {
	output := runZpoolCommand([]string{"list", pool})
	if strings.Contains(fmt.Sprintf("%s", output), "no such pool") {
		err = errors.New("No such pool")
	}
	return
}

func runZpoolCommand(args []string) string {
	zpoolPath, err := exec.LookPath("zpool")
	if err != nil {
		log.Fatal("Could not find zpool in PATH")
	}
	cmd := exec.Command(zpoolPath, args...)
	out, _ := cmd.CombinedOutput()
	return fmt.Sprintf("%s", out)
}

func main() {
	if versionCheck {
		fmt.Printf("nagios-zfs-go v%s (https://github.com/eripa/nagios-zfs-go)\n", toolVersion)
		os.Exit(0)
	}
	err := checkExistance(zfsPool)
	if err != nil {
		log.Fatal(err)
	}
	z := zpool{name: zfsPool}
	z.getStatus()
	message, exitcode := z.NagiosFormat()
	fmt.Println(message)
	os.Exit(exitcode)
}
<commit_msg>Upped version to v0.1.2 to justify binary build with Go 1.5<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"strconv"
	"strings"
)

const (
	toolVersion = "0.1.2"
)

var zfsPool string
var capWarning int64
var capCritical int64
var versionCheck bool

func init() {
	const (
		defaultPool     = "tank"
		poolUsage       = "what ZFS pool to check"
		defaultWarning  = 70
		warningUsage    = "Capacity warning limit"
		defaultCritical = 80
		criticalUsage   = "Capacity critical limit (80% is considered soft limit of ZFS)"
		versionUsage    = "Display current version"
	)
	flag.StringVar(&zfsPool, "pool", defaultPool, poolUsage)
	flag.StringVar(&zfsPool, "p", defaultPool, poolUsage+" (shorthand)")
	flag.Int64Var(&capWarning, "warning", defaultWarning, warningUsage)
	flag.Int64Var(&capWarning, "w", defaultWarning, warningUsage+" (shorthand)")
	flag.Int64Var(&capCritical, "critical", defaultCritical, criticalUsage)
	flag.Int64Var(&capCritical, "c", defaultCritical, criticalUsage+" (shorthand)")
	flag.BoolVar(&versionCheck, "version", false, versionUsage)
	flag.Parse()
}

type zpool struct {
	name     string
	capacity int64
	healthy  bool
	status   string
	faulted  int64
}

func (z *zpool) checkHealth(output string) (err error) {
	output = strings.Trim(output, "\n")
	if output == "ONLINE" {
		z.healthy = true
	} else if output == "DEGRADED" || output == "FAULTED" {
		z.healthy = false
	} else {
		z.healthy = false // just to make sure
		err = errors.New("Unknown status")
	}
	return err
}

func (z *zpool) getCapacity(output string) (err error) {
	s := strings.Split(output, "%")[0]
	z.capacity, err = strconv.ParseInt(s, 0, 8)
	if err != nil {
		return err
	}
	return err
}

func (z *zpool) getFaulted(output string) (err error) {
	lines := strings.Split(output, "\n")
	z.status = strings.Split(lines[1], " ")[2]
	if z.status == "ONLINE" {
		z.faulted = 0 // assume ONLINE means no faulted/unavailable providers
	} else if z.status == "DEGRADED" || z.status == "FAULTED" {
		var count int64
		for _, line := range lines {
			if (strings.Contains(line, "FAULTED") && !strings.Contains(line, "state:")) || strings.Contains(line, "UNAVAIL") {
				count = count + 1
			}
		}
		z.faulted = count
	} else {
		z.faulted = 1 // fake faulted if there is a parsing error
		err = errors.New("Error parsing faulted/unavailable disks")
	}
	return
}

func (z *zpool) getStatus() {
	output := runZpoolCommand([]string{"status", z.name})
	err := z.getFaulted(output)
	if err != nil {
		log.Fatal("Error parsing zpool status")
	}
	output = runZpoolCommand([]string{"list", "-H", "-o", "health", z.name})
	err = z.checkHealth(output)
	if err != nil {
		log.Fatal("Error parsing zpool list -H -o health ", z.name)
	}
	output = runZpoolCommand([]string{"list", "-H", "-o", "cap", z.name})
	err = z.getCapacity(output)
	if err != nil {
		log.Fatal("Error parsing zpool capacity")
	}
}

func checkExistance(pool string) (err error) {
	output := runZpoolCommand([]string{"list", pool})
	if strings.Contains(fmt.Sprintf("%s", output), "no such pool") {
		err = errors.New("No such pool")
	}
	return
}

func runZpoolCommand(args []string) string {
	zpoolPath, err := exec.LookPath("zpool")
	if err != nil {
		log.Fatal("Could not find zpool in PATH")
	}
	cmd := exec.Command(zpoolPath, args...)
	out, _ := cmd.CombinedOutput()
	return fmt.Sprintf("%s", out)
}

func main() {
	if versionCheck {
		fmt.Printf("nagios-zfs-go v%s (https://github.com/eripa/nagios-zfs-go)\n", toolVersion)
		os.Exit(0)
	}
	err := checkExistance(zfsPool)
	if err != nil {
		log.Fatal(err)
	}
	z := zpool{name: zfsPool}
	z.getStatus()
	message, exitcode := z.NagiosFormat()
	fmt.Println(message)
	os.Exit(exitcode)
}
<|endoftext|>


<commit_before>package frank

import (
	"code.google.com/p/go.net/html"
	"code.google.com/p/go.net/html/atom"
	irc "github.com/fluffle/goirc/client"
	"io"
	"log"
	"net"
	"net/http"
	"os/exec"
	"regexp"
	"strings"
	"time"
)

// how many URLs can the cache store
const cacheSize = 50

// how many hours an entry should be considered valid
const cacheValidHours = 12

// how many kilo bytes should be considered when looking for the title
// tag.
const httpReadKByte = 100

// abort HTTP requests if it takes longer than X seconds. Not sure, it’s
// definitely magic involved. Must be larger than 5.
const httpGetDeadline = 10

var ignoreDomainsRegex = regexp.MustCompile(`^http://p.nnev.de`)

func UriFind(conn *irc.Conn, line *irc.Line) {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("MEGA-WTF:pkg: %v", r)
		}
	}()

	msg := line.Args[1]

	urls := extract(msg)

	for _, url := range urls {
		if url == "" {
			continue
		}

		if title := findCache(url); title != "" {
			log.Printf("using cache for URL: %s", url)
			postTitle(conn, line, title, "Cache Info")
			continue
		}

		go func(url string) {
			if ignoreDomainsRegex.MatchString(url) {
				log.Printf("ignoring this URL: %s", url)
				return
			}

			log.Printf("testing URL: %s", url)
			title := titleGet(url)
			if title != "" {
				postTitle(conn, line, title, "")
				addCache(url, title)
			}
		}(url)
	}
}

// regexing ////////////////////////////////////////////////////////////

func extract(msg string) []string {
	find := exec.Command("./urifind", "-u")
	pipe, err := find.StdinPipe()
	if err != nil {
		log.Printf("WTF: couldn’t open stdin pipe to urifind: %s", err)
		return nil
	}
	pipe.Write([]byte(msg))
	pipe.Close()
	out, err := find.Output()
	if err != nil {
		log.Printf("WTF: urlfind failed with: %s", err)
		return nil
	}
	return strings.Split(strings.TrimSpace(string(out)), "\n")
}

// http/html stuff /////////////////////////////////////////////////////

func titleGet(url string) string {
	// via http://www.reddit.com/r/golang/comments/10awvj/timeout_on_httpget/c6bz49s
	c := http.Client{
		Transport: &http.Transport{
			Dial: func(netw, addr string) (net.Conn, error) {
				deadline := time.Now().Add(time.Second * httpGetDeadline)
				c, err := net.DialTimeout(netw, addr, time.Second*(httpGetDeadline-5))
				if err != nil {
					return nil, err
				}
				c.SetDeadline(deadline)
				return c, nil
			},
		},
	}

	r, err := c.Get(url)
	if err != nil {
		log.Printf("WTF: could not resolve %s: %s\n", url, err)
		return ""
	}
	defer r.Body.Close()

	// TODO: r.Body → utf8?
	title := titleParseHtml(io.LimitReader(r.Body, 1024*httpReadKByte))

	log.Printf("Title for URL %s: %s\n", url, title)
	return title
}

func titleParseHtml(r io.Reader) string {
	doc, err := html.Parse(r)
	if err != nil {
		log.Printf("WTF: html parser blew up: %s\r\n", err)
		return ""
	}

	title := ""

	var f func(*html.Node)
	f = func(n *html.Node) {
		if n.Type == html.ElementNode && n.DataAtom == atom.Title {
			title = ""
			for c := n.FirstChild; c != nil; c = c.NextSibling {
				if c.Type != html.TextNode {
					continue
				}
				title += c.Data
			}

		} else { // recurse down
			for c := n.FirstChild; c != nil; c = c.NextSibling {
				f(c)
			}
		}
	}
	f(doc)

	return strings.TrimSpace(title)
}

// Cache ///////////////////////////////////////////////////////////////
type Cache struct {
	url   string
	title string
	date  time.Time
}

var cache = [cacheSize]Cache{}
var cacheIndex = 0

func addCache(url string, title string) {
	if len(cache) == cacheIndex {
		cacheIndex = 0
	}
	cache[cacheIndex] = Cache{url, title, time.Now()}
	cacheIndex += 1
}

func findCache(url string) string {
	for _, cc := range cache {
		if cc.url == url && time.Since(cc.date).Hours() <= cacheValidHours {
			return cc.title
		}
	}
	return ""
}

// util ////////////////////////////////////////////////////////////////

func postTitle(conn *irc.Conn, line *irc.Line, title string, prefix string) {
	tgt := line.Args[0]

	log.Printf("nick=%s, target=%s, title=%s", line.Nick, tgt, title)
	// if target is our current nick, it was a private message.
	// Answer the users in this case.
	if tgt == conn.Me.Nick {
		tgt = line.Nick
	}
	if prefix == "" {
		prefix = "Link Info"
	}
	// use notice instead of PrivMsg to avoid bots answering each other
	conn.Notice(tgt, "["+prefix+"] "+title)
}
<commit_msg>replace newlines (upstream doesn’t escape /o\)<commit_after>package frank

import (
	"code.google.com/p/go.net/html"
	"code.google.com/p/go.net/html/atom"
	irc "github.com/fluffle/goirc/client"
	"io"
	"log"
	"net"
	"net/http"
	"os/exec"
	"regexp"
	"strings"
	"time"
)

// how many URLs can the cache store
const cacheSize = 50

// how many hours an entry should be considered valid
const cacheValidHours = 12

// how many kilo bytes should be considered when looking for the title
// tag.
const httpReadKByte = 100

// abort HTTP requests if it takes longer than X seconds. Not sure, it’s
// definitely magic involved. Must be larger than 5.
const httpGetDeadline = 10

// new line replace regex
var newlineReplacer = regexp.MustCompile(`\s+`)

var ignoreDomainsRegex = regexp.MustCompile(`^http://p.nnev.de`)

func UriFind(conn *irc.Conn, line *irc.Line) {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("MEGA-WTF:pkg: %v", r)
		}
	}()

	msg := line.Args[1]

	urls := extract(msg)

	for _, url := range urls {
		if url == "" {
			continue
		}

		if title := findCache(url); title != "" {
			log.Printf("using cache for URL: %s", url)
			postTitle(conn, line, title, "Cache Info")
			continue
		}

		go func(url string) {
			if ignoreDomainsRegex.MatchString(url) {
				log.Printf("ignoring this URL: %s", url)
				return
			}

			log.Printf("testing URL: %s", url)
			title := titleGet(url)
			if title != "" {
				postTitle(conn, line, title, "")
				addCache(url, title)
			}
		}(url)
	}
}

// regexing ////////////////////////////////////////////////////////////

func extract(msg string) []string {
	find := exec.Command("./urifind", "-u")
	pipe, err := find.StdinPipe()
	if err != nil {
		log.Printf("WTF: couldn’t open stdin pipe to urifind: %s", err)
		return nil
	}
	pipe.Write([]byte(msg))
	pipe.Close()
	out, err := find.Output()
	if err != nil {
		log.Printf("WTF: urlfind failed with: %s", err)
		return nil
	}
	return strings.Split(strings.TrimSpace(string(out)), "\n")
}

// http/html stuff /////////////////////////////////////////////////////

func titleGet(url string) string {
	// via http://www.reddit.com/r/golang/comments/10awvj/timeout_on_httpget/c6bz49s
	c := http.Client{
		Transport: &http.Transport{
			Dial: func(netw, addr string) (net.Conn, error) {
				deadline := time.Now().Add(time.Second * httpGetDeadline)
				c, err := net.DialTimeout(netw, addr, time.Second*(httpGetDeadline-5))
				if err != nil {
					return nil, err
				}
				c.SetDeadline(deadline)
				return c, nil
			},
		},
	}

	r, err := c.Get(url)
	if err != nil {
		log.Printf("WTF: could not resolve %s: %s\n", url, err)
		return ""
	}
	defer r.Body.Close()

	// TODO: r.Body → utf8?
	title := titleParseHtml(io.LimitReader(r.Body, 1024*httpReadKByte))
	title = newlineReplacer.ReplaceAllString(title, " ")

	log.Printf("Title for URL %s: %s\n", url, title)
	return title
}

func titleParseHtml(r io.Reader) string {
	doc, err := html.Parse(r)
	if err != nil {
		log.Printf("WTF: html parser blew up: %s\r\n", err)
		return ""
	}

	title := ""

	var f func(*html.Node)
	f = func(n *html.Node) {
		if n.Type == html.ElementNode && n.DataAtom == atom.Title {
			title = ""
			for c := n.FirstChild; c != nil; c = c.NextSibling {
				if c.Type != html.TextNode {
					continue
				}
				title += c.Data
			}

		} else { // recurse down
			for c := n.FirstChild; c != nil; c = c.NextSibling {
				f(c)
			}
		}
	}
	f(doc)

	return strings.TrimSpace(title)
}

// Cache ///////////////////////////////////////////////////////////////
type Cache struct {
	url   string
	title string
	date  time.Time
}

var cache = [cacheSize]Cache{}
var cacheIndex = 0

func addCache(url string, title string) {
	if len(cache) == cacheIndex {
		cacheIndex = 0
	}
	cache[cacheIndex] = Cache{url, title, time.Now()}
	cacheIndex += 1
}

func findCache(url string) string {
	for _, cc := range cache {
		if cc.url == url && time.Since(cc.date).Hours() <= cacheValidHours {
			return cc.title
		}
	}
	return ""
}

// util ////////////////////////////////////////////////////////////////

func postTitle(conn *irc.Conn, line *irc.Line, title string, prefix string) {
	tgt := line.Args[0]

	log.Printf("nick=%s, target=%s, title=%s", line.Nick, tgt, title)
	// if target is our current nick, it was a private message.
	// Answer the users in this case.
	if tgt == conn.Me.Nick {
		tgt = line.Nick
	}
	if prefix == "" {
		prefix = "Link Info"
	}
	// use notice instead of PrivMsg to avoid bots answering each other
	conn.Notice(tgt, "["+prefix+"] "+title)
}
<|endoftext|>


<commit_before>//  Copyright (c) 2014 Couchbase, Inc.

package gofast

import "compress/lzw"
import "bytes"
import "io"

func make_lzw(t *Transport, config map[string]interface{}) (uint64, tagfn, tagfn) {
	enc := func(in, out []byte) int {
		wbuf := bytes.NewBuffer(out[:])
		writer := lzw.NewWriter(wbuf, lzw.LSB, 8 /*litWidth*/)
		_, err := writer.Write(in)
		if err != nil {
			panic(err)
		}
		writer.Close()
		return copy(out, wbuf.Bytes())
	}
	dec := func(in, out []byte) int {
		reader := lzw.NewReader(bytes.NewReader(in), lzw.LSB, 8 /*litWidth*/)
		n, err := io.ReadFull(reader, out)
		if err != nil {
			panic(err)
		}
		return n
	}
	return tagLzw, enc, dec
}

func init() {
	tag_factory["lzw"] = make_lzw
}
<commit_msg>bug fixes to tag_lzw.<commit_after>//  Copyright (c) 2014 Couchbase, Inc.

package gofast

import "compress/lzw"
import "bytes"
import "io"

func make_lzw(t *Transport, config map[string]interface{}) (uint64, tagfn, tagfn) {
	var wbuf bytes.Buffer
	enc := func(in, out []byte) int {
		if len(in) == 0 {
			return 0
		}
		wbuf.Reset()
		writer := lzw.NewWriter(&wbuf, lzw.LSB, 8 /*litWidth*/)
		if _, err := writer.Write(in); err != nil {
			panic(err)
		}
		writer.Close()
		return copy(out, wbuf.Bytes())
	}
	dec := func(in, out []byte) int {
		if len(in) == 0 {
			return 0
		}
		reader := lzw.NewReader(bytes.NewReader(in), lzw.LSB, 8 /*litWidth*/)
		n, err := readAll(reader, out)
		if err != nil {
			panic(err)
		}
		reader.Close()
		return n
	}
	return tagLzw, enc, dec
}

func readAll(r io.Reader, out []byte) (n int, err error) {
	c := 0
	for err == nil {
		// Per http://golang.org/pkg/io/#Reader, it is valid for Read to
		// return EOF with non-zero number of bytes at the end of the
		// input stream
		c, err = r.Read(out[n:])
		n += c
	}
	if err == io.EOF {
		return n, nil
	}
	return n, err
}

func init() {
	tag_factory["lzw"] = make_lzw
}
<|endoftext|>


<commit_before>// +build clamav

package bot

// This file handles the ClamAV integration and is only built when specifying -tags clamav to build
// On OSX, you do the following to get all set up - you need of course Xcode and the command line tools
// See http://www.gctv.ne.jp/~yokota/clamav/
// 1. Download the latest stable version of ClamAV and extract it to ~/demisto/clamav-0.98.7 (version might change)
// 2. cd ~/demisto/clamav-0.98.7
// 3. CFLAGS="-O3 -march=nocona" CXXFLAGS="-O3 -march=nocona" ./configure --build=x86_64-apple-darwin`uname -r` --enable-llvm=no
// 4. CFLAGS="-O3 -march=nocona" CXXFLAGS="-O3 -march=nocona" make
// 5. CFLAGS="-O3 -march=nocona" CXXFLAGS="-O3 -march=nocona" make check
// 6. CGO_CFLAGS=-I/Users/YOURUSERNAME/demisto/clamav-0.98.7/libclamav CGO_LDFLAGS=-L/Users/YOURUSERNAME/demisto/clamav-0.98.7/libclamav/.libs go get github.com/mirtchovski/clamav
// Notice in the above to replace to your username as well as the actual version of clamav
// Now, download the current database
// 7. curl http://database.clamav.net/main.cvd > main.cvd
// 8. curl http://database.clamav.net/daily.cvd > daily.cvd
// 9. curl http://database.clamav.net/bytecode.cvd > bytecode.cvd
// Now, you are ready to build alfred with the clamav tag and run it with the DB directory location pointing to ~/demisto/clamav-0.98.7
// DYLD_LIBRARY_PATH=/Users/YOURUSERNAME/demisto/clamav-0.98.7/libclamav/.libs ./alfred --loglevel=debug --clamdb=/Users/YOURUSERNAME/demisto/clamav-0.98.7

// On Ubuntu, it's all very simple. Just sudo apt-get install clamav libclamav6 libclamav-dev and no need for flags, etc.

import (
	"bytes"
	"flag"
	"io"
	"net"
	"os"
	"sync"

	"github.com/Sirupsen/logrus"
	"github.com/demisto/alfred/conf"
	"github.com/mirtchovski/clamav"
)

var (
	clamdb = flag.String("clamdb", clamav.DBDir(), "Directory where we can find the ClamAV definition database")
)

type clamEngine struct {
	engine *clamav.Engine
	l      net.Listener
	mu     sync.Mutex
}

func newClamEngine() (*clamEngine, error) {
	err := clamav.Init(clamav.InitDefault)
	if err != nil {
		return nil, err
	}
	l, err := net.Listen("unix", conf.Options.ClamCtl)
	if err != nil {
		return nil, err
	}
	os.Chmod(conf.Options.ClamCtl, 0666)
	ce := &clamEngine{engine: clamav.New()}
	err = ce.loadSigs()
	if err != nil {
		return nil, err
	}
	ce.l = l
	go ce.listenUpdate()
	return ce, nil
}

func (ce *clamEngine) loadSigs() error {
	ce.mu.Lock()
	defer ce.mu.Unlock()
	sigs, err := ce.engine.Load(*clamdb, clamav.DbStdopt)
	if err != nil {
		logrus.Errorf("Cannot initialize ClamAV engine: %v", err)
		return err
	}
	logrus.Debugf("Loaded %d signatures", sigs)
	ce.engine.Compile()
	return nil
}

func (ce *clamEngine) listenUpdate() {
	for {
		c, err := ce.l.Accept()
		if err != nil {
			logrus.Debugf("Shutting down ClamAV engine update - %v", err)
			break
		}
		logrus.Debug("Updating ClamAV engine signatures")
		b := &bytes.Buffer{}
		_, err = io.Copy(b, c)
		logrus.Debug("Reading input...")
		if err != nil {
			logrus.Errorf("Error updating from freshclam - %v\n", err)
			continue
		}
		reload := b.String()
		if reload != "RELOAD" {
			logrus.Infof("Weird - got %s from freshclam\n", reload)
		}
		logrus.Debug("Writing RELOADING...")
		_, err = c.Write([]byte("RELOADING"))
		if err != nil {
			logrus.Infof("Error updating freshclam - %v\n", err)
		}
		logrus.Debug("Closing...")
		c.Close()
		logrus.Debug("Reloading signatures...")
		if err = ce.loadSigs(); err != nil {
			logrus.Errorf("Error reloading, stopping loop: %v", err)
			break
		}
	}
}

func (ce *clamEngine) close() {
	ce.l.Close()
	os.Remove(conf.Options.ClamCtl)
	ce.engine.Free()
}

// scan the given bytes (file) using clamav and return the virus name
func (ce *clamEngine) scan(filename string, b []byte) (string, error) {
	ce.mu.Lock()
	defer ce.mu.Unlock()
	fmap := clamav.OpenMemory(b)
	defer clamav.CloseMemory(fmap)

	virus, _, err := ce.engine.ScanMapCb(fmap, clamav.ScanStdopt|clamav.ScanBlockbroken, filename)
	return virus, err
}
<commit_msg>Another minor clamav fix<commit_after>// +build clamav

package bot

// This file handles the ClamAV integration and is only built when specifying -tags clamav to build
// On OSX, you do the following to get all set up - you need of course Xcode and the command line tools
// See http://www.gctv.ne.jp/~yokota/clamav/
// 1. Download the latest stable version of ClamAV and extract it to ~/demisto/clamav-0.98.7 (version might change)
// 2. cd ~/demisto/clamav-0.98.7
// 3. CFLAGS="-O3 -march=nocona" CXXFLAGS="-O3 -march=nocona" ./configure --build=x86_64-apple-darwin`uname -r` --enable-llvm=no
// 4. CFLAGS="-O3 -march=nocona" CXXFLAGS="-O3 -march=nocona" make
// 5. CFLAGS="-O3 -march=nocona" CXXFLAGS="-O3 -march=nocona" make check
// 6. CGO_CFLAGS=-I/Users/YOURUSERNAME/demisto/clamav-0.98.7/libclamav CGO_LDFLAGS=-L/Users/YOURUSERNAME/demisto/clamav-0.98.7/libclamav/.libs go get github.com/mirtchovski/clamav
// Notice in the above to replace to your username as well as the actual version of clamav
// Now, download the current database
// 7. curl http://database.clamav.net/main.cvd > main.cvd
// 8. curl http://database.clamav.net/daily.cvd > daily.cvd
// 9. curl http://database.clamav.net/bytecode.cvd > bytecode.cvd
// Now, you are ready to build alfred with the clamav tag and run it with the DB directory location pointing to ~/demisto/clamav-0.98.7
// DYLD_LIBRARY_PATH=/Users/YOURUSERNAME/demisto/clamav-0.98.7/libclamav/.libs ./alfred --loglevel=debug --clamdb=/Users/YOURUSERNAME/demisto/clamav-0.98.7

// On Ubuntu, it's all very simple. Just sudo apt-get install clamav libclamav6 libclamav-dev and no need for flags, etc.

import (
	"bytes"
	"flag"
	"io"
	"net"
	"os"
	"sync"

	"github.com/Sirupsen/logrus"
	"github.com/demisto/alfred/conf"
	"github.com/mirtchovski/clamav"
)

var (
	clamdb = flag.String("clamdb", clamav.DBDir(), "Directory where we can find the ClamAV definition database")
)

type clamEngine struct {
	engine *clamav.Engine
	l      net.Listener
	mu     sync.Mutex
}

func newClamEngine() (*clamEngine, error) {
	err := clamav.Init(clamav.InitDefault)
	if err != nil {
		return nil, err
	}
	l, err := net.Listen("unix", conf.Options.ClamCtl)
	if err != nil {
		return nil, err
	}
	os.Chmod(conf.Options.ClamCtl, 0666)
	ce := &clamEngine{engine: clamav.New()}
	err = ce.loadSigs()
	if err != nil {
		return nil, err
	}
	ce.l = l
	go ce.listenUpdate()
	return ce, nil
}

func (ce *clamEngine) loadSigs() error {
	ce.mu.Lock()
	defer ce.mu.Unlock()
	sigs, err := ce.engine.Load(*clamdb, clamav.DbStdopt)
	if err != nil {
		logrus.Errorf("Cannot initialize ClamAV engine: %v", err)
		return err
	}
	logrus.Debugf("Loaded %d signatures", sigs)
	ce.engine.Compile()
	return nil
}

func (ce *clamEngine) listenUpdate() {
	for {
		c, err := ce.l.Accept()
		if err != nil {
			logrus.Debugf("Shutting down ClamAV engine update - %v", err)
			break
		}
		logrus.Debug("Updating ClamAV engine signatures")
		b := &bytes.Buffer{}
		logrus.Debug("Reading input...")
		_, err = io.CopyN(b, c, 7)
		if err != nil {
			logrus.Errorf("Error updating from freshclam - %v\n", err)
			continue
		}
		reload := b.String()
		if reload != "RELOAD\n" {
			logrus.Infof("Weird - got %s from freshclam\n", reload)
		}
		logrus.Debug("Writing RELOADING...")
		_, err = c.Write([]byte("RELOADING"))
		if err != nil {
			logrus.Infof("Error updating freshclam - %v\n", err)
		}
		logrus.Debug("Closing...")
		c.Close()
		logrus.Debug("Reloading signatures...")
		if err = ce.loadSigs(); err != nil {
			logrus.Errorf("Error reloading, stopping loop: %v", err)
			break
		}
	}
}

func (ce *clamEngine) close() {
	ce.l.Close()
	os.Remove(conf.Options.ClamCtl)
	ce.engine.Free()
}

// scan the given bytes (file) using clamav and return the virus name
func (ce *clamEngine) scan(filename string, b []byte) (string, error) {
	ce.mu.Lock()
	defer ce.mu.Unlock()
	fmap := clamav.OpenMemory(b)
	defer clamav.CloseMemory(fmap)

	virus, _, err := ce.engine.ScanMapCb(fmap, clamav.ScanStdopt|clamav.ScanBlockbroken, filename)
	return virus, err
}
<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.

package tar

import (
	"archive/tar"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
)

// TarFiles writes a tar stream into target holding the files listed
// in fileList. strip will be removed from the beginning of all the paths
// when stored (much like gnu tar -C option)
// Returns a Sha sum of the tar and nil if everything went well
// or empty sting and error in case of error.
// We use a base64 encoded sha1 hash, because this is the hash
// used by RFC 3230 Digest headers in http responses
func TarFiles(fileList []string, target io.Writer, strip string) (shaSum string, err error) {
	shahash := sha1.New()
	if err := tarAndHashFiles(fileList, target, strip, shahash); err != nil {
		return "", err
	}
	encodedHash := base64.StdEncoding.EncodeToString(shahash.Sum(nil))
	return encodedHash, nil
}

func tarAndHashFiles(fileList []string, target io.Writer, strip string, hashw io.Writer) (err error) {
	checkClose := func(w io.Closer) {
		if closeErr := w.Close(); closeErr != nil && err == nil {
			err = fmt.Errorf("error closing tar writer: %v", closeErr)
		}
	}

	w := io.MultiWriter(target, hashw)
	tarw := tar.NewWriter(w)
	defer checkClose(tarw)
	for _, ent := range fileList {
		if err := writeContents(ent, strip, tarw); err != nil {
			return fmt.Errorf("write to tar file failed: %v", err)
		}
	}
	return nil
}

// writeContents creates an entry for the given file
// or directory in the given tar archive.
func writeContents(fileName, strip string, tarw *tar.Writer) error {
	f, err := os.Open(fileName)
	if err != nil {
		return err
	}
	defer f.Close()
	fInfo, err := f.Stat()
	if err != nil {
		return err
	}
	h, err := tar.FileInfoHeader(fInfo, "")
	if err != nil {
		return fmt.Errorf("cannot create tar header for %q: %v", fileName, err)
	}
	h.Name = filepath.ToSlash(strings.TrimPrefix(fileName, strip))
	if err := tarw.WriteHeader(h); err != nil {
		return fmt.Errorf("cannot write header for %q: %v", fileName, err)
	}
	if !fInfo.IsDir() {
		if _, err := io.Copy(tarw, f); err != nil {
			return fmt.Errorf("failed to write %q: %v", fileName, err)
		}
		return nil
	}
	if !strings.HasSuffix(fileName, string(os.PathSeparator)) {
		fileName = fileName + string(os.PathSeparator)
	}

	for {
		names, err := f.Readdirnames(100)
		// will return at most 100 names and if less than 100 remaining
		// next call will return io.EOF and no names
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return fmt.Errorf("error reading directory %q: %v", fileName, err)
		}
		for _, name := range names {
			if err := writeContents(filepath.Join(fileName, name), strip, tarw); err != nil {
				return err
			}
		}
	}

}

// UntarFiles will extract the contents of tarFile using
// outputFolder as root
func UntarFiles(tarFile io.Reader, outputFolder string) error {
	tr := tar.NewReader(tarFile)
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			// end of tar archive
			break
		}
		if err != nil {
			return fmt.Errorf("failed while reading tar header: %v", err)
		}
		fullPath := filepath.Join(outputFolder, hdr.Name)
		if hdr.Typeflag == tar.TypeDir {
			if err = os.MkdirAll(fullPath, os.FileMode(hdr.Mode)); err != nil {
				return fmt.Errorf("cannot extract directory %q: %v", fullPath, err)
			}
			continue
		}
		if err != nil {
			return fmt.Errorf("failed while reading tar contents: %v", err)
		}
		fh, err := os.Create(fullPath)
		if err != nil {
			return fmt.Errorf("some of the tar contents cannot be written to disk: %v", err)
		}
		_, err = io.Copy(fh, tr)
		if err != nil {
			fh.Close()
			return fmt.Errorf("failed while reading tar contents: %v", err)
		}
		err = fh.Chmod(os.FileMode(hdr.Mode))
		fh.Close()
		if err != nil {
			return fmt.Errorf("cannot set proper mode on file %q: %v", fullPath, err)
		}

	}
	return nil
}
<commit_msg>Small corrections from review comments<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.

package tar

import (
	"archive/tar"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
)

// TarFiles writes a tar stream into target holding the files listed
// in fileList. strip will be removed from the beginning of all the paths
// when stored (much like gnu tar -C option)
// Returns a Sha sum of the tar and nil if everything went well
// or empty sting and error in case of error.
// We use a base64 encoded sha1 hash, because this is the hash
// used by RFC 3230 Digest headers in http responses
func TarFiles(fileList []string, target io.Writer, strip string) (shaSum string, err error) {
	shahash := sha1.New()
	if err := tarAndHashFiles(fileList, target, strip, shahash); err != nil {
		return "", err
	}
	encodedHash := base64.StdEncoding.EncodeToString(shahash.Sum(nil))
	return encodedHash, nil
}

func tarAndHashFiles(fileList []string, target io.Writer, strip string, hashw io.Writer) (err error) {
	checkClose := func(w io.Closer) {
		if closeErr := w.Close(); closeErr != nil && err == nil {
			err = fmt.Errorf("error closing tar writer: %v", closeErr)
		}
	}

	w := io.MultiWriter(target, hashw)
	tarw := tar.NewWriter(w)
	defer checkClose(tarw)
	for _, ent := range fileList {
		if err := writeContents(ent, strip, tarw); err != nil {
			return fmt.Errorf("write to tar file failed: %v", err)
		}
	}
	return nil
}

// writeContents creates an entry for the given file
// or directory in the given tar archive.
func writeContents(fileName, strip string, tarw *tar.Writer) error {
	f, err := os.Open(fileName)
	if err != nil {
		return err
	}
	defer f.Close()
	fInfo, err := f.Stat()
	if err != nil {
		return err
	}
	h, err := tar.FileInfoHeader(fInfo, "")
	if err != nil {
		return fmt.Errorf("cannot create tar header for %q: %v", fileName, err)
	}
	h.Name = filepath.ToSlash(strings.TrimPrefix(fileName, strip))
	if err := tarw.WriteHeader(h); err != nil {
		return fmt.Errorf("cannot write header for %q: %v", fileName, err)
	}
	if !fInfo.IsDir() {
		if _, err := io.Copy(tarw, f); err != nil {
			return fmt.Errorf("failed to write %q: %v", fileName, err)
		}
		return nil
	}

	for {
		names, err := f.Readdirnames(100)
		// will return at most 100 names and if less than 100 remaining
		// next call will return io.EOF and no names
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return fmt.Errorf("error reading directory %q: %v", fileName, err)
		}
		for _, name := range names {
			if err := writeContents(filepath.Join(fileName, name), strip, tarw); err != nil {
				return err
			}
		}
	}

}

func createAndFill(filePath string, mode int64, content io.Reader) error {
	fh, err := os.Create(filePath)
	defer fh.Close()
	if err != nil {
		return fmt.Errorf("some of the tar contents cannot be written to disk: %v", err)
	}
	_, err = io.Copy(fh, content)
	if err != nil {
		return fmt.Errorf("failed while reading tar contents: %v", err)
	}
	err = fh.Chmod(os.FileMode(mode))
	if err != nil {
		return fmt.Errorf("cannot set proper mode on file %q: %v", filePath, err)
	}
	return nil
}

// UntarFiles will extract the contents of tarFile using
// outputFolder as root
func UntarFiles(tarFile io.Reader, outputFolder string) error {
	tr := tar.NewReader(tarFile)
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			// end of tar archive
			return nil
		}
		if err != nil {
			return fmt.Errorf("failed while reading tar header: %v", err)
		}
		fullPath := filepath.Join(outputFolder, hdr.Name)
		if hdr.Typeflag == tar.TypeDir {
			if err = os.MkdirAll(fullPath, os.FileMode(hdr.Mode)); err != nil {
				return fmt.Errorf("cannot extract directory %q: %v", fullPath, err)
			}
			continue
		}
		if err = createAndFill(fullPath, hdr.Mode, tr); err != nil {
			return fmt.Errorf("cannot extract file %q: %v", fullPath, err)
		}

	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2020 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package casbin

import (
	"encoding/json"
	"testing"
)

func contains(arr []string, target string) bool {
	for _, item := range arr {
		if item == target {
			return true
		}
	}
	return false
}

func TestCasbinJsGetPermissionForUser(t *testing.T) {
	e, err := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
	if err != nil {
		panic(err)
	}
	target_str, _ := CasbinJsGetPermissionForUser(e, "alice")
	t.Log("GetPermissionForUser Alice", string(target_str))
	alice_target := make(map[string][]string)
	err = json.Unmarshal(target_str, &alice_target)
	if err != nil {
		t.Errorf("Test error: %s", err)
	}
	perm, ok := alice_target["read"]
	if !ok {
		t.Errorf("Test error: Alice doesn't have read permission")
	}
	if !contains(perm, "data1") {
		t.Errorf("Test error: Alice cannot read data1")
	}
	if !contains(perm, "data2") {
		t.Errorf("Test error: Alice cannot read data2")
	}
	perm, ok = alice_target["write"]
	if !ok {
		t.Errorf("Test error: Alice doesn't have write permission")
	}
	if contains(perm, "data1") {
		t.Errorf("Test error: Alice can write data1")
	}
	if !contains(perm, "data2") {
		t.Errorf("Test error: Alice cannot write data2")
	}

	target_str, _ = CasbinJsGetPermissionForUser(e, "bob")
	t.Log("GetPermissionForUser Bob", string(target_str))
	bob_target := make(map[string][]string)
	err = json.Unmarshal(target_str, &bob_target)
	if err != nil {
		t.Errorf("Test error: %s", err)
	}
	_, ok = bob_target["read"]
	if ok {
		t.Errorf("Test error: Bob has read permission")
	}
	perm, ok = bob_target["write"]
	if !ok {
		t.Errorf("Test error: Bob doesn't have permission")
	}
	if !contains(perm, "data2") {
		t.Errorf("Test error: Bob cannot write data2")
	}
	if contains(perm, "data1") {
		t.Errorf("Test error: Bob can write data1")
	}
	if contains(perm, "data_not_exist") {
		t.Errorf("Test error: Bob can access a non-existing data")
	}

	_, ok = bob_target["rm_rf"]
	if ok {
		t.Errorf("Someone can have a non-existing action (rm -rf)")
	}
}

func TestCasbinJsGetPermissionForUser2(t *testing.T) {
	e, err := NewSyncedEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
	if err != nil {
		panic(err)
	}
	target_str, _ := CasbinJsGetPermissionForUser(e, "alice")
	t.Log("GetPermissionForUser Alice", string(target_str))
	alice_target := make(map[string][]string)
	err = json.Unmarshal(target_str, &alice_target)
	if err != nil {
		t.Errorf("Test error: %s", err)
	}
	perm, ok := alice_target["read"]
	if !ok {
		t.Errorf("Test error: Alice doesn't have read permission")
	}
	if !contains(perm, "data1") {
		t.Errorf("Test error: Alice cannot read data1")
	}
	if !contains(perm, "data2") {
		t.Errorf("Test error: Alice cannot read data2")
	}
	perm, ok = alice_target["write"]
	if !ok {
		t.Errorf("Test error: Alice doesn't have write permission")
	}
	if contains(perm, "data1") {
		t.Errorf("Test error: Alice can write data1")
	}
	if !contains(perm, "data2") {
		t.Errorf("Test error: Alice cannot write data2")
	}

	target_str, _ = CasbinJsGetPermissionForUser(e, "bob")
	t.Log("GetPermissionForUser Bob", string(target_str))
	bob_target := make(map[string][]string)
	err = json.Unmarshal(target_str, &bob_target)
	if err != nil {
		t.Errorf("Test error: %s", err)
	}
	_, ok = bob_target["read"]
	if ok {
		t.Errorf("Test error: Bob has read permission")
	}
	perm, ok = bob_target["write"]
	if !ok {
		t.Errorf("Test error: Bob doesn't have permission")
	}
	if !contains(perm, "data2") {
		t.Errorf("Test error: Bob cannot write data2")
	}
	if contains(perm, "data1") {
		t.Errorf("Test error: Bob can write data1")
	}
	if contains(perm, "data_not_exist") {
		t.Errorf("Test error: Bob can access a non-existing data")
	}

	_, ok = bob_target["rm_rf"]
	if ok {
		t.Errorf("Someone can have a non-existing action (rm -rf)")
	}
}
<commit_msg>test: Remove useless tests<commit_after>// Copyright 2020 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package casbin

import (
	"encoding/json"
	"testing"
)

func contains(arr []string, target string) bool {
	for _, item := range arr {
		if item == target {
			return true
		}
	}
	return false
}

func TestCasbinJsGetPermissionForUser(t *testing.T) {
	e, err := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
	if err != nil {
		panic(err)
	}
	target_str, _ := CasbinJsGetPermissionForUser(e, "alice")
	t.Log("GetPermissionForUser Alice", string(target_str))
	alice_target := make(map[string][]string)
	err = json.Unmarshal(target_str, &alice_target)
	if err != nil {
		t.Errorf("Test error: %s", err)
	}
	perm, ok := alice_target["read"]
	if !ok {
		t.Errorf("Test error: Alice doesn't have read permission")
	}
	if !contains(perm, "data1") {
		t.Errorf("Test error: Alice cannot read data1")
	}
	if !contains(perm, "data2") {
		t.Errorf("Test error: Alice cannot read data2")
	}
	perm, ok = alice_target["write"]
	if !ok {
		t.Errorf("Test error: Alice doesn't have write permission")
	}
	if contains(perm, "data1") {
		t.Errorf("Test error: Alice can write data1")
	}
	if !contains(perm, "data2") {
		t.Errorf("Test error: Alice cannot write data2")
	}

	target_str, _ = CasbinJsGetPermissionForUser(e, "bob")
	t.Log("GetPermissionForUser Bob", string(target_str))
	bob_target := make(map[string][]string)
	err = json.Unmarshal(target_str, &bob_target)
	if err != nil {
		t.Errorf("Test error: %s", err)
	}
	_, ok = bob_target["read"]
	if ok {
		t.Errorf("Test error: Bob has read permission")
	}
	perm, ok = bob_target["write"]
	if !ok {
		t.Errorf("Test error: Bob doesn't have permission")
	}
	if !contains(perm, "data2") {
		t.Errorf("Test error: Bob cannot write data2")
	}
	if contains(perm, "data1") {
		t.Errorf("Test error: Bob can write data1")
	}
	if contains(perm, "data_not_exist") {
		t.Errorf("Test error: Bob can access a non-existing data")
	}

	_, ok = bob_target["rm_rf"]
	if ok {
		t.Errorf("Someone can have a non-existing action (rm -rf)")
	}
}

func TestCasbinJsGetPermissionForUser2(t *testing.T) {
	e, err := NewSyncedEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
	if err != nil {
		panic(err)
	}
	_, _ = CasbinJsGetPermissionForUser(e, "alice") // make sure CasbinJsGetPermissionForUser can be used with a SyncedEnforcer.
}
<|endoftext|>


<commit_before>package proxy

import (
	log "github.com/Sirupsen/logrus"
	"github.com/aofry/go-tee/util"
	"github.com/vulcand/oxy/forward"
	"github.com/vulcand/oxy/utils"
	"io"
	"net/http"
)

type Tee struct {
	errHandler   utils.ErrorHandler
	next         http.Handler
	reqHeaders   []string
	respHeaders  []string
	writer       io.Writer
	requests     chan *http.Request
	debugForward *forward.Forwarder
	debugHost    string
}

type Option func(*Tee) error

func New(next http.Handler) (*Tee, error) {
	//TODO add external param for concurrent limit
	concurrentLimit := 1

	requestsChan := make(chan *http.Request, concurrentLimit)

	//not sending setters so no errors expected
	fw, _ := forward.New()

	t := &Tee{
		next:         next,
		requests:     requestsChan,
		debugForward: fw,
		debugHost:    util.GetenvNoDefault("DEBUG_BACKEND"),
	}

	if t.errHandler == nil {
		t.errHandler = utils.DefaultHandler
	}

	//proxy := http.HandlerFunc(DebugHandler)

	return t, nil
}

func (t *Tee) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	pw := &utils.ProxyWriter{W: w}
	log.Info("Now I'm before the real proxy")
	t.next.ServeHTTP(pw, req)
	log.Info("Now I'm after the real proxy. ", pw.StatusCode(), " ")

	//limit the actual requests that are going out
	if len(t.requests) < cap(t.requests) {
		t.requests <- req
		go t.sendDebugRequest()
	}

}

func (t *Tee) sendDebugRequest() {
	request := <-t.requests

	w := &DummyResponseWriter{}
	//clone request so the original can be free to GC and debug is completly independent
	newRequest := t.copyRequest(request, t.debugHost)
	log.Info(newRequest.Host)
	t.debugForward.ServeHTTP(w, newRequest)
	log.Info("Sent request to debug backend")
}

func (f *Tee) copyRequest(req *http.Request, host string) *http.Request {
	outReq := new(http.Request)
	*outReq = *req // includes shallow copies of maps, but we handle this below

	outReq.URL = utils.CopyURL(req.URL)
	outReq.URL.Host = host
	outReq.Host = host
	outReq.RequestURI = req.RequestURI
	outReq.URL.Opaque = req.RequestURI
	// raw query is already included in RequestURI, so ignore it to avoid dupes
	outReq.URL.RawQuery = ""

	outReq.Proto = "HTTP/1.1"
	outReq.ProtoMajor = 1
	outReq.ProtoMinor = 1

	// Overwrite close flag so we can keep persistent connection for the backend servers
	outReq.Close = false

	outReq.Header = make(http.Header)
	utils.CopyHeaders(outReq.Header, req.Header)

	return outReq
}
<commit_msg>fixed a pointer bug<commit_after>package proxy

import (
	log "github.com/Sirupsen/logrus"
	"github.com/aofry/go-tee/util"
	"github.com/vulcand/oxy/forward"
	"github.com/vulcand/oxy/utils"
	"io"
	"net/http"
)

type Tee struct {
	errHandler   utils.ErrorHandler
	next         http.Handler
	reqHeaders   []string
	respHeaders  []string
	writer       io.Writer
	requests     chan *http.Request
	debugForward *forward.Forwarder
	debugHost    string
}

type Option func(*Tee) error

func New(next http.Handler) (*Tee, error) {
	//TODO add external param for concurrent limit
	concurrentLimit := 1

	requestsChan := make(chan *http.Request, concurrentLimit)

	//not sending setters so no errors expected
	fw, _ := forward.New()

	t := &Tee{
		next:         next,
		requests:     requestsChan,
		debugForward: fw,
		debugHost:    util.GetenvNoDefault("DEBUG_BACKEND"),
	}

	if t.errHandler == nil {
		t.errHandler = utils.DefaultHandler
	}

	//proxy := http.HandlerFunc(DebugHandler)

	return t, nil
}

func (t *Tee) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	pw := &utils.ProxyWriter{W: w}
	log.Info("Now I'm before the real proxy")
	t.next.ServeHTTP(pw, req)
	log.Info("Now I'm after the real proxy. ", pw.StatusCode(), " ")

	//limit the actual requests that are going out
	if len(t.requests) < cap(t.requests) {
		t.requests <- req
		go t.sendDebugRequest()
	}

}

func (t *Tee) sendDebugRequest() {
	request := <-t.requests

	w := &DummyResponseWriter{}
	//clone request so the original can be free to GC and debug is completly independent
	newRequest := t.copyRequest(request, t.debugHost)
	log.Info(newRequest.Host)
	t.debugForward.ServeHTTP(w, newRequest)
	log.Info("Sent request to debug backend")
}

func (f *Tee) copyRequest(req *http.Request, host string) *http.Request {
	outReq := new(http.Request)
	//*outReq = *req // includes shallow copies of maps, but we handle this below

	outReq.URL = utils.CopyURL(req.URL)
	outReq.URL.Host = host
	outReq.Host = host
	outReq.RequestURI = req.RequestURI
	outReq.URL.Opaque = req.RequestURI
	// raw query is already included in RequestURI, so ignore it to avoid dupes
	outReq.URL.RawQuery = ""

	outReq.Proto = "HTTP/1.1"
	outReq.ProtoMajor = 1
	outReq.ProtoMinor = 1

	// Overwrite close flag so we can keep persistent connection for the backend servers
	outReq.Close = false

	outReq.Header = make(http.Header)
	utils.CopyHeaders(outReq.Header, req.Header)

	return outReq
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package vision

import (
	"image/color"
	"math"

	vkit "cloud.google.com/go/vision/apiv1"
	"golang.org/x/net/context"
	"google.golang.org/api/option"
	pb "google.golang.org/genproto/googleapis/cloud/vision/v1"
	cpb "google.golang.org/genproto/googleapis/type/color"
)

// Scope is the OAuth2 scope required by the Google Cloud Vision API.
const Scope = "https://www.googleapis.com/auth/cloud-platform"

// Client is a Google Cloud Vision API client.
type Client struct {
	client *vkit.ImageAnnotatorClient
}

// NewClient creates a new vision client.
func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) {
	c, err := vkit.NewImageAnnotatorClient(ctx, opts...)
	if err != nil {
		return nil, err
	}
	c.SetGoogleClientInfo("vision", "0.1.0")
	return &Client{client: c}, nil
}

// Close closes the client.
func (c *Client) Close() error {
	return c.client.Close()
}

// Annotate annotates multiple images, each with a potentially differeent set
// of features.
func (c *Client) Annotate(ctx context.Context, requests ...*AnnotateRequest) ([]*Annotations, error) {
	var reqs []*pb.AnnotateImageRequest
	for _, r := range requests {
		reqs = append(reqs, r.toProto())
	}
	res, err := c.client.BatchAnnotateImages(ctx, &pb.BatchAnnotateImagesRequest{Requests: reqs})
	if err != nil {
		return nil, err
	}
	var results []*Annotations
	for _, res := range res.Responses {
		results = append(results, annotationsFromProto(res))
	}
	return results, nil
}

// An AnnotateRequest specifies an image to annotate and the features to look for in that image.
type AnnotateRequest struct {
	// Image is the image to annotate.
	Image *Image
	// MaxFaces is the maximum number of faces to detect in the image.
	// Specifying a number greater than zero enables face detection.
	MaxFaces int
	// MaxLandmarks is the maximum number of landmarks to detect in the image.
	// Specifying a number greater than zero enables landmark detection.
	MaxLandmarks int
	// MaxLogos is the maximum number of logos to detect in the image.
	// Specifying a number greater than zero enables logo detection.
	MaxLogos int
	// MaxLabels is the maximum number of logos to detect in the image.
	// Specifying a number greater than zero enables logo detection.
	MaxLabels int
	// MaxTexts is the maximum number of separate pieces of text to detect in the
	// image. Specifying a number greater than zero enables text detection.
	MaxTexts int
	// SafeSearch specifies whether a safe-search detection should be run on the image.
	SafeSearch bool
	// ImageProps specifies whether image properties should be obtained for the image.
	ImageProps bool
}

func (ar *AnnotateRequest) toProto() *pb.AnnotateImageRequest {
	img, ictx := ar.Image.toProtos()
	var features []*pb.Feature
	add := func(typ pb.Feature_Type, max int) {
		var mr int32
		if max > math.MaxInt32 {
			mr = math.MaxInt32
		} else {
			mr = int32(max)
		}
		features = append(features, &pb.Feature{Type: typ, MaxResults: mr})
	}
	if ar.MaxFaces > 0 {
		add(pb.Feature_FACE_DETECTION, ar.MaxFaces)
	}
	if ar.MaxLandmarks > 0 {
		add(pb.Feature_LANDMARK_DETECTION, ar.MaxLandmarks)
	}
	if ar.MaxLogos > 0 {
		add(pb.Feature_LOGO_DETECTION, ar.MaxLogos)
	}
	if ar.MaxLabels > 0 {
		add(pb.Feature_LABEL_DETECTION, ar.MaxLabels)
	}
	if ar.MaxTexts > 0 {
		add(pb.Feature_TEXT_DETECTION, ar.MaxTexts)
	}
	if ar.SafeSearch {
		add(pb.Feature_SAFE_SEARCH_DETECTION, 0)
	}
	if ar.ImageProps {
		add(pb.Feature_IMAGE_PROPERTIES, 0)
	}
	return &pb.AnnotateImageRequest{
		Image:        img,
		Features:     features,
		ImageContext: ictx,
	}
}

// Called for a single image and a single feature.
func (c *Client) annotateOne(ctx context.Context, req *AnnotateRequest) (*Annotations, error) {
	annsSlice, err := c.Annotate(ctx, req)
	if err != nil {
		return nil, err
	}
	anns := annsSlice[0]
	// When there is only one image and one feature, the Annotations.Error field is
	// unambiguously about that one detection, so we "promote" it to the error return value.
	if anns.Error != nil {
		return nil, anns.Error
	}
	return anns, nil
}

// TODO(jba): add examples for all single-feature functions (below).

// DetectFaces performs face detection on the image.
// At most maxResults results are returned.
func (c *Client) DetectFaces(ctx context.Context, img *Image, maxResults int) ([]*FaceAnnotation, error) {
	anns, err := c.annotateOne(ctx, &AnnotateRequest{Image: img, MaxFaces: maxResults})
	if err != nil {
		return nil, err
	}
	return anns.Faces, nil
}

// DetectLandmarks performs landmark detection on the image.
// At most maxResults results are returned.
func (c *Client) DetectLandmarks(ctx context.Context, img *Image, maxResults int) ([]*EntityAnnotation, error) {
	anns, err := c.annotateOne(ctx, &AnnotateRequest{Image: img, MaxLandmarks: maxResults})
	if err != nil {
		return nil, err
	}
	return anns.Landmarks, nil
}

// DetectLogos performs logo detection on the image.
// At most maxResults results are returned.
func (c *Client) DetectLogos(ctx context.Context, img *Image, maxResults int) ([]*EntityAnnotation, error) {
	anns, err := c.annotateOne(ctx, &AnnotateRequest{Image: img, MaxLogos: maxResults})
	if err != nil {
		return nil, err
	}
	return anns.Logos, nil
}

// DetectLabels performs label detection on the image.
// At most maxResults results are returned.
func (c *Client) DetectLabels(ctx context.Context, img *Image, maxResults int) ([]*EntityAnnotation, error) {
	anns, err := c.annotateOne(ctx, &AnnotateRequest{Image: img, MaxLabels: maxResults})
	if err != nil {
		return nil, err
	}
	return anns.Labels, nil
}

// DetectTexts performs text detection on the image.
// At most maxResults results are returned.
func (c *Client) DetectTexts(ctx context.Context, img *Image, maxResults int) ([]*EntityAnnotation, error) {
	anns, err := c.annotateOne(ctx, &AnnotateRequest{Image: img, MaxTexts: maxResults})
	if err != nil {
		return nil, err
	}
	return anns.Texts, nil
}

// DetectSafeSearch performs safe-search detection on the image.
func (c *Client) DetectSafeSearch(ctx context.Context, img *Image) (*SafeSearchAnnotation, error) {
	anns, err := c.annotateOne(ctx, &AnnotateRequest{Image: img, SafeSearch: true})
	if err != nil {
		return nil, err
	}
	return anns.SafeSearch, nil
}

// DetectImageProps computes properties of the image.
func (c *Client) DetectImageProps(ctx context.Context, img *Image) (*ImageProps, error) {
	anns, err := c.annotateOne(ctx, &AnnotateRequest{Image: img, ImageProps: true})
	if err != nil {
		return nil, err
	}
	return anns.ImageProps, nil
}

// A Likelihood is an approximate representation of a probability.
type Likelihood int

const (
	// LikelihoodUnknown means the likelihood is unknown.
	LikelihoodUnknown = Likelihood(pb.Likelihood_UNKNOWN)

	// VeryUnlikely means the image is very unlikely to belong to the feature specified.
	VeryUnlikely = Likelihood(pb.Likelihood_VERY_UNLIKELY)

	// Unlikely means the image is unlikely to belong to the feature specified.
	Unlikely = Likelihood(pb.Likelihood_UNLIKELY)

	// Possible means the image possibly belongs to the feature specified.
	Possible = Likelihood(pb.Likelihood_POSSIBLE)

	// Likely means the image is likely to belong to the feature specified.
	Likely = Likelihood(pb.Likelihood_LIKELY)

	// VeryLikely means the image is very likely to belong to the feature specified.
	VeryLikely = Likelihood(pb.Likelihood_VERY_LIKELY)
)

// A Property is an arbitrary name-value pair.
type Property struct {
	Name  string
	Value string
}

func propertyFromProto(p *pb.Property) Property {
	return Property{Name: p.Name, Value: p.Value}
}

// ColorInfo consists of RGB channels, score and fraction of
// image the color occupies in the image.
type ColorInfo struct {
	// RGB components of the color.
	Color color.NRGBA64

	// Score is the image-specific score for this color, in the range [0, 1].
	Score float32

	// PixelFraction is the fraction of pixels the color occupies in the image,
	// in the range [0, 1].
	PixelFraction float32
}

func colorInfoFromProto(ci *pb.ColorInfo) *ColorInfo {
	return &ColorInfo{
		Color:         colorFromProto(ci.Color),
		Score:         ci.Score,
		PixelFraction: ci.PixelFraction,
	}
}

// Should this go into protobuf/ptypes? The color proto is in google/types, so
// not specific to this API.
func colorFromProto(c *cpb.Color) color.NRGBA64 {
	// Convert a color component from [0.0, 1.0] to a uint16.
	cvt := func(f float32) uint16 { return uint16(f*math.MaxUint16 + 0.5) }

	var alpha float32 = 1
	if c.Alpha != nil {
		alpha = c.Alpha.Value
	}
	return color.NRGBA64{
		R: cvt(c.Red),
		G: cvt(c.Green),
		B: cvt(c.Blue),
		A: cvt(alpha),
	}
}
<commit_msg>vision: fix doc<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package vision

import (
	"image/color"
	"math"

	vkit "cloud.google.com/go/vision/apiv1"
	"golang.org/x/net/context"
	"google.golang.org/api/option"
	pb "google.golang.org/genproto/googleapis/cloud/vision/v1"
	cpb "google.golang.org/genproto/googleapis/type/color"
)

// Scope is the OAuth2 scope required by the Google Cloud Vision API.
const Scope = "https://www.googleapis.com/auth/cloud-platform"

// Client is a Google Cloud Vision API client.
type Client struct {
	client *vkit.ImageAnnotatorClient
}

// NewClient creates a new vision client.
func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) {
	c, err := vkit.NewImageAnnotatorClient(ctx, opts...)
	if err != nil {
		return nil, err
	}
	c.SetGoogleClientInfo("vision", "0.1.0")
	return &Client{client: c}, nil
}

// Close closes the client.
func (c *Client) Close() error {
	return c.client.Close()
}

// Annotate annotates multiple images, each with a potentially differeent set
// of features.
func (c *Client) Annotate(ctx context.Context, requests ...*AnnotateRequest) ([]*Annotations, error) {
	var reqs []*pb.AnnotateImageRequest
	for _, r := range requests {
		reqs = append(reqs, r.toProto())
	}
	res, err := c.client.BatchAnnotateImages(ctx, &pb.BatchAnnotateImagesRequest{Requests: reqs})
	if err != nil {
		return nil, err
	}
	var results []*Annotations
	for _, res := range res.Responses {
		results = append(results, annotationsFromProto(res))
	}
	return results, nil
}

// An AnnotateRequest specifies an image to annotate and the features to look for in that image.
type AnnotateRequest struct {
	// Image is the image to annotate.
	Image *Image
	// MaxFaces is the maximum number of faces to detect in the image.
	// Specifying a number greater than zero enables face detection.
	MaxFaces int
	// MaxLandmarks is the maximum number of landmarks to detect in the image.
	// Specifying a number greater than zero enables landmark detection.
	MaxLandmarks int
	// MaxLogos is the maximum number of logos to detect in the image.
	// Specifying a number greater than zero enables logo detection.
	MaxLogos int
	// MaxLabels is the maximum number of labels to detect in the image.
	// Specifying a number greater than zero enables labels detection.
	MaxLabels int
	// MaxTexts is the maximum number of separate pieces of text to detect in the
	// image. Specifying a number greater than zero enables text detection.
	MaxTexts int
	// SafeSearch specifies whether a safe-search detection should be run on the image.
	SafeSearch bool
	// ImageProps specifies whether image properties should be obtained for the image.
	ImageProps bool
}

func (ar *AnnotateRequest) toProto() *pb.AnnotateImageRequest {
	img, ictx := ar.Image.toProtos()
	var features []*pb.Feature
	add := func(typ pb.Feature_Type, max int) {
		var mr int32
		if max > math.MaxInt32 {
			mr = math.MaxInt32
		} else {
			mr = int32(max)
		}
		features = append(features, &pb.Feature{Type: typ, MaxResults: mr})
	}
	if ar.MaxFaces > 0 {
		add(pb.Feature_FACE_DETECTION, ar.MaxFaces)
	}
	if ar.MaxLandmarks > 0 {
		add(pb.Feature_LANDMARK_DETECTION, ar.MaxLandmarks)
	}
	if ar.MaxLogos > 0 {
		add(pb.Feature_LOGO_DETECTION, ar.MaxLogos)
	}
	if ar.MaxLabels > 0 {
		add(pb.Feature_LABEL_DETECTION, ar.MaxLabels)
	}
	if ar.MaxTexts > 0 {
		add(pb.Feature_TEXT_DETECTION, ar.MaxTexts)
	}
	if ar.SafeSearch {
		add(pb.Feature_SAFE_SEARCH_DETECTION, 0)
	}
	if ar.ImageProps {
		add(pb.Feature_IMAGE_PROPERTIES, 0)
	}
	return &pb.AnnotateImageRequest{
		Image:        img,
		Features:     features,
		ImageContext: ictx,
	}
}

// Called for a single image and a single feature.
func (c *Client) annotateOne(ctx context.Context, req *AnnotateRequest) (*Annotations, error) {
	annsSlice, err := c.Annotate(ctx, req)
	if err != nil {
		return nil, err
	}
	anns := annsSlice[0]
	// When there is only one image and one feature, the Annotations.Error field is
	// unambiguously about that one detection, so we "promote" it to the error return value.
	if anns.Error != nil {
		return nil, anns.Error
	}
	return anns, nil
}

// TODO(jba): add examples for all single-feature functions (below).

// DetectFaces performs face detection on the image.
// At most maxResults results are returned.
func (c *Client) DetectFaces(ctx context.Context, img *Image, maxResults int) ([]*FaceAnnotation, error) {
	anns, err := c.annotateOne(ctx, &AnnotateRequest{Image: img, MaxFaces: maxResults})
	if err != nil {
		return nil, err
	}
	return anns.Faces, nil
}

// DetectLandmarks performs landmark detection on the image.
// At most maxResults results are returned.
func (c *Client) DetectLandmarks(ctx context.Context, img *Image, maxResults int) ([]*EntityAnnotation, error) {
	anns, err := c.annotateOne(ctx, &AnnotateRequest{Image: img, MaxLandmarks: maxResults})
	if err != nil {
		return nil, err
	}
	return anns.Landmarks, nil
}

// DetectLogos performs logo detection on the image.
// At most maxResults results are returned.
func (c *Client) DetectLogos(ctx context.Context, img *Image, maxResults int) ([]*EntityAnnotation, error) {
	anns, err := c.annotateOne(ctx, &AnnotateRequest{Image: img, MaxLogos: maxResults})
	if err != nil {
		return nil, err
	}
	return anns.Logos, nil
}

// DetectLabels performs label detection on the image.
// At most maxResults results are returned.
func (c *Client) DetectLabels(ctx context.Context, img *Image, maxResults int) ([]*EntityAnnotation, error) {
	anns, err := c.annotateOne(ctx, &AnnotateRequest{Image: img, MaxLabels: maxResults})
	if err != nil {
		return nil, err
	}
	return anns.Labels, nil
}

// DetectTexts performs text detection on the image.
// At most maxResults results are returned.
func (c *Client) DetectTexts(ctx context.Context, img *Image, maxResults int) ([]*EntityAnnotation, error) {
	anns, err := c.annotateOne(ctx, &AnnotateRequest{Image: img, MaxTexts: maxResults})
	if err != nil {
		return nil, err
	}
	return anns.Texts, nil
}

// DetectSafeSearch performs safe-search detection on the image.
func (c *Client) DetectSafeSearch(ctx context.Context, img *Image) (*SafeSearchAnnotation, error) {
	anns, err := c.annotateOne(ctx, &AnnotateRequest{Image: img, SafeSearch: true})
	if err != nil {
		return nil, err
	}
	return anns.SafeSearch, nil
}

// DetectImageProps computes properties of the image.
func (c *Client) DetectImageProps(ctx context.Context, img *Image) (*ImageProps, error) {
	anns, err := c.annotateOne(ctx, &AnnotateRequest{Image: img, ImageProps: true})
	if err != nil {
		return nil, err
	}
	return anns.ImageProps, nil
}

// A Likelihood is an approximate representation of a probability.
type Likelihood int

const (
	// LikelihoodUnknown means the likelihood is unknown.
	LikelihoodUnknown = Likelihood(pb.Likelihood_UNKNOWN)

	// VeryUnlikely means the image is very unlikely to belong to the feature specified.
	VeryUnlikely = Likelihood(pb.Likelihood_VERY_UNLIKELY)

	// Unlikely means the image is unlikely to belong to the feature specified.
	Unlikely = Likelihood(pb.Likelihood_UNLIKELY)

	// Possible means the image possibly belongs to the feature specified.
	Possible = Likelihood(pb.Likelihood_POSSIBLE)

	// Likely means the image is likely to belong to the feature specified.
	Likely = Likelihood(pb.Likelihood_LIKELY)

	// VeryLikely means the image is very likely to belong to the feature specified.
	VeryLikely = Likelihood(pb.Likelihood_VERY_LIKELY)
)

// A Property is an arbitrary name-value pair.
type Property struct {
	Name  string
	Value string
}

func propertyFromProto(p *pb.Property) Property {
	return Property{Name: p.Name, Value: p.Value}
}

// ColorInfo consists of RGB channels, score and fraction of
// image the color occupies in the image.
type ColorInfo struct {
	// RGB components of the color.
	Color color.NRGBA64

	// Score is the image-specific score for this color, in the range [0, 1].
	Score float32

	// PixelFraction is the fraction of pixels the color occupies in the image,
	// in the range [0, 1].
	PixelFraction float32
}

func colorInfoFromProto(ci *pb.ColorInfo) *ColorInfo {
	return &ColorInfo{
		Color:         colorFromProto(ci.Color),
		Score:         ci.Score,
		PixelFraction: ci.PixelFraction,
	}
}

// Should this go into protobuf/ptypes? The color proto is in google/types, so
// not specific to this API.
func colorFromProto(c *cpb.Color) color.NRGBA64 {
	// Convert a color component from [0.0, 1.0] to a uint16.
	cvt := func(f float32) uint16 { return uint16(f*math.MaxUint16 + 0.5) }

	var alpha float32 = 1
	if c.Alpha != nil {
		alpha = c.Alpha.Value
	}
	return color.NRGBA64{
		R: cvt(c.Red),
		G: cvt(c.Green),
		B: cvt(c.Blue),
		A: cvt(alpha),
	}
}
<|endoftext|>