<commit_before>package notifier

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/oinume/lekcije/server/emailer"
	"github.com/oinume/lekcije/server/fetcher"
	"github.com/oinume/lekcije/server/logger"
	"github.com/oinume/lekcije/server/model"
	"github.com/stretchr/testify/require"
)

var helper = model.NewTestHelper()
var _ = fmt.Print

type mockFetcherTransport struct {
	sync.Mutex
	called int
}

func (t *mockFetcherTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	t.Lock()
	t.called++
	t.Unlock()
	resp := &http.Response{
		Header:     make(http.Header),
		Request:    req,
		StatusCode: http.StatusOK,
		Status:     "200 OK",
	}
	resp.Header.Set("Content-Type", "text/html; charset=UTF-8")

	// TODO: file location
	file, err := os.Open("../fetcher/testdata/5982.html")
	if err != nil {
		return nil, err
	}
	resp.Body = file // Close() will be called by client
	return resp, nil
}

type mockSenderTransport struct {
	sync.Mutex
	called int
}

func (t *mockSenderTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	t.Lock()
	t.called++
	t.Unlock()
	resp := &http.Response{
		Header:     make(http.Header),
		Request:    req,
		StatusCode: http.StatusAccepted,
		Status:     "202 Accepted",
	}
	//resp.Header.Set("Content-Type", "text/html; charset=UTF-8")
	resp.Body = ioutil.NopCloser(strings.NewReader(""))
	return resp, nil
}

func TestMain(m *testing.M) {
	db := helper.DB()
	defer db.Close()
	helper.TruncateAllTables(db)
	os.Exit(m.Run())
}

func TestSendNotification(t *testing.T) {
	//a := assert.New(t)
	r := require.New(t)
	db := helper.DB()
	logger.InitializeAppLogger(os.Stdout)

	fetcherHTTPClient := &http.Client{
		Transport: &mockFetcherTransport{},
		Timeout:   5 * time.Second,
	}
	fetcher := fetcher.NewTeacherLessonFetcher(fetcherHTTPClient, 1, false, helper.LoadMCountries(), nil)

	user := helper.CreateUser("oinume", "oinume@gmail.com")
	teacher := helper.CreateRandomTeacher()
	helper.CreateFollowingTeacher(user.ID, teacher)

	senderHTTPClient := &http.Client{
		Transport: &mockSenderTransport{},
		Timeout:   5 * time.Second,
	}
	sender := emailer.NewSendGridSender(senderHTTPClient)
	//sender := &emailer.NoSender{}
	n := NewNotifier(db, fetcher, true, sender)
	err := n.SendNotification(user)
	r.Nil(err)
}
<commit_msg>Reproduce current notifier is slow<commit_after>package notifier

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/oinume/lekcije/server/emailer"
	"github.com/oinume/lekcije/server/fetcher"
	"github.com/oinume/lekcije/server/logger"
	"github.com/oinume/lekcije/server/model"
	"github.com/stretchr/testify/require"
)

var helper = model.NewTestHelper()
var _ = fmt.Print

type mockFetcherTransport struct {
	sync.Mutex
	called int
}

func (t *mockFetcherTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	t.Lock()
	t.called++
	t.Unlock()
	resp := &http.Response{
		Header:     make(http.Header),
		Request:    req,
		StatusCode: http.StatusOK,
		Status:     "200 OK",
	}
	resp.Header.Set("Content-Type", "text/html; charset=UTF-8")

	// TODO: file location
	file, err := os.Open("../fetcher/testdata/5982.html")
	if err != nil {
		return nil, err
	}
	resp.Body = file // Close() will be called by client
	return resp, nil
}

type mockSenderTransport struct {
	sync.Mutex
	called int
}

func (t *mockSenderTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	t.Lock()
	t.called++
	t.Unlock()
	time.Sleep(time.Millisecond * 500)
	resp := &http.Response{
		Header:     make(http.Header),
		Request:    req,
		StatusCode: http.StatusAccepted,
		Status:     "202 Accepted",
	}
	//resp.Header.Set("Content-Type", "text/html; charset=UTF-8")
	resp.Body = ioutil.NopCloser(strings.NewReader(""))
	return resp, nil
}

func TestMain(m *testing.M) {
	db := helper.DB()
	defer db.Close()
	helper.TruncateAllTables(db)
	os.Exit(m.Run())
}

