<commit_before>package main

import (
	"github.com/madhurjain/lirc"
	"github.com/stianeikeland/go-rpio"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"
)

const (
	// Triggered State
	TRIGGERED = iota
	ARMED
	DISARMED
)

type burglarm struct {
	buzzerPin rpio.Pin // PIN 15, GPIO 22
	pirPin    rpio.Pin // PIN 16, GPIO 23
	action    chan uint8
	stop      chan bool
}

func (b *burglarm) pollPir() {
	b.buzzerPin.High()
	time.Sleep(time.Second)
	b.buzzerPin.Low()
	// Keep reading PIR pin for trigger
	for {
		if b.pirPin.Read() == rpio.High {
			b.action <- TRIGGERED
			return
		}
	}
}

func (b *burglarm) start() {
	for {
		select {
		case action := <-b.action:
			switch action {
			case ARMED:
				// Start monitoring after 5 seconds the device is turned on
				time.AfterFunc(5*time.Second, func() { b.pollPir() })
			case DISARMED:
				b.buzzerPin.Low()
			case TRIGGERED:
				// Set alarm pin high
				b.buzzerPin.High()
			}

		case <-b.stop:
			b.buzzerPin.Low()
			log.Println("stopping service")
			b.stop <- true
			return
		}
	}
}

func (b *burglarm) terminate() {
	b.stop <- true
	<-b.stop // block until previous stop is processed
}

func irevent(ev lirc.LircEvent) {
	log.Println("remote event")
	log.Println(ev)
}

func main() {

	// Open memory range for GPIO access in /dev/mem
	err := rpio.Open()
	if err != nil {
		log.Println(err)
	}
	defer rpio.Close()

	b := &burglarm{
		action: make(chan uint8),
		stop:   make(chan bool),
	}
	// Init GPIO Pins
	b.buzzerPin = rpio.Pin(22)
	b.buzzerPin.Mode(rpio.Output)

	b.pirPin = rpio.Pin(23)
	b.pirPin.Mode(rpio.Input)

	// Init IR
	ir, err := lirc.Init("")
	if err != nil {
		log.Println("LIRC Error", err)
	}
	ir.Handle("", "", irevent)
	//ir.Run()

	// Start Service
	log.Println("Starting Service")
	go burglarm.start()
	burglarm.action <- ARMED // Arm alarm on start

	// Stop Service
	// Handle SIGINT and SIGTERM
	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
	log.Println(<-ch) // blocks main

	burglarm.terminate()

	// Disarm on key press of remote
	// Rearm on key press of remote

}
<commit_msg>Updated lirc package path<commit_after>package main

import (
	"github.com/chbmuc/lirc"
	"github.com/stianeikeland/go-rpio"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"
)

const (
	// Triggered State
	TRIGGERED = iota
	ARMED
	DISARMED
)

type burglarm struct {
	buzzerPin rpio.Pin // PIN 15, GPIO 22
	pirPin    rpio.Pin // PIN 16, GPIO 23
	action    chan uint8
	stop      chan bool
}

func (b *burglarm) pollPir() {
	b.buzzerPin.High()
	time.Sleep(time.Second)
	b.buzzerPin.Low()
	// Keep reading PIR pin for trigger
	for {
		if b.pirPin.Read() == rpio.High {
			b.action <- TRIGGERED
			return
		}
	}
}

func (b *burglarm) start() {
	for {
		select {
		case action := <-b.action:
			switch action {
			case ARMED:
				// Start monitoring after 5 seconds the device is turned on
				time.AfterFunc(5*time.Second, func() { b.pollPir() })
			case DISARMED:
				b.buzzerPin.Low()
			case TRIGGERED:
				// Set alarm pin high
				b.buzzerPin.High()
			}

		case <-b.stop:
			b.buzzerPin.Low()
			log.Println("stopping service")
			b.stop <- true
			return
		}
	}
}

func (b *burglarm) terminate() {
	b.stop <- true
	<-b.stop // block until previous stop is processed
}

func irevent(event lirc.Event) {
	log.Println("remote event")
	// Disarm on key press of remote
	// Rearm on key press of remote
	log.Println(event)
}

func main() {

	// Open memory range for GPIO access in /dev/mem
	err := rpio.Open()
	if err != nil {
		log.Println(err)
	}
	defer rpio.Close()

	b := &burglarm{
		action: make(chan uint8),
		stop:   make(chan bool),
	}
	// Init GPIO Pins
	b.buzzerPin = rpio.Pin(22)
	b.buzzerPin.Mode(rpio.Output)

	b.pirPin = rpio.Pin(23)
	b.pirPin.Mode(rpio.Input)

	// Init IR
	ir, err := lirc.Init("")
	if err != nil {
		log.Println("LIRC Error", err)
	}
	ir.Handle("", "", irevent)
	ir.Run()

	// Start Service
	log.Println("Starting Service")
	go burglarm.start()
	burglarm.action <- ARMED // Arm alarm on start

	// Stop Service
	// Handle SIGINT and SIGTERM
	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
	log.Println(<-ch) // blocks main

	burglarm.terminate()

}
<|endoftext|>


<commit_before>// Package bus_test runs full end-to-end tests of the bus system by
// running the loader against a small subset of live data and hitting
// the API, checking for sane results. Most settings will be read
// from the environment like the normal application, but
// $BUS_GTFS_URLS and $BUS_ROUTE_FILTER will be overidden by
// the tests.
package bus_test

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"testing"
	"time"

	"github.com/brnstz/bus/api"
	"github.com/brnstz/bus/internal/conf"
	"github.com/brnstz/bus/internal/etc"
	"github.com/brnstz/bus/loader"
	"github.com/kelseyhightower/envconfig"
)

var (
	// serverURL is the url of our test HTTP server
	serverURL string
)

// TestMain initializes/loads the database and starts an HTTP server to test
// against.
func TestMain(m *testing.M) {
	var err error

	err = envconfig.Process("bus", &conf.DB)
	if err != nil {
		log.Fatal(err)
	}

	err = envconfig.Process("bus", &conf.Loader)
	if err != nil {
		log.Fatal(err)
	}

	err = envconfig.Process("bus", &conf.API)
	if err != nil {
		log.Fatal(err)
	}

	// Load the just subway and Brooklyn bus files
	conf.Loader.GTFSURLs = []string{
		"http://web.mta.info/developers/data/nyct/subway/google_transit.zip",
		"http://web.mta.info/developers/data/nyct/bus/google_transit_brooklyn.zip",
	}

	// Filter on a few routes for our tests
	conf.Loader.RouteFilter = []string{
		"G", "L", "B62", "B43", "B32",
	}

	// Get a db connection
	etc.DBConn = etc.MustDB()

	// Load files once and return
	loader.LoadOnce()

	// Create an HTTP server for our tests and set the URL
	server := httptest.NewServer(api.NewHandler())
	defer server.Close()
	serverURL = server.URL

	// Exit when it's over
	os.Exit(m.Run())
}

// stopResponse is the response to /api/v2/stops
type stopResponse struct {
	Results []struct {
		Route struct {
			Route_ID     string
			Headsign     string
			Direction_ID string
		}

		Stop struct {
			Dist      string
			Lat       float64
			Lon       float64
			Stop_ID   string
			Stop_Name string
		}

		Departures struct {
			Live []struct {
				Time time.Time
			}

			Scheduled []struct {
				Time time.Time
			}
		}
	}
}

// getJSON performs an HTTP get on the incoming URL and marshals
// the body of the response into v (which should be a pointer to
// something).
func getJSON(v interface{}, u string) error {
	resp, err := http.Get(u)
	if err != nil {
		return err
	}

	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	err = json.Unmarshal(b, v)
	if err != nil {
		return err
	}

	return nil
}

// TestScheduledSubway tests for scheduled subway times
func TestScheduledSubway(t *testing.T) {
	var resp stopResponse
	var err error

	params := url.Values{}
	now := time.Now().Add(-time.Minute * 5)

	expectedStop := "Greenpoint Av"
	expectedRoute := "G"

	// Manhattan Av. and Greenpoint Av. in Brooklyn
	params.Set("lat", "40.730202")
	params.Set("lon", "-73.9564682")
	params.Set("miles", "0.1")
	params.Set("filter", "subway")

	err = getJSON(&resp, serverURL+"/api/v2/stops?"+params.Encode())
	if err != nil {
		t.Fatal("can't get API response for G train test", err)
	}

	if len(resp.Results) != 2 {
		t.Fatalf("expected %v results but got %v", 2, len(resp.Results))
	}

	// Check each result
	for _, v := range resp.Results {
		if v.Stop.Stop_Name != expectedStop {
			t.Errorf("expected %v stop_name but got %v", expectedStop, v.Stop.Stop_Name)
		}

		if v.Route.Route_ID != expectedRoute {
			t.Errorf("expected %v route_id but got %v", expectedRoute, v.Route.Route_ID)
		}

		if len(v.Departures.Scheduled) < 1 {
			t.Errorf("expected at least one scheduled departure but got none in %#v", v)
		}

		// Check that scheduled times are in the future
		for _, d := range v.Departures.Scheduled {
			if d.Time.Before(now) {
				t.Errorf("expected scheduled time %v would be after or equal to %v but it was not", v.Departures.Scheduled, now)
			}
		}
	}
}

// TestLiveSubway checks for live subway times
func TestLiveSubway(t *testing.T) {
	var resp stopResponse
	var err error

	params := url.Values{}
	now := time.Now().Add(-time.Minute * 5)

	expectedStop := "Bedford Av"
	expectedRoute := "L"

	// Bedford Av. and N. 7th St. in Brooklyn
	params.Set("lat", "40.717304")
	params.Set("lon", "-73.956872")
	params.Set("miles", "0.01")

	err = getJSON(&resp, serverURL+"/api/v2/stops?"+params.Encode())
	if err != nil {
		t.Fatal("can't get API response for L train test", err)
	}

	if len(resp.Results) != 2 {
		t.Fatalf("expected %v results but got %v", 2, len(resp.Results))
	}

	// Check each result
	for _, v := range resp.Results {
		if v.Stop.Stop_Name != expectedStop {
			t.Errorf("expected %v stop_name but got %v", expectedStop, v.Stop.Stop_Name)
		}

		if v.Route.Route_ID != expectedRoute {
			t.Errorf("expected %v route_id but got %v", expectedRoute, v.Route.Route_ID)
		}

		if len(v.Departures.Live) < 1 {
			t.Errorf("expected at least one live departure but got none in %#v", v)
		}

		// Check that live times are in the future
		for _, d := range v.Departures.Live {
			if d.Time.Before(now) {
				t.Errorf("expected live time %v would be after or equal to %v but it was not", d.Time, now)
			}
		}
	}
}

// TestLiveBus checks for live bus results
func TestLiveBus(t *testing.T) {
	var resp stopResponse
	var err error

	params := url.Values{}

	// Jackson Av. and 11th St. in Queens
	params.Set("lat", "40.7422511")
	params.Set("lon", "-73.9515471")
	params.Set("miles", "0.1")

	err = getJSON(&resp, serverURL+"/api/v2/stops?"+params.Encode())
	if err != nil {
		t.Fatal("can't get API response for B62, B32 bus test", err)
	}

	// We should get results for both B62 and B32
	if len(resp.Results) != 4 {
		t.Fatalf("expected %v results but got %v", 4, len(resp.Results))
	}

	// Check each result
	for _, v := range resp.Results {

		// FIXME: some bus routes won't always have live departures, may need to
		// pick different bus or make this a warning
		/*
			if len(v.Live) < 1 {
				t.Errorf("expected at least one live departure but got none in %#v", v)
			}
		*/

		// Check that
		for _, d := range v.Departures.Live {
			if d.Time.IsZero() {
				t.Errorf("empty time identified in live departure in %#v", v)
			}
		}
	}

}

// TestScheduledBus checks for scheduled bus results
func TestScheduledBus(t *testing.T) {
	var resp stopResponse
	var err error

	params := url.Values{}
	now := time.Now().Add(-time.Minute * 5)

	expectedStop := "BOX ST/MANHATTAN AV"
	expectedRoute := "B43"

	// Box St. and Manhattan Av. in Brooklyn
	params.Set("lat", "40.7373215")
	params.Set("lon", "-73.9563212")
	params.Set("miles", "0.1")

	err = getJSON(&resp, serverURL+"/api/v2/stops?"+params.Encode())
	if err != nil {
		t.Fatal("can't get API response for B43 bus test", err)
	}

	// Check each result
	for _, v := range resp.Results {
		if v.Stop.Stop_Name != expectedStop {
			t.Errorf("expected %v stop_name but got %v", expectedStop, v.Stop.Stop_Name)
		}

		if v.Route.Route_ID != expectedRoute {
			t.Errorf("expected %v route_id but got %v", expectedRoute, v.Route.Route_ID)
		}

		// Check that scheduled times are in the future
		for _, d := range v.Departures.Scheduled {
			if d.Time.Before(now) {
				t.Errorf("expected scheduled time %v would be after or equal to %v but it was not", d.Time, now)
			}
		}
	}
}
<commit_msg>add BUS_TEST_SKIP_LOADER<commit_after>// Package bus_test runs full end-to-end tests of the bus system by
// running the loader against a small subset of live data and hitting
// the API, checking for sane results. Most settings will be read
// from the environment like the normal application, but
// $BUS_GTFS_URLS and $BUS_ROUTE_FILTER will be overidden by
// the tests.
package bus_test

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"testing"
	"time"

	"github.com/brnstz/bus/api"
	"github.com/brnstz/bus/internal/conf"
	"github.com/brnstz/bus/internal/etc"
	"github.com/brnstz/bus/loader"
	"github.com/kelseyhightower/envconfig"
)