func TestSendNotification(t *testing.T) {
	//a := assert.New(t)
	r := require.New(t)
	db := helper.DB()
	logger.InitializeAppLogger(os.Stdout)

	fetcherHTTPClient := &http.Client{
		Transport: &mockFetcherTransport{},
		Timeout:   5 * time.Second,
	}
	fetcher := fetcher.NewTeacherLessonFetcher(fetcherHTTPClient, 1, false, helper.LoadMCountries(), nil)

	usersData := []struct {
		name  string
		email string
	}{
		{"oinume", "oinume@gmail.com"},
		{"oinume2", "oinume+2@gmail.com"},
		{"oinume3", "oinume+3@gmail.com"},
	}
	var users []*model.User
	for _, u := range usersData {
		user := helper.CreateUser(u.name, u.email)
		teacher := helper.CreateRandomTeacher()
		helper.CreateFollowingTeacher(user.ID, teacher)
		users = append(users, user)
	}

	senderHTTPClient := &http.Client{
		Transport: &mockSenderTransport{},
		Timeout:   5 * time.Second,
	}
	sender := emailer.NewSendGridSender(senderHTTPClient)
	//sender := &emailer.NoSender{}
	n := NewNotifier(db, fetcher, true, sender)

	for _, user := range users {
		err := n.SendNotification(user)
		r.Nil(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"runtime"

	"github.com/codegangsta/cli"
	"github.com/ethereum/go-ethereum/cmd/utils"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/logger/glog"
	"github.com/ethereum/go-ethereum/node"
	"github.com/ethereum/go-ethereum/params"
	"github.com/ethereum/go-ethereum/release"
	"github.com/ethereum/go-ethereum/rlp"
)

const (
	clientIdentifier = "Geth"     // Client identifier to advertise over the network
	versionMajor     = 1          // Major version component of the current release
	versionMinor     = 5          // Minor version component of the current release
	versionPatch     = 0          // Patch version component of the current release
	versionMeta      = "unstable" // Version metadata to append to the version string

	versionOracle = "0xfa7b9770ca4cb04296cac84f37736d4041251cdf" // Ethereum address of the Geth release oracle
)

var (
	vString     string          // Combined textual representation of the version
	rConfig     release.Config  // Structured version information and release oracle config
	currentNode *node.Node      // currently running geth node
	c           *cli.Context    // the CLI context used to start the geth node
	accountSync *[]node.Service // the object used to sync accounts between geth services
	datadir     string          // data directory for geth
)

func main() {

	// Placeholder for anything we want to run by default
	fmt.Println("You are running statusgo!")

}

// MakeNode create a geth node entity
func MakeNode(inputDir string) *node.Node {

	datadir = inputDir

	// TODO remove admin rpcapi flag
	set := flag.NewFlagSet("test", 0)
	set.Bool("shh", true, "whisper")
	set.Bool("noeth", true, "disable eth")
	set.Bool("rpc", true, "enable rpc")
	set.String("rpcaddr", "localhost", "host for RPC")
	set.String("rpcport", "8545", "rpc port")
	set.String("rpcapi", "db,eth,net,web3,shh,admin", "rpc api(s)")
	set.String("datadir", datadir, "data directory for geth")
	//set.String("logdir", datadir, "log dir for glog")
	c = cli.NewContext(nil, set, nil)

	// Construct the textual version string from the individual components
	vString = fmt.Sprintf("%d.%d.%d", versionMajor, versionMinor, versionPatch)

	// Construct the version release oracle configuration
	rConfig.Oracle = common.HexToAddress(versionOracle)

	rConfig.Major = uint32(versionMajor)
	rConfig.Minor = uint32(versionMinor)
	rConfig.Patch = uint32(versionPatch)

	utils.DebugSetup(c)
	currentNode, accountSync = utils.MakeSystemNode(clientIdentifier, vString, rConfig, makeDefaultExtra(), c)
	fmt.Println(accountSync)
	return currentNode

}

// StartNode starts a geth node entity
func RunNode(nodeIn *node.Node) {
	utils.StartNode(nodeIn)
	nodeIn.Wait()
}

func makeDefaultExtra() []byte {
	var clientInfo = struct {
		Version   uint
		Name      string
		GoVersion string
		Os        string
	}{uint(versionMajor<<16 | versionMinor<<8 | versionPatch), clientIdentifier, runtime.Version(), runtime.GOOS}
	extra, err := rlp.EncodeToBytes(clientInfo)
	if err != nil {
		glog.V(logger.Warn).Infoln("error setting canonical miner information:", err)
	}

	if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() {
		glog.V(logger.Warn).Infoln("error setting canonical miner information: extra exceeds", params.MaximumExtraDataSize)
		glog.V(logger.Debug).Infof("extra: %x\n", extra)
		return nil
	}
	return extra
}
<commit_msg>remove other debugging<commit_after>package main

import (
	"flag"
	"fmt"
	"runtime"

	"github.com/codegangsta/cli"
	"github.com/ethereum/go-ethereum/cmd/utils"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/logger/glog"
	"github.com/ethereum/go-ethereum/node"
	"github.com/ethereum/go-ethereum/params"
	"github.com/ethereum/go-ethereum/release"
	"github.com/ethereum/go-ethereum/rlp"
)

const (
	clientIdentifier = "Geth"     // Client identifier to advertise over the network
	versionMajor     = 1          // Major version component of the current release
	versionMinor     = 5          // Minor version component of the current release
	versionPatch     = 0          // Patch version component of the current release
	versionMeta      = "unstable" // Version metadata to append to the version string

	versionOracle = "0xfa7b9770ca4cb04296cac84f37736d4041251cdf" // Ethereum address of the Geth release oracle
)

var (
	vString     string          // Combined textual representation of the version
	rConfig     release.Config  // Structured version information and release oracle config
	currentNode *node.Node      // currently running geth node
	c           *cli.Context    // the CLI context used to start the geth node
	accountSync *[]node.Service // the object used to sync accounts between geth services
	datadir     string          // data directory for geth
)

func main() {

	// Placeholder for anything we want to run by default
	fmt.Println("You are running statusgo!")

}

// MakeNode create a geth node entity
func MakeNode(inputDir string) *node.Node {

	datadir = inputDir

	// TODO remove admin rpcapi flag
	set := flag.NewFlagSet("test", 0)
	set.Bool("shh", true, "whisper")
	set.Bool("noeth", true, "disable eth")
	set.Bool("rpc", true, "enable rpc")
	set.String("rpcaddr", "localhost", "host for RPC")
	set.String("rpcport", "8545", "rpc port")
	set.String("rpcapi", "db,eth,net,web3,shh,admin", "rpc api(s)")
	set.String("datadir", datadir, "data directory for geth")
	set.String("logdir", datadir, "log dir for glog")
	c = cli.NewContext(nil, set, nil)

	// Construct the textual version string from the individual components
	vString = fmt.Sprintf("%d.%d.%d", versionMajor, versionMinor, versionPatch)

	// Construct the version release oracle configuration
	rConfig.Oracle = common.HexToAddress(versionOracle)

	rConfig.Major = uint32(versionMajor)
	rConfig.Minor = uint32(versionMinor)
	rConfig.Patch = uint32(versionPatch)

	utils.DebugSetup(c)
	currentNode, accountSync = utils.MakeSystemNode(clientIdentifier, vString, rConfig, makeDefaultExtra(), c)
	return currentNode

}

// StartNode starts a geth node entity
func RunNode(nodeIn *node.Node) {
	utils.StartNode(nodeIn)
	nodeIn.Wait()
}

func makeDefaultExtra() []byte {
	var clientInfo = struct {
		Version   uint
		Name      string
		GoVersion string
		Os        string
	}{uint(versionMajor<<16 | versionMinor<<8 | versionPatch), clientIdentifier, runtime.Version(), runtime.GOOS}
	extra, err := rlp.EncodeToBytes(clientInfo)
	if err != nil {
		glog.V(logger.Warn).Infoln("error setting canonical miner information:", err)
	}

	if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() {
		glog.V(logger.Warn).Infoln("error setting canonical miner information: extra exceeds", params.MaximumExtraDataSize)
		glog.V(logger.Debug).Infof("extra: %x\n", extra)
		return nil
	}
	return extra
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
	"io"
	"encoding/json"
	"errors"
)

const SURICATA = "suricata"

func init() {
	parser.Add(SURICATA, "/usr/local/var/run/suricata/suricata-command.socket", "dump Suricata's performance counters")
}

type Suricata struct {
	SocketName string
}

func (self *Suricata) Prefix() string {
	return SURICATA
}

func (self *Suricata) Collect(c *MetricsCollection) (e error) {
	name := "testTag"
	tags := map[string]string{"name": name}
	c.AddWithTags("suricata.test", 1024, tags)
	r,e := getCountersFromSocket(self.SocketName)
	if e != nil {
		return
	}
	for k,v := range r {
		for kk,vv := range v {
			// add thread name as tag
			if k != "Detect" && k != "FlowManagerThread" {
				tags := map[string]string{"thread": k}
				c.AddWithTags(kk, vv, tags)
			} else {
				c.Add(kk, vv)
			}
		}
	}
	return
}

type Response struct {
    ReturnCode string         `json:"return"`
    Message map[string]map[string]int64 `json:"message"`
}

func getCountersFromSocket(socketName string) (counts map[string]map[string]int64, err error) {
	conn, err := net.Dial("unix", socketName)
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	// see https://github.com/inliniac/suricata/blob/94571c5dd28858ff68c44b648fd41c5d87c0e28d/src/unix-manager.c#L288
	_, err = fmt.Fprint(conn, "{\"version\": \"0.1\"}")
	if err != nil {
			return nil, errors.New("can not send version :: "+err.Error())
	}
	var buf [128]byte
	_, err = conn.Read(buf[0:])
	if err != nil {
			// see https://github.com/inliniac/suricata/blob/94571c5dd28858ff68c44b648fd41c5d87c0e28d/src/unix-manager.c#L319
			return nil, errors.New("got kick on version :: "+err.Error())
	}
	_, err = fmt.Fprint(conn, "{\"command\": \"dump-counters\"}")
	if err != nil {
		return nil, errors.New("can not send command :: "+err.Error())
	}

	data := ""
	// read anser for command
	//  see https://github.com/inliniac/suricata/blob/672049632431bb695f56798c9c5f196afcf2fb27/scripts/suricatasc/src/suricatasc.py#L83
	for i := 0; i < 32; i++ {
		var buf2 [4096]byte
		result2, err := conn.Read(buf2[0:])
		if err != nil {
			if err != io.EOF {
				return nil, err
			}
		}
		data = data + string(buf2[:result2])
		var isJson  Response
		jerr := json.Unmarshal([]byte(data), &isJson)
		if jerr == nil {
			if isJson.ReturnCode == "OK" {
				return isJson.Message, nil
			} else {
				return nil, errors.New(isJson.ReturnCode)
			}

		} else {
			expect := "unexpected end of JSON input"
			if jerr.Error() != expect {
				// is json but not our counters
				return nil, errors.New(data)
			}
		}
	}
	return nil, errors.New("max limit for loop")
}<commit_msg>suricata - added sleep before read<commit_after>package main

import (
	"time"
	"net"
	"io"
	"encoding/json"
	"errors"
)

const SURICATA = "suricata"

func init() {
	parser.Add(SURICATA, "/usr/local/var/run/suricata/suricata-command.socket", "dump Suricata's performance counters")
}

type Suricata struct {
	SocketName string
}

func (self *Suricata) Prefix() string {
	return SURICATA
}

func (self *Suricata) Collect(c *MetricsCollection) (e error) {
	name := "testTag"
	tags := map[string]string{"name": name}
	c.AddWithTags("suricata.test", 1024, tags)
	r,e := getCountersFromSocket(self.SocketName)
	if e != nil {
		return
	}
	for k,v := range r {
		for kk,vv := range v {
			// add thread name as tag
			if k != "Detect" && k != "FlowManagerThread" {
				tags := map[string]string{"thread": k}
				c.AddWithTags(kk, vv, tags)
			} else {
				c.Add(kk, vv)
			}
		}
	}
	return
}

type Response struct {
    ReturnCode string         `json:"return"`
    Message map[string]map[string]int64 `json:"message"`
}

func getCountersFromSocket(socketName string) (counts map[string]map[string]int64, err error) {
	conn, err := net.Dial("unix", socketName)
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	// see https://github.com/inliniac/suricata/blob/94571c5dd28858ff68c44b648fd41c5d87c0e28d/src/unix-manager.c#L288
	_, err = conn.Write([]byte("{\"version\": \"0.1\"}"))
	if err != nil {
			return nil, errors.New("can not send version :: "+err.Error())
	}
	time.Sleep(100 * time.Millisecond)
	var buf [128]byte
	_, err = conn.Read(buf[0:])
	if err != nil {
			// see https://github.com/inliniac/suricata/blob/94571c5dd28858ff68c44b648fd41c5d87c0e28d/src/unix-manager.c#L319
			return nil, errors.New("got kick on version :: "+err.Error())
	}
	_, err = conn.Write([]byte("{\"command\": \"dump-counters\"}"))
	if err != nil {
		return nil, errors.New("can not send command :: "+err.Error())
	}
	time.Sleep(100 * time.Millisecond)
	data := ""
	// read anser for command
	//  see https://github.com/inliniac/suricata/blob/672049632431bb695f56798c9c5f196afcf2fb27/scripts/suricatasc/src/suricatasc.py#L83
	for i := 0; i < 16; i++ {
		var buf2 [4096]byte
		result2, err := conn.Read(buf2[0:])
		if err != nil {
			if err != io.EOF {
				return nil, err
			}
		}
		data = data + string(buf2[:result2])
		var isJson  Response
		jerr := json.Unmarshal([]byte(data), &isJson)
		if jerr == nil {
			if isJson.ReturnCode == "OK" {
				return isJson.Message, nil
			} else {
				return nil, errors.New(isJson.ReturnCode)
			}

		} else {
			expect := "unexpected end of JSON input"
			if jerr.Error() != expect {
				// is json but not our counters
				return nil, errors.New(data)
			}
		}
		time.Sleep(10 * time.Millisecond)
	}
	return nil, errors.New("max limit for loop")
}<|endoftext|>


<commit_before>// Copyright 2013 Ooyala, Inc.

/*
Package dogstatsd provides a Go DogStatsD client. DogStatsD extends StatsD - adding tags and
histograms. Refer to http://docs.datadoghq.com/guides/dogstatsd/ for information about DogStatsD.

Example Usage:
		// Create the client
		c, err := dogstatsd.New("127.0.0.1:8125")
		if err != nil {
			log.Fatal(err)
		}
		// Prefix every metric with the app name
		c.Namespace = "flubber."
		// Send the EC2 availability zone as a tag with every metric
		append(c.Tags, "us-east-1a")
		err = c.Gauge("request.duration", 1.2, nil, 1)

dogstatsd is based on go-statsd-client.
*/
package dogstatsd

import (
	"fmt"
	"math/rand"
	"net"
	"strings"
)

type Client struct {
	conn net.Conn
	// Namespace to prepend to all statsd calls
	Namespace string
	// Global tags to be added to every statsd call
	Tags []string
}

// New returns a pointer to a new Client and an error.
// addr must have the format "hostname:port"
func New(addr string) (*Client, error) {
	conn, err := net.Dial("udp", addr)
	if err != nil {
		return nil, err
	}
	client := &Client{conn: conn}
	return client, nil
}

// send handles sampling and sends the message over UDP. It also adds global namespace prefixes and tags.
func (c *Client) send(name string, value string, tags []string, rate float64) error {
	if c == nil {
		return nil
	}
	if rate < 1 {
		if rand.Float64() < rate {
			value = fmt.Sprintf("%s|@%f", value, rate)
		} else {
			return nil
		}
	}

	if c.Namespace != "" {
		name = fmt.Sprintf("%s%s", c.Namespace, name)
	}

	tags = append(c.Tags, tags...)
	if len(tags) > 0 {
		value = fmt.Sprintf("%s|#%s", value, strings.Join(tags, ","))
	}

	data := fmt.Sprintf("%s:%s", name, value)
	_, err := c.conn.Write([]byte(data))
	return err
}

// Gauges measure the value of a metric at a particular time
func (c *Client) Gauge(name string, value float64, tags []string, rate float64) error {
	stat := fmt.Sprintf("%f|g", value)
	return c.send(name, stat, tags, rate)
}

// Counters track how many times something happened per second
func (c *Client) Count(name string, value int64, tags []string, rate float64) error {
	stat := fmt.Sprintf("%d|c", value)
	return c.send(name, stat, tags, rate)
}

// Histograms track the statistical distribution of a set of values
func (c *Client) Histogram(name string, value float64, tags []string, rate float64) error {
	stat := fmt.Sprintf("%f|h", value)
	return c.send(name, stat, tags, rate)
}

// Sets count the number of unique elements in a group
func (c *Client) Set(name string, value string, tags []string, rate float64) error {
	stat := fmt.Sprintf("%s|s", value)
	return c.send(name, stat, tags, rate)
}
<commit_msg>Close() method for closing connection<commit_after>// Copyright 2013 Ooyala, Inc.

/*
Package dogstatsd provides a Go DogStatsD client. DogStatsD extends StatsD - adding tags and
histograms. Refer to http://docs.datadoghq.com/guides/dogstatsd/ for information about DogStatsD.

Example Usage:
		// Create the client
		c, err := dogstatsd.New("127.0.0.1:8125")
		if err != nil {
			log.Fatal(err)
		}
		// Prefix every metric with the app name
		c.Namespace = "flubber."
		// Send the EC2 availability zone as a tag with every metric
		append(c.Tags, "us-east-1a")
		err = c.Gauge("request.duration", 1.2, nil, 1)

dogstatsd is based on go-statsd-client.
*/
package dogstatsd

import (
	"fmt"
	"math/rand"
	"net"
	"strings"
)

type Client struct {
	conn net.Conn
	// Namespace to prepend to all statsd calls
	Namespace string
	// Global tags to be added to every statsd call
	Tags []string
}

// New returns a pointer to a new Client and an error.
// addr must have the format "hostname:port"
func New(addr string) (*Client, error) {
	conn, err := net.Dial("udp", addr)
	if err != nil {
		return nil, err
	}
	client := &Client{conn: conn}
	return client, nil
}

// send handles sampling and sends the message over UDP. It also adds global namespace prefixes and tags.
func (c *Client) send(name string, value string, tags []string, rate float64) error {
	if c == nil {
		return nil
	}
	if rate < 1 {
		if rand.Float64() < rate {
			value = fmt.Sprintf("%s|@%f", value, rate)
		} else {
			return nil
		}
	}

	if c.Namespace != "" {
		name = fmt.Sprintf("%s%s", c.Namespace, name)
	}

	tags = append(c.Tags, tags...)
	if len(tags) > 0 {
		value = fmt.Sprintf("%s|#%s", value, strings.Join(tags, ","))
	}

	data := fmt.Sprintf("%s:%s", name, value)
	_, err := c.conn.Write([]byte(data))
	return err
}

// Gauges measure the value of a metric at a particular time
func (c *Client) Gauge(name string, value float64, tags []string, rate float64) error {
	stat := fmt.Sprintf("%f|g", value)
	return c.send(name, stat, tags, rate)
}

// Counters track how many times something happened per second
func (c *Client) Count(name string, value int64, tags []string, rate float64) error {
	stat := fmt.Sprintf("%d|c", value)
	return c.send(name, stat, tags, rate)
}

// Histograms track the statistical distribution of a set of values
func (c *Client) Histogram(name string, value float64, tags []string, rate float64) error {
	stat := fmt.Sprintf("%f|h", value)
	return c.send(name, stat, tags, rate)
}

// Sets count the number of unique elements in a group
func (c *Client) Set(name string, value string, tags []string, rate float64) error {
	stat := fmt.Sprintf("%s|s", value)
	return c.send(name, stat, tags, rate)
}

// Close the client connection
func (c *Client) Close() error {
	return c.conn.Close()
}
<|endoftext|>


<commit_before>package main

type colorcode string

const (
	Black     = "\x1b[30;22m"
	Darkred   = "\x1b[31;22m"
	Darkgreen = "\x1b[32;22m"
	Brown     = "\x1b[33;22m"
	Darkblue  = "\x1b[34m;22m"
	Darkpink  = "\x1b[35m;22m"
	Darkcyan  = "\x1b[36m;22m"
	Grey      = "\x1b[37m;22m"
	Darkgrey  = "\x1b[30m;1m"
	Red       = "\x1b[40;31;1m"
	Green     = "\x1b[40;32;1m"
	Yellow    = "\x1b[40;33;1m"
	Blue      = "\x1b[34;1m"
	Pink      = "\x1b[35;1m"
	Cyan      = "\x1b[36;1m"
	White     = "\x1b[37;1m"
	Reset     = "\x1b[0m"
)
<commit_msg>fixed ansi color codes<commit_after>package main

type colorcode string

const (
	Black     = "\x1b[0;30m"
	Darkred   = "\x1b[0;31m"
	Darkgreen = "\x1b[0;32m"
	Brown     = "\x1b[0;33m"
	Darkblue  = "\x1b[0;34m"
	Darkpink  = "\x1b[0;35m"
	Darkcyan  = "\x1b[0;36m"
	Grey      = "\x1b[0;37m"
	Darkgrey  = "\x1b[1;30m"
	Red       = "\x1b[1;31m"
	Green     = "\x1b[1;32m"
	Yellow    = "\x1b[1;33m"
	Blue      = "\x1b[1;34m"
	Pink      = "\x1b[1;35m"
	Cyan      = "\x1b[1;36m"
	White     = "\x1b[0;30m"
	Reset     = "\x1b[0m"
)
<|endoftext|>


<commit_before>package flint

import (
	"github.com/codegangsta/cli"

	"fmt"
	"os"
	"runtime"
)

func NewApp() *cli.App {
	app := cli.NewApp()
	app.Name = "flint"
	app.Usage = "Check a project for common sources of contributor friction"
	app.Version = "0.0.4"
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "skip-readme",
			Usage: "skip check for README",
		},
		cli.BoolFlag{
			Name:  "skip-contributing",
			Usage: "skip check for contributing guide",
		},
		cli.BoolFlag{
			Name:  "skip-license",
			Usage: "skip check for license",
		},
		cli.BoolFlag{
			Name:  "skip-bootstrap",
			Usage: "skip check for bootstrap script",
		},
		cli.BoolFlag{
			Name:  "skip-test-script",
			Usage: "skip check for test script",
		},
		cli.BoolFlag{
			Name:  "skip-scripts",
			Usage: "skip check for all scripts",
		},
		cli.BoolFlag{
			Name:  "no-color",
			Usage: "skip coloring the terminal output",
		},
		cli.BoolFlag{
			Name:  "skip-changelog",
			Usage: "skip check for changelog",
		},
		cli.BoolFlag{
			Name:  "skip-code-of-conduct",
			Usage: "skip check for code of conduct",
		},
		cli.StringFlag{
			Name:  "github, g",
			Value: "",
			Usage: "GitHub repository as owner/repo",
		},
		cli.StringFlag{
			Name:   "token, t",
			Value:  "",
			EnvVar: "FLINT_TOKEN",
			Usage:  "GitHub API access token",
		},
	}
	app.Action = func(c *cli.Context) {
		run(c)
	}

	return app
}