var (
	// serverURL is the url of our test HTTP server
	serverURL string
)

// TestMain initializes/loads the database and starts an HTTP server to test
// against.
func TestMain(m *testing.M) {
	var err error

	err = envconfig.Process("bus", &conf.DB)
	if err != nil {
		log.Fatal(err)
	}

	err = envconfig.Process("bus", &conf.Loader)
	if err != nil {
		log.Fatal(err)
	}

	err = envconfig.Process("bus", &conf.API)
	if err != nil {
		log.Fatal(err)
	}

	// Load the just subway and Brooklyn bus files
	conf.Loader.GTFSURLs = []string{
		"http://web.mta.info/developers/data/nyct/subway/google_transit.zip",
		"http://web.mta.info/developers/data/nyct/bus/google_transit_brooklyn.zip",
	}

	// Filter on a few routes for our tests
	conf.Loader.RouteFilter = []string{
		"G", "L", "B62", "B43", "B32",
	}

	// Get a db connection
	etc.DBConn = etc.MustDB()

	// Alow skipping the load if we trust our db is ok
	if os.Getenv("BUS_TEST_SKIP_LOADER") != "true" {
		// Load files once and return
		loader.LoadOnce()
	}

	// Create an HTTP server for our tests and set the URL
	server := httptest.NewServer(api.NewHandler())
	defer server.Close()
	serverURL = server.URL

	// Exit when it's over
	os.Exit(m.Run())
}

// stopResponse is the response to /api/v2/stops
type stopResponse struct {
	Results []struct {
		Route struct {
			Route_ID     string
			Headsign     string
			Direction_ID string
		}

		Stop struct {
			Dist      string
			Lat       float64
			Lon       float64
			Stop_ID   string
			Stop_Name string
		}

		Departures struct {
			Live []struct {
				Time time.Time
			}

			Scheduled []struct {
				Time time.Time
			}
		}
	}
}

// getJSON performs an HTTP get on the incoming URL and marshals
// the body of the response into v (which should be a pointer to
// something).
func getJSON(v interface{}, u string) error {
	resp, err := http.Get(u)
	if err != nil {
		return err
	}

	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	err = json.Unmarshal(b, v)
	if err != nil {
		return err
	}

	return nil
}

// TestScheduledSubway tests for scheduled subway times
func TestScheduledSubway(t *testing.T) {
	var resp stopResponse
	var err error

	params := url.Values{}
	now := time.Now().Add(-time.Minute * 5)

	expectedStop := "Greenpoint Av"
	expectedRoute := "G"

	// Manhattan Av. and Greenpoint Av. in Brooklyn
	params.Set("lat", "40.730202")
	params.Set("lon", "-73.9564682")
	params.Set("miles", "0.1")
	params.Set("filter", "subway")

	err = getJSON(&resp, serverURL+"/api/v2/stops?"+params.Encode())
	if err != nil {
		t.Fatal("can't get API response for G train test", err)
	}

	if len(resp.Results) != 2 {
		t.Fatalf("expected %v results but got %v", 2, len(resp.Results))
	}

	// Check each result
	for _, v := range resp.Results {
		if v.Stop.Stop_Name != expectedStop {
			t.Errorf("expected %v stop_name but got %v", expectedStop, v.Stop.Stop_Name)
		}

		if v.Route.Route_ID != expectedRoute {
			t.Errorf("expected %v route_id but got %v", expectedRoute, v.Route.Route_ID)
		}

		if len(v.Departures.Scheduled) < 1 {
			t.Errorf("expected at least one scheduled departure but got none in %#v", v)
		}

		// Check that scheduled times are in the future
		for _, d := range v.Departures.Scheduled {
			if d.Time.Before(now) {
				t.Errorf("expected scheduled time %v would be after or equal to %v but it was not", v.Departures.Scheduled, now)
			}
		}
	}
}

// TestLiveSubway checks for live subway times
func TestLiveSubway(t *testing.T) {
	var resp stopResponse
	var err error

	params := url.Values{}
	now := time.Now().Add(-time.Minute * 5)

	expectedStop := "Bedford Av"
	expectedRoute := "L"

	// Bedford Av. and N. 7th St. in Brooklyn
	params.Set("lat", "40.717304")
	params.Set("lon", "-73.956872")
	params.Set("miles", "0.01")

	err = getJSON(&resp, serverURL+"/api/v2/stops?"+params.Encode())
	if err != nil {
		t.Fatal("can't get API response for L train test", err)
	}

	if len(resp.Results) != 2 {
		t.Fatalf("expected %v results but got %v", 2, len(resp.Results))
	}

	// Check each result
	for _, v := range resp.Results {
		if v.Stop.Stop_Name != expectedStop {
			t.Errorf("expected %v stop_name but got %v", expectedStop, v.Stop.Stop_Name)
		}

		if v.Route.Route_ID != expectedRoute {
			t.Errorf("expected %v route_id but got %v", expectedRoute, v.Route.Route_ID)
		}

		if len(v.Departures.Live) < 1 {
			t.Errorf("expected at least one live departure but got none in %#v", v)
		}

		// Check that live times are in the future
		for _, d := range v.Departures.Live {
			if d.Time.Before(now) {
				t.Errorf("expected live time %v would be after or equal to %v but it was not", d.Time, now)
			}
		}
	}
}

// TestLiveBus checks for live bus results
func TestLiveBus(t *testing.T) {
	var resp stopResponse
	var err error

	params := url.Values{}

	// Jackson Av. and 11th St. in Queens
	params.Set("lat", "40.7422511")
	params.Set("lon", "-73.9515471")
	params.Set("miles", "0.1")

	err = getJSON(&resp, serverURL+"/api/v2/stops?"+params.Encode())
	if err != nil {
		t.Fatal("can't get API response for B62, B32 bus test", err)
	}

	// We should get results for both B62 and B32
	if len(resp.Results) != 4 {
		t.Fatalf("expected %v results but got %v", 4, len(resp.Results))
	}

	// Check each result
	for _, v := range resp.Results {

		// FIXME: some bus routes won't always have live departures, may need to
		// pick different bus or make this a warning
		/*
			if len(v.Live) < 1 {
				t.Errorf("expected at least one live departure but got none in %#v", v)
			}
		*/

		// Check that
		for _, d := range v.Departures.Live {
			if d.Time.IsZero() {
				t.Errorf("empty time identified in live departure in %#v", v)
			}
		}
	}

}

// TestScheduledBus checks for scheduled bus results
func TestScheduledBus(t *testing.T) {
	var resp stopResponse
	var err error

	params := url.Values{}
	now := time.Now().Add(-time.Minute * 5)

	expectedStop := "BOX ST/MANHATTAN AV"
	expectedRoute := "B43"

	// Box St. and Manhattan Av. in Brooklyn
	params.Set("lat", "40.7373215")
	params.Set("lon", "-73.9563212")
	params.Set("miles", "0.1")

	err = getJSON(&resp, serverURL+"/api/v2/stops?"+params.Encode())
	if err != nil {
		t.Fatal("can't get API response for B43 bus test", err)
	}

	// Check each result
	for _, v := range resp.Results {
		if v.Stop.Stop_Name != expectedStop {
			t.Errorf("expected %v stop_name but got %v", expectedStop, v.Stop.Stop_Name)
		}

		if v.Route.Route_ID != expectedRoute {
			t.Errorf("expected %v route_id but got %v", expectedRoute, v.Route.Route_ID)
		}

		// Check that scheduled times are in the future
		for _, d := range v.Departures.Scheduled {
			if d.Time.Before(now) {
				t.Errorf("expected scheduled time %v would be after or equal to %v but it was not", d.Time, now)
			}
		}
	}
}
<|endoftext|>


<commit_before>package dispatcher

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"path"
)

const (
	defaultAPIBaseURL = "https://api.growthpush.com"
	defaultAPIVersion = "4"
)

type (
	RequiredParameter struct {
		ApplicationID string `json:"applicationId"`
		CredentialID  string `json:"credentialId"`
	}
	Client struct {
		HTTPClient *http.Client

		APIBaseURL           string
		APIVersion           string
		APIRequiredParameter RequiredParameter
	}
)

func NewClientWithParam(applicationID, credentialID string) *Client {
	return &Client{
		HTTPClient: http.DefaultClient,

		APIBaseURL: defaultAPIBaseURL,
		APIVersion: defaultAPIVersion,
		APIRequiredParameter: RequiredParameter{
			ApplicationID: applicationID,
			CredentialID:  credentialID,
		},
	}
}

// DispatchGetRequest GrowthPushへのGETリクエスト
func (c *Client) DispatchGetRequest(endpoint string, parameters map[string]string) ([]byte, error) {
	u, err := url.Parse(c.APIBaseURL)
	if err != nil {
		return nil, err
	}
	u.Path = path.Join(c.APIVersion, endpoint)

	values := url.Values{}
	values.Set("applicationId", c.APIRequiredParameter.ApplicationID)
	values.Set("credentialId", c.APIRequiredParameter.CredentialID)

	for key, param := range parameters {
		values.Set(key, param)
	}

	resp, err := http.Get(u.String() + "?" + values.Encode())
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	// Return error when status code less than 200 or equal more than 300
	if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
		return nil, fmt.Errorf("Dispatcher.Client.DispatchGetRequest: code:%d body:%s", resp.StatusCode, string(respBody))
	}
	return respBody, nil
}

// DispatchPostRequest GrowthPushへのPOSTリクエスト
func (c *Client) DispatchPostRequest(endpoint string, parameters map[string]string) ([]byte, error) {
	u, err := url.Parse(c.APIBaseURL)
	if err != nil {
		return nil, err
	}
	u.Path = path.Join(c.APIVersion, endpoint)

	values := url.Values{}
	values.Set("applicationId", c.APIRequiredParameter.ApplicationID)
	values.Set("credentialId", c.APIRequiredParameter.CredentialID)

	for key, param := range parameters {
		values.Set(key, param)
	}

	resp, err := http.PostForm(u.String(), values)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
		return nil, fmt.Errorf("Dispatcher.Client.DispatchPostRequest: code:%d body:%s", resp.StatusCode, string(respBody))
	}
	return respBody, nil
}
<commit_msg>Set correct values to header<commit_after>package dispatcher

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"path"
	"strings"
)

const (
	defaultAPIBaseURL = "https://api.growthpush.com"
	defaultAPIVersion = "4"
)

type (
	RequiredParameter struct {
		ApplicationID string `json:"applicationId"`
		CredentialID  string `json:"credentialId"`
	}
	Client struct {
		HTTPClient *http.Client

		APIBaseURL           string
		APIVersion           string
		APIRequiredParameter RequiredParameter
	}
)

func NewClientWithParam(applicationID, credentialID string) *Client {
	return &Client{
		HTTPClient: http.DefaultClient,

		APIBaseURL: defaultAPIBaseURL,
		APIVersion: defaultAPIVersion,
		APIRequiredParameter: RequiredParameter{
			ApplicationID: applicationID,
			CredentialID:  credentialID,
		},
	}
}

// DispatchGetRequest GrowthPushへのGETリクエスト
func (c *Client) DispatchGetRequest(endpoint string, parameters map[string]string) ([]byte, error) {
	u, err := url.Parse(c.APIBaseURL)
	if err != nil {
		return nil, err
	}
	u.Path = path.Join(c.APIVersion, endpoint)

	values := url.Values{}
	values.Set("applicationId", c.APIRequiredParameter.ApplicationID)
	values.Set("credentialId", c.APIRequiredParameter.CredentialID)

	for key, param := range parameters {
		values.Set(key, param)
	}

	req, err := http.NewRequest("GET", u.String()+"?"+values.Encode(), nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	// Return error when status code less than 200 or equal more than 300
	if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
		return nil, fmt.Errorf("Dispatcher.Client.DispatchGetRequest endpoint:%s code:%d body:%s", endpoint, resp.StatusCode, string(respBody))
	}
	return respBody, nil
}

// DispatchPostRequest GrowthPushへのPOSTリクエスト
func (c *Client) DispatchPostRequest(endpoint string, parameters map[string]string) ([]byte, error) {
	u, err := url.Parse(c.APIBaseURL)
	if err != nil {
		return nil, err
	}
	u.Path = path.Join(c.APIVersion, endpoint)

	values := url.Values{}
	values.Set("applicationId", c.APIRequiredParameter.ApplicationID)
	values.Set("credentialId", c.APIRequiredParameter.CredentialID)

	for key, param := range parameters {
		values.Set(key, param)
	}

	req, err := http.NewRequest("POST", u.String(), strings.NewReader(values.Encode()))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
		return nil, fmt.Errorf("Dispatcher.Client.DispatchPostRequest endpoint:%s code:%d body:%s", endpoint, resp.StatusCode, string(respBody))
	}
	return respBody, nil
}
<|endoftext|>