type runFunc func(*cli.Context)

var run = func(c *cli.Context) {
	project := newProject(c)
	flags := newFlagsFromContext(c)
	linter := &Linter{}
	summary, err := linter.Run(project, flags)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
		return
	}
	if summary != nil {
		color := !c.Bool("no-color")
		// Windows doesn't support colors
		if runtime.GOOS == "windows" {
			color = false
		}
		summary.Print(os.Stderr, color)
		os.Exit(summary.Severity())
	}
}

func newProject(c *cli.Context) Project {
	github := c.String("github")
	if len(github) > 0 {
		project := &RemoteProject{FullName: github}
		fetcher := newGitHubFetcher(c)
		err := project.Fetch(fetcher)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		return project
	} else {
		path, _ := os.Getwd()
		if len(c.Args()) > 0 {
			path = c.Args()[0]
		}
		return &LocalProject{Path: path}
	}
}

func newFlagsFromContext(c *cli.Context) *Flags {
	runBootstrap := !c.Bool("skip-bootstrap")
	runTestScript := !c.Bool("skip-test-script")
	if c.Bool("skip-scripts") {
		runBootstrap = false
		runTestScript = false
	}

	flags := &Flags{
		RunReadme:        !c.Bool("skip-readme"),
		RunContributing:  !c.Bool("skip-contributing"),
		RunLicense:       !c.Bool("skip-license"),
		RunBootstrap:     runBootstrap,
		RunTestScript:    runTestScript,
		RunChangelog:     !c.Bool("skip-changelog"),
		RunCodeOfConduct: !c.Bool("skip-code-of-conduct"),
	}
	return flags
}

var newGitHubFetcher = func(c *cli.Context) RemoteRepositoryFetcher {
	token := c.String("token")
	if len(token) > 0 {
		return NewGitHubFetcherWithToken(token)
	} else {
		return NewGitHubFetcher()
	}
}
<commit_msg>v0.1.0<commit_after>package flint

import (
	"github.com/codegangsta/cli"

	"fmt"
	"os"
	"runtime"
)

func NewApp() *cli.App {
	app := cli.NewApp()
	app.Name = "flint"
	app.Usage = "Check a project for common sources of contributor friction"
	app.Version = "0.1.0"
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "skip-readme",
			Usage: "skip check for README",
		},
		cli.BoolFlag{
			Name:  "skip-contributing",
			Usage: "skip check for contributing guide",
		},
		cli.BoolFlag{
			Name:  "skip-license",
			Usage: "skip check for license",
		},
		cli.BoolFlag{
			Name:  "skip-bootstrap",
			Usage: "skip check for bootstrap script",
		},
		cli.BoolFlag{
			Name:  "skip-test-script",
			Usage: "skip check for test script",
		},
		cli.BoolFlag{
			Name:  "skip-scripts",
			Usage: "skip check for all scripts",
		},
		cli.BoolFlag{
			Name:  "no-color",
			Usage: "skip coloring the terminal output",
		},
		cli.BoolFlag{
			Name:  "skip-changelog",
			Usage: "skip check for changelog",
		},
		cli.BoolFlag{
			Name:  "skip-code-of-conduct",
			Usage: "skip check for code of conduct",
		},
		cli.StringFlag{
			Name:  "github, g",
			Value: "",
			Usage: "GitHub repository as owner/repo",
		},
		cli.StringFlag{
			Name:   "token, t",
			Value:  "",
			EnvVar: "FLINT_TOKEN",
			Usage:  "GitHub API access token",
		},
	}
	app.Action = func(c *cli.Context) {
		run(c)
	}

	return app
}

type runFunc func(*cli.Context)

var run = func(c *cli.Context) {
	project := newProject(c)
	flags := newFlagsFromContext(c)
	linter := &Linter{}
	summary, err := linter.Run(project, flags)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
		return
	}
	if summary != nil {
		color := !c.Bool("no-color")
		// Windows doesn't support colors
		if runtime.GOOS == "windows" {
			color = false
		}
		summary.Print(os.Stderr, color)
		os.Exit(summary.Severity())
	}
}

func newProject(c *cli.Context) Project {
	github := c.String("github")
	if len(github) > 0 {
		project := &RemoteProject{FullName: github}
		fetcher := newGitHubFetcher(c)
		err := project.Fetch(fetcher)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		return project
	} else {
		path, _ := os.Getwd()
		if len(c.Args()) > 0 {
			path = c.Args()[0]
		}
		return &LocalProject{Path: path}
	}
}

func newFlagsFromContext(c *cli.Context) *Flags {
	runBootstrap := !c.Bool("skip-bootstrap")
	runTestScript := !c.Bool("skip-test-script")
	if c.Bool("skip-scripts") {
		runBootstrap = false
		runTestScript = false
	}

	flags := &Flags{
		RunReadme:        !c.Bool("skip-readme"),
		RunContributing:  !c.Bool("skip-contributing"),
		RunLicense:       !c.Bool("skip-license"),
		RunBootstrap:     runBootstrap,
		RunTestScript:    runTestScript,
		RunChangelog:     !c.Bool("skip-changelog"),
		RunCodeOfConduct: !c.Bool("skip-code-of-conduct"),
	}
	return flags
}