<commit_before>package apps

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"

	"github.com/leancloud/lean-cli/lean/output"
)

var (
	// ErrNoAppLinked means no app was linked to the project
	ErrNoAppLinked = errors.New("No Leancloud Application was linked to the project")
)

func appDirPath(projectPath string) string {
	return filepath.Join(projectPath, ".leancloud")
}

func currentAppIDFilePath(projectPath string) string {
	return filepath.Join(appDirPath(projectPath), "current_app_id")
}

// LinkApp will write the specific appID to ${projectPath}/.leancloud/current_app_id
func LinkApp(projectPath string, appID string) error {
	err := os.Mkdir(appDirPath(projectPath), 0700)
	if err != nil && !os.IsExist(err) {
		return err
	}

	return ioutil.WriteFile(currentAppIDFilePath(projectPath), []byte(appID), 0700)
}

// GetCurrentAppID will return the content of ${projectPath}/.leancloud/current_app_id
func GetCurrentAppID(projectPath string) (string, error) {
	content, err := ioutil.ReadFile(currentAppIDFilePath(projectPath))
	if os.IsNotExist(err) {
		return migrateLegencyProjectConfig(projectPath)
	}
	if err != nil {
		return "", err
	}
	return string(content), nil
}

func migrateLegencyProjectConfig(projectPath string) (string, error) {
	content, err := ioutil.ReadFile(filepath.Join(projectPath, ".avoscloud", "curr_app"))
	if err != nil {
		return "", ErrNoAppLinked
	}
	appName := string(content)

	content, err = ioutil.ReadFile(filepath.Join(projectPath, ".avoscloud", "apps.json"))
	if err != nil {
		return "", ErrNoAppLinked
	}

	var apps map[string]string
	err = json.Unmarshal(content, &apps)
	if err != nil {
		return "", ErrNoAppLinked
	}

	appID, ok := apps[appName]
	if !ok {
		return "", ErrNoAppLinked
	}

	op := output.NewOutput(os.Stdout)
	op.Write("检测到旧版命令行工具项目配置，正在迁移")

	err = LinkApp(projectPath, appID)
	if err != nil {
		op.Failed()
		return "", err
	}
	op.Successed()

	log.Printf("> 迁移完毕，`%s`可进行删除\r\n", filepath.Join(projectPath, ".avoscloud", "curr_app"))

	return appID, nil
}
<commit_msg>fix: support old style legency project config<commit_after>package apps

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"

	"github.com/leancloud/lean-cli/lean/output"
)

var (
	// ErrNoAppLinked means no app was linked to the project
	ErrNoAppLinked = errors.New("No Leancloud Application was linked to the project")
)

func appDirPath(projectPath string) string {
	return filepath.Join(projectPath, ".leancloud")
}

func currentAppIDFilePath(projectPath string) string {
	return filepath.Join(appDirPath(projectPath), "current_app_id")
}

// LinkApp will write the specific appID to ${projectPath}/.leancloud/current_app_id
func LinkApp(projectPath string, appID string) error {
	err := os.Mkdir(appDirPath(projectPath), 0700)
	if err != nil && !os.IsExist(err) {
		return err
	}

	return ioutil.WriteFile(currentAppIDFilePath(projectPath), []byte(appID), 0700)
}

// GetCurrentAppID will return the content of ${projectPath}/.leancloud/current_app_id
func GetCurrentAppID(projectPath string) (string, error) {
	content, err := ioutil.ReadFile(currentAppIDFilePath(projectPath))
	if os.IsNotExist(err) {
		return migrateLegencyProjectConfig(projectPath)
	}
	if err != nil {
		return "", err
	}
	return string(content), nil
}

func getLegencyAppID(projectPath string) (string, error) {
	content, err := ioutil.ReadFile(filepath.Join(projectPath, ".avoscloud", "apps.json"))
	if err != nil {
		return "", ErrNoAppLinked
	}

	var apps map[string]string
	err = json.Unmarshal(content, &apps)
	if err != nil {
		return "", ErrNoAppLinked
	}

	if len(apps) == 0 {
		return "", ErrNoAppLinked
	}

	if len(apps) == 1 {
		for _, v := range apps {
			return v, nil
		}
	}

	content, err = ioutil.ReadFile(filepath.Join(projectPath, ".avoscloud", "curr_app"))
	if err != nil {
		return "", ErrNoAppLinked
	}
	appName := string(content)

	appID, ok := apps[appName]
	if !ok {
		return "", ErrNoAppLinked
	}
	return appID, nil
}

func migrateLegencyProjectConfig(projectPath string) (string, error) {
	appID, err := getLegencyAppID(projectPath)
	if err != nil {
		return "", err
	}

	op := output.NewOutput(os.Stdout)
	op.Write("检测到旧版命令行工具项目配置，正在迁移")

	err = LinkApp(projectPath, appID)
	if err != nil {
		op.Failed()
		return "", err
	}
	op.Successed()

	log.Printf("> 迁移完毕，`%s`可进行删除\r\n", filepath.Join(projectPath, ".avoscloud", "curr_app"))

	return appID, nil
}
<|endoftext|>


<commit_before>package ics

import (
	"errors"
	"fmt"
	"time"
)

type Calendar struct {
	name         string
	description  string
	version      float64
	timezone     time.Location
	events       []Event
	eventsByDate map[string][]*Event
	eventByID    map[string]*Event
}

func NewCalendar() *Calendar {
	c := new(Calendar)
	// c.events = make([]Event)
	c.eventsByDate = make(map[string][]*Event)
	c.eventByID = make(map[string]*Event)
	return c
}

func (c *Calendar) SetName(n string) *Calendar {
	c.name = n
	return c
}

func (c *Calendar) GetName() string {
	return ""
}

func (c *Calendar) SetDesc(desc string) *Calendar {
	c.description = desc
	return c
}

func (c *Calendar) GetDesc() string {
	return ""
}

func (c *Calendar) SetVersion(ver float64) *Calendar {
	c.version = ver
	return c
}

func (c *Calendar) GetVersion() float64 {
	return c.version
}

func (c *Calendar) SetTimezone(tz time.Location) *Calendar {
	c.timezone = tz
	return c
}

func (c *Calendar) GetTimezone() time.Location {
	return c.timezone
}

//  add event to the calendar
func (c *Calendar) SetEvent(event Event) (*Calendar, error) {
	//  lock so that the events array doesn't change its size from other goruote
	mutex.Lock()

	// reference to the calendar
	if event.GetCalendar() == nil || event.GetCalendar() != c {
		event.SetCalendar(c)
	}
	// add the event to the main array with events
	c.events = append(c.events, event)

	// pointer to the added event in the main array
	eventPtr := &c.events[len(c.events)-1]

	// calculate the start day of the event
	eventStartTime := event.GetStart()
	tz := c.GetTimezone()
	eventDate := time.Date(eventStartTime.Year(), eventStartTime.Month(), eventStartTime.Day(), 0, 0, 0, 0, &tz)

	// faster search by date
	c.eventsByDate[eventDate.Format(YmdHis)] = append(c.eventsByDate[eventDate.Format(YmdHis)], eventPtr)
	// faster search by id
	c.eventByID[event.GetID()] = eventPtr

	mutex.Unlock()
	return c, nil
}

//  get event by id
func (c *Calendar) GetEventByID(eventID string) (*Event, error) {
	event, ok := c.eventByID[eventID]
	if ok {
		return event, nil
	}
	return nil, errors.New(fmt.Sprintf("There is no event with id %s", eventID))
}

//  get all events in the calendar
func (c *Calendar) GetEvents() []Event {
	return c.events
}

//  get all events in the calendar ordered by date
func (c *Calendar) GetEventsByDates() map[string][]*Event {
	return c.eventsByDate
}

// get all events for specified date
func (c *Calendar) GetEventsByDate(dateTime time.Time) ([]*Event, error) {
	tz := c.GetTimezone()
	day := time.Date(dateTime.Year(), dateTime.Month(), dateTime.Day(), 0, 0, 0, 0, &tz)
	events, ok := c.eventsByDate[day.Format(YmdHis)]
	if ok {
		return events, nil
	}
	return nil, errors.New(fmt.Sprintf("There are no events for the day %s", day.Format(YmdHis)))
}
<commit_msg>implements stringer<commit_after>package ics

import (
	"errors"
	"fmt"
	"time"
)

type Calendar struct {
	name         string
	description  string
	version      float64
	timezone     time.Location
	events       []Event
	eventsByDate map[string][]*Event
	eventByID    map[string]*Event
}

func NewCalendar() *Calendar {
	c := new(Calendar)
	// c.events = make([]Event)
	c.eventsByDate = make(map[string][]*Event)
	c.eventByID = make(map[string]*Event)
	return c
}

func (c *Calendar) SetName(n string) *Calendar {
	c.name = n
	return c
}

func (c *Calendar) GetName() string {
	return ""
}

func (c *Calendar) SetDesc(desc string) *Calendar {
	c.description = desc
	return c
}

func (c *Calendar) GetDesc() string {
	return ""
}

func (c *Calendar) SetVersion(ver float64) *Calendar {
	c.version = ver
	return c
}

func (c *Calendar) GetVersion() float64 {
	return c.version
}

func (c *Calendar) SetTimezone(tz time.Location) *Calendar {
	c.timezone = tz
	return c
}

func (c *Calendar) GetTimezone() time.Location {
	return c.timezone
}

//  add event to the calendar
func (c *Calendar) SetEvent(event Event) (*Calendar, error) {
	//  lock so that the events array doesn't change its size from other goruote
	mutex.Lock()

	// reference to the calendar
	if event.GetCalendar() == nil || event.GetCalendar() != c {
		event.SetCalendar(c)
	}
	// add the event to the main array with events
	c.events = append(c.events, event)

	// pointer to the added event in the main array
	eventPtr := &c.events[len(c.events)-1]

	// calculate the start day of the event
	eventStartTime := event.GetStart()
	tz := c.GetTimezone()
	eventDate := time.Date(eventStartTime.Year(), eventStartTime.Month(), eventStartTime.Day(), 0, 0, 0, 0, &tz)

	// faster search by date
	c.eventsByDate[eventDate.Format(YmdHis)] = append(c.eventsByDate[eventDate.Format(YmdHis)], eventPtr)
	// faster search by id
	c.eventByID[event.GetID()] = eventPtr

	mutex.Unlock()
	return c, nil
}

//  get event by id
func (c *Calendar) GetEventByID(eventID string) (*Event, error) {
	event, ok := c.eventByID[eventID]
	if ok {
		return event, nil
	}
	return nil, errors.New(fmt.Sprintf("There is no event with id %s", eventID))
}

//  get all events in the calendar
func (c *Calendar) GetEvents() []Event {
	return c.events
}

//  get all events in the calendar ordered by date
func (c *Calendar) GetEventsByDates() map[string][]*Event {
	return c.eventsByDate
}

// get all events for specified date
func (c *Calendar) GetEventsByDate(dateTime time.Time) ([]*Event, error) {
	tz := c.GetTimezone()
	day := time.Date(dateTime.Year(), dateTime.Month(), dateTime.Day(), 0, 0, 0, 0, &tz)
	events, ok := c.eventsByDate[day.Format(YmdHis)]
	if ok {
		return events, nil
	}
	return nil, errors.New(fmt.Sprintf("There are no events for the day %s", day.Format(YmdHis)))
}
func (c *Calendar) String() string {
	eventsCount := len(c.GetEvents())
	name := c.GetName()
	desc := c.GetDesc()
	return fmt.Sprintf("Calendar %s about %s has %d events", name, desc, eventsCount)
}
<|endoftext|>


<commit_before>package myqlib

import (
	"bufio"
	"bytes"
	"io"
	"log"
	"strings"
	"strconv"
	"time"
	// "fmt"
)

// Different types of files to parse
type showoutputtype uint8

const (
	BATCH showoutputtype = iota
	TABULAR
)