var newGitHubFetcher = func(c *cli.Context) RemoteRepositoryFetcher {
	token := c.String("token")
	if len(token) > 0 {
		return NewGitHubFetcherWithToken(token)
	} else {
		return NewGitHubFetcher()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.74"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.41", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<commit_msg>fnlb: 0.0.75 release [skip ci]<commit_after>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.75"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.42", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<|endoftext|>


<commit_before>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package font defines an interface for font faces, for drawing text on an
// image.
//
// Other packages provide font face implementations. For example, a truetype
// package would provide one based on .ttf font files.
package font // import "golang.org/x/image/font"

import (
	"image"
	"image/draw"
	"io"
	"unicode/utf8"

	"golang.org/x/image/math/fixed"
)

// TODO: who is responsible for caches (glyph images, glyph indices, kerns)?
// The Drawer or the Face?

// Face is a font face. Its glyphs are often derived from a font file, such as
// "Comic_Sans_MS.ttf", but a face has a specific size, style, weight and
// hinting. For example, the 12pt and 18pt versions of Comic Sans are two
// different faces, even if derived from the same font file.
//
// A Face is not safe for concurrent use by multiple goroutines, as its methods
// may re-use implementation-specific caches and mask image buffers.
//
// To create a Face, look to other packages that implement specific font file
// formats.
type Face interface {
	io.Closer

	// Glyph returns the draw.DrawMask parameters (dr, mask, maskp) to draw r's
	// glyph at the sub-pixel destination location dot, and that glyph's
	// advance width.
	//
	// It returns !ok if the face does not contain a glyph for r.
	//
	// The contents of the mask image returned by one Glyph call may change
	// after the next Glyph call. Callers that want to cache the mask must make
	// a copy.
	Glyph(dot fixed.Point26_6, r rune) (
		dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool)

	// GlyphBounds returns the bounding box of r's glyph, drawn at a dot equal
	// to the origin, and that glyph's advance width.
	//
	// It returns !ok if the face does not contain a glyph for r.
	//
	// The glyph's ascent and descent equal -bounds.Min.Y and +bounds.Max.Y. A
	// visual depiction of what these metrics are is at
	// https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyph_metrics_2x.png
	GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool)

	// GlyphAdvance returns the advance width of r's glyph.
	//
	// It returns !ok if the face does not contain a glyph for r.
	GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool)

	// Kern returns the horizontal adjustment for the kerning pair (r0, r1). A
	// positive kern means to move the glyphs further apart.
	Kern(r0, r1 rune) fixed.Int26_6

	// Metrics returns the metrics for this Face.
	Metrics() Metrics

	// TODO: ColoredGlyph for various emoji?
	// TODO: Ligatures? Shaping?
}

// Metrics holds the metrics for a Face. A visual depiction is at
// https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyph_metrics_2x.png
type Metrics struct {
	// Height is the recommended amount of vertical space between two lines of
	// text.
	Height fixed.Int26_6

	// Ascent is the distance from the top of a line to its baseline.
	Ascent fixed.Int26_6

	// Descent is the distance from the bottom of a line to its baseline. The
	// value is typically positive, even though a descender goes below the
	// baseline.
	Descent fixed.Int26_6
}

// Drawer draws text on a destination image.
//
// A Drawer is not safe for concurrent use by multiple goroutines, since its
// Face is not.
type Drawer struct {
	// Dst is the destination image.
	Dst draw.Image
	// Src is the source image.
	Src image.Image
	// Face provides the glyph mask images.
	Face Face
	// Dot is the baseline location to draw the next glyph. The majority of the
	// affected pixels will be above and to the right of the dot, but some may
	// be below or to the left. For example, drawing a 'j' in an italic face
	// may affect pixels below and to the left of the dot.
	Dot fixed.Point26_6

	// TODO: Clip image.Image?
	// TODO: SrcP image.Point for Src images other than *image.Uniform? How
	// does it get updated during DrawString?
}

// TODO: should DrawString return the last rune drawn, so the next DrawString
// call can kern beforehand? Or should that be the responsibility of the caller
// if they really want to do that, since they have to explicitly shift d.Dot
// anyway? What if ligatures span more than two runes? What if grapheme
// clusters span multiple runes?
//
// TODO: do we assume that the input is in any particular Unicode Normalization
// Form?
//
// TODO: have DrawRunes(s []rune)? DrawRuneReader(io.RuneReader)?? If we take
// io.RuneReader, we can't assume that we can rewind the stream.
//
// TODO: how does this work with line breaking: drawing text up until a
// vertical line? Should DrawString return the number of runes drawn?

// DrawBytes draws s at the dot and advances the dot's location.
//
// It is equivalent to DrawString(string(s)) but may be more efficient.
func (d *Drawer) DrawBytes(s []byte) {
	prevC := rune(-1)
	for len(s) > 0 {
		c, size := utf8.DecodeRune(s)
		s = s[size:]
		if prevC >= 0 {
			d.Dot.X += d.Face.Kern(prevC, c)
		}
		dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c)
		if !ok {
			// TODO: is falling back on the U+FFFD glyph the responsibility of
			// the Drawer or the Face?
			// TODO: set prevC = '\ufffd'?
			continue
		}
		draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
		d.Dot.X += advance
		prevC = c
	}
}

// DrawString draws s at the dot and advances the dot's location.
func (d *Drawer) DrawString(s string) {
	prevC := rune(-1)
	for _, c := range s {
		if prevC >= 0 {
			d.Dot.X += d.Face.Kern(prevC, c)
		}
		dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c)
		if !ok {
			// TODO: is falling back on the U+FFFD glyph the responsibility of
			// the Drawer or the Face?
			// TODO: set prevC = '\ufffd'?
			continue
		}
		draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
		d.Dot.X += advance
		prevC = c
	}
}

// MeasureBytes returns how far dot would advance by drawing s.
//
// It is equivalent to MeasureString(string(s)) but may be more efficient.
func (d *Drawer) MeasureBytes(s []byte) (advance fixed.Int26_6) {
	return MeasureBytes(d.Face, s)
}

// MeasureString returns how far dot would advance by drawing s.
func (d *Drawer) MeasureString(s string) (advance fixed.Int26_6) {
	return MeasureString(d.Face, s)
}

// MeasureBytes returns how far dot would advance by drawing s with f.
//
// It is equivalent to MeasureString(string(s)) but may be more efficient.
func MeasureBytes(f Face, s []byte) (advance fixed.Int26_6) {
	prevC := rune(-1)
	for len(s) > 0 {
		c, size := utf8.DecodeRune(s)
		s = s[size:]
		if prevC >= 0 {
			advance += f.Kern(prevC, c)
		}
		a, ok := f.GlyphAdvance(c)
		if !ok {
			// TODO: is falling back on the U+FFFD glyph the responsibility of
			// the Drawer or the Face?
			// TODO: set prevC = '\ufffd'?
			continue
		}
		advance += a
		prevC = c
	}
	return advance
}

// MeasureString returns how far dot would advance by drawing s with f.
func MeasureString(f Face, s string) (advance fixed.Int26_6) {
	prevC := rune(-1)
	for _, c := range s {
		if prevC >= 0 {
			advance += f.Kern(prevC, c)
		}
		a, ok := f.GlyphAdvance(c)
		if !ok {
			// TODO: is falling back on the U+FFFD glyph the responsibility of
			// the Drawer or the Face?
			// TODO: set prevC = '\ufffd'?
			continue
		}
		advance += a
		prevC = c
	}
	return advance
}

// Hinting selects how to quantize a vector font's glyph nodes.
//
// Not all fonts support hinting.
type Hinting int

const (
	HintingNone Hinting = iota
	HintingVertical
	HintingFull
)

// Stretch selects a normal, condensed, or expanded face.
//
// Not all fonts support stretches.
type Stretch int

const (
	StretchUltraCondensed Stretch = -4
	StretchExtraCondensed Stretch = -3
	StretchCondensed      Stretch = -2
	StretchSemiCondensed  Stretch = -1
	StretchNormal         Stretch = +0
	StretchSemiExpanded   Stretch = +1
	StretchExpanded       Stretch = +2
	StretchExtraExpanded  Stretch = +3
	StretchUltraExpanded  Stretch = +4
)

// Style selects a normal, italic, or oblique face.
//
// Not all fonts support styles.
type Style int

const (
	StyleNormal Style = iota
	StyleItalic
	StyleOblique
)

// Weight selects a normal, light or bold face.
//
// Not all fonts support weights.
//
// The named Weight constants (e.g. WeightBold) correspond to CSS' common
// weight names (e.g. "Bold"), but the numerical values differ, so that in Go,
// the zero value means to use a normal weight. For the CSS names and values,
// see https://developer.mozilla.org/en/docs/Web/CSS/font-weight
type Weight int

const (
	WeightThin       Weight = -3 // CSS font-weight value 100.
	WeightExtraLight Weight = -2 // CSS font-weight value 200.
	WeightLight      Weight = -1 // CSS font-weight value 300.
	WeightNormal     Weight = +0 // CSS font-weight value 400.
	WeightMedium     Weight = +1 // CSS font-weight value 500.
	WeightSemiBold   Weight = +2 // CSS font-weight value 600.
	WeightBold       Weight = +3 // CSS font-weight value 700.
	WeightExtraBold  Weight = +4 // CSS font-weight value 800.
	WeightBlack      Weight = +5 // CSS font-weight value 900.
)
<commit_msg>font: add bounds measurement methods<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package font defines an interface for font faces, for drawing text on an
// image.
//
// Other packages provide font face implementations. For example, a truetype
// package would provide one based on .ttf font files.
package font // import "golang.org/x/image/font"

import (
	"image"
	"image/draw"
	"io"
	"unicode/utf8"

	"golang.org/x/image/math/fixed"
)

// TODO: who is responsible for caches (glyph images, glyph indices, kerns)?
// The Drawer or the Face?

// Face is a font face. Its glyphs are often derived from a font file, such as
// "Comic_Sans_MS.ttf", but a face has a specific size, style, weight and
// hinting. For example, the 12pt and 18pt versions of Comic Sans are two
// different faces, even if derived from the same font file.
//
// A Face is not safe for concurrent use by multiple goroutines, as its methods
// may re-use implementation-specific caches and mask image buffers.
//
// To create a Face, look to other packages that implement specific font file
// formats.
type Face interface {
	io.Closer

	// Glyph returns the draw.DrawMask parameters (dr, mask, maskp) to draw r's
	// glyph at the sub-pixel destination location dot, and that glyph's
	// advance width.
	//
	// It returns !ok if the face does not contain a glyph for r.
	//
	// The contents of the mask image returned by one Glyph call may change
	// after the next Glyph call. Callers that want to cache the mask must make
	// a copy.
	Glyph(dot fixed.Point26_6, r rune) (
		dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool)

	// GlyphBounds returns the bounding box of r's glyph, drawn at a dot equal
	// to the origin, and that glyph's advance width.
	//
	// It returns !ok if the face does not contain a glyph for r.
	//
	// The glyph's ascent and descent equal -bounds.Min.Y and +bounds.Max.Y. A
	// visual depiction of what these metrics are is at
	// https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyph_metrics_2x.png
	GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool)

	// GlyphAdvance returns the advance width of r's glyph.
	//
	// It returns !ok if the face does not contain a glyph for r.
	GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool)

	// Kern returns the horizontal adjustment for the kerning pair (r0, r1). A
	// positive kern means to move the glyphs further apart.
	Kern(r0, r1 rune) fixed.Int26_6

	// Metrics returns the metrics for this Face.
	Metrics() Metrics

	// TODO: ColoredGlyph for various emoji?
	// TODO: Ligatures? Shaping?
}

// Metrics holds the metrics for a Face. A visual depiction is at
// https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyph_metrics_2x.png
type Metrics struct {
	// Height is the recommended amount of vertical space between two lines of
	// text.
	Height fixed.Int26_6

	// Ascent is the distance from the top of a line to its baseline.
	Ascent fixed.Int26_6

	// Descent is the distance from the bottom of a line to its baseline. The
	// value is typically positive, even though a descender goes below the
	// baseline.
	Descent fixed.Int26_6
}