// Parse lines from mysql SHOW output.
func parseSamples(reader io.Reader, ch chan MyqSample, interval time.Duration) {
	outputtype := BATCH // default to BATCH
	typechecked := false
	recordmatch := []byte(`Variable_name`)

	// We can't have intervals smaller than 1s
	// if the interval is larger, we check samples for intervals
	// so we can avoid parsing them fully.
	check_intervals := false
	var prev_uptime float64
	if interval.Nanoseconds() > 1000000 {
		check_intervals = true
	}

	// This scanner will look for the start of a new set of SHOW STATUS output
	scanner := bufio.NewScanner(reader)
	scanner.Split( func (data []byte, atEOF bool) (advance int, token []byte, err error) {
		// Check if this looks like a TABULAR file, but only once
		if !typechecked {
			if bytes.HasPrefix( data, []byte(`+`)) || bytes.HasPrefix( data, []byte(`|`)) {
				outputtype, recordmatch = TABULAR, []byte(`| Variable_name`)
			}
			typechecked = true
		}

		if i := bytes.Index( data, recordmatch ); i >= 0 {
			// Found a new record
			nl := bytes.IndexByte( data[i:], '\n' ) // Find the subsequent newline

			if check_intervals {
				// Scan back for the Uptime
				uptime_str := []byte(`Uptime`)
				upt_pos := bytes.Index( data[0:i], uptime_str) + len(uptime_str) // After the Uptime
				if upt_pos >= 0 && upt_pos < i {
					upt_nl := bytes.IndexByte( data[upt_pos:i], '\n' ) + upt_pos // Find the next newline
					uptime_str := string(bytes.Trim( data[upt_pos:upt_nl], `| ` ))
					current_uptime, _ := strconv.ParseFloat( uptime_str, 64 )
					if prev_uptime == 0 {
						prev_uptime = current_uptime
					} else {
						if current_uptime - prev_uptime < interval.Seconds() {
							// This sample's uptime is too early, skip it
							return i+nl+1, nil, nil
						}
					}
				}
			}
			return i+nl+1, data[0:i], nil
		}

		// if we're at EOF and have data, return it, otherwise let it fall through
		if atEOF && len(data) > 0 {
			return len(data), data, nil
		}

		return 0, nil, nil
	})

	for scanner.Scan() {
		// The scanner sends complete samples
		parseBatch(ch, bytes.NewBuffer(scanner.Bytes()), outputtype)
	}

	// Not sure if we care here or not, remains to be seen
	if err := scanner.Err(); err != nil {
		log.Fatal(err)
	}
}

func parseBatch( ch chan MyqSample, buffer *bytes.Buffer, outputtype showoutputtype) {
	var divideridx int

	timesample := make(MyqSample)
	scanner := bufio.NewScanner(buffer)

	for scanner.Scan() {
		line := scanner.Bytes()
		var key, value []byte

		switch outputtype {
			case TABULAR:
				// Line here looks like this: (value can contain spaces)
				// | varname   | value    |
				if !bytes.HasPrefix(line, []byte(`|`)) {
					continue
				}

				if divideridx == 0 {
					divideridx = bytes.Index(line, []byte(` | `))
				} else if len(line) < divideridx {
					continue // line truncated, probably EOF
				}

				key = bytes.Trim(line[:divideridx], `| `)
				value = bytes.Trim(line[divideridx:], `| `)
			case BATCH:
				raw := bytes.Split(line, []byte("\t"))
				if len(raw) != 2 {
					continue
				}
				key, value = raw[0], raw[1]
		}

		timesample[strings.ToLower(string(key))] = string(value)
	}

	if timesample.Length() > 0 {
		ch <- timesample
	}
}<commit_msg>Moved interval checking to a closure and cleaned up<commit_after>package myqlib

import (
	"bufio"
	"bytes"
	"io"
	"log"
	"strings"
	"strconv"
	"time"
	// "fmt"
)

// Different types of files to parse
type showoutputtype uint8

const (
	BATCH showoutputtype = iota
	TABULAR
)

// Parse lines from mysql SHOW output.
func parseSamples(reader io.Reader, ch chan MyqSample, interval time.Duration) {
	outputtype := BATCH // default to BATCH
	typechecked := false
	recordmatch := []byte(`Variable_name`)

	// We can't have intervals smaller than 1s
	// if the interval is larger, we check samples for intervals
	// so we can avoid parsing them fully.
	check_intervals := false
	uptime_str := []byte(`Uptime`)
	var prev_uptime float64
	if interval.Nanoseconds() > 1000000 {
		check_intervals = true
	}
	// Scan back for the Uptime in the given record and return true if it can be skipped
	skip_interval := func( record []byte) (skippable bool) {
		upt_pos := bytes.Index( record, uptime_str) + len(uptime_str) // After the Uptime
		if upt_pos >= 0 {
			upt_nl := bytes.IndexByte( record[upt_pos:], '\n' ) + upt_pos // Find the next newline
			uptime_str := string(bytes.Trim( record[upt_pos:upt_nl], `| ` )) // Trim extra chars
			current_uptime, _ := strconv.ParseFloat( uptime_str, 64 ) // Parse the str to float
			if prev_uptime == 0 {
				prev_uptime = current_uptime
			} else {
				if current_uptime - prev_uptime < interval.Seconds() {
					// This sample's uptime is too early, skip it
					return true
				}
			}
		}
		return false
	}

	// This scanner will look for the start of a new set of SHOW STATUS output
	scanner := bufio.NewScanner(reader)
	scanner.Split( func (data []byte, atEOF bool) (advance int, token []byte, err error) {
		// Check if this looks like a TABULAR file, but only once
		if !typechecked {
			if bytes.HasPrefix( data, []byte(`+`)) || bytes.HasPrefix( data, []byte(`|`)) {
				outputtype, recordmatch = TABULAR, []byte(`| Variable_name`)
			}
			typechecked = true
		}

		if end := bytes.Index( data, recordmatch ); end > 0 {
			// Found a new record
			nl := bytes.IndexByte( data[end:], '\n' ) // Find the subsequent newline

			if check_intervals && skip_interval(data[0:end]) {
				return end+nl+1, nil, nil
			}
			return end+nl+1, data[0:end], nil
		}

		// if we're at EOF and have data, return it, otherwise let it fall through
		if atEOF && len(data) > 0 {
			return len(data), data, nil
		}

		return 0, nil, nil
	})

	for scanner.Scan() {
		// The scanner sends complete samples
		parseBatch(ch, bytes.NewBuffer(scanner.Bytes()), outputtype)
	}

	// Not sure if we care here or not, remains to be seen
	if err := scanner.Err(); err != nil {
		log.Fatal(err)
	}
}

func parseBatch( ch chan MyqSample, buffer *bytes.Buffer, outputtype showoutputtype) {
	var divideridx int

	timesample := make(MyqSample)
	scanner := bufio.NewScanner(buffer)

	for scanner.Scan() {
		line := scanner.Bytes()
		var key, value []byte

		switch outputtype {
			case TABULAR:
				// Line here looks like this: (value can contain spaces)
				// | varname   | value    |
				if !bytes.HasPrefix(line, []byte(`|`)) {
					continue
				}

				if divideridx == 0 {
					divideridx = bytes.Index(line, []byte(` | `))
				} else if len(line) < divideridx {
					continue // line truncated, probably EOF
				}

				key = bytes.Trim(line[:divideridx], `| `)
				value = bytes.Trim(line[divideridx:], `| `)
			case BATCH:
				raw := bytes.Split(line, []byte("\t"))
				if len(raw) != 2 {
					continue
				}
				key, value = raw[0], raw[1]
		}

		timesample[strings.ToLower(string(key))] = string(value)
	}

	if timesample.Length() > 0 {
		ch <- timesample
	}
}<|endoftext|>


<commit_before>package dax

import (
	math "github.com/dlespiau/dax/math"
)

type Color struct {
	R, G, B, A float32
}

func (color *Color) FromRGBA(r, g, b, a float32) {
	color.R = r
	color.G = g
	color.B = b
	color.A = a
}

func (color *Color) FromRGB(r, g, b float32) {
	color.FromRGBA(r, g, b, 1.0)
}

func u8toF(x uint8) float32 {
	return float32(x) / 255.
}

func (color *Color) FromRGBAu8(r, g, b, a uint8) {
	color.FromRGBA(u8toF(r), u8toF(g), u8toF(b), u8toF(a))
}

func (color *Color) FromRGBu8(r, g, b uint8) {
	color.FromRGBAu8(r, g, b, 255)
}

// The RGB <-> HSL functions could do with some benchmarking and ideas from:
//   http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv

func hue2rgb(p, q, t float32) float32 {
	if t < 0 {
		t++
	}
	if t > 1 {
		t--
	}
	if t < 1./6 {
		return p + (q-p)*6*t
	}
	if t < 1./2 {
		return q
	}
	if t < 2./3 {
		return p + (q-p)*(2./3-t)*6
	}
	return p
}

// Initialize a color from h, s, l values.
// Conversion formula adapted from:
//   http://en.wikipedia.org/wiki/HSL_color_space
// h, s, l are in [0, 1]
func (color *Color) FromHSL(h, s, l float32) {
	color.A = 1.0

	if s == 0 {
		// achromatic
		color.R = l
		color.G = l
		color.B = l
		return
	}

	var q float32
	if l < 0.5 {
		q = l * (1 + s)
	} else {
		q = l + s - l*s
	}
	p := 2*l - q

	color.R = hue2rgb(p, q, h+1./3)
	color.G = hue2rgb(p, q, h)
	color.B = hue2rgb(p, q, h-1./3)
}

// Convert a color to HSL.
// Conversion formula adapted from:
//   http://en.wikipedia.org/wiki/HSL_color_space.
// h, s, l are in [0, 1]
func (color *Color) ToHSL() (h, s, l float32) {
	r := color.R
	g := color.G
	b := color.B

	max := math.Max(r, math.Max(g, b))
	min := math.Min(r, math.Min(g, b))

	h = float32(0.0)
	s = float32(0.0)
	l = (max + min) / 2

	if max == min {
		return
	}

	d := max - min
	if l > 0.5 {
		s = d / (2 - max - min)
	} else {
		s = d / (max + min)
	}

	switch max {
	case r:
		var k float32
		if g < b {
			k = float32(6)
		} else {
			k = float32(0)
		}
		h = (g-b)/d + k
	case g:
		h = (b-r)/d + 2
	case b:
		h = (r-g)/d + 4
	}
	h /= 6

	return
}
<commit_msg>color: Fix linter warnings<commit_after>package dax

import (
	math "github.com/dlespiau/dax/math"
)

// Color represents a color encoded in RGBA.
type Color struct {
	R, G, B, A float32
}

// FromRGBA initializes a color from (r,g,b,a) values. Components should be
// between 0 and 1.
func (color *Color) FromRGBA(r, g, b, a float32) {
	color.R = r
	color.G = g
	color.B = b
	color.A = a
}

// FromRGB initializes a color from (r,g,b) values. Components should be
// between 0 and 1. The alpha is initiazed to 1 (fully opaque).
func (color *Color) FromRGB(r, g, b float32) {
	color.FromRGBA(r, g, b, 1.0)
}

func u8toF(x uint8) float32 {
	return float32(x) / 255.
}

// FromRGBAu8 initializes a color from (r,g,b,a) values. Components should be
// between 0 and 255.
func (color *Color) FromRGBAu8(r, g, b, a uint8) {
	color.FromRGBA(u8toF(r), u8toF(g), u8toF(b), u8toF(a))
}

// FromRGBu8 initializes a color from (r,g,b) values. Components should be
// between 0 and 255. The alpha is initiazed to 1 (ie 255, fully opaque).
func (color *Color) FromRGBu8(r, g, b uint8) {
	color.FromRGBAu8(r, g, b, 255)
}

// XXX: The RGB <-> HSL functions could do with some benchmarking and ideas
// from: http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv
func hue2rgb(p, q, t float32) float32 {
	if t < 0 {
		t++
	}
	if t > 1 {
		t--
	}
	if t < 1./6 {
		return p + (q-p)*6*t
	}
	if t < 1./2 {
		return q
	}
	if t < 2./3 {
		return p + (q-p)*(2./3-t)*6
	}
	return p
}

// FromHSL initializes a color from (h,s,l) values. h, s, l are between 0 and 1.
// Conversion formula is adapted from:
// http://en.wikipedia.org/wiki/HSL_color_space
func (color *Color) FromHSL(h, s, l float32) {
	color.A = 1.0

	if s == 0 {
		// achromatic
		color.R = l
		color.G = l
		color.B = l
		return
	}

	var q float32
	if l < 0.5 {
		q = l * (1 + s)
	} else {
		q = l + s - l*s
	}
	p := 2*l - q

	color.R = hue2rgb(p, q, h+1./3)
	color.G = hue2rgb(p, q, h)
	color.B = hue2rgb(p, q, h-1./3)
}

// ToHSL converts a color to HSL. Returned (h,s,l) components are between 0 and
// 1. Conversion formula adapted from:
// http://en.wikipedia.org/wiki/HSL_color_space.
func (color *Color) ToHSL() (h, s, l float32) {
	r := color.R
	g := color.G
	b := color.B

	max := math.Max(r, math.Max(g, b))
	min := math.Min(r, math.Min(g, b))

	h = float32(0.0)
	s = float32(0.0)
	l = (max + min) / 2

	if max == min {
		return
	}

	d := max - min
	if l > 0.5 {
		s = d / (2 - max - min)
	} else {
		s = d / (max + min)
	}

	switch max {
	case r:
		var k float32
		if g < b {
			k = float32(6)
		} else {
			k = float32(0)
		}
		h = (g-b)/d + k
	case g:
		h = (b-r)/d + 2
	case b:
		h = (r-g)/d + 4
	}
	h /= 6

	return
}
<|endoftext|>


<commit_before>/*
 *    Copyright (C) 2014-2017 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

// Package ircbee is a Bee that can connect to an IRC server.
package ircbee

import (
	"strings"
	"time"

	irc "github.com/fluffle/goirc/client"

	"github.com/muesli/beehive/bees"
)

// IrcBee is a Bee that can connect to an IRC server.
type IrcBee struct {
	bees.Bee

	// channel signaling irc connection status
	connectedState chan bool

	// setup IRC client:
	client   *irc.Conn
	channels []string

	server   string
	nick     string
	password string
	ssl      bool
}

// Action triggers the action passed to it.
func (mod *IrcBee) Action(action bees.Action) []bees.Placeholder {
	outs := []bees.Placeholder{}

	switch action.Name {
	case "send":
		tos := []string{}
		text := ""
		action.Options.Bind("text", &text)

		for _, opt := range action.Options {
			if opt.Name == "channel" {
				tos = append(tos, opt.Value.(string))
			}
		}

		for _, recv := range tos {
			if recv == "*" {
				// special: send to all joined channels
				for _, to := range mod.channels {
					mod.client.Privmsg(to, text)
				}
			} else {
				// needs stripping hostname when sending to user!host
				if strings.Index(recv, "!") > 0 {
					recv = recv[0:strings.Index(recv, "!")]
				}

				mod.client.Privmsg(recv, text)
			}
		}

	case "join":
		for _, opt := range action.Options {
			if opt.Name == "channel" {
				mod.join(opt.Value.(string))
			}
		}
	case "part":
		for _, opt := range action.Options {
			if opt.Name == "channel" {
				mod.part(opt.Value.(string))
			}
		}

	default:
		panic("Unknown action triggered in " + mod.Name() + ": " + action.Name)
	}

	return outs
}

// ircbee specific impl

func (mod *IrcBee) rejoin() {
	for _, channel := range mod.channels {
		mod.client.Join(channel)
	}
}

func (mod *IrcBee) join(channel string) {
	channel = strings.TrimSpace(channel)
	mod.client.Join(channel)

	mod.channels = append(mod.channels, channel)
}

func (mod *IrcBee) part(channel string) {
	channel = strings.TrimSpace(channel)
	mod.client.Part(channel)

	for k, v := range mod.channels {
		if v == channel {
			mod.channels = append(mod.channels[:k], mod.channels[k+1:]...)
			return
		}
	}
}

// Run executes the Bee's event loop.
func (mod *IrcBee) Run(eventChan chan bees.Event) {
	if len(mod.server) == 0 {
		return
	}

	// channel signaling IRC connection status
	mod.connectedState = make(chan bool)

	// setup IRC client:
	cfg := irc.NewConfig(mod.nick, "beehive", "beehive")
	cfg.SSL = mod.ssl
	cfg.Server = mod.server
	cfg.Pass = mod.password
	cfg.NewNick = func(n string) string { return n + "_" }
	mod.client = irc.Client(cfg)

	mod.client.HandleFunc("connected", func(conn *irc.Conn, line *irc.Line) {
		mod.connectedState <- true
	})
	mod.client.HandleFunc("disconnected", func(conn *irc.Conn, line *irc.Line) {
		mod.connectedState <- false
	})
	mod.client.HandleFunc("PRIVMSG", func(conn *irc.Conn, line *irc.Line) {
		channel := line.Args[0]
		if channel == mod.client.Config().Me.Nick {
			channel = line.Src // replies go via PM too.
		}
		msg := ""
		if len(line.Args) > 1 {
			msg = line.Args[1]
		}
		user := line.Src[:strings.Index(line.Src, "!")]
		hostmask := line.Src[strings.Index(line.Src, "!")+2:]

		ev := bees.Event{
			Bee:  mod.Name(),
			Name: "message",
			Options: []bees.Placeholder{
				{
					Name:  "channel",
					Type:  "string",
					Value: channel,
				},
				{
					Name:  "user",
					Type:  "string",
					Value: user,
				},
				{
					Name:  "hostmask",
					Type:  "string",
					Value: hostmask,
				},
				{
					Name:  "text",
					Type:  "string",
					Value: msg,
				},
			},
		}
		eventChan <- ev
	})

	// loop on IRC dis/connected events
	connecting := false
	disconnected := true
	waitForDisconnect := false
	for {
		if disconnected {
			if waitForDisconnect {
				return
			}

			if !connecting {
				connecting = true
				mod.Logln("Connecting to IRC:", mod.server)
				err := mod.client.Connect()
				if err != nil {
					mod.Logln("Failed to connect to IRC:", mod.server, err)
					connecting = false
				}
			}
		}
		select {
		case status := <-mod.connectedState:
			if status {
				mod.Logln("Connected to IRC:", mod.server)
				connecting = false
				disconnected = false
				mod.rejoin()
			} else {
				mod.Logln("Disconnected from IRC:", mod.server)
				connecting = false
				disconnected = true
				break
			}

		case <-mod.SigChan:
			if !waitForDisconnect {
				mod.client.Quit()
			}
			waitForDisconnect = true

		default:
			time.Sleep(1 * time.Second)
		}
	}
}

// ReloadOptions parses the config options and initializes the Bee.
func (mod *IrcBee) ReloadOptions(options bees.BeeOptions) {
	mod.SetOptions(options)

	options.Bind("address", &mod.server)
	options.Bind("nick", &mod.nick)
	options.Bind("password", &mod.password)
	options.Bind("ssl", &mod.ssl)

	for _, channel := range options.Value("channels").([]interface{}) {
		mod.channels = append(mod.channels, channel.(string))
	}
}
<commit_msg>Reset channel list when reloading options in IRCBee<commit_after>/*
 *    Copyright (C) 2014-2017 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

// Package ircbee is a Bee that can connect to an IRC server.
package ircbee

import (
	"strings"
	"time"

	irc "github.com/fluffle/goirc/client"

	"github.com/muesli/beehive/bees"
)

// IrcBee is a Bee that can connect to an IRC server.
type IrcBee struct {
	bees.Bee

	// channel signaling irc connection status
	connectedState chan bool

	// setup IRC client:
	client   *irc.Conn
	channels []string

	server   string
	nick     string
	password string
	ssl      bool
}

// Action triggers the action passed to it.
func (mod *IrcBee) Action(action bees.Action) []bees.Placeholder {
	outs := []bees.Placeholder{}

	switch action.Name {
	case "send":
		tos := []string{}
		text := ""
		action.Options.Bind("text", &text)

		for _, opt := range action.Options {
			if opt.Name == "channel" {
				tos = append(tos, opt.Value.(string))
			}
		}

		for _, recv := range tos {
			if recv == "*" {
				// special: send to all joined channels
				for _, to := range mod.channels {
					mod.client.Privmsg(to, text)
				}
			} else {
				// needs stripping hostname when sending to user!host
				if strings.Index(recv, "!") > 0 {
					recv = recv[0:strings.Index(recv, "!")]
				}

				mod.client.Privmsg(recv, text)
			}
		}

	case "join":
		for _, opt := range action.Options {
			if opt.Name == "channel" {
				mod.join(opt.Value.(string))
			}
		}
	case "part":
		for _, opt := range action.Options {
			if opt.Name == "channel" {
				mod.part(opt.Value.(string))
			}
		}

	default:
		panic("Unknown action triggered in " + mod.Name() + ": " + action.Name)
	}

	return outs
}

// ircbee specific impl

func (mod *IrcBee) rejoin() {
	for _, channel := range mod.channels {
		mod.client.Join(channel)
	}
}

func (mod *IrcBee) join(channel string) {
	channel = strings.TrimSpace(channel)
	mod.client.Join(channel)

	mod.channels = append(mod.channels, channel)
}

func (mod *IrcBee) part(channel string) {
	channel = strings.TrimSpace(channel)
	mod.client.Part(channel)

	for k, v := range mod.channels {
		if v == channel {
			mod.channels = append(mod.channels[:k], mod.channels[k+1:]...)
			return
		}
	}
}

// Run executes the Bee's event loop.
func (mod *IrcBee) Run(eventChan chan bees.Event) {
	if len(mod.server) == 0 {
		return
	}

	// channel signaling IRC connection status
	mod.connectedState = make(chan bool)

	// setup IRC client:
	cfg := irc.NewConfig(mod.nick, "beehive", "beehive")
	cfg.SSL = mod.ssl
	cfg.Server = mod.server
	cfg.Pass = mod.password
	cfg.NewNick = func(n string) string { return n + "_" }
	mod.client = irc.Client(cfg)

	mod.client.HandleFunc("connected", func(conn *irc.Conn, line *irc.Line) {
		mod.connectedState <- true
	})
	mod.client.HandleFunc("disconnected", func(conn *irc.Conn, line *irc.Line) {
		mod.connectedState <- false
	})
	mod.client.HandleFunc("PRIVMSG", func(conn *irc.Conn, line *irc.Line) {
		channel := line.Args[0]
		if channel == mod.client.Config().Me.Nick {
			channel = line.Src // replies go via PM too.
		}
		msg := ""
		if len(line.Args) > 1 {
			msg = line.Args[1]
		}
		user := line.Src[:strings.Index(line.Src, "!")]
		hostmask := line.Src[strings.Index(line.Src, "!")+2:]

		ev := bees.Event{
			Bee:  mod.Name(),
			Name: "message",
			Options: []bees.Placeholder{
				{
					Name:  "channel",
					Type:  "string",
					Value: channel,
				},
				{
					Name:  "user",
					Type:  "string",
					Value: user,
				},
				{
					Name:  "hostmask",
					Type:  "string",
					Value: hostmask,
				},
				{
					Name:  "text",
					Type:  "string",
					Value: msg,
				},
			},
		}
		eventChan <- ev
	})

	// loop on IRC dis/connected events
	connecting := false
	disconnected := true
	waitForDisconnect := false
	for {
		if disconnected {
			if waitForDisconnect {
				return
			}

			if !connecting {
				connecting = true
				mod.Logln("Connecting to IRC:", mod.server)
				err := mod.client.Connect()
				if err != nil {
					mod.Logln("Failed to connect to IRC:", mod.server, err)
					connecting = false
				}
			}
		}
		select {
		case status := <-mod.connectedState:
			if status {
				mod.Logln("Connected to IRC:", mod.server)
				connecting = false
				disconnected = false
				mod.rejoin()
			} else {
				mod.Logln("Disconnected from IRC:", mod.server)
				connecting = false
				disconnected = true
				break
			}

		case <-mod.SigChan:
			if !waitForDisconnect {
				mod.client.Quit()
			}
			waitForDisconnect = true

		default:
			time.Sleep(1 * time.Second)
		}
	}
}

// ReloadOptions parses the config options and initializes the Bee.
func (mod *IrcBee) ReloadOptions(options bees.BeeOptions) {
	mod.SetOptions(options)

	options.Bind("address", &mod.server)
	options.Bind("nick", &mod.nick)
	options.Bind("password", &mod.password)
	options.Bind("ssl", &mod.ssl)

	mod.channels = []string{}
	for _, channel := range options.Value("channels").([]interface{}) {
		mod.channels = append(mod.channels, channel.(string))
	}
}
<|endoftext|>


<commit_before>// Package dnsimple implements a client for the DNSimple API.
//
// In order to use this package you will need a DNSimple account and your API Token.
package dnsimple

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
)

const (
	libraryVersion = "0.1"
	defaultBaseURL = "https://api.dnsimple.com/"
	userAgent      = "dnsimple-go/" + libraryVersion

	apiVersion = "v1"
)

type Client struct {
	// HTTP client used to communicate with the API.
	HttpClient *http.Client

	// API Token for the DNSimple account you want to use.
	ApiToken string

	// Email associated with the provided DNSimple API Token.
	Email string

	// Domain Token to be used for authentication
	// as an alternative to the DNSimple API Token for some domain-scoped operations.
	DomainToken string

	// Base URL for API requests.
	// Defaults to the public DNSimple API, but can be set to a different endpoint (e.g. the sandbox).
	// BaseURL should always be specified with a trailing slash.
	BaseURL string

	// User agent used when communicating with the DNSimple API.
	UserAgent string

	// Services used for talking to different parts of the DNSimple API.
	Domains *DomainsService
	Records *RecordsService
}

// NewClient returns a new DNSimple API client.
func NewClient(apiToken, email string) *Client {
	c := &Client{ApiToken: apiToken, Email: email, HttpClient: &http.Client{}, BaseURL: defaultBaseURL, UserAgent: userAgent}
	c.Domains = &DomainsService{client: c}
	c.Records = &RecordsService{client: c}
	return c
}

// NewRequest creates an API request.
// The path is expected to be a relative path and will be resolved
// according to the BaseURL of the Client. Paths should always be specified without a preceding slash.
func (client *Client) NewRequest(method, path string, payload interface{}) (*http.Request, error) {
	url := client.BaseURL + fmt.Sprintf("%s/%s", apiVersion, path)

	body := new(bytes.Buffer)
	if payload != nil {
		err := json.NewEncoder(body).Encode(payload)
		if err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, url, body)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Add("Accept", "application/json")
	req.Header.Add("User-Agent", client.UserAgent)
	req.Header.Add("X-DNSimple-Token", fmt.Sprintf("%s:%s", client.Email, client.ApiToken))

	return req, nil
}

func (client *Client) get(path string, val interface{}) (*http.Response, error) {
	return client.sendRequest("GET", path, nil, val)
}

func (client *Client) post(path string, payload, val interface{}) (*http.Response, error) {
	return client.sendRequest("POST", path, payload, val)
}

func (client *Client) put(path string, payload, val interface{}) (*http.Response, error) {
	return client.sendRequest("PUT", path, payload, val)
}

func (client *Client) delete(path string, payload interface{}) (*http.Response, error) {
	return client.sendRequest("DELETE", path, payload, nil)
}

func (client *Client) sendRequest(method, path string, payload, v interface{}) (*http.Response, error) {
	req, err := client.NewRequest(method, path, payload)
	if err != nil {
		return nil, err
	}

	resp, err := client.HttpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	err = CheckResponse(resp)
	if err != nil {
		return resp, err
	}

	if v != nil {
		err = json.NewDecoder(resp.Body).Decode(v)
	}

	return resp, err
}

// ErrorResponse represents an error caused by an API request.
type ErrorResponse struct {
	Response *http.Response // HTTP response that caused this error
	Message  string         `json:"message"` // human-readable message
}

// Error implements the error interface.
func (r *ErrorResponse) Error() string {
	return fmt.Sprintf("%v %v: %d %v",
		r.Response.Request.Method, r.Response.Request.URL,
		r.Response.StatusCode, r.Message)
}

// newErrorResponse creates a new ErrorResponse parsing the message from the response body.
// This is useful if you want to inspect the response message
// and customize the error handling for a request.
func NewErrorResponse(r *http.Response) (*ErrorResponse, error) {
	errorResponse := &ErrorResponse{Response: r}
	err := json.NewDecoder(r.Body).Decode(errorResponse)
	return errorResponse, err
}

// CheckResponse checks the API response for errors, and returns them if present.
// A response is considered an error if the status code is different than 2xx. Specific requests
// may have additional requirements, but this is sufficient in most of the cases.
func CheckResponse(r *http.Response) error {
	if code := r.StatusCode; 200 <= code && code <= 299 {
		return nil
	}

	errorResponse, err := NewErrorResponse(r)
	if err != nil {
		return err
	}

	return errorResponse
}
<commit_msg>Wrap the http.Response into a custom Response<commit_after>// Package dnsimple implements a client for the DNSimple API.
//
// In order to use this package you will need a DNSimple account and your API Token.
package dnsimple

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
)

const (
	libraryVersion = "0.1"
	defaultBaseURL = "https://api.dnsimple.com/"
	userAgent      = "dnsimple-go/" + libraryVersion

	apiVersion = "v1"
)

type Client struct {
	// HTTP client used to communicate with the API.
	HttpClient *http.Client

	// API Token for the DNSimple account you want to use.
	ApiToken string

	// Email associated with the provided DNSimple API Token.
	Email string

	// Domain Token to be used for authentication
	// as an alternative to the DNSimple API Token for some domain-scoped operations.
	DomainToken string

	// Base URL for API requests.
	// Defaults to the public DNSimple API, but can be set to a different endpoint (e.g. the sandbox).
	// BaseURL should always be specified with a trailing slash.
	BaseURL string

	// User agent used when communicating with the DNSimple API.
	UserAgent string

	// Services used for talking to different parts of the DNSimple API.
	Domains *DomainsService
	Records *RecordsService
}

// NewClient returns a new DNSimple API client.
func NewClient(apiToken, email string) *Client {
	c := &Client{ApiToken: apiToken, Email: email, HttpClient: &http.Client{}, BaseURL: defaultBaseURL, UserAgent: userAgent}
	c.Domains = &DomainsService{client: c}
	c.Records = &RecordsService{client: c}
	return c
}

// NewRequest creates an API request.
// The path is expected to be a relative path and will be resolved
// according to the BaseURL of the Client. Paths should always be specified without a preceding slash.
func (client *Client) NewRequest(method, path string, payload interface{}) (*http.Request, error) {
	url := client.BaseURL + fmt.Sprintf("%s/%s", apiVersion, path)

	body := new(bytes.Buffer)
	if payload != nil {
		err := json.NewEncoder(body).Encode(payload)
		if err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, url, body)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Add("Accept", "application/json")
	req.Header.Add("User-Agent", client.UserAgent)
	req.Header.Add("X-DNSimple-Token", fmt.Sprintf("%s:%s", client.Email, client.ApiToken))

	return req, nil
}

func (client *Client) get(path string, val interface{}) (*Response, error) {
	return client.sendRequest("GET", path, nil, val)
}

func (client *Client) post(path string, payload, val interface{}) (*Response, error) {
	return client.sendRequest("POST", path, payload, val)
}

func (client *Client) put(path string, payload, val interface{}) (*Response, error) {
	return client.sendRequest("PUT", path, payload, val)
}

func (client *Client) delete(path string, payload interface{}) (*Response, error) {
	return client.sendRequest("DELETE", path, payload, nil)
}

func (client *Client) sendRequest(method, path string, payload, v interface{}) (*Response, error) {
	req, err := client.NewRequest(method, path, payload)
	if err != nil {
		return nil, err
	}

	resp, err := client.HttpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	response := &Response{Response: resp}

	err = CheckResponse(resp)
	if err != nil {
		return response, err
	}

	if v != nil {
		err = json.NewDecoder(response.Body).Decode(v)
	}

	return response, err
}

// A Response represents an API response.
type Response struct {
	*http.Response
}

// An ErrorResponse represents an error caused by an API request.
type ErrorResponse struct {
	Response *http.Response // HTTP response that caused this error
	Message  string         `json:"message"` // human-readable message
}

// Error implements the error interface.
func (r *ErrorResponse) Error() string {
	return fmt.Sprintf("%v %v: %d %v",
		r.Response.Request.Method, r.Response.Request.URL,
		r.Response.StatusCode, r.Message)
}

// CheckResponse checks the API response for errors, and returns them if present.
// A response is considered an error if the status code is different than 2xx. Specific requests
// may have additional requirements, but this is sufficient in most of the cases.
func CheckResponse(r *http.Response) error {
	if code := r.StatusCode; 200 <= code && code <= 299 {
		return nil
	}

	errorResponse := &ErrorResponse{Response: r}
	err := json.NewDecoder(r.Body).Decode(errorResponse)
	if err != nil {
		return err
	}

	return errorResponse
}
<|endoftext|>


<commit_before>package sockjs

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/http/httputil"
	"sync"
	"time"
)

type Session struct {
	Service                      *Service
	ReceiveChan, SendChan        chan interface{}
	DoConnCheck, ConnCheckResult chan bool
	ReadSemaphore                chan bool
	WriteMutex                   sync.Mutex
	WriteOpenFrame               bool
	LastActivity                 time.Time
	Broken                       bool
	Cookie                       string
}

func (session *Session) readMessages(data []byte) bool {
	var obj interface{}
	err := json.Unmarshal(data, &obj)
	if err != nil {
		return false
	}
	if messages, ok := obj.([]interface{}); ok {
		for _, message := range messages {
			session.ReceiveChan <- message
		}
	} else {
		session.ReceiveChan <- obj
	}
	return true
}

func (session *Session) writeFrames(w http.ResponseWriter, streaming, chunked bool, frameStart, frameEnd []byte, escape bool) {
	select {
	case session.ReadSemaphore <- true:
		// can read
	default:
		session.DoConnCheck <- true
		if <-session.ConnCheckResult {
			w.Write(createFrame('c', `[2010,"Another connection still open"]`, frameStart, frameEnd, escape))
		} else {
			w.Write(createFrame('c', `[1002,"Connection interrupted"]`, frameStart, frameEnd, escape))
		}
		return
	}
	defer func() {
		<-session.ReadSemaphore
	}()

	c := make(chan []byte)
	defer close(c)
	go func() {
		conn, buf, _ := w.(http.Hijacker).Hijack()
		defer conn.Close()
		defer buf.Flush()

		var frameWriter io.Writer
		if chunked {
			defer buf.Write([]byte("\r\n"))
			chunkedWriter := httputil.NewChunkedWriter(buf)
			frameWriter = chunkedWriter
			defer chunkedWriter.Close()
		} else {
			frameWriter = buf
		}

		for {
			select {
			case frame, ok := <-c:
				if !ok {
					return
				}
				frameWriter.Write(frame)
				if streaming {
					buf.Flush()
				}
			case <-session.DoConnCheck:
				_, err := conn.Write([]byte("0\r\n"))
				if err != nil {
					session.ConnCheckResult <- false
					session.Broken = true
					return
				}
				session.ConnCheckResult <- true
			}
		}
	}()

	var frame []byte
	var closed bool
	total := 0
	for !closed && total < session.Service.StreamLimit {
		frame, closed = session.createNextFrame(frameStart, frameEnd, escape)
		total += len(frame)
		c <- frame
		if !streaming {
			break
		}
	}
}

func (session *Session) createNextFrame(frameStart, frameEnd []byte, escape bool) ([]byte, bool) {
	if session.WriteOpenFrame {
		session.WriteOpenFrame = false
		return createFrame('o', "", frameStart, frameEnd, escape), false
	}

	messages := make([]interface{}, 0)
	message, ok := <-session.SendChan
	if !ok {
		return createFrame('c', `[3000,"Go away!"]`, frameStart, frameEnd, escape), true
	}
	messages = append(messages, message)

	for moreMessages := true; moreMessages; {
		select {
		case message, ok := <-session.SendChan:
			if ok {
				messages = append(messages, message)
			} else {
				moreMessages = false
			}
		default:
			moreMessages = false
		}
	}

	data, _ := json.Marshal(messages)
	return createFrame('a', string(data), frameStart, frameEnd, escape), false
}

func createFrame(kind byte, data string, frameStart, frameEnd []byte, escape bool) []byte {
	frame := bytes.NewBuffer(nil)
	frame.Write(frameStart)
	frame.WriteByte(kind)
	for _, r := range data {
		if escape && r == '\\' {
			frame.WriteString(`\\`)
		} else if escape && r == '"' {
			frame.WriteString(`\"`)
		} else if (0x200c <= r && r <= 0x200f) || (0x2028 <= r && r <= 0x202f) || (0x2060 <= r && r <= 0x206f) || (0xfff0 <= r && r <= 0xffff) {
			if escape {
				frame.WriteByte('\\')
			}
			frame.WriteString(fmt.Sprintf(`\u%04x`, r))
		} else {
			frame.WriteRune(r)
		}
	}
	frame.Write(frameEnd)
	return frame.Bytes()
}
<commit_msg>Added heartbeat to sockjs.<commit_after>package sockjs

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/http/httputil"
	"sync"
	"time"
)

type Session struct {
	Service                      *Service
	ReceiveChan, SendChan        chan interface{}
	DoConnCheck, ConnCheckResult chan bool
	ReadSemaphore                chan bool
	WriteMutex                   sync.Mutex
	WriteOpenFrame               bool
	LastActivity                 time.Time
	Broken                       bool
	Cookie                       string
}

func (session *Session) readMessages(data []byte) bool {
	var obj interface{}
	err := json.Unmarshal(data, &obj)
	if err != nil {
		return false
	}
	if messages, ok := obj.([]interface{}); ok {
		for _, message := range messages {
			session.ReceiveChan <- message
		}
	} else {
		session.ReceiveChan <- obj
	}
	return true
}

func (session *Session) writeFrames(w http.ResponseWriter, streaming, chunked bool, frameStart, frameEnd []byte, escape bool) {
	select {
	case session.ReadSemaphore <- true:
		// can read
	default:
		session.DoConnCheck <- true
		if <-session.ConnCheckResult {
			w.Write(createFrame('c', `[2010,"Another connection still open"]`, frameStart, frameEnd, escape))
		} else {
			w.Write(createFrame('c', `[1002,"Connection interrupted"]`, frameStart, frameEnd, escape))
		}
		return
	}
	defer func() {
		<-session.ReadSemaphore
	}()

	c := make(chan []byte)
	defer close(c)
	go func() {
		conn, buf, _ := w.(http.Hijacker).Hijack()
		defer conn.Close()
		defer buf.Flush()

		var frameWriter io.Writer
		if chunked {
			defer buf.Write([]byte("\r\n"))
			chunkedWriter := httputil.NewChunkedWriter(buf)
			frameWriter = chunkedWriter
			defer chunkedWriter.Close()
		} else {
			frameWriter = buf
		}

		for {
			select {
			case frame, ok := <-c:
				if !ok {
					return
				}
				frameWriter.Write(frame)
				if streaming {
					buf.Flush()
				}
			case <-session.DoConnCheck:
				_, err := conn.Write([]byte("0\r\n"))
				if err != nil {
					session.ConnCheckResult <- false
					session.Broken = true
					return
				}
				session.ConnCheckResult <- true
			}
		}
	}()

	var frame []byte
	var closed bool
	total := 0
	for !closed && total < session.Service.StreamLimit {
		frame, closed = session.createNextFrame(frameStart, frameEnd, escape)
		total += len(frame)
		c <- frame
		if !streaming {
			break
		}
	}
}

func (session *Session) createNextFrame(frameStart, frameEnd []byte, escape bool) ([]byte, bool) {
	if session.WriteOpenFrame {
		session.WriteOpenFrame = false
		return createFrame('o', "", frameStart, frameEnd, escape), false
	}

	messages := make([]interface{}, 0)
	select {
	case message, ok := <-session.SendChan:
		if !ok {
			return createFrame('c', `[3000,"Go away!"]`, frameStart, frameEnd, escape), true
		}
		messages = append(messages, message)
	case <-time.After(25 * time.Second):
		return createFrame('h', "", frameStart, frameEnd, escape), false
	}

	for moreMessages := true; moreMessages; {
		select {
		case message, ok := <-session.SendChan:
			if ok {
				messages = append(messages, message)
			} else {
				moreMessages = false
			}
		default:
			moreMessages = false
		}
	}

	data, _ := json.Marshal(messages)
	return createFrame('a', string(data), frameStart, frameEnd, escape), false
}

func createFrame(kind byte, data string, frameStart, frameEnd []byte, escape bool) []byte {
	frame := bytes.NewBuffer(nil)
	frame.Write(frameStart)
	frame.WriteByte(kind)
	for _, r := range data {
		if escape && r == '\\' {
			frame.WriteString(`\\`)
		} else if escape && r == '"' {
			frame.WriteString(`\"`)
		} else if (0x200c <= r && r <= 0x200f) || (0x2028 <= r && r <= 0x202f) || (0x2060 <= r && r <= 0x206f) || (0xfff0 <= r && r <= 0xffff) {
			if escape {
				frame.WriteByte('\\')
			}
			frame.WriteString(fmt.Sprintf(`\u%04x`, r))
		} else {
			frame.WriteRune(r)
		}
	}
	frame.Write(frameEnd)
	return frame.Bytes()
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Vitess Authors.

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 tabletserver

import (
	"fmt"
	"html/template"
	"io"
	"net/http"
	"time"

	"vitess.io/vitess/go/acl"
	"vitess.io/vitess/go/streamlog"
	"vitess.io/vitess/go/vt/callerid"
	"vitess.io/vitess/go/vt/log"
	"vitess.io/vitess/go/vt/logz"
	"vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv"

	querypb "vitess.io/vitess/go/vt/proto/query"
	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
)

var (
	txlogzHeader = []byte(`

				Transaction id
				Effective caller
				Immediate caller
				Start
				End
				Duration
				Decision
				Statements

	`)
	txlogzFuncMap = template.FuncMap{
		"stampMicro":         func(t time.Time) string { return t.Format(time.StampMicro) },
		"getEffectiveCaller": func(e *vtrpcpb.CallerID) string { return callerid.GetPrincipal(e) },
		"getImmediateCaller": func(i *querypb.VTGateCallerID) string { return callerid.GetUsername(i) },
	}
	txlogzTmpl = template.Must(template.New("example").Funcs(txlogzFuncMap).Parse(`

			{{.TransactionID}}
			{{.EffectiveCallerID | getEffectiveCaller}}
			{{.ImmediateCallerID | getImmediateCaller}}
			{{.StartTime | stampMicro}}
			{{.EndTime | stampMicro}}
			{{.Duration}}
			{{.Conclusion}}

				{{ range .Queries }}
					{{.}}

				{{ end}}

`))
)

func init() {
	http.HandleFunc("/txlogz", txlogzHandler)
}

// txlogzHandler serves a human readable snapshot of the
// current transaction log.
// Endpoint: /txlogz?timeout=%d&limit=%d
// timeout: the txlogz will keep dumping transactions until timeout
// limit: txlogz will keep dumping transactions until it hits the limit
func txlogzHandler(w http.ResponseWriter, req *http.Request) {
	if err := acl.CheckAccessHTTP(req, acl.DEBUGGING); err != nil {
		acl.SendError(w, err)
		return
	}

	if *streamlog.RedactDebugUIQueries {
		io.WriteString(w, `
<!DOCTYPE html>

Redacted

/txlogz has been redacted for your protection

`)
		return
	}

	timeout, limit := parseTimeoutLimitParams(req)
	ch := tabletenv.TxLogger.Subscribe("txlogz")
	defer tabletenv.TxLogger.Unsubscribe(ch)
	logz.StartHTMLTable(w)
	defer logz.EndHTMLTable(w)
	w.Write(txlogzHeader)

	tmr := time.NewTimer(timeout)
	defer tmr.Stop()
	for i := 0; i < limit; i++ {
		select {
		case out := <-ch:
			txc, ok := out.(*StatefulConnection)
			if !ok {
				err := fmt.Errorf("unexpected value in %s: %#v (expecting value of type %T)", tabletenv.TxLogger.Name(), out, &StatefulConnection{})
				io.WriteString(w, `<tr class="error">`)
				io.WriteString(w, err.Error())
				io.WriteString(w, "
")
				log.Error(err)
				continue
			}
			duration := txc.txProps.EndTime.Sub(txc.txProps.StartTime).Seconds()
			var level string
			if duration < 0.1 {
				level = "low"
			} else if duration < 1.0 {
				level = "medium"
			} else {
				level = "high"
			}
			tmplData := struct {
				*StatefulConnection
				Duration   float64
				ColorLevel string
			}{txc, duration, level}
			if err := txlogzTmpl.Execute(w, tmplData); err != nil {
				log.Errorf("txlogz: couldn't execute template: %v", err)
			}
		case <-tmr.C:
			return
		}
	}
}
<commit_msg>Check for nil before using struct (#6238)<commit_after>/*
Copyright 2019 The Vitess Authors.

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 tabletserver

import (
	"fmt"
	"html/template"
	"io"
	"net/http"
	"time"

	"vitess.io/vitess/go/acl"
	"vitess.io/vitess/go/streamlog"
	"vitess.io/vitess/go/vt/callerid"
	"vitess.io/vitess/go/vt/log"
	"vitess.io/vitess/go/vt/logz"
	"vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv"

	querypb "vitess.io/vitess/go/vt/proto/query"
	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
)

var (
	txlogzHeader = []byte(`

				Transaction id
				Effective caller
				Immediate caller
				Start
				End
				Duration
				Decision
				Statements

	`)
	txlogzFuncMap = template.FuncMap{
		"stampMicro":         func(t time.Time) string { return t.Format(time.StampMicro) },
		"getEffectiveCaller": func(e *vtrpcpb.CallerID) string { return callerid.GetPrincipal(e) },
		"getImmediateCaller": func(i *querypb.VTGateCallerID) string { return callerid.GetUsername(i) },
	}
	txlogzTmpl = template.Must(template.New("example").Funcs(txlogzFuncMap).Parse(`

			{{.TransactionID}}
			{{.EffectiveCallerID | getEffectiveCaller}}
			{{.ImmediateCallerID | getImmediateCaller}}
			{{.StartTime | stampMicro}}
			{{.EndTime | stampMicro}}
			{{.Duration}}
			{{.Conclusion}}

				{{ range .Queries }}
					{{.}}

				{{ end}}

`))
)

func init() {
	http.HandleFunc("/txlogz", txlogzHandler)
}

// txlogzHandler serves a human readable snapshot of the
// current transaction log.
// Endpoint: /txlogz?timeout=%d&limit=%d
// timeout: the txlogz will keep dumping transactions until timeout
// limit: txlogz will keep dumping transactions until it hits the limit
func txlogzHandler(w http.ResponseWriter, req *http.Request) {
	if err := acl.CheckAccessHTTP(req, acl.DEBUGGING); err != nil {
		acl.SendError(w, err)
		return
	}

	if *streamlog.RedactDebugUIQueries {
		io.WriteString(w, `
<!DOCTYPE html>

Redacted

/txlogz has been redacted for your protection

`)
		return
	}

	timeout, limit := parseTimeoutLimitParams(req)
	ch := tabletenv.TxLogger.Subscribe("txlogz")
	defer tabletenv.TxLogger.Unsubscribe(ch)
	logz.StartHTMLTable(w)
	defer logz.EndHTMLTable(w)
	w.Write(txlogzHeader)

	tmr := time.NewTimer(timeout)
	defer tmr.Stop()
	for i := 0; i < limit; i++ {
		select {
		case out := <-ch:
			txc, ok := out.(*StatefulConnection)
			if !ok {
				err := fmt.Errorf("unexpected value in %s: %#v (expecting value of type %T)", tabletenv.TxLogger.Name(), out, &StatefulConnection{})
				io.WriteString(w, `<tr class="error">`)
				io.WriteString(w, err.Error())
				io.WriteString(w, "
")
				log.Error(err)
				continue
			}
			// not all StatefulConnections contain transactions
			if txc.txProps != nil {
				writeTransactionData(w, txc)
			}
		case <-tmr.C:
			return
		}
	}
}

func writeTransactionData(w http.ResponseWriter, txc *StatefulConnection) {
	props := txc.txProps
	var level string
	duration := props.EndTime.Sub(props.StartTime).Seconds()
	if duration < 0.1 {
		level = "low"
	} else if duration < 1.0 {
		level = "medium"
	} else {
		level = "high"
	}
	tmplData := struct {
		*StatefulConnection
		Duration   float64
		ColorLevel string
	}{txc, duration, level}
	if err := txlogzTmpl.Execute(w, tmplData); err != nil {
		log.Errorf("txlogz: couldn't execute template: %v", err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2011 The Graphics-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 graphicstest

import (
	"bytes"
	"errors"
	"fmt"
	"image"
	"image/color"
	"os"
)

// LoadImage decodes an image from a file.
func LoadImage(path string) (img image.Image, err error) {
	file, err := os.Open(path)
	if err != nil {
		return
	}
	defer file.Close()
	img, _, err = image.Decode(file)
	return
}

func delta(u0, u1 uint32) int {
	d := int(u0) - int(u1)
	if d < 0 {
		return -d
	}
	return d
}

func withinTolerance(c0, c1 color.Color, tol int) bool {
	r0, g0, b0, a0 := c0.RGBA()
	r1, g1, b1, a1 := c1.RGBA()
	r := delta(r0, r1)
	g := delta(g0, g1)
	b := delta(b0, b1)
	a := delta(a0, a1)
	return r <= tol && g <= tol && b <= tol && a <= tol
}

// ImageWithinTolerance checks that each pixel varies by no more than tol.
func ImageWithinTolerance(m0, m1 image.Image, tol int) error {
	b0 := m0.Bounds()
	b1 := m1.Bounds()
	if !b0.Eq(b1) {
		return errors.New(fmt.Sprintf("got bounds %v want %v", b0, b1))
	}

	for y := b0.Min.Y; y < b0.Max.Y; y++ {
		for x := b0.Min.X; x < b0.Max.X; x++ {
			c0 := m0.At(x, y)
			c1 := m1.At(x, y)
			if !withinTolerance(c0, c1, tol) {
				e := fmt.Sprintf("got %v want %v at (%d, %d)", c0, c1, x, y)
				return errors.New(e)
			}
		}
	}
	return nil
}

// SprintBox pretty prints the array as a hexidecimal matrix.
func SprintBox(box []byte, width, height int) string {
	buf := bytes.NewBuffer(nil)
	i := 0
	for y := 0; y < height; y++ {
		for x := 0; x < width; x++ {
			fmt.Fprintf(buf, " 0x%02x,", box[i])
			i++
		}
		buf.WriteByte('\n')
	}
	return buf.String()
}
<commit_msg>graphics/graphicstest: add MakeRGBA and SprintImageR<commit_after>// Copyright 2011 The Graphics-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 graphicstest

import (
	"bytes"
	"errors"
	"fmt"
	"image"
	"image/color"
	"os"
)

// LoadImage decodes an image from a file.
func LoadImage(path string) (img image.Image, err error) {
	file, err := os.Open(path)
	if err != nil {
		return
	}
	defer file.Close()
	img, _, err = image.Decode(file)
	return
}

func delta(u0, u1 uint32) int {
	d := int(u0) - int(u1)
	if d < 0 {
		return -d
	}
	return d
}

func withinTolerance(c0, c1 color.Color, tol int) bool {
	r0, g0, b0, a0 := c0.RGBA()
	r1, g1, b1, a1 := c1.RGBA()
	r := delta(r0, r1)
	g := delta(g0, g1)
	b := delta(b0, b1)
	a := delta(a0, a1)
	return r <= tol && g <= tol && b <= tol && a <= tol
}

// ImageWithinTolerance checks that each pixel varies by no more than tol.
func ImageWithinTolerance(m0, m1 image.Image, tol int) error {
	b0 := m0.Bounds()
	b1 := m1.Bounds()
	if !b0.Eq(b1) {
		return errors.New(fmt.Sprintf("got bounds %v want %v", b0, b1))
	}

	for y := b0.Min.Y; y < b0.Max.Y; y++ {
		for x := b0.Min.X; x < b0.Max.X; x++ {
			c0 := m0.At(x, y)
			c1 := m1.At(x, y)
			if !withinTolerance(c0, c1, tol) {
				e := fmt.Sprintf("got %v want %v at (%d, %d)", c0, c1, x, y)
				return errors.New(e)
			}
		}
	}
	return nil
}

// SprintBox pretty prints the array as a hexidecimal matrix.
func SprintBox(box []byte, width, height int) string {
	buf := bytes.NewBuffer(nil)
	i := 0
	for y := 0; y < height; y++ {
		for x := 0; x < width; x++ {
			fmt.Fprintf(buf, " 0x%02x,", box[i])
			i++
		}
		buf.WriteByte('\n')
	}
	return buf.String()
}

// SprintImageR pretty prints the red channel of src. It looks like SprintBox.
func SprintImageR(src *image.RGBA) string {
	w, h := src.Rect.Dx(), src.Rect.Dy()
	i := 0
	box := make([]byte, w*h)
	for y := src.Rect.Min.Y; y < src.Rect.Max.Y; y++ {
		for x := src.Rect.Min.X; x < src.Rect.Max.X; x++ {
			off := (y-src.Rect.Min.Y)*src.Stride + (x-src.Rect.Min.X)*4
			box[i] = src.Pix[off]
			i++
		}
	}
	return SprintBox(box, w, h)
}

// MakeRGBA returns an image with R, G, B taken from src.
func MakeRGBA(src []uint8, width int) *image.RGBA {
	b := image.Rect(0, 0, width, len(src)/width)
	ret := image.NewRGBA(b)
	i := 0
	for y := b.Min.Y; y < b.Max.Y; y++ {
		for x := b.Min.X; x < b.Max.X; x++ {
			ret.SetRGBA(x, y, color.RGBA{
				R: src[i],
				G: src[i],
				B: src[i],
				A: 0xff,
			})
			i++
		}
	}
	return ret
}
<|endoftext|>


<commit_before>// The articles command is used for easily managing article files.
//
// To install this tool, type go install gnd.la/apps/articles/cmd/articles.
//
// Then, view its help and usage by typing:
//
//  articles help
package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"

	"gnd.la/apps/articles/article"

	"gopkgs.com/command.v1"
)

func openArticle(p string) (*article.Article, error) {
	f, err := os.Open(p)
	if err != nil {
		return nil, fmt.Errorf("error opening %s: %s", p, err)
	}
	defer f.Close()
	article, err := article.New(f)
	if err != nil {
		return nil, fmt.Errorf("error loading %s: %s", p, err)
	}
	return article, nil
}

func dumpCommand(args []string) {
	for _, v := range args {
		article, err := openArticle(v)
		if err != nil {
			log.Print(err)
			continue
		}
		fmt.Printf("article %s\n%+v\n", v, article)
	}
}

func setCommand(args []string) error {
	if len(args) != 3 {
		return fmt.Errorf("invalid number of arguments %d, must be <property> <value> <article>", len(args))
	}
	p := args[2]
	article, err := openArticle(p)
	if err != nil {
		return err
	}
	if err := article.Set(args[0], args[1]); err != nil {
		return err
	}
	var buf bytes.Buffer
	if _, err := article.WriteTo(&buf); err != nil {
		return err
	}
	return ioutil.WriteFile(p, buf.Bytes(), 0644)
}

const (
	dumpHelp = `The dump command dumps the articles it parses to the
standard output. It can be used to validate articles files.`
	setHelp = `The set command sets properties in article files. The parsed
properties include:
    id (string)
    title ([]string)
    slug ([]string)
    synopsis (string)
    updated ([]time.Time)
    priority (int)

Setting a property stored in a slice prepends the new value to the existing ones. To
delete a value, simply remove its line with a text editor.

time.Time properties must use one of the following formats:

    now
    today
    yyyy-mm-dd
    yyyy-mm-dd hh:MM
    yyyy-mm-dd hh:MM:ss
    time.RFC822
    time.RFC822Z`
)

var (
	commands = []*command.Cmd{
		{
			Name:     "dump",
			Help:     "Dump parsed articles to command line",
			LongHelp: dumpHelp,
			Usage:    "<article-1> [article-2] ... [article-n]",
			Func:     dumpCommand,
		},
		{
			Name:     "set",
			Help:     "Set or add a property to the given article",
			LongHelp: setHelp,
			Usage:    "<property> <value> <article>",
			Func:     setCommand,
		},
	}
)

func main() {
	command.Run(commands)
}
<commit_msg>Formatting changes in help messages<commit_after>// The articles command is used for easily managing article files.
//
// To install this tool, type go install gnd.la/apps/articles/cmd/articles.
//
// Then, view its help and usage by typing:
//
//  articles help
package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"

	"gnd.la/apps/articles/article"

	"gopkgs.com/command.v1"
)

func openArticle(p string) (*article.Article, error) {
	f, err := os.Open(p)
	if err != nil {
		return nil, fmt.Errorf("error opening %s: %s", p, err)
	}
	defer f.Close()
	article, err := article.New(f)
	if err != nil {
		return nil, fmt.Errorf("error loading %s: %s", p, err)
	}
	return article, nil
}

func dumpCommand(args []string) {
	for _, v := range args {
		article, err := openArticle(v)
		if err != nil {
			log.Print(err)
			continue
		}
		fmt.Printf("article %s\n%+v\n", v, article)
	}
}

func setCommand(args []string) error {
	if len(args) != 3 {
		return fmt.Errorf("invalid number of arguments %d, must be <property> <value> <article>", len(args))
	}
	p := args[2]
	article, err := openArticle(p)
	if err != nil {
		return err
	}
	if err := article.Set(args[0], args[1]); err != nil {
		return err
	}
	var buf bytes.Buffer
	if _, err := article.WriteTo(&buf); err != nil {
		return err
	}
	return ioutil.WriteFile(p, buf.Bytes(), 0644)
}

const (
	dumpHelp = `The dump command dumps the articles it parses to the
standard output. It can be used to validate articles files.`
	setHelp = `The set command sets properties in article files. The parsed
properties include:

    - id (string)
    - title ([]string)
    - slug ([]string)
    - synopsis (string)
    - updated ([]time.Time)
    - priority (int)

Setting a property stored in a slice prepends the new value to the existing ones. To
delete a value, simply remove its line with a text editor.

time.Time properties must use one of the following formats:

    - now
    - today
    - yyyy-mm-dd
    - yyyy-mm-dd hh:MM
    - yyyy-mm-dd hh:MM:ss
    - time.RFC822
    - time.RFC822Z`
)

var (
	commands = []*command.Cmd{
		{
			Name:     "dump",
			Help:     "Dump parsed articles to command line",
			LongHelp: dumpHelp,
			Usage:    "<article-1> [article-2] ... [article-n]",
			Func:     dumpCommand,
		},
		{
			Name:     "set",
			Help:     "Set or add a property to the given article",
			LongHelp: setHelp,
			Usage:    "<property> <value> <article>",
			Func:     setCommand,
		},
	}
)

func main() {
	command.Run(commands)
}
<|endoftext|>


<commit_before>package libkb

import (
	"time"

	"github.com/davecgh/go-spew/spew"
	"github.com/keybase/client/go/protocol/keybase1"
)

func getUsernameIfProvisioned(m MetaContext, uc UserConfig) (ret NormalizedUsername, err error) {
	m.Debug("getUsernameIfProvisioned(%+v)", uc)
	did := uc.GetDeviceID()
	if did.IsNil() {
		m.Debug("- no valid username since nil deviceID")
		return ret, nil
	}
	err = checkDeviceValidForUID(m.Ctx(), m.G().GetUPAKLoader(), uc.GetUID(), did)
	switch err.(type) {
	case nil:
		m.Debug("- checks out")
		return uc.GetUsername(), nil
	case DeviceNotFoundError:
		m.Debug("- user was likely reset (%s)", err)
		return ret, nil
	case KeyRevokedError:
		m.Debug("- device was revoked (%s)", err)
		return ret, nil
	case UserDeletedError:
		m.Debug(" - user was deleted (%s)", err)
		return ret, nil
	case NotFoundError:
		// This can happen in development if the dev db is nuked or a mobile
		// device is connected to dev servers.
		m.Debug(" - user wasn't found (%s)", err)
		return ret, nil
	default:
		m.Debug("- unexpected error; propagating (%s)", err)
		return ret, err
	}
}

type deviceForUsersRet struct {
	AppStatusEmbed
	UserConfigs []deviceForUser `json:"user_configs"`
}
type deviceForUser struct {
	UID      keybase1.UID       `json:"uid"`
	DeviceID keybase1.DeviceID  `json:"device_id"`
	OK       bool               `json:"ok"`
	Username NormalizedUsername `json:"username"`
}

// GetAllProvisionedUsernames looks into the current config.json file, and
// finds all usernames that are currently provisioned on this device. Then, it
// asks the server to filter out revoked devices or reset users.
func GetAllProvisionedUsernames(mctx MetaContext) (current NormalizedUsername, all []NormalizedUsername, err error) {
	mctx = mctx.WithLogTag("GAPU")
	defer mctx.Trace("GetAllProvisionedUsernames", func() error { return err })()

	currentUC, allUCs, err := mctx.G().Env.GetConfig().GetAllUserConfigs()
	if err != nil {
		return current, nil, err
	}

	var userConfigs []deviceForUser
	if currentUC != nil {
		userConfigs = append(userConfigs, deviceForUser{UID: currentUC.GetUID(), DeviceID: currentUC.GetDeviceID()})
	}
	for _, uc := range allUCs {
		userConfigs = append(userConfigs, deviceForUser{UID: uc.GetUID(), DeviceID: uc.GetDeviceID()})
	}

	if len(userConfigs) == 0 {
		mctx.Debug("GAPU: no userConfigs to lookup")
		return current, nil, nil
	}

	payload := make(JSONPayload)
	payload["user_configs"] = userConfigs
	spew.Dump(payload)
	arg := APIArg{
		Endpoint:       "device/for_users",
		JSONPayload:    payload,
		SessionType:    APISessionTypeNONE,
		InitialTimeout: 5 * time.Second,
		RetryCount:     3,
	}

	resp := deviceForUsersRet{}
	err = mctx.G().API.PostDecode(mctx, arg, &resp)
	if err != nil {
		return "", nil, err
	}

	for _, userConfig := range resp.UserConfigs {
		if userConfig.OK {
			all = append(all, userConfig.Username)
			if userConfig.Username == currentUC.GetUsername() {
				current = userConfig.Username
			}
		}
	}

	return current, all, nil
}
<commit_msg>Remove spew.Dump from GetAllProvisionedUsernames (#19113)<commit_after>package libkb

import (
	"time"

	"github.com/keybase/client/go/protocol/keybase1"
)

func getUsernameIfProvisioned(m MetaContext, uc UserConfig) (ret NormalizedUsername, err error) {
	m.Debug("getUsernameIfProvisioned(%+v)", uc)
	did := uc.GetDeviceID()
	if did.IsNil() {
		m.Debug("- no valid username since nil deviceID")
		return ret, nil
	}
	err = checkDeviceValidForUID(m.Ctx(), m.G().GetUPAKLoader(), uc.GetUID(), did)
	switch err.(type) {
	case nil:
		m.Debug("- checks out")
		return uc.GetUsername(), nil
	case DeviceNotFoundError:
		m.Debug("- user was likely reset (%s)", err)
		return ret, nil
	case KeyRevokedError:
		m.Debug("- device was revoked (%s)", err)
		return ret, nil
	case UserDeletedError:
		m.Debug(" - user was deleted (%s)", err)
		return ret, nil
	case NotFoundError:
		// This can happen in development if the dev db is nuked or a mobile
		// device is connected to dev servers.
		m.Debug(" - user wasn't found (%s)", err)
		return ret, nil
	default:
		m.Debug("- unexpected error; propagating (%s)", err)
		return ret, err
	}
}

type deviceForUsersRet struct {
	AppStatusEmbed
	UserConfigs []deviceForUser `json:"user_configs"`
}
type deviceForUser struct {
	UID      keybase1.UID       `json:"uid"`
	DeviceID keybase1.DeviceID  `json:"device_id"`
	OK       bool               `json:"ok"`
	Username NormalizedUsername `json:"username"`
}

// GetAllProvisionedUsernames looks into the current config.json file, and
// finds all usernames that are currently provisioned on this device. Then, it
// asks the server to filter out revoked devices or reset users.
func GetAllProvisionedUsernames(mctx MetaContext) (current NormalizedUsername, all []NormalizedUsername, err error) {
	mctx = mctx.WithLogTag("GAPU")
	defer mctx.Trace("GetAllProvisionedUsernames", func() error { return err })()

	currentUC, allUCs, err := mctx.G().Env.GetConfig().GetAllUserConfigs()
	if err != nil {
		return current, nil, err
	}

	var userConfigs []deviceForUser
	if currentUC != nil {
		userConfigs = append(userConfigs, deviceForUser{UID: currentUC.GetUID(), DeviceID: currentUC.GetDeviceID()})
	}
	for _, uc := range allUCs {
		userConfigs = append(userConfigs, deviceForUser{UID: uc.GetUID(), DeviceID: uc.GetDeviceID()})
	}

	if len(userConfigs) == 0 {
		mctx.Debug("GAPU: no userConfigs to lookup")
		return current, nil, nil
	}

	payload := make(JSONPayload)
	payload["user_configs"] = userConfigs
	arg := APIArg{
		Endpoint:       "device/for_users",
		JSONPayload:    payload,
		SessionType:    APISessionTypeNONE,
		InitialTimeout: 5 * time.Second,
		RetryCount:     3,
	}

	resp := deviceForUsersRet{}
	err = mctx.G().API.PostDecode(mctx, arg, &resp)
	if err != nil {
		return "", nil, err
	}

	for _, userConfig := range resp.UserConfigs {
		if userConfig.OK {
			all = append(all, userConfig.Username)
			if userConfig.Username == currentUC.GetUsername() {
				current = userConfig.Username
			}
		}
	}

	return current, all, nil
}
<|endoftext|>