// Drawer draws text on a destination image.
//
// A Drawer is not safe for concurrent use by multiple goroutines, since its
// Face is not.
type Drawer struct {
	// Dst is the destination image.
	Dst draw.Image
	// Src is the source image.
	Src image.Image
	// Face provides the glyph mask images.
	Face Face
	// Dot is the baseline location to draw the next glyph. The majority of the
	// affected pixels will be above and to the right of the dot, but some may
	// be below or to the left. For example, drawing a 'j' in an italic face
	// may affect pixels below and to the left of the dot.
	Dot fixed.Point26_6

	// TODO: Clip image.Image?
	// TODO: SrcP image.Point for Src images other than *image.Uniform? How
	// does it get updated during DrawString?
}

// TODO: should DrawString return the last rune drawn, so the next DrawString
// call can kern beforehand? Or should that be the responsibility of the caller
// if they really want to do that, since they have to explicitly shift d.Dot
// anyway? What if ligatures span more than two runes? What if grapheme
// clusters span multiple runes?
//
// TODO: do we assume that the input is in any particular Unicode Normalization
// Form?
//
// TODO: have DrawRunes(s []rune)? DrawRuneReader(io.RuneReader)?? If we take
// io.RuneReader, we can't assume that we can rewind the stream.
//
// TODO: how does this work with line breaking: drawing text up until a
// vertical line? Should DrawString return the number of runes drawn?

// DrawBytes draws s at the dot and advances the dot's location.
//
// It is equivalent to DrawString(string(s)) but may be more efficient.
func (d *Drawer) DrawBytes(s []byte) {
	prevC := rune(-1)
	for len(s) > 0 {
		c, size := utf8.DecodeRune(s)
		s = s[size:]
		if prevC >= 0 {
			d.Dot.X += d.Face.Kern(prevC, c)
		}
		dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c)
		if !ok {
			// TODO: is falling back on the U+FFFD glyph the responsibility of
			// the Drawer or the Face?
			// TODO: set prevC = '\ufffd'?
			continue
		}
		draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
		d.Dot.X += advance
		prevC = c
	}
}

// DrawString draws s at the dot and advances the dot's location.
func (d *Drawer) DrawString(s string) {
	prevC := rune(-1)
	for _, c := range s {
		if prevC >= 0 {
			d.Dot.X += d.Face.Kern(prevC, c)
		}
		dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c)
		if !ok {
			// TODO: is falling back on the U+FFFD glyph the responsibility of
			// the Drawer or the Face?
			// TODO: set prevC = '\ufffd'?
			continue
		}
		draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
		d.Dot.X += advance
		prevC = c
	}
}

// BoundBytes returns the bounding box of s, drawn at the drawer dot, as well as
// the advance.
//
// It is equivalent to BoundBytes(string(s)) but may be more efficient.
func (d *Drawer) BoundBytes(s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
	bounds, advance = BoundBytes(d.Face, s)
	bounds.Min = bounds.Min.Add(d.Dot)
	bounds.Max = bounds.Max.Add(d.Dot)
	return
}

// BoundString returns the bounding box of s, drawn at the drawer dot, as well
// as the advance.
func (d *Drawer) BoundString(s string) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
	bounds, advance = BoundString(d.Face, s)
	bounds.Min = bounds.Min.Add(d.Dot)
	bounds.Max = bounds.Max.Add(d.Dot)
	return
}

// MeasureBytes returns how far dot would advance by drawing s.
//
// It is equivalent to MeasureString(string(s)) but may be more efficient.
func (d *Drawer) MeasureBytes(s []byte) (advance fixed.Int26_6) {
	return MeasureBytes(d.Face, s)
}

// MeasureString returns how far dot would advance by drawing s.
func (d *Drawer) MeasureString(s string) (advance fixed.Int26_6) {
	return MeasureString(d.Face, s)
}

// BoundBytes returns the bounding box of s with f, drawn at a dot equal to the
// origin, as well as the advance.
//
// It is equivalent to BoundString(string(s)) but may be more efficient.
func BoundBytes(f Face, s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
	prevC := rune(-1)
	for len(s) > 0 {
		c, size := utf8.DecodeRune(s)
		s = s[size:]
		if prevC >= 0 {
			advance += f.Kern(prevC, c)
		}
		b, a, ok := f.GlyphBounds(c)
		if !ok {
			// TODO: is falling back on the U+FFFD glyph the responsibility of
			// the Drawer or the Face?
			// TODO: set prevC = '\ufffd'?
			continue
		}
		bounds = grow(bounds, b, advance)
		advance += a
		prevC = c
	}
	return
}

// BoundString returns the bounding box of s with f, drawn at a dot equal to the
// origin, as well as the advance.
func BoundString(f Face, s string) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
	prevC := rune(-1)
	for _, c := range s {
		if prevC >= 0 {
			advance += f.Kern(prevC, c)
		}
		b, a, ok := f.GlyphBounds(c)
		if !ok {
			// TODO: is falling back on the U+FFFD glyph the responsibility of
			// the Drawer or the Face?
			// TODO: set prevC = '\ufffd'?
			continue
		}
		bounds = grow(bounds, b, advance)
		advance += a
		prevC = c
	}
	return
}

// grow returns the smallest rectangle containing both b and b2+shift.
func grow(b, b2 fixed.Rectangle26_6, shift fixed.Int26_6) fixed.Rectangle26_6 {
	x := b2.Min.X + shift
	if b.Min.X > x {
		b.Min.X = x
	}
	if b.Min.Y > b2.Min.Y {
		b.Min.Y = b2.Min.Y
	}
	x = b2.Max.X + shift
	if b.Max.X < x {
		b.Max.X = x
	}
	if b.Max.Y < b2.Max.Y {
		b.Max.Y = b2.Max.Y
	}
	return b
}

// MeasureBytes returns how far dot would advance by drawing s with f.
//
// It is equivalent to MeasureString(string(s)) but may be more efficient.
func MeasureBytes(f Face, s []byte) (advance fixed.Int26_6) {
	prevC := rune(-1)
	for len(s) > 0 {
		c, size := utf8.DecodeRune(s)
		s = s[size:]
		if prevC >= 0 {
			advance += f.Kern(prevC, c)
		}
		a, ok := f.GlyphAdvance(c)
		if !ok {
			// TODO: is falling back on the U+FFFD glyph the responsibility of
			// the Drawer or the Face?
			// TODO: set prevC = '\ufffd'?
			continue
		}
		advance += a
		prevC = c
	}
	return advance
}

// MeasureString returns how far dot would advance by drawing s with f.
func MeasureString(f Face, s string) (advance fixed.Int26_6) {
	prevC := rune(-1)
	for _, c := range s {
		if prevC >= 0 {
			advance += f.Kern(prevC, c)
		}
		a, ok := f.GlyphAdvance(c)
		if !ok {
			// TODO: is falling back on the U+FFFD glyph the responsibility of
			// the Drawer or the Face?
			// TODO: set prevC = '\ufffd'?
			continue
		}
		advance += a
		prevC = c
	}
	return advance
}

// Hinting selects how to quantize a vector font's glyph nodes.
//
// Not all fonts support hinting.
type Hinting int

const (
	HintingNone Hinting = iota
	HintingVertical
	HintingFull
)

// Stretch selects a normal, condensed, or expanded face.
//
// Not all fonts support stretches.
type Stretch int

const (
	StretchUltraCondensed Stretch = -4
	StretchExtraCondensed Stretch = -3
	StretchCondensed      Stretch = -2
	StretchSemiCondensed  Stretch = -1
	StretchNormal         Stretch = +0
	StretchSemiExpanded   Stretch = +1
	StretchExpanded       Stretch = +2
	StretchExtraExpanded  Stretch = +3
	StretchUltraExpanded  Stretch = +4
)

// Style selects a normal, italic, or oblique face.
//
// Not all fonts support styles.
type Style int

const (
	StyleNormal Style = iota
	StyleItalic
	StyleOblique
)

// Weight selects a normal, light or bold face.
//
// Not all fonts support weights.
//
// The named Weight constants (e.g. WeightBold) correspond to CSS' common
// weight names (e.g. "Bold"), but the numerical values differ, so that in Go,
// the zero value means to use a normal weight. For the CSS names and values,
// see https://developer.mozilla.org/en/docs/Web/CSS/font-weight
type Weight int

const (
	WeightThin       Weight = -3 // CSS font-weight value 100.
	WeightExtraLight Weight = -2 // CSS font-weight value 200.
	WeightLight      Weight = -1 // CSS font-weight value 300.
	WeightNormal     Weight = +0 // CSS font-weight value 400.
	WeightMedium     Weight = +1 // CSS font-weight value 500.
	WeightSemiBold   Weight = +2 // CSS font-weight value 600.
	WeightBold       Weight = +3 // CSS font-weight value 700.
	WeightExtraBold  Weight = +4 // CSS font-weight value 800.
	WeightBlack      Weight = +5 // CSS font-weight value 900.
)
<|endoftext|>


<commit_before>package main

// This is a direct port of https://gist.github.com/benjojo/0124c7875113831a4274

import (
	"fmt"
	"strconv"
	"strings"
)

// PacketType can be:
// * Status Report
// * GPGGA
// * New Mic-E
// * Old Mic-E
// * Location
type APRSPacket struct {
	Callsign      string // Done!
	PacketType    string
	Latitude      string
	Longitude     string
	Altitude      string
	GPSTime       string
	RawData       string
	Symbol        string
	Heading       string
	PHG           string
	Speed         string
	Destination   string // Done!
	Status        string
	WindDirection string
	WindSpeed     string
	WindGust      string
	WeatherTemp   string
	RainHour      string
	RainDay       string
	RainMidnight  string
	Humidity      string
	Pressure      string
	Luminosity    string
	Snowfall      string
	Raincounter   string
}

func ParseAPRSPacket(input string) (p APRSPacket, e error) {
	if input == "" {
		e = fmt.Errorf("Could not parse the packet because the packet line is blank")
		return p, e
	}

	if !strings.Contains(input, ">") {
		e = fmt.Errorf("This libary does not support this kind of packet.")
		return p, e
	}
	p = APRSPacket{}
	CommaParts := strings.Split(input, ",")
	RouteString := CommaParts[0]
	RouteParts := strings.Split(RouteString, ">")
	if len(RouteParts) != 2 {
		e = fmt.Errorf("There was not one > in the route part of the packet, dunno how to decode this")
		return p, e
	}
	p.Callsign = RouteParts[0]
	p.Destination = RouteParts[1]

	LocationOfStatusMarker := strings.Index(input, ":>")
	LocationOfNormalMarker := strings.Index(input, ">")

	if LocationOfStatusMarker > LocationOfNormalMarker {
		p.PacketType = "Status Report"
		RawArray := []byte(input[LocationOfStatusMarker+2 : (LocationOfStatusMarker+2)+(len(input)-LocationOfStatusMarker-2)])
		if len(RawArray) > 6 && strings.ToLower(string(RawArray[6])) == "z" {
			p.GPSTime = input[LocationOfStatusMarker+2 : LocationOfStatusMarker+8]
			p.Status = input[LocationOfStatusMarker+2 : (LocationOfStatusMarker+2)+len(input)-LocationOfStatusMarker-9]
		} else {
			p.Status = input[LocationOfStatusMarker+2 : (LocationOfStatusMarker+2)+len(input)-LocationOfStatusMarker-2]
		}
	}

	// Test if the packet is a GPGGA packet
	if strings.Contains(input, ":$GPGGA,") {
		p.PacketType = "GPGGA"
		GPGGALocation := strings.Index(input, ":$GPGGA,")
		RawData := input[GPGGALocation : GPGGALocation+(len(input)-GPGGALocation)]
		SplitData := strings.Split(RawData, ",")
		if len(SplitData) < 9 {
			e = fmt.Errorf("There was not enough data inside the GPGGA packet to decode it")
			return p, e
		}
		p.GPSTime = SplitData[1]

		// Lat
		DegLatitude := SplitData[2]
		DegLatMin, e := strconv.ParseFloat(DegLatitude[2:2+len(DegLatitude)-2], 64)
		if e != nil {
			e = fmt.Errorf("Could not decode the DegLatMin part of the GPGGA packet")
			return p, e
		}
		DegLatMin = DegLatMin / 60
		StrDegLatMin := fmt.Sprintf("%f", DegLatMin)
		p.Latitude = fmt.Sprintf("%s%s", DegLatitude[:2], StrDegLatMin[1:len(StrDegLatMin)-1])

		if SplitData[3] == "S" {
			p.Latitude = fmt.Sprintf("-%s", p.Latitude)
		}

		// Long
		DegLongitude := SplitData[4]
		DegLonMin, e := strconv.ParseFloat(DegLongitude[3:3+len(DegLongitude)-3], 64)
		if e != nil {
			e = fmt.Errorf("Could not decode the DegLonMin part of the GPGGA packet")
			return p, e
		}
		DegLonMin = DegLonMin / 60
		StrDegLonMin := fmt.Sprintf("%f", DegLonMin)
		p.Longitude = fmt.Sprintf("%s%s", DegLongitude[:3], StrDegLonMin[1:len(StrDegLonMin)-1])

		if SplitData[3] == "W" {
			p.Longitude = fmt.Sprintf("-%s", p.Longitude)
		}

		f, e := strconv.ParseFloat(SplitData[9], 64)
		if e != nil {
			e = fmt.Errorf("Could not decode the Altitude part of the GPGGA packet")
			return p, e
		}
		p.Altitude = fmt.Sprintf("%f", f)
	}

	// Test if the packet is a Mic-E packet
	if strings.Index(input, ":`") != -1 || strings.Index(input, ":'") != -1 {
		// MicEPtr := 0
		if strings.Index(input, ":`") != -1 {
			p.PacketType = "New Mic-E"
			// MicEPtr = strings.Index(input, ":`")
		} else {
			p.PacketType = "Old Mic-E"
			// MicEPtr = strings.Index(input, ":'")
		}
		e = fmt.Errorf("Mic-E is currently not supported")
		return p, e
	}

	// Test to see if its a location packet

	// FirstChr = line.IndexOf(":/")  // With Timestamp
	// SecondChr = line.IndexOf(":!") // Without Timestamp
	// ThirdChr = line.IndexOf(":@")  // With Timestamp and APRS Messaging
	// FourthChr = line.IndexOf(":=") // Without Timestamp and Messaging
	LocationPtr := 0
	TimestampPtr := strings.Index(input, ":!")
	if strings.Index(input, ":@") != -1 { // With Timestamp and APRS Messaging
		LocationPtr = strings.Index(input, ":@")
	}

	if strings.Index(input, ":=") != -1 { // Without Timestamp and Messaging
		LocationPtr = strings.Index(input, ":=")
	}
	LocationPtrStr := LocationSlice(input, int64(LocationPtr), 8)
	TimestampPtrStr := LocationSlice(input, int64(TimestampPtr), 9)

	if (LocationPtr != -1 && (LocationPtrStr == "H" || LocationPtrStr == "Z" || LocationPtrStr == "/")) ||
		(TimestampPtr != -1 && (TimestampPtrStr == "S" || TimestampPtrStr == "N")) {

		p.PacketType = "Location"
		if LocationPtr != -1 && (LocationPtrStr == "H" || LocationPtrStr == "Z" || LocationPtrStr == "/") {
			p.GPSTime = input[TimestampPtr+2 : TimestampPtr+8]
		} else {
			TimestampPtr = TimestampPtr - 7
		}
		p.Symbol = fmt.Sprintf("%s%s", input[LocationPtr+17:LocationPtr+18], input[LocationPtr+27:LocationPtr+28])

		// Lat
		DegLatMin, e := strconv.ParseFloat(input[LocationPtr+11:LocationPtr+16], 64)
		if e != nil {
			// Go bang
			e = fmt.Errorf("Could not make DegLatMin a float")
			return p, e
		}
		DegLatMin = (DegLatMin / 60)

		DegLatMinStr := fmt.Sprintf("%f", DegLatMin)
		p.Latitude = fmt.Sprintf("%s%s", input[LocationPtr+9:LocationPtr+11], DegLatMinStr[1:len(DegLatMinStr)-1])

		if input[LocationPtr+16:LocationPtr+17] == "S" {
			p.Latitude = fmt.Sprintf("-%s", p.Latitude)
		}

		// Long
		DegLonMin, e := strconv.ParseFloat(input[LocationPtr+21:LocationPtr+26], 64)
		if e != nil {
			// Go bang
			e = fmt.Errorf("Could not make DegLonMin a float")
			return p, e
		}
		DegLonMin = (DegLonMin / 60)

		DegLonMinStr := fmt.Sprintf("%f", DegLonMin)
		p.Longitude = fmt.Sprintf("%s%s", input[LocationPtr+19:LocationPtr+21], DegLonMinStr[1:len(DegLonMinStr)-1])

		if input[LocationPtr+16:LocationPtr+17] == "S" {
			p.Longitude = fmt.Sprintf("-%s", p.Longitude)
		}

	}

	return p, e
}

func LocationSlice(line string, LocationPtr int64, ptr int64) string {
	bit := strings.ToUpper(line[LocationPtr+ptr : (LocationPtr+ptr)+1])
	return bit
}
<commit_msg>Detect weather reports<commit_after>package main

// This is a direct port of https://gist.github.com/benjojo/0124c7875113831a4274

import (
	"fmt"
	"strconv"
	"strings"
)

// PacketType can be:
// * Status Report
// * GPGGA
// * New Mic-E
// * Old Mic-E
// * Location
// * Weather Report
type APRSPacket struct {
	Callsign      string // Done!
	PacketType    string
	Latitude      string
	Longitude     string
	Altitude      string
	GPSTime       string
	RawData       string
	Symbol        string
	Heading       string
	PHG           string
	Speed         string
	Destination   string // Done!
	Status        string
	WindDirection string
	WindSpeed     string
	WindGust      string
	WeatherTemp   string
	RainHour      string
	RainDay       string
	RainMidnight  string
	Humidity      string
	Pressure      string
	Luminosity    string
	Snowfall      string
	Raincounter   string
}

func ParseAPRSPacket(input string) (p APRSPacket, e error) {
	if input == "" {
		e = fmt.Errorf("Could not parse the packet because the packet line is blank")
		return p, e
	}

	if !strings.Contains(input, ">") {
		e = fmt.Errorf("This libary does not support this kind of packet.")
		return p, e
	}
	p = APRSPacket{}
	CommaParts := strings.Split(input, ",")
	RouteString := CommaParts[0]
	RouteParts := strings.Split(RouteString, ">")
	if len(RouteParts) != 2 {
		e = fmt.Errorf("There was not one > in the route part of the packet, dunno how to decode this")
		return p, e
	}
	p.Callsign = RouteParts[0]
	p.Destination = RouteParts[1]

	LocationOfStatusMarker := strings.Index(input, ":>")
	LocationOfNormalMarker := strings.Index(input, ">")

	if LocationOfStatusMarker > LocationOfNormalMarker {
		p.PacketType = "Status Report"
		RawArray := []byte(input[LocationOfStatusMarker+2 : (LocationOfStatusMarker+2)+(len(input)-LocationOfStatusMarker-2)])
		if len(RawArray) > 6 && strings.ToLower(string(RawArray[6])) == "z" {
			p.GPSTime = input[LocationOfStatusMarker+2 : LocationOfStatusMarker+8]
			p.Status = input[LocationOfStatusMarker+2 : (LocationOfStatusMarker+2)+len(input)-LocationOfStatusMarker-9]
		} else {
			p.Status = input[LocationOfStatusMarker+2 : (LocationOfStatusMarker+2)+len(input)-LocationOfStatusMarker-2]
		}
	}

	// Test if the packet is a GPGGA packet
	if strings.Contains(input, ":$GPGGA,") {
		p.PacketType = "GPGGA"
		GPGGALocation := strings.Index(input, ":$GPGGA,")
		RawData := input[GPGGALocation : GPGGALocation+(len(input)-GPGGALocation)]
		SplitData := strings.Split(RawData, ",")
		if len(SplitData) < 9 {
			e = fmt.Errorf("There was not enough data inside the GPGGA packet to decode it")
			return p, e
		}
		p.GPSTime = SplitData[1]

		// Lat
		DegLatitude := SplitData[2]
		DegLatMin, e := strconv.ParseFloat(DegLatitude[2:2+len(DegLatitude)-2], 64)
		if e != nil {
			e = fmt.Errorf("Could not decode the DegLatMin part of the GPGGA packet")
			return p, e
		}
		DegLatMin = DegLatMin / 60
		StrDegLatMin := fmt.Sprintf("%f", DegLatMin)
		p.Latitude = fmt.Sprintf("%s%s", DegLatitude[:2], StrDegLatMin[1:len(StrDegLatMin)-1])

		if SplitData[3] == "S" {
			p.Latitude = fmt.Sprintf("-%s", p.Latitude)
		}

		// Long
		DegLongitude := SplitData[4]
		DegLonMin, e := strconv.ParseFloat(DegLongitude[3:3+len(DegLongitude)-3], 64)
		if e != nil {
			e = fmt.Errorf("Could not decode the DegLonMin part of the GPGGA packet")
			return p, e
		}
		DegLonMin = DegLonMin / 60
		StrDegLonMin := fmt.Sprintf("%f", DegLonMin)
		p.Longitude = fmt.Sprintf("%s%s", DegLongitude[:3], StrDegLonMin[1:len(StrDegLonMin)-1])

		if SplitData[3] == "W" {
			p.Longitude = fmt.Sprintf("-%s", p.Longitude)
		}

		f, e := strconv.ParseFloat(SplitData[9], 64)
		if e != nil {
			e = fmt.Errorf("Could not decode the Altitude part of the GPGGA packet")
			return p, e
		}
		p.Altitude = fmt.Sprintf("%f", f)
	}

	// Test if the packet is a Mic-E packet
	if strings.Index(input, ":`") != -1 || strings.Index(input, ":'") != -1 {
		// MicEPtr := 0
		if strings.Index(input, ":`") != -1 {
			p.PacketType = "New Mic-E"
			// MicEPtr = strings.Index(input, ":`")
		} else {
			p.PacketType = "Old Mic-E"
			// MicEPtr = strings.Index(input, ":'")
		}
		e = fmt.Errorf("Mic-E is currently not supported")
		return p, e
	}

	// Test to see if its a location packet

	// FirstChr = line.IndexOf(":/")  // With Timestamp
	// SecondChr = line.IndexOf(":!") // Without Timestamp
	// ThirdChr = line.IndexOf(":@")  // With Timestamp and APRS Messaging
	// FourthChr = line.IndexOf(":=") // Without Timestamp and Messaging
	LocationPtr := 0
	TimestampPtr := strings.Index(input, ":!")
	if strings.Index(input, ":@") != -1 { // With Timestamp and APRS Messaging
		LocationPtr = strings.Index(input, ":@")
	}

	if strings.Index(input, ":=") != -1 { // Without Timestamp and Messaging
		LocationPtr = strings.Index(input, ":=")
	}
	LocationPtrStr := LocationSlice(input, int64(LocationPtr), 8)
	TimestampPtrStr := LocationSlice(input, int64(TimestampPtr), 9)

	if (LocationPtr != -1 && (LocationPtrStr == "H" || LocationPtrStr == "Z" || LocationPtrStr == "/")) ||
		(TimestampPtr != -1 && (TimestampPtrStr == "S" || TimestampPtrStr == "N")) {

		p.PacketType = "Location"
		if LocationPtr != -1 && (LocationPtrStr == "H" || LocationPtrStr == "Z" || LocationPtrStr == "/") {
			p.GPSTime = input[TimestampPtr+2 : TimestampPtr+8]
		} else {
			TimestampPtr = TimestampPtr - 7
		}
		p.Symbol = fmt.Sprintf("%s%s", input[LocationPtr+17:LocationPtr+18], input[LocationPtr+27:LocationPtr+28])

		// Lat
		DegLatMin, e := strconv.ParseFloat(input[LocationPtr+11:LocationPtr+16], 64)
		if e != nil {
			// Go bang
			e = fmt.Errorf("Could not make DegLatMin a float")
			return p, e
		}
		DegLatMin = (DegLatMin / 60)

		DegLatMinStr := fmt.Sprintf("%f", DegLatMin)
		p.Latitude = fmt.Sprintf("%s%s", input[LocationPtr+9:LocationPtr+11], DegLatMinStr[1:len(DegLatMinStr)-1])

		if input[LocationPtr+16:LocationPtr+17] == "S" {
			p.Latitude = fmt.Sprintf("-%s", p.Latitude)
		}

		// Long
		DegLonMin, e := strconv.ParseFloat(input[LocationPtr+21:LocationPtr+26], 64)
		if e != nil {
			// Go bang
			e = fmt.Errorf("Could not make DegLonMin a float")
			return p, e
		}
		DegLonMin = (DegLonMin / 60)

		DegLonMinStr := fmt.Sprintf("%f", DegLonMin)
		p.Longitude = fmt.Sprintf("%s%s", input[LocationPtr+19:LocationPtr+21], DegLonMinStr[1:len(DegLonMinStr)-1])

		if input[LocationPtr+16:LocationPtr+17] == "S" {
			p.Longitude = fmt.Sprintf("-%s", p.Longitude)
		}

		// Is this packet a weather report?
		if input[LocationPtr+27:LocationPtr+28] == "_" && input[LocationPtr+31:LocationPtr+32] == "/" {
			// Yes it is.
			p.PacketType = "Weather Report"
		}
	}

	return p, e
}

func LocationSlice(line string, LocationPtr int64, ptr int64) string {
	bit := strings.ToUpper(line[LocationPtr+ptr : (LocationPtr+ptr)+1])
	return bit
}
<|endoftext|>


<commit_before>package framework

import (
	"net/http"
)

type Server interface {
	SetHandler(http.Handler)
	SetLogger(LogWriter)
	SetAddr(string)
	ListenAndServe() error
	ListenAndServeTLS(string, string) error
}

type Error interface {
	error
	GetStatus() int
	GetCode() string
	GetType() string
	GetMessage() string
	Log(LogWriter)
}

type Config interface {
	Get(string) Value
}

type Valuer interface {
	Values() Values
	SetValue(interface{}, interface{})
	GetValue(interface{}) Value
	Value(interface{}) interface{}
}

type ParamValuer interface {
	Param(string) ParamValue
	ParamOk(string) (ParamValue, bool)
	Params(...string) ParamValues
}

type Context interface {
	LogWriter
	Request
	Response
	Valuer
	Operation() Operation
	Locale() Locale
	ID() int64
	User() User
}

type Request interface {
	Sessioner
	ParamValuer
	Path() string
	Method() string
}

type Response interface {
	http.ResponseWriter
	IsIndented() bool
}

type Operations interface {
	Append(...Operation)
	Set(...Operation)
	Get() []Operation
	GetByIndex(int) Operation
	GetByName(string) Operation
	Len() int
}

type ModelStore interface {
	Get()
	Create()
	Edit()
	Remove()
}

type Operation interface {
	BuildPather
	Route() Route
	GetName() string
	GetMethods() []string
	GetPath() string
	GetFullPath() string
	GetSchemes() []string
	GetAllSchemes() []string
	GetAccepts() []string
	GetAllAccepts() []string
	GetReturns() []string
	GetAllReturns() []string
	// Param(string) Param
	// Params(...string) Params
	// BodyParam(string) Param
	// BodyParams(...string) Params
	// HeaderParam(string) Param
	// HeaderParams(...string) Params
	// PathParam(string) Param
	// PathParams(...string) Params
	// QueryParam(string) Param
	// QueryParams(...string) Params
}

type Resource interface {
	Create(Context) interface{}
	Retrieve(Context) interface{}
	Update(Context) interface{}
	Delete(Context) interface{}
}

type Values map[interface{}]interface{}

func (vs *Values) Set(k interface{}, v interface{}) {
	(*vs)[k] = v
}

func (vs *Values) Get(k interface{}) Value {
	return &value{(*vs)[k]}
}

type Value interface {
	Value() interface{}
	Int() int
	Int64() int64
	Uint() uint
	Uint64() uint64
	Float32() float32
	Float64() float64
	String() string
	Bool() bool
}

type Params interface {
	ContainsFiles() bool
	ContainsBodyParams() bool
}

type Param interface {
}

type ParamValues map[string]ParamValue

type ParamValue interface {
	Value
	Name() string
	As() ValueType
	RawString() string
	IntE() (int, error)
	Int64E() (int64, error)
	UintE() (uint, error)
	Uint64E() (uint64, error)
	Float32E() (float32, error)
	Float64E() (float64, error)
	BoolE() (bool, error)
}

type BuildPather interface {
	BuildPath(...interface{}) string
}

type Route interface {
	BuildPather
	GetPath() string
	GetFullPath() string
	GetSchemes() []string
	GetAllSchemes() []string
	GetAccepts() []string
	GetAllAccepts() []string
	GetReturns() []string
	GetAllReturns() []string
}
<commit_msg>Edited Operation and Route interfaces<commit_after>package framework

import (
	"net/http"
)

type Server interface {
	SetHandler(http.Handler)
	SetLogger(LogWriter)
	SetAddr(string)
	ListenAndServe() error
	ListenAndServeTLS(string, string) error
}

type Error interface {
	error
	GetStatus() int
	GetCode() string
	GetType() string
	GetMessage() string
	Log(LogWriter)
}

type Config interface {
	Get(string) Value
}

type Valuer interface {
	Values() Values
	SetValue(interface{}, interface{})
	GetValue(interface{}) Value
	Value(interface{}) interface{}
}

type ParamValuer interface {
	Param(string) ParamValue
	ParamOk(string) (ParamValue, bool)
	Params(...string) ParamValues
}

type Context interface {
	LogWriter
	Request
	Response
	Valuer
	Operation() Operation
	Locale() Locale
	ID() int64
	User() User
}

type Request interface {
	Sessioner
	ParamValuer
	Path() string
	Method() string
}

type Response interface {
	http.ResponseWriter
	IsIndented() bool
}

type Operations interface {
	Append(...Operation)
	Set(...Operation)
	Get() []Operation
	GetByIndex(int) Operation
	GetByName(string) Operation
	Len() int
}

type ModelStore interface {
	Get()
	Create()
	Edit()
	Remove()
}

type Operation interface {
	BuildPather
	GetRoute() Route
	GetName() string
	GetMethods() []string
	GetPath() string
	GetFullPath() string
	GetSchemes() []string
	GetAccepts() []string
	GetReturns() []string
	// Param(string) Param
	// Params(...string) Params
	// BodyParam(string) Param
	// BodyParams(...string) Params
	// HeaderParam(string) Param
	// HeaderParams(...string) Params
	// PathParam(string) Param
	// PathParams(...string) Params
	// QueryParam(string) Param
	// QueryParams(...string) Params
}

type Resource interface {
	Create(Context) interface{}
	Retrieve(Context) interface{}
	Update(Context) interface{}
	Delete(Context) interface{}
}

type Values map[interface{}]interface{}

func (vs *Values) Set(k interface{}, v interface{}) {
	(*vs)[k] = v
}

func (vs *Values) Get(k interface{}) Value {
	return &value{(*vs)[k]}
}

type Value interface {
	Value() interface{}
	Int() int
	Int64() int64
	Uint() uint
	Uint64() uint64
	Float32() float32
	Float64() float64
	String() string
	Bool() bool
}

type Params interface {
	ContainsFiles() bool
	ContainsBodyParams() bool
}

type Param interface {
}

type ParamValues map[string]ParamValue

type ParamValue interface {
	Value
	Name() string
	As() ValueType
	RawString() string
	IntE() (int, error)
	Int64E() (int64, error)
	UintE() (uint, error)
	Uint64E() (uint64, error)
	Float32E() (float32, error)
	Float64E() (float64, error)
	BoolE() (bool, error)
}

type BuildPather interface {
	BuildPath(...interface{}) string
}

type Route interface {
	BuildPather
	GetPath() string
	GetFullPath() string
	GetSchemes() []string
	GetAccepts() []string
	GetReturns() []string
}
<|endoftext|>


<commit_before>// The dump package describes Lua APIs.
package dump

import (
	"bytes"
	"encoding/json"

	"github.com/anaminus/rbxmk/dump/dt"
)

func marshal(v interface{}) (b []byte, err error) {
	var buf bytes.Buffer
	j := json.NewEncoder(&buf)
	j.SetEscapeHTML(false)
	if err = j.Encode(v); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// Library describes the API of a library.
type Library struct {
	// Name is the name of the library.
	Name string
	// ImportedAs is the name that the library is imported as. Empty indicates
	// that the contents of the library are merged into the global environment.
	ImportedAs string
	// Struct contains the items of the library.
	Struct Struct `json:",omitempty"`
	// Types contains types defined by the library.
	Types TypeDefs `json:",omitempty"`
}

// Fields maps a name to a value.
type Fields map[string]Value

func (f Fields) MarshalJSON() (b []byte, err error) {
	type field struct {
		Kind  string
		Value Value
	}
	m := make(map[string]field, len(f))
	for k, v := range f {
		f := field{Kind: "", Value: v}
		switch v.(type) {
		case Property:
			f.Kind = "Property"
		case Struct:
			f.Kind = "Struct"
		case Function:
			f.Kind = "Function"
		case MultiFunction:
			f.Kind = "MultiFunction"
		default:
			continue
		}
		m[k] = f
	}
	return marshal(m)
}

// TypeDefs maps a name to a type definition.
type TypeDefs = map[string]TypeDef

// Value is a value that has a Type.
type Value interface {
	Type() dt.Type
}

// Property describes the API of a property.
type Property struct {
	// ValueType is the type of the property's value.
	ValueType dt.Type
	// ReadOnly indicates whether the property can be written to.
	ReadOnly bool `json:",omitempty"`
	// Description is a detailed description of the property.
	Description string `json:",omitempty"`
}

// Type implements Value by returning v.ValueType.
func (v Property) Type() dt.Type {
	return v.ValueType
}

// Struct describes the API of a table with a number of fields.
type Struct struct {
	// Fields are the fields of the structure.
	Fields Fields
	// Description is a detailed description of the structure.
	Description string `json:",omitempty"`
}

// Type implements Value by returning a dt.Struct that maps each field name the
// type of the field's value.
func (v Struct) Type() dt.Type {
	t := make(dt.Struct, len(v.Fields))
	for name, value := range v.Fields {
		t[name] = value.Type()
	}
	return t
}

// TypeDef describes the definition of a type.
type TypeDef struct {
	// Underlying indicates that the type has an underlying type.
	Underlying dt.Type `json:",omitempty"`
	// Operators describes the operators defined on the type.
	Operators *Operators `json:",omitempty"`
	// Operators describes the properties defined on the type.
	Properties Properties `json:",omitempty"`
	// Operators describes the methods defined on the type.
	Methods Methods `json:",omitempty"`
	// Operators describes constructor functions that create the type.
	Constructors Constructors `json:",omitempty"`
	// Description is a detailed description of the type definition.
	Description string `json:",omitempty"`
}

// Properties maps a name to a Property.
type Properties = map[string]Property

// Methods maps a name to a method.
type Methods = map[string]Function

// Constructors maps a name to a number of constructor functions.
type Constructors = map[string]MultiFunction

// Function describes the API of a function.
type Function struct {
	// Parameters are the values received by the function.
	Parameters Parameters `json:",omitempty"`
	// Returns are the values returned by the function.
	Returns Parameters `json:",omitempty"`
	// CanError returns whether the function may throw an error, excluding type
	// errors from received arguments.
	CanError bool `json:",omitempty"`
	// Description is a detailed description of the function.
	Description string `json:",omitempty"`
}

// Type implements Value by returning a dt.Function with the parameters and
// returns of the value.
func (v Function) Type() dt.Type {
	fn := dt.Function{
		Parameters: make(Parameters, len(v.Parameters)),
		Returns:    make(Parameters, len(v.Returns)),
	}
	copy(fn.Parameters, v.Parameters)
	copy(fn.Returns, v.Returns)
	return fn
}

// MultiFunction describes a Function with multiple signatures.
type MultiFunction []Function

// Type implements Value by returning dt.MultiFunctionType.
func (MultiFunction) Type() dt.Type {
	return dt.MultiFunctionType{}
}

// Parameter describes a function parameter.
type Parameter = dt.Parameter

// Parameters is a list of function parameters.
type Parameters = []Parameter

// Operators describes the operators of a type.
type Operators struct {
	// Add describes a number of signatures for the __add operator.
	Add []Binop `json:"__add,omitempty"`
	// Add describes a number of signatures for the __sub operator.
	Sub []Binop `json:"__sub,omitempty"`
	// Add describes a number of signatures for the __mul operator.
	Mul []Binop `json:"__mul,omitempty"`
	// Add describes a number of signatures for the __div operator.
	Div []Binop `json:"__div,omitempty"`
	// Add describes a number of signatures for the __mod operator.
	Mod []Binop `json:"__mod,omitempty"`
	// Add describes a number of signatures for the __pow operator.
	Pow []Binop `json:"__pow,omitempty"`
	// Add describes a number of signatures for the __concat operator.
	Concat []Binop `json:"__concat,omitempty"`

	// Eq indicates whether the type defines a __eq operator.
	Eq bool `json:"__eq,omitempty"`
	// Eq indicates whether the type defines a __le operator.
	Le bool `json:"__le,omitempty"`
	// Eq indicates whether the type defines a __lt operator.
	Lt bool `json:"__lt,omitempty"`

	// Len describes the signature for the __len operator, if defined.
	Len *Unop `json:"__len,omitempty"`
	// Len describes the signature for the __unm operator, if defined.
	Unm *Unop `json:"__unm,omitempty"`

	// Call describes the function signature for the __call operator, if
	// defined.
	Call *Function `json:"__call,omitempty"`

	Index    Value `json:"__index,omitempty"`
	Newindex Value `json:"__newindex,omitempty"`
}

// Binop describes a binary operator. The left operand is assumed to be of an
// outer type definition.
type Binop struct {
	// Operand is the type of the right operand.
	Operand dt.Type
	// Result is the type of the result of the operation.
	Result dt.Type
	// Description is a detailed description of the operator.
	Description string `json:",omitempty"`
}

// Unop describes a unary operator. The operand is assumed to be of an outer
// type definition.
type Unop struct {
	// Result is the type of the result of the operation.
	Result dt.Type
	// Description is a detailed description of the operator.
	Description string `json:",omitempty"`
}
<commit_msg>Add dump.Root to contain a number of libraries.<commit_after>// The dump package describes Lua APIs.
package dump

import (
	"bytes"
	"encoding/json"

	"github.com/anaminus/rbxmk/dump/dt"
)

func marshal(v interface{}) (b []byte, err error) {
	var buf bytes.Buffer
	j := json.NewEncoder(&buf)
	j.SetEscapeHTML(false)
	if err = j.Encode(v); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// Root describes an entire API.
type Root struct {
	// Libraries contains libraries defined in the API.
	Libraries Libraries
	// Types contains types defined by the API.
	Types TypeDefs `json:",omitempty"`
}

// Libraries is a list of libraries.
type Libraries = []Library

// Library describes the API of a library.
type Library struct {
	// Name is the name of the library.
	Name string
	// ImportedAs is the name that the library is imported as. Empty indicates
	// that the contents of the library are merged into the global environment.
	ImportedAs string
	// Struct contains the items of the library.
	Struct Struct `json:",omitempty"`
	// Types contains types defined by the library.
	Types TypeDefs `json:",omitempty"`
}

// Fields maps a name to a value.
type Fields map[string]Value

func (f Fields) MarshalJSON() (b []byte, err error) {
	type field struct {
		Kind  string
		Value Value
	}
	m := make(map[string]field, len(f))
	for k, v := range f {
		f := field{Kind: "", Value: v}
		switch v.(type) {
		case Property:
			f.Kind = "Property"
		case Struct:
			f.Kind = "Struct"
		case Function:
			f.Kind = "Function"
		case MultiFunction:
			f.Kind = "MultiFunction"
		default:
			continue
		}
		m[k] = f
	}
	return marshal(m)
}

// TypeDefs maps a name to a type definition.
type TypeDefs = map[string]TypeDef

// Value is a value that has a Type.
type Value interface {
	Type() dt.Type
}

// Property describes the API of a property.
type Property struct {
	// ValueType is the type of the property's value.
	ValueType dt.Type
	// ReadOnly indicates whether the property can be written to.
	ReadOnly bool `json:",omitempty"`
	// Description is a detailed description of the property.
	Description string `json:",omitempty"`
}

// Type implements Value by returning v.ValueType.
func (v Property) Type() dt.Type {
	return v.ValueType
}

// Struct describes the API of a table with a number of fields.
type Struct struct {
	// Fields are the fields of the structure.
	Fields Fields
	// Description is a detailed description of the structure.
	Description string `json:",omitempty"`
}

// Type implements Value by returning a dt.Struct that maps each field name the
// type of the field's value.
func (v Struct) Type() dt.Type {
	t := make(dt.Struct, len(v.Fields))
	for name, value := range v.Fields {
		t[name] = value.Type()
	}
	return t
}

// TypeDef describes the definition of a type.
type TypeDef struct {
	// Underlying indicates that the type has an underlying type.
	Underlying dt.Type `json:",omitempty"`
	// Operators describes the operators defined on the type.
	Operators *Operators `json:",omitempty"`
	// Operators describes the properties defined on the type.
	Properties Properties `json:",omitempty"`
	// Operators describes the methods defined on the type.
	Methods Methods `json:",omitempty"`
	// Operators describes constructor functions that create the type.
	Constructors Constructors `json:",omitempty"`
	// Description is a detailed description of the type definition.
	Description string `json:",omitempty"`
}

// Properties maps a name to a Property.
type Properties = map[string]Property

// Methods maps a name to a method.
type Methods = map[string]Function

// Constructors maps a name to a number of constructor functions.
type Constructors = map[string]MultiFunction

// Function describes the API of a function.
type Function struct {
	// Parameters are the values received by the function.
	Parameters Parameters `json:",omitempty"`
	// Returns are the values returned by the function.
	Returns Parameters `json:",omitempty"`
	// CanError returns whether the function may throw an error, excluding type
	// errors from received arguments.
	CanError bool `json:",omitempty"`
	// Description is a detailed description of the function.
	Description string `json:",omitempty"`
}

// Type implements Value by returning a dt.Function with the parameters and
// returns of the value.
func (v Function) Type() dt.Type {
	fn := dt.Function{
		Parameters: make(Parameters, len(v.Parameters)),
		Returns:    make(Parameters, len(v.Returns)),
	}
	copy(fn.Parameters, v.Parameters)
	copy(fn.Returns, v.Returns)
	return fn
}

// MultiFunction describes a Function with multiple signatures.
type MultiFunction []Function

// Type implements Value by returning dt.MultiFunctionType.
func (MultiFunction) Type() dt.Type {
	return dt.MultiFunctionType{}
}

// Parameter describes a function parameter.
type Parameter = dt.Parameter

// Parameters is a list of function parameters.
type Parameters = []Parameter

// Operators describes the operators of a type.
type Operators struct {
	// Add describes a number of signatures for the __add operator.
	Add []Binop `json:"__add,omitempty"`
	// Add describes a number of signatures for the __sub operator.
	Sub []Binop `json:"__sub,omitempty"`
	// Add describes a number of signatures for the __mul operator.
	Mul []Binop `json:"__mul,omitempty"`
	// Add describes a number of signatures for the __div operator.
	Div []Binop `json:"__div,omitempty"`
	// Add describes a number of signatures for the __mod operator.
	Mod []Binop `json:"__mod,omitempty"`
	// Add describes a number of signatures for the __pow operator.
	Pow []Binop `json:"__pow,omitempty"`
	// Add describes a number of signatures for the __concat operator.
	Concat []Binop `json:"__concat,omitempty"`

	// Eq indicates whether the type defines a __eq operator.
	Eq bool `json:"__eq,omitempty"`
	// Eq indicates whether the type defines a __le operator.
	Le bool `json:"__le,omitempty"`
	// Eq indicates whether the type defines a __lt operator.
	Lt bool `json:"__lt,omitempty"`

	// Len describes the signature for the __len operator, if defined.
	Len *Unop `json:"__len,omitempty"`
	// Len describes the signature for the __unm operator, if defined.
	Unm *Unop `json:"__unm,omitempty"`

	// Call describes the function signature for the __call operator, if
	// defined.
	Call *Function `json:"__call,omitempty"`

	Index    Value `json:"__index,omitempty"`
	Newindex Value `json:"__newindex,omitempty"`
}

// Binop describes a binary operator. The left operand is assumed to be of an
// outer type definition.
type Binop struct {
	// Operand is the type of the right operand.
	Operand dt.Type
	// Result is the type of the result of the operation.
	Result dt.Type
	// Description is a detailed description of the operator.
	Description string `json:",omitempty"`
}

// Unop describes a unary operator. The operand is assumed to be of an outer
// type definition.
type Unop struct {
	// Result is the type of the result of the operation.
	Result dt.Type
	// Description is a detailed description of the operator.
	Description string `json:",omitempty"`
}
<|endoftext|>