<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math/rand"
	"net"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

var remoteAddr = flag.String("r", "", "remote addr")
var payloadSize = flag.Int("s", 64, "payload size")
var interval = flag.Int64("i", 50, "interval in milliseconds")
var count = flag.Int("c", 50, "send count")
var number = flag.Int("n", 1, "how many connections")
var protocol = flag.String("p", "tcp", "protocol: tcp or udp")
var genCharts = flag.Bool("g", false, "generate charts")

var payload string

const headSize = 15

type Result struct {
	max, min, avg int
	data          []int
}

func init() {
	payload = randString(*payloadSize)
}

func encodePacket() []byte {
	sendTime, _ := time.Now().MarshalBinary()
	sendTime = append(sendTime, payload...)
	return sendTime
}

func decodeLatency(bs []byte) int {
	before := time.Time{}
	err := before.UnmarshalBinary(bs)
	if err != nil {
		log.Fatal(err)
	}
	t := time.Since(before) / time.Millisecond
	return int(t)
}

func handleReceive(conn net.Conn, notify chan Result) {
	bs := make([]byte, headSize)
	ps := make([]byte, *payloadSize)
	all := int64(0)
	max := 0
	min := 0xFFFFFFFFFFFFFFF
	avg := (0)
	data := make([]int, *count)
	for i := 0; i < *count; i++ {
		_, err := io.ReadFull(conn, bs)
		if err != nil {
			log.Println(err)
			break
		}
		elapsed := decodeLatency(bs)
		if elapsed > max {
			max = elapsed
		}
		if elapsed < min {
			min = elapsed
		}
		log.Printf("[%d] packet RTT: [%d] ms", i, elapsed)
		data[i] = elapsed
		_, err = io.ReadFull(conn, ps)
		if err != nil {
			log.Println(err)
			break
		}
		all = all + int64(elapsed)
		avg = int(all / int64(i+1))
	}
	notify <- Result{max, min, avg, data}
}

func runOne(remoteAddr string, notify chan Result) {
	conn, err := net.Dial(*protocol, remoteAddr)
	if err != nil {
		log.Panicln(err)
	}
	defer conn.Close()
	go handleReceive(conn, notify)
	for i := 0; i < *count; i++ {
		buf := strings.NewReader(string(encodePacket()))
		_, err := io.CopyN(conn, buf, int64(buf.Len()))
		if err != nil {
			log.Println(err)
			break
		}
		time.Sleep(time.Duration(*interval) * time.Millisecond)
	}
}

func makeCharts(idx int, data []int) {
	t := time.Now()
	now := fmt.Sprintf("%d-%d-%dH%dM%dS%d-%d", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), idx)
	const header = `
# The chart type , option : spline/line/bar/column/area
ChartType = spline
Title = packet RTT latency (ms)
SubTitle = %s
ValueSuffix = ms

# The x Axis numbers. The count this numbers MUST be the same with the data series
XAxisNumbers = %s

# The y Axis text
YAxisText = Latency (ms)

# The data and the name of the lines
Data|Latency = %s
`
	x := []string{}
	d := []string{}
	for i := 0; i < len(data); i++ {
		x = append(x, strconv.Itoa(i))
		d = append(d, strconv.Itoa(data[i]))
	}
	sx := strings.Join(x, ", ")
	sd := strings.Join(d, ", ")

	all := fmt.Sprintf(header, now, sx, sd)
	ioutil.WriteFile(now+".chart", []byte(all), os.ModePerm)
}

func main() {
	flag.Parse()
	results := make(chan Result, *number)
	wg := &sync.WaitGroup{}
	for i := 0; i < *number; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			runOne(*remoteAddr, results)
		}()
	}
	wg.Wait()
	for i := 0; i < *number; i++ {
		ret := <-results
		if *genCharts {
			makeCharts(i, ret.data)
		}
		log.Printf("RTT min: [%d] ms, RTT max: [%d] ms, RTT avg: [%d] ms\n", ret.min, ret.max, ret.avg)
	}
}

var src = rand.NewSource(time.Now().UnixNano())

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const (
	letterIdxBits = 6                    // 6 bits to represent a letter index
	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
	letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
)

func randString(n int) string {
	b := make([]byte, n)
	// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
	for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
		if remain == 0 {
			cache, remain = src.Int63(), letterIdxMax
		}
		if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
			b[i] = letterBytes[idx]
			i--
		}
		cache >>= letterIdxBits
		remain--
	}

	return string(b)
}
<commit_msg>default 100ms<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math/rand"
	"net"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

var remoteAddr = flag.String("r", "", "remote addr")
var payloadSize = flag.Int("s", 64, "payload size")
var interval = flag.Int64("i", 100, "interval in milliseconds")
var count = flag.Int("c", 50, "send count")
var number = flag.Int("n", 1, "how many connections")
var protocol = flag.String("p", "tcp", "protocol: tcp or udp")
var genCharts = flag.Bool("g", false, "generate charts")

var payload string

const headSize = 15

type Result struct {
	max, min, avg int
	data          []int
}

func init() {
	payload = randString(*payloadSize)
}

func encodePacket() []byte {
	sendTime, _ := time.Now().MarshalBinary()
	sendTime = append(sendTime, payload...)
	return sendTime
}

func decodeLatency(bs []byte) int {
	before := time.Time{}
	err := before.UnmarshalBinary(bs)
	if err != nil {
		log.Fatal(err)
	}
	t := time.Since(before) / time.Millisecond
	return int(t)
}

func handleReceive(conn net.Conn, notify chan Result) {
	bs := make([]byte, headSize)
	ps := make([]byte, *payloadSize)
	all := int64(0)
	max := 0
	min := 0xFFFFFFFFFFFFFFF
	avg := (0)
	data := make([]int, *count)
	for i := 0; i < *count; i++ {
		_, err := io.ReadFull(conn, bs)
		if err != nil {
			log.Println(err)
			break
		}
		elapsed := decodeLatency(bs)
		if elapsed > max {
			max = elapsed
		}
		if elapsed < min {
			min = elapsed
		}
		log.Printf("[%d] packet RTT: [%d] ms", i, elapsed)
		data[i] = elapsed
		_, err = io.ReadFull(conn, ps)
		if err != nil {
			log.Println(err)
			break
		}
		all = all + int64(elapsed)
		avg = int(all / int64(i+1))
	}
	notify <- Result{max, min, avg, data}
}

func runOne(remoteAddr string, notify chan Result) {
	conn, err := net.Dial(*protocol, remoteAddr)
	if err != nil {
		log.Panicln(err)
	}
	defer conn.Close()
	go handleReceive(conn, notify)
	for i := 0; i < *count; i++ {
		buf := strings.NewReader(string(encodePacket()))
		_, err := io.CopyN(conn, buf, int64(buf.Len()))
		if err != nil {
			log.Println(err)
			break
		}
		time.Sleep(time.Duration(*interval) * time.Millisecond)
	}
}

func makeCharts(idx int, data []int) {
	t := time.Now()
	now := fmt.Sprintf("%d-%d-%dH%dM%dS%d-%d", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), idx)
	const header = `
# The chart type , option : spline/line/bar/column/area
ChartType = spline
Title = packet RTT latency (ms)
SubTitle = %s
ValueSuffix = ms

# The x Axis numbers. The count this numbers MUST be the same with the data series
XAxisNumbers = %s

# The y Axis text
YAxisText = Latency (ms)

# The data and the name of the lines
Data|Latency = %s
`
	x := []string{}
	d := []string{}
	for i := 0; i < len(data); i++ {
		x = append(x, strconv.Itoa(i))
		d = append(d, strconv.Itoa(data[i]))
	}
	sx := strings.Join(x, ", ")
	sd := strings.Join(d, ", ")

	all := fmt.Sprintf(header, now, sx, sd)
	ioutil.WriteFile(now+".chart", []byte(all), os.ModePerm)
}

func main() {
	flag.Parse()
	results := make(chan Result, *number)
	wg := &sync.WaitGroup{}
	for i := 0; i < *number; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			runOne(*remoteAddr, results)
		}()
	}
	wg.Wait()
	for i := 0; i < *number; i++ {
		ret := <-results
		if *genCharts {
			makeCharts(i, ret.data)
		}
		log.Printf("RTT min: [%d] ms, RTT max: [%d] ms, RTT avg: [%d] ms\n", ret.min, ret.max, ret.avg)
	}
}

var src = rand.NewSource(time.Now().UnixNano())

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const (
	letterIdxBits = 6                    // 6 bits to represent a letter index
	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
	letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
)

func randString(n int) string {
	b := make([]byte, n)
	// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
	for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
		if remain == 0 {
			cache, remain = src.Int63(), letterIdxMax
		}
		if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
			b[i] = letterBytes[idx]
			i--
		}
		cache >>= letterIdxBits
		remain--
	}

	return string(b)
}
<|endoftext|>


<commit_before>//go:generate esc -o static.go -prefix static static

package main

import (
	"encoding/json"
	"flag"
	"github.com/fatih/structs"
	"github.com/nfnt/resize"
	"gopkg.in/yaml.v2"
	"image/jpeg"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"time"
)

var photos = make(map[string]struct{})
var dirToMetadata = make(map[string]metadata)
var photoDir string
var cacheDir string

type metadata struct {
	Event        string
	Photographer string
	Date         string
	Location     string
	Directory    string `json:"-" structs:"directory"`
}

func handleIndex(w http.ResponseWriter, r *http.Request) {
	enc := json.NewEncoder(w)
	if err := enc.Encode(dirToMetadata); err != nil {
		log.Print(err)
		return
	}
}

func handleFilters(w http.ResponseWriter, r *http.Request) {
	keys := []string{"Event", "Photographer", "Date", "Location"}

	filters := make(map[string]map[string]struct{})
	for _, k := range keys {
		filters[k] = make(map[string]struct{})
	}

	for _, meta := range dirToMetadata {
		m := structs.Map(meta)
		for _, k := range keys {
			if _, ok := m[k]; ok {
				filters[k][m[k].(string)] = struct{}{}
			}
		}
	}

	jFilters := make(map[string][]string)
	for _, k := range keys {
		jFilters[k] = make([]string, 0)
	}

	for i := range filters {
		for j := range filters[i] {
			jFilters[i] = append(jFilters[i], j)
		}
		sort.Strings(jFilters[i])
		if len(jFilters[i]) == 0 {
			delete(jFilters, i)
		}
	}

	enc := json.NewEncoder(w)
	if err := enc.Encode(jFilters); err != nil {
		log.Print(err)
		return
	}
}

func handleFilter(w http.ResponseWriter, r *http.Request) {
	filterToEligible := make(map[string][]string)

	filters := make(map[string][]string)
	for filterKey := range r.URL.Query() {
		filters[filterKey] = r.URL.Query()[filterKey]
	}

	// find all directories with matching filters
	for filterKey, filterValues := range filters {
		for dir, meta := range dirToMetadata {
			m := structs.Map(meta)
			for k, v := range m {
				if filterKey == k {
					for _, filterValue := range filterValues {
						if filterValue == v {
							filterToEligible[filterKey] = append(filterToEligible[filterKey], dir)
						}
					}
				}
			}
		}
	}

	// find intersection of all filter matches
	eligible := make(map[string]bool)

	for _, dirs := range filterToEligible {
		for _, dir := range dirs {
			count := 0
			for _, dirTests := range filterToEligible {
				for _, dirTest := range dirTests {
					if dir == dirTest {
						count += 1
					}
				}
			}
			if count == len(filterToEligible) {
				eligible[dir] = true
			}
		}
	}

	eligiblePhotos := make([]string, 0)
	for photo := range photos {
		dir := filepath.Dir(photo)
		if _, ok := eligible[dir]; ok {
			eligiblePhotos = append(eligiblePhotos, photo)
		}
	}

	enc := json.NewEncoder(w)
	if err := enc.Encode(eligiblePhotos); err != nil {
		log.Print(err)
		return
	}
}

func handlePhoto(w http.ResponseWriter, r *http.Request) {
	if filepath.Ext(r.URL.Path) != ".jpg" {
		http.Error(w, http.StatusText(404), 404)
		return
	}

	// serve photo
	photoFilepath := filepath.Join(photoDir, r.URL.Path[len("/photo/"):])
	http.ServeFile(w, r, photoFilepath)
}

func handleThumb(w http.ResponseWriter, r *http.Request) {
	if filepath.Ext(r.URL.Path) != ".jpg" {
		http.Error(w, http.StatusText(404), 404)
		return
	}

	photoFilepath := filepath.Join(photoDir, r.URL.Path[len("/cache/"):])
	cacheFilepath := filepath.Join(cacheDir, r.URL.Path[len("/cache/"):])

	if _, err := os.Stat(cacheFilepath); err != nil {
		if os.IsNotExist(err) {
			// create thumbnail

			file, err := os.Open(photoFilepath)
			if err != nil {
				log.Print(err)
				return
			}

			img, err := jpeg.Decode(file)
			if err != nil {
				log.Print(err)
				return
			}
			file.Close()

			m := resize.Thumbnail(500, 1000, img, resize.Bicubic)

			parentDir, _ := filepath.Split(cacheFilepath)
			err = os.MkdirAll(parentDir, os.FileMode(0764))
			if err != nil {
				log.Print(err)
				return
			}

			out, err := os.Create(cacheFilepath)
			if err != nil {
				log.Print(err)
				return
			}
			defer out.Close()

			jpeg.Encode(out, m, nil)
		} else {
			log.Print(err)
			return
		}
	}

	// serve thumbnail
	http.ServeFile(w, r, cacheFilepath)
}

func walkFunc(path string, info os.FileInfo, err error) error {
	if err != nil {
		return err
	}

	dir, filename := filepath.Split(path)
	dir, err = filepath.Rel(photoDir, dir)
	if err != nil {
		return err
	}

	if filename == "metadata.yaml" {
		m := metadata{Directory: dir}

		data, err := ioutil.ReadFile(path)
		if err != nil {
			return err
		}

		err = yaml.Unmarshal(data, &m)
		dirToMetadata[dir] = m
	} else if filepath.Ext(filename) == ".jpg" {
		filename = filepath.Join(dir, filename)
		photos[filename] = struct{}{}
	}
	return nil
}

func walk() {
	for {
		filepath.Walk(photoDir, walkFunc)
		time.Sleep(5 * time.Second)
	}
}

func main() {
	flag.StringVar(&photoDir, "photoDir", "photos", "path to photos")
	flag.StringVar(&cacheDir, "cacheDir", "cache", "path to photo cache directory")
	flag.Parse()

	go walk()

	http.Handle("/", http.FileServer(FS(true))) // esc for static content. true uses local files, false uses embedded
	http.HandleFunc("/photo/", handlePhoto)
	http.HandleFunc("/thumb/", handleThumb)

	http.HandleFunc("/api/filters", handleFilters)
	http.HandleFunc("/api/filter", handleFilter)
	http.ListenAndServe("127.0.0.1:8000", nil)
}
<commit_msg>Remove index code<commit_after>//go:generate esc -o static.go -prefix static static

package main

import (
	"encoding/json"
	"flag"
	"github.com/fatih/structs"
	"github.com/nfnt/resize"
	"gopkg.in/yaml.v2"
	"image/jpeg"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"time"
)

var photos = make(map[string]struct{})
var dirToMetadata = make(map[string]metadata)
var photoDir string
var cacheDir string

type metadata struct {
	Event        string
	Photographer string
	Date         string
	Location     string
	Directory    string `json:"-" structs:"directory"`
}

func handleFilters(w http.ResponseWriter, r *http.Request) {
	keys := []string{"Event", "Photographer", "Date", "Location"}

	filters := make(map[string]map[string]struct{})
	for _, k := range keys {
		filters[k] = make(map[string]struct{})
	}

	for _, meta := range dirToMetadata {
		m := structs.Map(meta)
		for _, k := range keys {
			if _, ok := m[k]; ok {
				filters[k][m[k].(string)] = struct{}{}
			}
		}
	}

	jFilters := make(map[string][]string)
	for _, k := range keys {
		jFilters[k] = make([]string, 0)
	}

	for i := range filters {
		for j := range filters[i] {
			jFilters[i] = append(jFilters[i], j)
		}
		sort.Strings(jFilters[i])
		if len(jFilters[i]) == 0 {
			delete(jFilters, i)
		}
	}

	enc := json.NewEncoder(w)
	if err := enc.Encode(jFilters); err != nil {
		log.Print(err)
		return
	}
}

func handleFilter(w http.ResponseWriter, r *http.Request) {
	filterToEligible := make(map[string][]string)

	filters := make(map[string][]string)
	for filterKey := range r.URL.Query() {
		filters[filterKey] = r.URL.Query()[filterKey]
	}

	// find all directories with matching filters
	for filterKey, filterValues := range filters {
		for dir, meta := range dirToMetadata {
			m := structs.Map(meta)
			for k, v := range m {
				if filterKey == k {
					for _, filterValue := range filterValues {
						if filterValue == v {
							filterToEligible[filterKey] = append(filterToEligible[filterKey], dir)
						}
					}
				}
			}
		}
	}

	// find intersection of all filter matches
	eligible := make(map[string]bool)

	for _, dirs := range filterToEligible {
		for _, dir := range dirs {
			count := 0
			for _, dirTests := range filterToEligible {
				for _, dirTest := range dirTests {
					if dir == dirTest {
						count += 1
					}
				}
			}
			if count == len(filterToEligible) {
				eligible[dir] = true
			}
		}
	}

	eligiblePhotos := make([]string, 0)
	for photo := range photos {
		dir := filepath.Dir(photo)
		if _, ok := eligible[dir]; ok {
			eligiblePhotos = append(eligiblePhotos, photo)
		}
	}

	enc := json.NewEncoder(w)
	if err := enc.Encode(eligiblePhotos); err != nil {
		log.Print(err)
		return
	}
}

func handlePhoto(w http.ResponseWriter, r *http.Request) {
	if filepath.Ext(r.URL.Path) != ".jpg" {
		http.Error(w, http.StatusText(404), 404)
		return
	}

	// serve photo
	photoFilepath := filepath.Join(photoDir, r.URL.Path[len("/photo/"):])
	http.ServeFile(w, r, photoFilepath)
}

func handleThumb(w http.ResponseWriter, r *http.Request) {
	if filepath.Ext(r.URL.Path) != ".jpg" {
		http.Error(w, http.StatusText(404), 404)
		return
	}

	photoFilepath := filepath.Join(photoDir, r.URL.Path[len("/cache/"):])
	cacheFilepath := filepath.Join(cacheDir, r.URL.Path[len("/cache/"):])

	if _, err := os.Stat(cacheFilepath); err != nil {
		if os.IsNotExist(err) {
			// create thumbnail

			file, err := os.Open(photoFilepath)
			if err != nil {
				log.Print(err)
				return
			}

			img, err := jpeg.Decode(file)
			if err != nil {
				log.Print(err)
				return
			}
			file.Close()

			m := resize.Thumbnail(500, 1000, img, resize.Bicubic)

			parentDir, _ := filepath.Split(cacheFilepath)
			err = os.MkdirAll(parentDir, os.FileMode(0764))
			if err != nil {
				log.Print(err)
				return
			}

			out, err := os.Create(cacheFilepath)
			if err != nil {
				log.Print(err)
				return
			}
			defer out.Close()

			jpeg.Encode(out, m, nil)
		} else {
			log.Print(err)
			return
		}
	}

	// serve thumbnail
	http.ServeFile(w, r, cacheFilepath)
}

func walkFunc(path string, info os.FileInfo, err error) error {
	if err != nil {
		return err
	}

	dir, filename := filepath.Split(path)
	dir, err = filepath.Rel(photoDir, dir)
	if err != nil {
		return err
	}

	if filename == "metadata.yaml" {
		m := metadata{Directory: dir}

		data, err := ioutil.ReadFile(path)
		if err != nil {
			return err
		}

		err = yaml.Unmarshal(data, &m)
		dirToMetadata[dir] = m
	} else if filepath.Ext(filename) == ".jpg" {
		filename = filepath.Join(dir, filename)
		photos[filename] = struct{}{}
	}
	return nil
}

func walk() {
	for {
		filepath.Walk(photoDir, walkFunc)
		time.Sleep(5 * time.Second)
	}
}

func main() {
	flag.StringVar(&photoDir, "photoDir", "photos", "path to photos")
	flag.StringVar(&cacheDir, "cacheDir", "cache", "path to photo cache directory")
	flag.Parse()

	go walk()

	http.Handle("/", http.FileServer(FS(true))) // esc for static content. true uses local files, false uses embedded
	http.HandleFunc("/photo/", handlePhoto)
	http.HandleFunc("/thumb/", handleThumb)

	http.HandleFunc("/api/filters", handleFilters)
	http.HandleFunc("/api/filter", handleFilter)
	http.ListenAndServe("127.0.0.1:8000", nil)
}
<|endoftext|>


<commit_before>// Some parts of this file are taken from Lakrizz' example on GitHub
// https://github.com/lakrizz/go-pidioder/blob/master/main.go

package dioder

import (
	"bufio"
	"errors"
	"os"
	"strconv"
)

const (
	redPin   = "18"
	bluePin  = "17"
	greenPin = "4"
)

var currentColorList [3]uint8

func floatToString(floatValue float64) string {
	return strconv.FormatFloat(floatValue, 'f', 6, 64)
}

func setColor(channel string, value float64) error {
	piBlasterCommand := channel + "=" + floatToString(value) + "\n"

	file, error := os.OpenFile("/dev/pi-blaster", os.O_RDWR, os.ModeNamedPipe)

	if error != nil {
		panic(error)
	}

	defer file.Close()

	stream := bufio.NewWriter(file)

	_, error = stream.WriteString(piBlasterCommand)

	if error != nil {
		panic(error)
	}

	stream.Flush()

	return nil
}

func setChannelInteger(value uint8, channel string) error {
	if value > 255 {
		return errors.New("Value can not be over 255")
	}

	if value < 0 {
		return errors.New("Value can not be under 0")
	}

	floatval := float64(value) / 255.0

	setColor(channel, float64(floatval))

	return nil
}

// SetAll sets the given values for the channels
func SetAll(r, g, b uint8) {
	SetRed(r)
	SetGreen(g)
	SetBlue(b)
}

// SetRed sets the given value on the Red channel
func SetRed(value uint8) error {
	// Do nothing if the new value is the same as the old
	if value == currentColorList[0] {
		return nil
	}

	currentColorList[0] = value
	return setChannelInteger(value, redPin)
}

// SetGreen sets the given value on the Green channel
func SetGreen(value uint8) error {
	// Do nothing if the new value is the same as the old
	if value == currentColorList[1] {
		return nil
	}

	currentColorList[1] = value
	return setChannelInteger(value, greenPin)
}

// SetBlue sets the given value on the Blue channel
func SetBlue(value uint8) error {
	// Do nothing if the new value is the same as the old
	if value == currentColorList[2] {
		return nil
	}

	currentColorList[2] = value
	return setChannelInteger(value, bluePin)
}

// GetCurrentColor returns the current color
func GetCurrentColor() [3]uint8 {
	return currentColorList
}
<commit_msg>Set the pins at runtime<commit_after>// Some parts of this file are taken from Lakrizz' example on GitHub
// https://github.com/lakrizz/go-pidioder/blob/master/main.go

package dioder

import (
	"bufio"
	"errors"
	"os"
	"strconv"
)

var (
	redPin   = "18"
	bluePin  = "17"
	greenPin = "4"
)

var currentColorList [3]uint8

func floatToString(floatValue float64) string {
	return strconv.FormatFloat(floatValue, 'f', 6, 64)
}

func setColor(channel string, value float64) error {
	piBlasterCommand := channel + "=" + floatToString(value) + "\n"

	file, error := os.OpenFile("/dev/pi-blaster", os.O_RDWR, os.ModeNamedPipe)

	if error != nil {
		panic(error)
	}

	defer file.Close()

	stream := bufio.NewWriter(file)

	_, error = stream.WriteString(piBlasterCommand)

	if error != nil {
		panic(error)
	}

	stream.Flush()

	return nil
}

func setChannelInteger(value uint8, channel string) error {
	if value > 255 {
		return errors.New("Value can not be over 255")
	}

	if value < 0 {
		return errors.New("Value can not be under 0")
	}

	floatval := float64(value) / 255.0

	setColor(channel, float64(floatval))

	return nil
}

// SetAll sets the given values for the channels
func SetAll(r, g, b uint8) {
	SetRed(r)
	SetGreen(g)
	SetBlue(b)
}

// SetRed sets the given value on the Red channel
func SetRed(value uint8) error {
	// Do nothing if the new value is the same as the old
	if value == currentColorList[0] {
		return nil
	}

	currentColorList[0] = value
	return setChannelInteger(value, redPin)
}

// SetGreen sets the given value on the Green channel
func SetGreen(value uint8) error {
	// Do nothing if the new value is the same as the old
	if value == currentColorList[1] {
		return nil
	}

	currentColorList[1] = value
	return setChannelInteger(value, greenPin)
}

// SetBlue sets the given value on the Blue channel
func SetBlue(value uint8) error {
	// Do nothing if the new value is the same as the old
	if value == currentColorList[2] {
		return nil
	}

	currentColorList[2] = value
	return setChannelInteger(value, bluePin)
}

func SetPins(red, green, blue int) {
	redPin = strconv.Itoa(red)
	greenPin = strconv.Itoa(green)
	bluePin = strconv.Itoa(blue)
}

// GetCurrentColor returns the current color
func GetCurrentColor() [3]uint8 {
	return currentColorList
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"time"

	"github.com/NikolayGenov/sofiatraffic-crawler/crawler"
	"github.com/garyburd/redigo/redis"
)

//newPool returns a new initialized redis pool for connections
// It takes address e.g ":6379" as a parameter and uses it in the Dial function
func newPool(address string) *redis.Pool {
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 360 * time.Second,
		Dial:        func() (redis.Conn, error) { return redis.Dial("tcp", address) }}
}

func main() {
	pool := newPool(":6379")
	st := crawler.NewSofiaTrafficCrawler(pool)

	st.CrawlLines()
	//for _, line := range st.Lines {
	//	fmt.Printf("Line [%v %v]\nOperations:  %v\n", line.Transportation, line.Name, &line.OperationIDMap)
	//	for operationID, routes := range line.OperationIDRoutesMap {
	//		fmt.Printf("%v -> \n", operationID)
	//		for _, route := range routes {
	//			fmt.Print(route)
	//		}
	//	}
	//	fmt.Println()
	//}
	//fmt.Println(len(st.Lines))

	//st.CrawlSchedules(0)
	//for k, v := range st.Schedules {
	//	fmt.Printf("%v,%v\n", k, v)
	//}
	//fmt.Println(len(st.Schedules))

	st.CrawlVirtualTablesLines(crawler.Normal)
	//for _, vtStop := range st.VirtualTableStops {
	//	fmt.Println(vtStop)
	//}
	fmt.Println(len(st.VirtualTableStops))

	st.CrawlVirtualTablesStopsForTimes(0)
	//for k, v := range st.VirtualTableStopsTimes {
	//	fmt.Printf("%v -> %v\n", k, v)
	//}
	fmt.Println(len(st.VirtualTableStopsTimes))

}
<commit_msg>Update main to print the extracted structure<commit_after>package main

import (
	"fmt"

	"time"

	"github.com/NikolayGenov/sofiatraffic-crawler/crawler"
	"github.com/garyburd/redigo/redis"
)

//newPool returns a new initialized redis pool for connections
// It takes address e.g ":6379" as a parameter and uses it in the Dial function
func newPool(address string) *redis.Pool {
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 360 * time.Second,
		Dial:        func() (redis.Conn, error) { return redis.Dial("tcp", address) }}
}

func main() {
	pool := newPool(":6379")
	st := crawler.NewSofiaTrafficCrawler(pool)

	st.CrawlLines()
	for _, line := range st.Lines {
		fmt.Printf("Line [%v %v]\nOperations:  %v\n", line.Transportation, line.Name, &line.OperationIDMap)
		for operationID, routes := range line.OperationIDRoutesMap {
			fmt.Printf("%v -> \n", operationID)
			for _, route := range routes {
				fmt.Print(route)
			}
		}
		fmt.Println()
	}
	fmt.Println(len(st.Lines))

	st.CrawlSchedules(1)
	for k, v := range st.Schedules {
		fmt.Printf("%v,%v\n", k, v)
	}
	fmt.Println(len(st.Schedules))

	st.CrawlVirtualTablesLines(crawler.Normal)
	//for _, vtStop := range st.VirtualTableStops {
	//	fmt.Println(vtStop)
	//}
	fmt.Println(len(st.VirtualTableStops))

	st.CrawlVirtualTablesStopsForTimes(100)
	for k, v := range st.VirtualTableStopsTimes {
		fmt.Printf("%v -> %v\n", k, v)
	}
	fmt.Println(len(st.VirtualTableStopsTimes))

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
)

const (
	exitOk = iota
)

func main() {
	os.Exit(run())
}

func run() int {
	n := 1
	m := 2
	result := Plus(n, m)

	fmt.Println(n, " + ", m, " = ", result)

	return exitOk
}

// Plus is adding two arguments.
func Plus(n, m int) int {
	return n + m
}
<commit_msg>Rename Ok -> OK<commit_after>package main

import (
	"fmt"
	"os"
)

const (
	exitOK = iota
)

func main() {
	os.Exit(run())
}

func run() int {
	n := 1
	m := 2
	result := Plus(n, m)

	fmt.Println(n, " + ", m, " = ", result)

	return exitOK
}

// Plus is adding two arguments.
func Plus(n, m int) int {
	return n + m
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"regexp"
	"sync"
	"text/template"

	_ "github.com/alecthomas/chroma/formatters"
	"github.com/alecthomas/chroma/quick"
	"github.com/fatih/color"
	"github.com/go-logr/logr"
	"github.com/spf13/pflag"
	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/client-go/kubernetes"
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/klog/v2"
)

func main() {
	klog.SetLogger(logr.New(&kubeLogger{}))

	var (
		contextName           string
		kubeconfigPath        string
		labelSelectorExpr     string
		namespaces            []string
		allNamespaces         bool
		quiet                 bool
		timestamps            bool
		raw                   bool
		tmplString            string
		sinceStart            bool
		showVersion           bool
		includePatterns       []*regexp.Regexp
		excludePatternStrings []string
		noColor               bool
		colorMode             string
	)

	flags := pflag.NewFlagSet("ktail", pflag.ExitOnError)
	flags.Usage = func() {
		flags.PrintDefaults()
	}
	flags.StringVar(&contextName, "context", "", "Kubernetes context name")
	flags.StringVar(&kubeconfigPath, "kubeconfig", "",
		"Path to kubeconfig (only required out-of-cluster)")
	flags.StringArrayVarP(&namespaces, "namespace", "n", []string{}, "Kubernetes namespace")
	flags.StringArrayVarP(&excludePatternStrings, "exclude", "x", []string{},
		"Exclude using a regular expression. Pattern can be repeated. Takes priority over"+
			" include patterns and labels.")
	flags.StringVarP(&labelSelectorExpr, "selector", "l", "",
		"Match pods by label (see 'kubectl get -h' for syntax).")
	flags.StringVarP(&tmplString, "template", "t", "",
		"Template to format each line. For example, for"+
			" just the message, use --template '{{ .Message }}'.")
	flags.BoolVar(&allNamespaces, "all-namespaces", false, "Apply to all Kubernetes namespaces")
	flags.BoolVarP(&raw, "raw", "r", false, "Don't format output; output messages only (unless --timestamps)")
	flags.BoolVarP(&timestamps, "timestamps", "T", false, "Include timestamps on each line")
	flags.BoolVarP(&quiet, "quiet", "q", false, "Don't print events about new/deleted pods")
	flags.BoolVarP(&sinceStart, "since-start", "s", false,
		"Start reading log from the beginning of the container's lifetime.")
	flags.BoolVarP(&showVersion, "version", "", false, "Show version.")
	flags.BoolVar(&noColor, "no-color", false, "Alias for --color=never.")
	flags.StringVar(&colorMode, "color", "auto", "Set color mode: one of 'auto' (default), 'never', or 'always'.")
	flags.StringVar(&colorMode, "colour", "auto", "Set color mode: one of 'auto' (default), 'never', or 'always'.")

	if err := flags.Parse(os.Args[1:]); err != nil {
		if err == pflag.ErrHelp {
			os.Exit(2)
		}
		fail(err.Error())
		os.Exit(1)
	}

	if noColor {
		colorMode = "never"
	}
	var colorEnabled bool
	switch colorMode {
	case "always":
		colorEnabled = true
	case "auto":
		colorEnabled = isTerminal(os.Stdout)
	case "never":
	}

	color.NoColor = !colorEnabled

	if showVersion {
		fmt.Printf("ktail %s\n", version)
		os.Exit(0)
	}

	var excludePatterns []*regexp.Regexp
	for _, p := range excludePatternStrings {
		r, err := regexp.Compile(p)
		if err != nil {
			fail("Invalid regexp: %q: %s\n", p, err)
		}
		excludePatterns = append(excludePatterns, r)
	}

	for _, arg := range flags.Args() {
		r, err := regexp.Compile(arg)
		if err != nil {
			fail("Invalid regexp: %q: %s\n", arg, err)
		}
		includePatterns = append(includePatterns, r)
	}

	labelSelector := labels.Everything()
	if labelSelectorExpr != "" {
		if sel, err := labels.Parse(labelSelectorExpr); err != nil {
			fail(err.Error())
		} else {
			labelSelector = sel
		}
	}

	inclusionMatcher := buildMatcher(includePatterns, labelSelector, true)
	exclusionMatcher := buildMatcher(excludePatterns, nil, false)

	var loadingRules *clientcmd.ClientConfigLoadingRules
	if kubeconfigPath != "" {
		loadingRules = &clientcmd.ClientConfigLoadingRules{
			ExplicitPath: kubeconfigPath,
		}
	} else {
		loadingRules = clientcmd.NewDefaultClientConfigLoadingRules()
	}

	clientConfig := clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules,
		&clientcmd.ConfigOverrides{
			CurrentContext: contextName,
		},
		nil)

	config, err := clientConfig.ClientConfig()
	if err != nil {
		fail(err.Error())
	}

	// Set higher rate limits
	config.QPS = 100
	config.Burst = 100

	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		fail(err.Error())
	}

	rawConfig, err := clientConfig.RawConfig()
	if err != nil {
		fail(err.Error())
	}

	if allNamespaces {
		namespaces = []string{v1.NamespaceAll}
	} else if len(namespaces) == 0 {
		if rawConfig.Contexts[rawConfig.CurrentContext].Namespace == "" {
			namespaces = []string{v1.NamespaceDefault}
		} else {
			namespaces = []string{rawConfig.Contexts[rawConfig.CurrentContext].Namespace}
		}
	}

	var tmpl *template.Template
	if tmplString != "" {
		var err error
		tmpl, err = template.New("line").Parse(tmplString)
		if err != nil {
			fail("invalid template: %s", err)
		}
	}

	formatPod := func(pod *v1.Pod) string {
		if allNamespaces || len(namespaces) > 1 {
			return fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)
		}
		return pod.Name
	}

	formatPodAndContainer := func(pod *v1.Pod, container *v1.Container) string {
		return fmt.Sprintf("%s:%s", formatPod(pod), container.Name)
	}

	var printEvent func(*LogEvent) error

	if tmpl != nil {
		printEvent = func(event *LogEvent) error {
			type templateEvent struct {
				Pod       *v1.Pod
				Container *v1.Container
				Timestamp string
				Message   string
			}

			var buf bytes.Buffer
			if err := tmpl.Execute(&buf, &templateEvent{
				Pod:       event.Pod,
				Container: event.Container,
				Message:   event.Message,
				Timestamp: formatTimestamp(event.Timestamp),
			}); err != nil {
				return err
			}

			_, err := fmt.Fprintln(os.Stdout, string(buf.Bytes()))
			return err
		}
	} else {
		printEvent = func(event *LogEvent) error {
			col := getColorConfig(event.Pod.Name, event.Container.Name)

			var line string
			if !raw {
				if timestamps {
					line = col.metadata.Sprint(formatTimestamp(event.Timestamp))
					line += " "
				}
				if allNamespaces {
					line += col.labels.Sprint(fmt.Sprintf("%s/%s:%s",
						event.Pod.Namespace, event.Pod.Name, event.Container.Name))
				} else {
					line += col.labels.Sprint(fmt.Sprintf("%s:%s", event.Pod.Name, event.Container.Name))
				}
				line += " "
			}

			payload := event.Message
			if colorEnabled && len(payload) >= 2 && payload[0] == '{' && payload[len(payload)-1] == '}' {
				var dest interface{}
				if err := json.Unmarshal([]byte(payload), &dest); err == nil {
					var buf bytes.Buffer
					if err := quick.Highlight(&buf, payload, "json", "terminal256", "monokai"); err == nil {
						payload = buf.String()
					}
				}
			}

			line += payload

			_, err := fmt.Fprintln(os.Stdout, line)
			return err
		}
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	var stdoutMutex sync.Mutex
	controller := NewController(clientset, ControllerOptions{
		Namespaces:       namespaces,
		InclusionMatcher: inclusionMatcher,
		ExclusionMatcher: exclusionMatcher,
		SinceStart:       sinceStart,
	},
		Callbacks{
			OnEvent: func(event LogEvent) {
				stdoutMutex.Lock()
				defer stdoutMutex.Unlock()
				if err := printEvent(&event); err != nil {
					printError(fmt.Sprintf("Could not write event: %s", err))
					cancel()
				}
			},
			OnEnter: func(pod *v1.Pod, container *v1.Container, initialAddPhase bool) bool {
				if !quiet {
					if initialAddPhase {
						printInfo("Attached to container [%s]", formatPodAndContainer(pod, container))
					} else {
						printInfo("New container [%s]", formatPodAndContainer(pod, container))
					}
				}
				return true
			},
			OnExit: func(pod *v1.Pod, container *v1.Container) {
				if !quiet {
					var status = "unknown"
					for _, containerStatus := range pod.Status.ContainerStatuses {
						if containerStatus.Name == container.Name {
							if containerStatus.State.Running != nil {
								status = "running"
							} else if containerStatus.State.Waiting != nil {
								status = "waiting"
							} else if containerStatus.State.Terminated != nil {
								status = "terminated"
							}
							break
						}
					}
					printInfo(fmt.Sprintf("Container left (%s) [%s]", status,
						formatPodAndContainer(pod, container)))
				}
			},
			OnError: func(pod *v1.Pod, container *v1.Container, err error) {
				printError(fmt.Sprintf("Error while tailing container [%s]: %s",
					formatPodAndContainer(pod, container), err))
			},
		})

	if err := controller.Run(ctx); err != nil && !errors.Is(err, context.Canceled) {
		printError(err.Error())
	}
}

func fail(format string, args ...interface{}) {
	msg := fmt.Sprintf(format, args...)
	_, _ = fmt.Fprintf(os.Stderr, fmt.Sprintf("fatal: %s\n", msg))
	os.Exit(1)
}

var (
	colorInfo  = color.New(color.FgYellow).SprintFunc()
	colorError = color.New(color.FgRed).SprintFunc()
)
<commit_msg>feat: adds --color-scheme/--colour-scheme to set scheme; now defaults to 'bw'.<commit_after>package main

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"regexp"
	"sync"
	"text/template"

	_ "github.com/alecthomas/chroma/formatters"
	"github.com/alecthomas/chroma/quick"
	"github.com/fatih/color"
	"github.com/go-logr/logr"
	"github.com/spf13/pflag"
	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/client-go/kubernetes"
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/klog/v2"
)

const defaultColorScheme = "bw"

func main() {
	klog.SetLogger(logr.New(&kubeLogger{}))

	var (
		contextName           string
		kubeconfigPath        string
		labelSelectorExpr     string
		namespaces            []string
		allNamespaces         bool
		quiet                 bool
		timestamps            bool
		raw                   bool
		tmplString            string
		sinceStart            bool
		showVersion           bool
		includePatterns       []*regexp.Regexp
		excludePatternStrings []string
		noColor               bool
		colorMode             string
		colorScheme           string
	)

	flags := pflag.NewFlagSet("ktail", pflag.ExitOnError)
	flags.Usage = func() {
		flags.PrintDefaults()
	}
	flags.StringVar(&contextName, "context", "", "Kubernetes context name")
	flags.StringVar(&kubeconfigPath, "kubeconfig", "",
		"Path to kubeconfig (only required out-of-cluster)")
	flags.StringArrayVarP(&namespaces, "namespace", "n", []string{}, "Kubernetes namespace")
	flags.StringArrayVarP(&excludePatternStrings, "exclude", "x", []string{},
		"Exclude using a regular expression. Pattern can be repeated. Takes priority over"+
			" include patterns and labels.")
	flags.StringVarP(&labelSelectorExpr, "selector", "l", "",
		"Match pods by label (see 'kubectl get -h' for syntax).")
	flags.StringVarP(&tmplString, "template", "t", "",
		"Template to format each line. For example, for"+
			" just the message, use --template '{{ .Message }}'.")
	flags.BoolVar(&allNamespaces, "all-namespaces", false, "Apply to all Kubernetes namespaces")
	flags.BoolVarP(&raw, "raw", "r", false, "Don't format output; output messages only (unless --timestamps)")
	flags.BoolVarP(&timestamps, "timestamps", "T", false, "Include timestamps on each line")
	flags.BoolVarP(&quiet, "quiet", "q", false, "Don't print events about new/deleted pods")
	flags.BoolVarP(&sinceStart, "since-start", "s", false,
		"Start reading log from the beginning of the container's lifetime.")
	flags.BoolVarP(&showVersion, "version", "", false, "Show version.")
	flags.BoolVar(&noColor, "no-color", false, "Alias for --color=never.")
	flags.StringVar(&colorMode, "color", "auto", "Set color mode: one of 'auto' (default), 'never', or 'always'.")
	flags.StringVar(&colorMode, "colour", "auto", "Set color mode: one of 'auto' (default), 'never', or 'always'.")
	flags.StringVar(&colorScheme, "color-scheme", defaultColorScheme, "Set color scheme (see https://github.com/alecthomas/chroma/tree/master/styles).")
	flags.StringVar(&colorScheme, "colour-scheme", defaultColorScheme, "Set color scheme (see https://github.com/alecthomas/chroma/tree/master/styles).")

	if err := flags.Parse(os.Args[1:]); err != nil {
		if err == pflag.ErrHelp {
			os.Exit(2)
		}
		fail(err.Error())
		os.Exit(1)
	}

	if noColor {
		colorMode = "never"
	}
	var colorEnabled bool
	switch colorMode {
	case "always":
		colorEnabled = true
	case "auto":
		colorEnabled = isTerminal(os.Stdout)
	case "never":
	}

	color.NoColor = !colorEnabled

	if showVersion {
		fmt.Printf("ktail %s\n", version)
		os.Exit(0)
	}

	var excludePatterns []*regexp.Regexp
	for _, p := range excludePatternStrings {
		r, err := regexp.Compile(p)
		if err != nil {
			fail("Invalid regexp: %q: %s\n", p, err)
		}
		excludePatterns = append(excludePatterns, r)
	}

	for _, arg := range flags.Args() {
		r, err := regexp.Compile(arg)
		if err != nil {
			fail("Invalid regexp: %q: %s\n", arg, err)
		}
		includePatterns = append(includePatterns, r)
	}

	labelSelector := labels.Everything()
	if labelSelectorExpr != "" {
		if sel, err := labels.Parse(labelSelectorExpr); err != nil {
			fail(err.Error())
		} else {
			labelSelector = sel
		}
	}

	inclusionMatcher := buildMatcher(includePatterns, labelSelector, true)
	exclusionMatcher := buildMatcher(excludePatterns, nil, false)

	var loadingRules *clientcmd.ClientConfigLoadingRules
	if kubeconfigPath != "" {
		loadingRules = &clientcmd.ClientConfigLoadingRules{
			ExplicitPath: kubeconfigPath,
		}
	} else {
		loadingRules = clientcmd.NewDefaultClientConfigLoadingRules()
	}

	clientConfig := clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules,
		&clientcmd.ConfigOverrides{
			CurrentContext: contextName,
		},
		nil)

	config, err := clientConfig.ClientConfig()
	if err != nil {
		fail(err.Error())
	}

	// Set higher rate limits
	config.QPS = 100
	config.Burst = 100

	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		fail(err.Error())
	}

	rawConfig, err := clientConfig.RawConfig()
	if err != nil {
		fail(err.Error())
	}

	if allNamespaces {
		namespaces = []string{v1.NamespaceAll}
	} else if len(namespaces) == 0 {
		if rawConfig.Contexts[rawConfig.CurrentContext].Namespace == "" {
			namespaces = []string{v1.NamespaceDefault}
		} else {
			namespaces = []string{rawConfig.Contexts[rawConfig.CurrentContext].Namespace}
		}
	}

	var tmpl *template.Template
	if tmplString != "" {
		var err error
		tmpl, err = template.New("line").Parse(tmplString)
		if err != nil {
			fail("invalid template: %s", err)
		}
	}

	formatPod := func(pod *v1.Pod) string {
		if allNamespaces || len(namespaces) > 1 {
			return fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)
		}
		return pod.Name
	}

	formatPodAndContainer := func(pod *v1.Pod, container *v1.Container) string {
		return fmt.Sprintf("%s:%s", formatPod(pod), container.Name)
	}

	var printEvent func(*LogEvent) error

	if tmpl != nil {
		printEvent = func(event *LogEvent) error {
			type templateEvent struct {
				Pod       *v1.Pod
				Container *v1.Container
				Timestamp string
				Message   string
			}

			var buf bytes.Buffer
			if err := tmpl.Execute(&buf, &templateEvent{
				Pod:       event.Pod,
				Container: event.Container,
				Message:   event.Message,
				Timestamp: formatTimestamp(event.Timestamp),
			}); err != nil {
				return err
			}

			_, err := fmt.Fprintln(os.Stdout, string(buf.Bytes()))
			return err
		}
	} else {
		printEvent = func(event *LogEvent) error {
			col := getColorConfig(event.Pod.Name, event.Container.Name)

			var line string
			if !raw {
				if timestamps {
					line = col.metadata.Sprint(formatTimestamp(event.Timestamp))
					line += " "
				}
				if allNamespaces {
					line += col.labels.Sprint(fmt.Sprintf("%s/%s:%s",
						event.Pod.Namespace, event.Pod.Name, event.Container.Name))
				} else {
					line += col.labels.Sprint(fmt.Sprintf("%s:%s", event.Pod.Name, event.Container.Name))
				}
				line += " "
			}

			payload := event.Message
			if colorEnabled && len(payload) >= 2 && payload[0] == '{' && payload[len(payload)-1] == '}' {
				var dest interface{}
				if err := json.Unmarshal([]byte(payload), &dest); err == nil {
					var buf bytes.Buffer
					if err := quick.Highlight(&buf, payload, "json", "terminal256", colorScheme); err == nil {
						payload = buf.String()
					}
				}
			}

			line += payload

			_, err := fmt.Fprintln(os.Stdout, line)
			return err
		}
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	var stdoutMutex sync.Mutex
	controller := NewController(clientset, ControllerOptions{
		Namespaces:       namespaces,
		InclusionMatcher: inclusionMatcher,
		ExclusionMatcher: exclusionMatcher,
		SinceStart:       sinceStart,
	},
		Callbacks{
			OnEvent: func(event LogEvent) {
				stdoutMutex.Lock()
				defer stdoutMutex.Unlock()
				if err := printEvent(&event); err != nil {
					printError(fmt.Sprintf("Could not write event: %s", err))
					cancel()
				}
			},
			OnEnter: func(pod *v1.Pod, container *v1.Container, initialAddPhase bool) bool {
				if !quiet {
					if initialAddPhase {
						printInfo("Attached to container [%s]", formatPodAndContainer(pod, container))
					} else {
						printInfo("New container [%s]", formatPodAndContainer(pod, container))
					}
				}
				return true
			},
			OnExit: func(pod *v1.Pod, container *v1.Container) {
				if !quiet {
					var status = "unknown"
					for _, containerStatus := range pod.Status.ContainerStatuses {
						if containerStatus.Name == container.Name {
							if containerStatus.State.Running != nil {
								status = "running"
							} else if containerStatus.State.Waiting != nil {
								status = "waiting"
							} else if containerStatus.State.Terminated != nil {
								status = "terminated"
							}
							break
						}
					}
					printInfo(fmt.Sprintf("Container left (%s) [%s]", status,
						formatPodAndContainer(pod, container)))
				}
			},
			OnError: func(pod *v1.Pod, container *v1.Container, err error) {
				printError(fmt.Sprintf("Error while tailing container [%s]: %s",
					formatPodAndContainer(pod, container), err))
			},
		})

	if err := controller.Run(ctx); err != nil && !errors.Is(err, context.Canceled) {
		printError(err.Error())
	}
}

func fail(format string, args ...interface{}) {
	msg := fmt.Sprintf(format, args...)
	_, _ = fmt.Fprintf(os.Stderr, fmt.Sprintf("fatal: %s\n", msg))
	os.Exit(1)
}

var (
	colorInfo  = color.New(color.FgYellow).SprintFunc()
	colorError = color.New(color.FgRed).SprintFunc()
)
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/user"
	"path/filepath"
	"runtime"
	"time"
)

var verbose bool
var quiet bool
var tm bool
var chan_depth int
var buffSize int64
var ignoreMTime bool
var dbpath string
var dataRate float64

func main() {
	runtime.GOMAXPROCS(8)

	var copy_dir string
	var check_dir string
	var err error

	flag.Usage = func() {
		fmt.Printf("Usage of %s:\n", os.Args[0])
		fmt.Printf("%s [-q] [-v] [-tm] [-m] [-depth n] [-buff n] [source [dest]]\n", os.Args[0])
		fmt.Println()
		fmt.Println("This utility checks the contents of files against themselves")
		fmt.Println("and backup copies to try to detect bit failures on disk.  In its")
		fmt.Println("most basic form (with no arguments), it will read all of the files")
		fmt.Println("in the current directory recursively.  As it reads the files, it")
		fmt.Println("creates a database of the files' checksums and modification times.")
		fmt.Println("The next time it is run, any file with the same modification time,")
		fmt.Println("but a different checksum will be flagged.")
		fmt.Println()
		fmt.Println("Given a source parameter, it will check that directory instead.")
		fmt.Println("Given a source and dest, it will do the same database checks,")
		fmt.Println("but also compare the contents of source recursively with dest.")
		fmt.Println()
		fmt.Println("The -tm flag causes it to use the TimeMachine directory that")
		fmt.Println("corresponds to source as the dest.")
		fmt.Println()
		fmt.Println("The -q flag will suppress all output except possible bit failures.")
		fmt.Println()
		fmt.Println("The -v flag will print information about all files checked, even")
		fmt.Println("the ones that are OK.")
		fmt.Println()
		fmt.Println("Normally, if the modification time of a file has changed, it")
		fmt.Println("is not considered a problem if the contents are different.")
		fmt.Println("If the -m flag is given, then files are compared regardless.")
		fmt.Println()
		fmt.Println("The --depth and --buff flags are for tuning.  The default values")
		fmt.Println("should work well in most situations.")
		fmt.Println()

		flag.PrintDefaults()
	}

	flag.CommandLine.SetOutput(os.Stdout)
	flag.BoolVar(&verbose, "v", false, "Print info about files that are OK")
	flag.BoolVar(&quiet, "q", false, "Only print info about checksum errors.  Other file access problems are ignored.")
	flag.BoolVar(&tm, "tm", false, "Compare against TimeMachine")
	flag.BoolVar(&ignoreMTime, "m", false, "Compare files, even if mtime is different.")
	flag.IntVar(&chan_depth, "depth", 10, "Work queue depth")
	flag.Int64Var(&buffSize, "buff", 128*1024*1024, "Size of IO buffer")
	flag.StringVar(&dbpath, "db", "", "Path to database file")
	flag.Float64Var(&dataRate, "rate", 0.0, "Max data rate in bytes/sec")
	flag.Parse()

	// If we're rate limiting, and the buff flag was not explicitly set,
	// the cut down the buff size to 128k
	buffSet := false
	flag.Visit(func(f *flag.Flag) {
		if f.Name == "buff" {
			buffSet = true
		}
	})

	if dataRate != 0.0 && !buffSet {
		buffSize /= 1024
	}

	switch {
	case flag.NArg() == 0:
		// set check_dir to cwd
		check_dir, err = os.Getwd()
		if err != nil {
			fmt.Println("Cannot get current working directory.  Please supply a directory as an argument.")
			log.Fatal(err)
		}

	case flag.NArg() == 1:
		// use arg as check dir
		check_dir = flag.Arg(0)

	case flag.NArg() == 2:
		// use arg as check dir
		check_dir = flag.Arg(0)
		copy_dir = flag.Arg(1)

	default:
		// print usage, exit
		fmt.Println("Supply one or two directories")
		os.Exit(1)
	}

	check_dir, err = filepath.Abs(check_dir)
	if err != nil {
		fmt.Println("Cannot get absolute path of directory to check.")
		log.Fatal(err)
	}
	check_dir = volPath(check_dir)

	if copy_dir == "" {
		if tm {
			// Set copy dir to latest tm backup
			copy_dir, err := getTMDir()
			if err != nil {
				fmt.Println("Cannot get latest time machine directory.  Please supply a backup directory.")
				log.Fatal(err)
			}
			copy_dir = filepath.Join(copy_dir, check_dir)
		}
	} else {
		copy_dir, err = filepath.Abs(copy_dir)
		if err != nil {
			fmt.Println("Cannot get absolute path of copy directory.")
			log.Fatal(err)
		}
	}

	if !quiet {
		fmt.Printf("Checking: %s\n", check_dir)
		if copy_dir != "" {
			fmt.Printf("Comparing with backup at: %s\n", copy_dir)
		}
	}

	if dbpath == "" {
		me, err := user.Current()
		if err != nil {
			log.Fatal(err)
		}

		dbpath = filepath.Join(me.HomeDir, ".sumcheck.sqlite3")
	}
	db, err := newDBConnection(dbpath)
	if err != nil {
		fmt.Println("Cannot connect to db at " + dbpath)
		log.Fatal(err)
	}
	defer closeDBConnection(db)

	initWalkers()

	start := time.Now()

	final_out := make(chan *fileJob, chan_depth)
	defer close(final_out)

	if copy_dir == "" {
		in1_chan := make(chan *fileJob, chan_depth)
		defer close(in1_chan)
		out1_chan := make(chan *fileJob, chan_depth)
		defer close(out1_chan)

		go Walker(in1_chan, nil, check_dir, "")
		go Calculator(in1_chan, out1_chan, buffSize, dataRate)
		go dbChecker(out1_chan, final_out, db)
	} else {
		in1_chan := make(chan *fileJob, chan_depth)
		defer close(in1_chan)
		in2_chan := make(chan *fileJob, chan_depth)
		defer close(in2_chan)
		out1_chan := make(chan *fileJob, chan_depth)
		defer close(out1_chan)
		out2_chan := make(chan *fileJob, chan_depth)
		defer close(out2_chan)
		comp_out := make(chan *fileJob, chan_depth)
		defer close(comp_out)

		go Walker(in1_chan, in2_chan, check_dir, copy_dir)
		go Calculator(in1_chan, out1_chan, buffSize, dataRate/2.0)
		go Calculator(in2_chan, out2_chan, buffSize, dataRate/2.0)
		go Comparator(out1_chan, out2_chan, comp_out)
		go dbChecker(comp_out, final_out, db)
	}

	var totalIO int64
	var fileCount int64

	for f := range final_out {
		if f == nil {
			break
		}

		if f.IoLen >= 0 {
			totalIO += f.IoLen
			fileCount++
		}
		if f.Err != nil {
			if !quiet || f.Err.code == code_BAD_SUM {
				fmt.Println(f.Err.Error())
			}
		} else if verbose {
			fmt.Println(NewError(code_OK, f, "").Error())
		}
	}

	stop := time.Now()

	if !quiet {
		elapsed := stop.Sub(start)
		fmt.Printf("%v bytes in %v (%v bytes per sec.)\n",
			Eng_int64(totalIO), elapsed.String(),
			Eng(float64(totalIO)/elapsed.Seconds()))
		fmt.Printf("%v files in %v (%v files per sec.)\n",
			Eng_int64(fileCount), elapsed.String(),
			Eng(float64(fileCount)/elapsed.Seconds()))
	}
}
<commit_msg>Use logging output for errors, instead of stdout.<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/user"
	"path/filepath"
	"runtime"
	"time"
)

var verbose bool
var quiet bool
var tm bool
var chan_depth int
var buffSize int64
var ignoreMTime bool
var dbpath string
var dataRate float64

func main() {
	runtime.GOMAXPROCS(8)

	var copy_dir string
	var check_dir string
	var err error

	flag.Usage = func() {
		fmt.Printf("Usage of %s:\n", os.Args[0])
		fmt.Printf("%s [-q] [-v] [-tm] [-m] [-depth n] [-buff n] [source [dest]]\n", os.Args[0])
		fmt.Println()
		fmt.Println("This utility checks the contents of files against themselves")
		fmt.Println("and backup copies to try to detect bit failures on disk.  In its")
		fmt.Println("most basic form (with no arguments), it will read all of the files")
		fmt.Println("in the current directory recursively.  As it reads the files, it")
		fmt.Println("creates a database of the files' checksums and modification times.")
		fmt.Println("The next time it is run, any file with the same modification time,")
		fmt.Println("but a different checksum will be flagged.")
		fmt.Println()
		fmt.Println("Given a source parameter, it will check that directory instead.")
		fmt.Println("Given a source and dest, it will do the same database checks,")
		fmt.Println("but also compare the contents of source recursively with dest.")
		fmt.Println()
		fmt.Println("The -tm flag causes it to use the TimeMachine directory that")
		fmt.Println("corresponds to source as the dest.")
		fmt.Println()
		fmt.Println("The -q flag will suppress all output except possible bit failures.")
		fmt.Println()
		fmt.Println("The -v flag will print information about all files checked, even")
		fmt.Println("the ones that are OK.")
		fmt.Println()
		fmt.Println("Normally, if the modification time of a file has changed, it")
		fmt.Println("is not considered a problem if the contents are different.")
		fmt.Println("If the -m flag is given, then files are compared regardless.")
		fmt.Println()
		fmt.Println("The --depth and --buff flags are for tuning.  The default values")
		fmt.Println("should work well in most situations.")
		fmt.Println()

		flag.PrintDefaults()
	}

	flag.CommandLine.SetOutput(os.Stdout)
	flag.BoolVar(&verbose, "v", false, "Print info about files that are OK")
	flag.BoolVar(&quiet, "q", false, "Only print info about checksum errors.  Other file access problems are ignored.")
	flag.BoolVar(&tm, "tm", false, "Compare against TimeMachine")
	flag.BoolVar(&ignoreMTime, "m", false, "Compare files, even if mtime is different.")
	flag.IntVar(&chan_depth, "depth", 10, "Work queue depth")
	flag.Int64Var(&buffSize, "buff", 128*1024*1024, "Size of IO buffer")
	flag.StringVar(&dbpath, "db", "", "Path to database file")
	flag.Float64Var(&dataRate, "rate", 0.0, "Max data rate in bytes/sec")
	flag.Parse()

	// If we're rate limiting, and the buff flag was not explicitly set,
	// the cut down the buff size to 128k
	buffSet := false
	flag.Visit(func(f *flag.Flag) {
		if f.Name == "buff" {
			buffSet = true
		}
	})

	if dataRate != 0.0 && !buffSet {
		buffSize /= 1024
	}

	switch {
	case flag.NArg() == 0:
		// set check_dir to cwd
		check_dir, err = os.Getwd()
		if err != nil {
			log.Println("Cannot get current working directory.  Please supply a directory as an argument.")
			log.Fatal(err)
		}

	case flag.NArg() == 1:
		// use arg as check dir
		check_dir = flag.Arg(0)

	case flag.NArg() == 2:
		// use arg as check dir
		check_dir = flag.Arg(0)
		copy_dir = flag.Arg(1)

	default:
		// print usage, exit
		fmt.Println("Supply one or two directories")
		flag.Usage()
		os.Exit(1)
	}

	check_dir, err = filepath.Abs(check_dir)
	if err != nil {
		log.Println("Cannot get absolute path of directory to check.")
		log.Fatal(err)
	}
	check_dir = volPath(check_dir)

	if copy_dir == "" {
		if tm {
			// Set copy dir to latest tm backup
			copy_dir, err := getTMDir()
			if err != nil {
				log.Println("Cannot get latest time machine directory.  Please supply a backup directory.")
				log.Fatal(err)
			}
			copy_dir = filepath.Join(copy_dir, check_dir)
		}
	} else {
		copy_dir, err = filepath.Abs(copy_dir)
		if err != nil {
			log.Println("Cannot get absolute path of copy directory.")
			log.Fatal(err)
		}
	}

	if !quiet {
		fmt.Printf("Checking: %s\n", check_dir)
		if copy_dir != "" {
			fmt.Printf("Comparing with backup at: %s\n", copy_dir)
		}
	}

	if dbpath == "" {
		me, err := user.Current()
		if err != nil {
			log.Fatal(err)
		}

		dbpath = filepath.Join(me.HomeDir, ".sumcheck.sqlite3")
	}
	db, err := newDBConnection(dbpath)
	if err != nil {
		log.Println("Cannot connect to db at " + dbpath)
		log.Fatal(err)
	}
	defer closeDBConnection(db)

	initWalkers()

	start := time.Now()

	final_out := make(chan *fileJob, chan_depth)
	defer close(final_out)

	if copy_dir == "" {
		in1_chan := make(chan *fileJob, chan_depth)
		defer close(in1_chan)
		out1_chan := make(chan *fileJob, chan_depth)
		defer close(out1_chan)

		go Walker(in1_chan, nil, check_dir, "")
		go Calculator(in1_chan, out1_chan, buffSize, dataRate)
		go dbChecker(out1_chan, final_out, db)
	} else {
		in1_chan := make(chan *fileJob, chan_depth)
		defer close(in1_chan)
		in2_chan := make(chan *fileJob, chan_depth)
		defer close(in2_chan)
		out1_chan := make(chan *fileJob, chan_depth)
		defer close(out1_chan)
		out2_chan := make(chan *fileJob, chan_depth)
		defer close(out2_chan)
		comp_out := make(chan *fileJob, chan_depth)
		defer close(comp_out)

		go Walker(in1_chan, in2_chan, check_dir, copy_dir)
		go Calculator(in1_chan, out1_chan, buffSize, dataRate/2.0)
		go Calculator(in2_chan, out2_chan, buffSize, dataRate/2.0)
		go Comparator(out1_chan, out2_chan, comp_out)
		go dbChecker(comp_out, final_out, db)
	}

	var totalIO int64
	var fileCount int64

	for f := range final_out {
		if f == nil {
			break
		}

		if f.IoLen >= 0 {
			totalIO += f.IoLen
			fileCount++
		}
		if f.Err != nil {
			if !quiet || f.Err.code == code_BAD_SUM {
				log.Println(f.Err.Error())
			}
		} else if verbose {
			log.Println(NewError(code_OK, f, "").Error())
		}
	}

	stop := time.Now()

	if !quiet {
		elapsed := stop.Sub(start)
		fmt.Printf("%v bytes in %v (%v bytes per sec.)\n",
			Eng_int64(totalIO), elapsed.String(),
			Eng(float64(totalIO)/elapsed.Seconds()))
		fmt.Printf("%v files in %v (%v files per sec.)\n",
			Eng_int64(fileCount), elapsed.String(),
			Eng(float64(fileCount)/elapsed.Seconds()))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"flag"
	"fmt"
	"github.com/franela/goreq"
	"log"
	"net/http"
	"net/http/httputil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

var dir *string
var root *string
var host *string
var port *string
var iport int
var burpBuddyURL *string
var localURL string

var count int

func init() {
	host = flag.String("host", "localhost", "host for the file server to listen on")
	port = flag.String("port", "9999", "port for the file server to listen on")
	dir = flag.String("dir", "", "directory with code to scan")
	root = flag.String("root", "", "root to serve from")
	burpBuddyURL = flag.String("burpbuddy", "http://localhost:8001", "HTTP API URL for burpbuddy")
	flag.Parse()

	if *dir == "" {
		log.Fatal("--dir is required")
	}

	d, err := filepath.Abs(*dir)
	if err != nil {
		log.Fatalf("Error getting absolute path of dir: %s", err.Error())
	}
	dir = &d

	iport, err = strconv.Atoi(*port)
	if err != nil {
		log.Fatalf("Error converting port to int: %s", err.Error())
	}
	count = 0
	localURL = fmt.Sprintf("http://%s:%s%s", *host, *port, *root)
}

func main() {

	go func() {
		log.Fatal(http.ListenAndServe(*host+":"+*port, http.StripPrefix(*root+"/", http.FileServer(http.Dir(*dir)))))
	}()

	log.Printf("Static file server listening on %s, serving %s", localURL, *dir)
	log.Printf("Adding %s to scope", localURL)

	s := ScopeRequest{URL: localURL + "/"}
	resp, err := goreq.Request{
		Method: "POST",
		Uri:    *burpBuddyURL + "/scope",
		Body:   s,
	}.Do()

	if err != nil {
		log.Fatalf("Error adding site to scope: %s", err.Error())
	}
	if resp.StatusCode != 201 {
		log.Fatal("Non 201 status code when adding to scope")
	}
	resp.Body.Close()

	log.Println("Walking directory, each file will be sent to burp's passive scan")

	if err := filepath.Walk(*dir, walker); err != nil {
		log.Printf("Error during directory walk: %s", err.Error())
	}

	log.Printf("%d files sent to burp", count)
}

func walker(path string, info os.FileInfo, err error) error {
	parts := strings.Split(path, *dir)
	if parts[1] == "" {
		return nil
	}

	resp, err := http.Get(localURL + parts[1])

	if err != nil {
		log.Printf("Error getting %s from go http server: %s", parts[1], err.Error())
		return nil
	}
	if resp.StatusCode != 200 {
		log.Printf("Non 200 status code from go for %s", parts[1])
		return nil
	}

	rawResponse, err := httputil.DumpResponse(resp, true)
	if err != nil {
		log.Printf("Error dumping response: %s", err.Error())
		return nil
	}
	rawRequest, err := httputil.DumpRequest(resp.Request, true)
	if err != nil {
		log.Printf("Error dumping request: %s", err.Error())
		return nil
	}

	r := PassivScanRequest{
		Host:     *host,
		Port:     iport,
		UseHTTPS: false,
		Request:  base64.StdEncoding.EncodeToString(rawRequest),
		Response: base64.StdEncoding.EncodeToString(rawResponse),
	}

	presp, err := goreq.Request{
		Method: "POST",
		Uri:    *burpBuddyURL + "/scan/passive",
		Body:   r,
	}.Do()

	if err != nil {
		log.Printf("Error during passive scan request to burpbuddy: %s", err.Error())
		return nil
	}

	if presp.StatusCode != 201 {
		log.Println("Non 201 status code during passive scan request to burpbuddy")
		return nil
	}

	defer resp.Body.Close()
	defer presp.Body.Close()
	count += 1

	return nil
}
<commit_msg>goimports<commit_after>package main

import (
	"encoding/base64"
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/franela/goreq"
)

var dir *string
var root *string
var host *string
var port *string
var iport int
var burpBuddyURL *string
var localURL string

var count int

func init() {
	host = flag.String("host", "localhost", "host for the file server to listen on")
	port = flag.String("port", "9999", "port for the file server to listen on")
	dir = flag.String("dir", "", "directory with code to scan")
	root = flag.String("root", "", "root to serve from")
	burpBuddyURL = flag.String("burpbuddy", "http://localhost:8001", "HTTP API URL for burpbuddy")
	flag.Parse()

	if *dir == "" {
		log.Fatal("--dir is required")
	}

	d, err := filepath.Abs(*dir)
	if err != nil {
		log.Fatalf("Error getting absolute path of dir: %s", err.Error())
	}
	dir = &d

	iport, err = strconv.Atoi(*port)
	if err != nil {
		log.Fatalf("Error converting port to int: %s", err.Error())
	}
	count = 0
	localURL = fmt.Sprintf("http://%s:%s%s", *host, *port, *root)
}

func main() {

	go func() {
		log.Fatal(http.ListenAndServe(*host+":"+*port, http.StripPrefix(*root+"/", http.FileServer(http.Dir(*dir)))))
	}()

	log.Printf("Static file server listening on %s, serving %s", localURL, *dir)
	log.Printf("Adding %s to scope", localURL)

	s := ScopeRequest{URL: localURL + "/"}
	resp, err := goreq.Request{
		Method: "POST",
		Uri:    *burpBuddyURL + "/scope",
		Body:   s,
	}.Do()

	if err != nil {
		log.Fatalf("Error adding site to scope: %s", err.Error())
	}
	if resp.StatusCode != 201 {
		log.Fatal("Non 201 status code when adding to scope")
	}
	resp.Body.Close()

	log.Println("Walking directory, each file will be sent to burp's passive scan")

	if err := filepath.Walk(*dir, walker); err != nil {
		log.Printf("Error during directory walk: %s", err.Error())
	}

	log.Printf("%d files sent to burp", count)
}

func walker(path string, info os.FileInfo, err error) error {
	parts := strings.Split(path, *dir)
	if parts[1] == "" {
		return nil
	}

	resp, err := http.Get(localURL + parts[1])

	if err != nil {
		log.Printf("Error getting %s from go http server: %s", parts[1], err.Error())
		return nil
	}
	if resp.StatusCode != 200 {
		log.Printf("Non 200 status code from go for %s", parts[1])
		return nil
	}

	rawResponse, err := httputil.DumpResponse(resp, true)
	if err != nil {
		log.Printf("Error dumping response: %s", err.Error())
		return nil
	}
	rawRequest, err := httputil.DumpRequest(resp.Request, true)
	if err != nil {
		log.Printf("Error dumping request: %s", err.Error())
		return nil
	}

	r := PassivScanRequest{
		Host:     *host,
		Port:     iport,
		UseHTTPS: false,
		Request:  base64.StdEncoding.EncodeToString(rawRequest),
		Response: base64.StdEncoding.EncodeToString(rawResponse),
	}

	presp, err := goreq.Request{
		Method: "POST",
		Uri:    *burpBuddyURL + "/scan/passive",
		Body:   r,
	}.Do()

	if err != nil {
		log.Printf("Error during passive scan request to burpbuddy: %s", err.Error())
		return nil
	}

	if presp.StatusCode != 201 {
		log.Println("Non 201 status code during passive scan request to burpbuddy")
		return nil
	}

	defer resp.Body.Close()
	defer presp.Body.Close()
	count += 1

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net/http"
	"os"

	"github.com/braintree/manners"
	"github.com/labstack/echo"
	"github.com/zenazn/goji/bind"

	"github.com/kyokomi/go-docomo/docomo"
	"github.com/kyokomi/nepu-bot/plugins/nepubot"
	"github.com/kyokomi/slackbot"
	"github.com/kyokomi/slackbot/plugins/cron"
	"github.com/kyokomi/slackbot/plugins/lgtm"
	"github.com/kyokomi/slackbot/plugins/naruhodo"
	"github.com/kyokomi/slackbot/plugins/suddendeath"
)

//go:generate ego -package main

func init() {
	bind.WithFlag()
	if fl := log.Flags(); fl&log.Ltime != 0 {
		log.SetFlags(fl | log.Lmicroseconds)
	}
}

func main() {
	listener := bind.Default()
	log.Println("Starting on", listener.Addr())

	var apikey string
	flag.StringVar(&apikey, "d", os.Getenv("DOCOMO_APIKEY"), "ドコモのAPIKEY")
	var token string
	flag.StringVar(&token, "token", os.Getenv("SLACK_BOT_TOKEN"), "SlackのBotToken")
	if !flag.Parsed() {
		flag.Parse()
	}

	botCtx, err := slackbot.NewBotContext(token)
	if err != nil {
		panic(err)
	}
	// cronを設定
	cronCtx := cron.NewCronContext(cron.NewHerokuRedisRepository())
	defer cronCtx.Close()
	cronCtx.AllRefreshCron(botCtx)

	d := docomo.NewClient(apikey)

	// add plugin
	nepuBotPlugin := nepubot.Plugin{Docomo: d, Plugins: botCtx.Plugins}
	botCtx.AddPlugin("nepu", &nepuBotPlugin)
	botCtx.AddPlugin("cron", cron.Plugin{CronContext: cronCtx})
	botCtx.AddPlugin("naruhodo", naruhodo.Plugin{})
	botCtx.AddPlugin("lgtm", lgtm.Plugin{})
	botCtx.AddPlugin("suddendeath", suddendeath.Plugin{})

	// start
	botCtx.WebSocketRTM()

	// herokuで動くように

	e := echo.New()
	e.Get("/", func(w http.ResponseWriter, r *http.Request) {
		IndexTmpl(w, botCtx.Plugins.GetPlugins())
	})
	e.Get("/ping", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("PONG"))
	})

	manners.Serve(listener, e.Router())
}
<commit_msg>fix nepubot 順番<commit_after>package main

import (
	"flag"
	"log"
	"net/http"
	"os"

	"github.com/braintree/manners"
	"github.com/labstack/echo"
	"github.com/zenazn/goji/bind"

	"github.com/kyokomi/go-docomo/docomo"
	"github.com/kyokomi/nepu-bot/plugins/nepubot"
	"github.com/kyokomi/slackbot"
	"github.com/kyokomi/slackbot/plugins/cron"
	"github.com/kyokomi/slackbot/plugins/lgtm"
	"github.com/kyokomi/slackbot/plugins/naruhodo"
	"github.com/kyokomi/slackbot/plugins/suddendeath"
)

//go:generate ego -package main

func init() {
	bind.WithFlag()
	if fl := log.Flags(); fl&log.Ltime != 0 {
		log.SetFlags(fl | log.Lmicroseconds)
	}
}

func main() {
	listener := bind.Default()
	log.Println("Starting on", listener.Addr())

	var apikey string
	flag.StringVar(&apikey, "d", os.Getenv("DOCOMO_APIKEY"), "ドコモのAPIKEY")
	var token string
	flag.StringVar(&token, "token", os.Getenv("SLACK_BOT_TOKEN"), "SlackのBotToken")
	if !flag.Parsed() {
		flag.Parse()
	}

	botCtx, err := slackbot.NewBotContext(token)
	if err != nil {
		panic(err)
	}
	// cronを設定
	cronCtx := cron.NewCronContext(cron.NewHerokuRedisRepository())
	defer cronCtx.Close()
	cronCtx.AllRefreshCron(botCtx)

	d := docomo.NewClient(apikey)

	// add plugin
	nepuBotPlugin := nepubot.Plugin{Docomo: d, Plugins: botCtx.Plugins}
	botCtx.AddPlugin("cron", cron.Plugin{CronContext: cronCtx})
	botCtx.AddPlugin("naruhodo", naruhodo.Plugin{})
	botCtx.AddPlugin("lgtm", lgtm.Plugin{})
	botCtx.AddPlugin("suddendeath", suddendeath.Plugin{})
	botCtx.AddPlugin("nepu", &nepuBotPlugin)

	// start
	botCtx.WebSocketRTM()

	// herokuで動くように

	e := echo.New()
	e.Get("/", func(w http.ResponseWriter, r *http.Request) {
		IndexTmpl(w, botCtx.Plugins.GetPlugins())
	})
	e.Get("/ping", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("PONG"))
	})

	manners.Serve(listener, e.Router())
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"github.com/jcoene/gologger"
	"io/ioutil"
	"math"
	"net"
	"net/http"
	"os"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"
)

type Packet struct {
	Bucket   string
	Value    string
	Modifier string
	Sampling float32
}

var log *logger.Logger
var sanitizeRegexp = regexp.MustCompile("[^a-zA-Z0-9\\-_\\.:\\|@]")
var packetRegexp = regexp.MustCompile("([a-zA-Z0-9_\\.]+):(\\-?[0-9\\.]+)\\|(c|ms|g)(\\|@([0-9\\.]+))?")

var (
	serviceAddress = flag.String("address", "0.0.0.0:8125", "udp listen address")
	libratoUser    = flag.String("user", "", "librato api username (LIBRATO_USER)")
	libratoToken   = flag.String("token", "", "librato api token (LIBRATO_TOKEN)")
	libratoSource  = flag.String("source", "", "librato api source (LIBRATO_SOURCE)")
	flushInterval  = flag.Int64("flush", 60, "interval at which data is sent to librato (in seconds)")
	percentiles    = flag.String("percentiles", "", "comma separated list of percentiles to calculate for timers (eg. \"95,99.5\")")
	debug          = flag.Bool("debug", false, "enable logging of inputs and submissions")
)

var (
	In       = make(chan Packet, 10000)
	counters = make(map[string]int64)
	timers   = make(map[string][]float64)
	gauges   = make(map[string]float64)
)

type Measurement struct {
	Counters []Counter     `json:"counters"`
	Gauges   []interface{} `json:"gauges"`
	Source   *string       `json:"source,omitempty"`
}

func (m *Measurement) Count() int {
	return (len(m.Counters) + len(m.Gauges))
}

type Counter struct {
	Name  string `json:"name"`
	Value int64  `json:"value"`
}

type SimpleGauge struct {
	Name  string  `json:"name"`
	Value float64 `json:"value"`
}

type ComplexGauge struct {
	Name       string  `json:"name"`
	Count      int     `json:"count"`
	Sum        float64 `json:"sum"`
	Min        float64 `json:"min"`
	Max        float64 `json:"max"`
	SumSquares float64 `json:"sum_squares"`
	Median     float64 `json:"median"`
}

func monitor() {
	t := time.NewTicker(time.Duration(*flushInterval) * time.Second)

	for {
		select {
		case <-t.C:
			if err := submit(); err != nil {
				log.Error("submit: %s", err)
			}
		case s := <-In:
			if s.Modifier == "ms" {
				_, ok := timers[s.Bucket]
				if !ok {
					var t []float64
					timers[s.Bucket] = t
				}
				floatValue, _ := strconv.ParseFloat(s.Value, 64)
				timers[s.Bucket] = append(timers[s.Bucket], floatValue)
			} else if s.Modifier == "g" {
				_, ok := gauges[s.Bucket]
				if !ok {
					gauges[s.Bucket] = float64(0)
				}
				floatValue, _ := strconv.ParseFloat(s.Value, 64)
				gauges[s.Bucket] = floatValue
			} else {
				_, ok := counters[s.Bucket]
				if !ok {
					counters[s.Bucket] = 0
				}
				floatValue, _ := strconv.ParseFloat(s.Value, 32)
				counters[s.Bucket] += int64(float32(floatValue) * (1 / s.Sampling))
			}
		}
	}
}

func submit() (err error) {
	m := new(Measurement)
	if *libratoSource != "" {
		m.Source = libratoSource
	}
	m.Counters = make([]Counter, 0)
	m.Gauges = make([]interface{}, 0)

	for k, v := range counters {
		c := new(Counter)
		c.Name = k
		c.Value = v
		m.Counters = append(m.Counters, *c)
	}

	for k, v := range gauges {
		g := new(SimpleGauge)
		g.Name = k
		g.Value = v
		m.Gauges = append(m.Gauges, *g)
	}

	for k, t := range timers {
		g := gaugePercentile(k, t, 100.0, "")
		m.Gauges = append(m.Gauges, *g)

		if *percentiles != "" {
			pcts := strings.Split(*percentiles, ",")
			log.Info("pctiles: %+v", pcts)
			for _, pct := range pcts {
				pctf, err := strconv.ParseFloat(pct, 64)
				if err != nil {
					log.Warn("error parsing '%s' as float: %s", pct, err)
					continue
				}

				g = gaugePercentile(k, t, pctf, pct)
				m.Gauges = append(m.Gauges, *g)
			}
		}
	}

	if m.Count() == 0 {
		log.Info("no new measurements in the last %d seconds", *flushInterval)
		return
	}

	payload, err := json.MarshalIndent(m, "", "  ")
	if err != nil {
		return
	}

	log.Debug("sending payload:\n%s", payload)

	req, err := http.NewRequest("POST", "https://metrics-api.librato.com/v1/metrics", bytes.NewBuffer(payload))
	if err != nil {
		return
	}

	req.Header.Add("Content-Type", "application/json")
	req.Header.Set("User-Agent", "statsd/1.0")
	req.SetBasicAuth(*libratoUser, *libratoToken)
	resp, err := http.DefaultClient.Do(req)
	if err == nil && resp.StatusCode != 200 {
		if err == nil {
			raw, _ := ioutil.ReadAll(resp.Body)
			err = errors.New(fmt.Sprintf("%s: %s", resp.Status, string(raw)))
		}
		log.Warn("error sending %d measurements: %s", m.Count(), err)
		return
	}

	log.Info("%d measurements sent", m.Count())

	for k, _ := range timers {
		delete(timers, k)
	}

	return
}

func gaugePercentile(k string, t []float64, pct float64, suffix string) *ComplexGauge {
	thresholdIdx := ((100.0 - pct) / 100.0) * float64(len(t))
	thresholdIdx = math.Floor(thresholdIdx + 0.5)

	numInPct := len(t) - int(thresholdIdx)
	if numInPct <= 0 {
		return nil
	}

	g := new(ComplexGauge)
	g.Count = numInPct
	g.Name = k
	if suffix != "" {
		g.Name += "." + suffix
	}

	if g.Count > 0 {
		sort.Float64s(t)
		g.Min = t[0]
		g.Max = t[numInPct-1]
		for i := 0; i < numInPct; i++ {
			v := t[i]
			g.Sum += v
			g.SumSquares += (v * v)
		}

		mid := g.Count / 2
		g.Median = t[mid]

		if g.Count > 2 && g.Count%2 == 0 {
			g.Median += t[mid-1]
		}
	}

	return g
}

func handle(conn *net.UDPConn, remaddr net.Addr, buf *bytes.Buffer) {
	var packet Packet
	var value string
	s := sanitizeRegexp.ReplaceAllString(buf.String(), "")

	for _, item := range packetRegexp.FindAllStringSubmatch(s, -1) {
		value = item[2]
		if item[3] == "ms" {
			_, err := strconv.ParseFloat(item[2], 32)
			if err != nil {
				value = "0"
			}
		}

		sampleRate, err := strconv.ParseFloat(item[5], 32)
		if err != nil {
			sampleRate = 1
		}

		packet.Bucket = item[1]
		packet.Value = value
		packet.Modifier = item[3]
		packet.Sampling = float32(sampleRate)

		In <- packet
	}
}

func listen() {
	address, _ := net.ResolveUDPAddr("udp", *serviceAddress)
	listener, err := net.ListenUDP("udp", address)
	defer listener.Close()
	if err != nil {
		log.Fatal("unable to listen: %s", err)
		os.Exit(1)
	}

	log.Info("listening for events...")

	for {
		message := make([]byte, 512)
		n, remaddr, error := listener.ReadFrom(message)

		if error != nil {
			continue
		}

		log.Debug("received metric: %s", message)

		buf := bytes.NewBuffer(message[0:n])
		go handle(listener, remaddr, buf)
	}
}

func main() {
	flag.Parse()

	if *debug {
		log = logger.NewLogger(logger.LOG_LEVEL_DEBUG, "statsd")
	} else {
		log = logger.NewLogger(logger.LOG_LEVEL_INFO, "statsd")
	}

	if *libratoUser == "" {
		if !getEnv(libratoUser, "LIBRATO_USER") {
			log.Fatal("specify a librato user with -user or the LIBRATO_USER environment variable")
		}
	}

	if *libratoToken == "" {
		if !getEnv(libratoToken, "LIBRATO_TOKEN") {
			log.Fatal("specify a librato token with -token or the LIBRATO_TOKEN environment variable")
		}
	}

	if *libratoSource == "" {
		getEnv(libratoSource, "LIBRATO_SOURCE")
	}

	log.Info("user: %s, token: %s, source: %s", *libratoUser, *libratoToken, *libratoSource)

	go listen()
	monitor()
}

func getEnv(p *string, key string) bool {
	if s := os.Getenv(key); s != "" {
		*p = s
		return true
	}

	return false
}
<commit_msg>Remove debug messages<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"github.com/jcoene/gologger"
	"io/ioutil"
	"math"
	"net"
	"net/http"
	"os"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"
)

type Packet struct {
	Bucket   string
	Value    string
	Modifier string
	Sampling float32
}

var log *logger.Logger
var sanitizeRegexp = regexp.MustCompile("[^a-zA-Z0-9\\-_\\.:\\|@]")
var packetRegexp = regexp.MustCompile("([a-zA-Z0-9_\\.]+):(\\-?[0-9\\.]+)\\|(c|ms|g)(\\|@([0-9\\.]+))?")

var (
	serviceAddress = flag.String("address", "0.0.0.0:8125", "udp listen address")
	libratoUser    = flag.String("user", "", "librato api username (LIBRATO_USER)")
	libratoToken   = flag.String("token", "", "librato api token (LIBRATO_TOKEN)")
	libratoSource  = flag.String("source", "", "librato api source (LIBRATO_SOURCE)")
	flushInterval  = flag.Int64("flush", 60, "interval at which data is sent to librato (in seconds)")
	percentiles    = flag.String("percentiles", "", "comma separated list of percentiles to calculate for timers (eg. \"95,99.5\")")
	debug          = flag.Bool("debug", false, "enable logging of inputs and submissions")
)

var (
	In       = make(chan Packet, 10000)
	counters = make(map[string]int64)
	timers   = make(map[string][]float64)
	gauges   = make(map[string]float64)
)

type Measurement struct {
	Counters []Counter     `json:"counters"`
	Gauges   []interface{} `json:"gauges"`
	Source   *string       `json:"source,omitempty"`
}

func (m *Measurement) Count() int {
	return (len(m.Counters) + len(m.Gauges))
}

type Counter struct {
	Name  string `json:"name"`
	Value int64  `json:"value"`
}

type SimpleGauge struct {
	Name  string  `json:"name"`
	Value float64 `json:"value"`
}

type ComplexGauge struct {
	Name       string  `json:"name"`
	Count      int     `json:"count"`
	Sum        float64 `json:"sum"`
	Min        float64 `json:"min"`
	Max        float64 `json:"max"`
	SumSquares float64 `json:"sum_squares"`
	Median     float64 `json:"median"`
}

func monitor() {
	t := time.NewTicker(time.Duration(*flushInterval) * time.Second)

	for {
		select {
		case <-t.C:
			if err := submit(); err != nil {
				log.Error("submit: %s", err)
			}
		case s := <-In:
			if s.Modifier == "ms" {
				_, ok := timers[s.Bucket]
				if !ok {
					var t []float64
					timers[s.Bucket] = t
				}
				floatValue, _ := strconv.ParseFloat(s.Value, 64)
				timers[s.Bucket] = append(timers[s.Bucket], floatValue)
			} else if s.Modifier == "g" {
				_, ok := gauges[s.Bucket]
				if !ok {
					gauges[s.Bucket] = float64(0)
				}
				floatValue, _ := strconv.ParseFloat(s.Value, 64)
				gauges[s.Bucket] = floatValue
			} else {
				_, ok := counters[s.Bucket]
				if !ok {
					counters[s.Bucket] = 0
				}
				floatValue, _ := strconv.ParseFloat(s.Value, 32)
				counters[s.Bucket] += int64(float32(floatValue) * (1 / s.Sampling))
			}
		}
	}
}

func submit() (err error) {
	m := new(Measurement)
	if *libratoSource != "" {
		m.Source = libratoSource
	}
	m.Counters = make([]Counter, 0)
	m.Gauges = make([]interface{}, 0)

	for k, v := range counters {
		c := new(Counter)
		c.Name = k
		c.Value = v
		m.Counters = append(m.Counters, *c)
	}

	for k, v := range gauges {
		g := new(SimpleGauge)
		g.Name = k
		g.Value = v
		m.Gauges = append(m.Gauges, *g)
	}

	for k, t := range timers {
		g := gaugePercentile(k, t, 100.0, "")
		m.Gauges = append(m.Gauges, *g)

		if *percentiles != "" {
			pcts := strings.Split(*percentiles, ",")
			for _, pct := range pcts {
				pctf, err := strconv.ParseFloat(pct, 64)
				if err != nil {
					log.Warn("error parsing '%s' as float: %s", pct, err)
					continue
				}

				g = gaugePercentile(k, t, pctf, pct)
				m.Gauges = append(m.Gauges, *g)
			}
		}
	}

	if m.Count() == 0 {
		log.Info("no new measurements in the last %d seconds", *flushInterval)
		return
	}

	payload, err := json.MarshalIndent(m, "", "  ")
	if err != nil {
		return
	}

	log.Debug("sending payload:\n%s", payload)

	req, err := http.NewRequest("POST", "https://metrics-api.librato.com/v1/metrics", bytes.NewBuffer(payload))
	if err != nil {
		return
	}

	req.Header.Add("Content-Type", "application/json")
	req.Header.Set("User-Agent", "statsd/1.0")
	req.SetBasicAuth(*libratoUser, *libratoToken)
	resp, err := http.DefaultClient.Do(req)
	if err == nil && resp.StatusCode != 200 {
		if err == nil {
			raw, _ := ioutil.ReadAll(resp.Body)
			err = errors.New(fmt.Sprintf("%s: %s", resp.Status, string(raw)))
		}
		log.Warn("error sending %d measurements: %s", m.Count(), err)
		return
	}

	log.Info("%d measurements sent", m.Count())

	for k, _ := range timers {
		delete(timers, k)
	}

	return
}

func gaugePercentile(k string, t []float64, pct float64, suffix string) *ComplexGauge {
	thresholdIdx := ((100.0 - pct) / 100.0) * float64(len(t))
	thresholdIdx = math.Floor(thresholdIdx + 0.5)

	numInPct := len(t) - int(thresholdIdx)
	if numInPct <= 0 {
		return nil
	}

	g := new(ComplexGauge)
	g.Count = numInPct
	g.Name = k
	if suffix != "" {
		g.Name += "." + suffix
	}

	if g.Count > 0 {
		sort.Float64s(t)
		g.Min = t[0]
		g.Max = t[numInPct-1]
		for i := 0; i < numInPct; i++ {
			v := t[i]
			g.Sum += v
			g.SumSquares += (v * v)
		}

		mid := g.Count / 2
		g.Median = t[mid]

		if g.Count > 2 && g.Count%2 == 0 {
			g.Median += t[mid-1]
		}
	}

	return g
}

func handle(conn *net.UDPConn, remaddr net.Addr, buf *bytes.Buffer) {
	var packet Packet
	var value string
	s := sanitizeRegexp.ReplaceAllString(buf.String(), "")

	for _, item := range packetRegexp.FindAllStringSubmatch(s, -1) {
		value = item[2]
		if item[3] == "ms" {
			_, err := strconv.ParseFloat(item[2], 32)
			if err != nil {
				value = "0"
			}
		}

		sampleRate, err := strconv.ParseFloat(item[5], 32)
		if err != nil {
			sampleRate = 1
		}

		packet.Bucket = item[1]
		packet.Value = value
		packet.Modifier = item[3]
		packet.Sampling = float32(sampleRate)

		In <- packet
	}
}

func listen() {
	address, _ := net.ResolveUDPAddr("udp", *serviceAddress)
	listener, err := net.ListenUDP("udp", address)
	defer listener.Close()
	if err != nil {
		log.Fatal("unable to listen: %s", err)
		os.Exit(1)
	}

	log.Info("listening for events...")

	for {
		message := make([]byte, 512)
		n, remaddr, error := listener.ReadFrom(message)

		if error != nil {
			continue
		}

		log.Debug("received metric: %s", message)

		buf := bytes.NewBuffer(message[0:n])
		go handle(listener, remaddr, buf)
	}
}

func main() {
	flag.Parse()

	if *debug {
		log = logger.NewLogger(logger.LOG_LEVEL_DEBUG, "statsd")
	} else {
		log = logger.NewLogger(logger.LOG_LEVEL_INFO, "statsd")
	}

	if *libratoUser == "" {
		if !getEnv(libratoUser, "LIBRATO_USER") {
			log.Fatal("specify a librato user with -user or the LIBRATO_USER environment variable")
		}
	}

	if *libratoToken == "" {
		if !getEnv(libratoToken, "LIBRATO_TOKEN") {
			log.Fatal("specify a librato token with -token or the LIBRATO_TOKEN environment variable")
		}
	}

	if *libratoSource == "" {
		getEnv(libratoSource, "LIBRATO_SOURCE")
	}

	go listen()
	monitor()
}

func getEnv(p *string, key string) bool {
	if s := os.Getenv(key); s != "" {
		*p = s
		return true
	}

	return false
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"github.com/facebookgo/errgroup"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

type EmojiResponse struct {
	OK           bool              `json:"ok"`
	Emoji        map[string]string `json:"emoji"`
	ErrorMessage string            `json:"error"`
}

func (er EmojiResponse) Error() string {
	return er.ErrorMessage
}

func (er EmojiResponse) String() string {
	return er.ErrorMessage
}

func Filename(k, url string) string {
	ext := filepath.Ext(url)
	if ext == "" {
		ext = ".png"
	}
	return filepath.Join("emoji", k+ext)
}

func SaveEmoji(name, url string) error {
	filename := Filename(name, url)
	if _, err := os.Stat(filename); err == nil {
		log.Println("exists", filename)
		return nil
	}

	log.Println("saved", filename)

	resp, err := http.Get(url)
	if err != nil {
		return err
	}

	defer resp.Body.Close()

	blob, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(filename, blob, 0644)
}

func BackupEmoji(key string) error {
	if _, err := os.Stat("emoji"); os.IsNotExist(err) {
		if err = os.Mkdir("emoji", 755); err != nil {
			return err
		}
	}

	if _, err := os.Stat("aliases"); os.IsNotExist(err) {
		if err = os.Mkdir("aliases", 755); err != nil {
			return err
		}
	}

	resp, err := http.Get("https://slack.com/api/emoji.list?token=" + key)
	if err != nil {
		return err
	}

	defer resp.Body.Close()

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

	var er EmojiResponse

	if err := json.Unmarshal(blob, &er); err != nil {
		return err
	}

	if !er.OK {
		return er
	}

	wg := errgroup.Group{}

	for k, v := range er.Emoji {
		if strings.HasPrefix(v, "alias:") {
			continue
		}

		wg.Add(1)

		go func(name, url string) {
			err := SaveEmoji(name, url)
			if err != nil {
				wg.Error(err)
			} else {
				wg.Done()
			}
		}(k, v)
	}

	if err = wg.Wait(); err != nil {
		return err
	}

	for k, v := range er.Emoji {
		if !strings.HasPrefix(v, "alias:") {
			continue
		}

		alias := strings.Replace(v, "alias:", "", -1)
		image := Filename(alias, er.Emoji[alias])
		link := filepath.Join("aliases", k)

		if _, err := os.Stat(link); err == nil {
			log.Println("exists", link)
			continue
		}

		log.Println("linked", link)
		_ = os.Link(image, link)
	}

	return nil
}

func main() {
	flag.Parse()

	err := BackupEmoji(flag.Arg(0))

	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Use 15 workers to download emojis. Don't use links anymore<commit_after>package main

import (
	"encoding/json"
	"flag"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

type EmojiResponse struct {
	OK           bool              `json:"ok"`
	Emoji        map[string]string `json:"emoji"`
	ErrorMessage string            `json:"error"`
}

func (er EmojiResponse) Error() string {
	return er.ErrorMessage
}

func (er EmojiResponse) String() string {
	return er.ErrorMessage
}

func Filename(k, url string) string {
	ext := filepath.Ext(url)
	if ext == "" {
		ext = ".png"
	}
	return filepath.Join("emoji", k+ext)
}

func cp(dst, src string) error {
	s, err := os.Open(src)
	if err != nil {
		return err
	}
	// no need to check errors on read only file, we already got everything
	// we need from the filesystem, so nothing can go wrong now.
	defer s.Close()
	d, err := os.Create(dst)
	if err != nil {
		return err
	}
	if _, err := io.Copy(d, s); err != nil {
		d.Close()
		return err
	}
	return d.Close()
}

func SaveEmoji(name, url string) error {
	filename := Filename(name, url)
	if _, err := os.Stat(filename); err == nil {
		log.Println("exists", filename)
		return nil
	}

	log.Println("saved", filename)

	resp, err := http.Get(url)
	if err != nil {
		return err
	}

	defer resp.Body.Close()

	blob, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(filename, blob, 0644)
}

func BackupEmoji(key string) error {
	if _, err := os.Stat("emoji"); os.IsNotExist(err) {
		if err = os.Mkdir("emoji", 0755); err != nil {
			return err
		}
	}

	resp, err := http.Get("https://slack.com/api/emoji.list?token=" + key)
	if err != nil {
		return err
	}

	defer resp.Body.Close()

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

	var er EmojiResponse

	if err := json.Unmarshal(blob, &er); err != nil {
		return err
	}

	if !er.OK {
		return er
	}

	type emoPair struct {
		name string
		url  string
	}

	var wg sync.WaitGroup

	emoChan := make(chan emoPair)

	for i := 1; i <= 15; i++ {
		wg.Add(1)
		go func() {
			for {
				ep, ok := <-emoChan
				if !ok {
					wg.Done()
					return
				}
				err := SaveEmoji(ep.name, ep.url)
				if err != nil {
					log.Printf("API error: %s\n", err)
				}
			}
		}()
	}

	for k, v := range er.Emoji {
		if strings.HasPrefix(v, "alias:") {
			continue
		}
		emoChan <- emoPair{k, v}
	}

	close(emoChan)
	wg.Wait()

	for k, v := range er.Emoji {
		if !strings.HasPrefix(v, "alias:") {
			continue
		}

		alias := strings.Replace(v, "alias:", "", -1)
		image := Filename(alias, er.Emoji[alias])
		link := filepath.Join("emoji", k)

		if _, err := os.Stat(link); err == nil {
			log.Println("exists", link)
			continue
		}

		log.Println("linked", link)
		_ = cp(image, link)
	}

	return nil
}

func main() {
	flag.Parse()

	err := BackupEmoji(flag.Arg(0))

	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
)

const tmpl = `Title:

Description:

Owner:

Projects:

Priority:

Points:
`

var keysToConduit = map[string]string{
	"title":       "title",
	"description": "description",
	"owner":       "ownerPHID",
	"priority":    "priority",
	"projects":    "projectPHIDs",
	"points":      "points",
}

var re = regexp.MustCompile(`(?m)^(\w+):`)

func main() {
	log.SetFlags(0)

	// prepare a temp file
	// TODO: add maybe extension
	f, err := ioutil.TempFile("", "task")
	fatalIf(err)

	// try to get the editor otherwise use a default one
	editor := os.Getenv("EDITOR")
	if editor == "" {
		editor = "vim"
	}

	// write our template in it
	_, err = f.WriteString(tmpl)
	fatalIf(err)

	err = f.Close()
	fatalIf(err)

	// open the file in the editor
	cmd := exec.Command(editor, f.Name())
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	log.Printf("Executing %s %s", editor, f.Name())
	err = cmd.Start()
	fatalIf(err)

	err = cmd.Wait()
	fatalIf(err)

	// sync and seek to 0 so we can read it again
	f, err = os.Open(f.Name())
	fatalIf(err)

	buf, err := ioutil.ReadAll(f)

	// parse the template
	res := re.FindAllIndex(buf, -1)

	// matches is the index where each key starts and its key
	type keyMatch struct {
		index [2]int // start/finish
		key   string
	}
	matches := []keyMatch{}
	for _, m := range res {
		if len(m) != 2 {
			log.Fatal("Invalid index length")
		}

		// get start and beginning and transform it to a string
		s, e := m[0], m[1]-1
		key := string(buf[s:e])

		// store its start and key map
		if key, ok := keysToConduit[strings.ToLower(key)]; ok {
			matches = append(matches, keyMatch{[2]int{s, e}, key})
		}
	}

	// now pair the keys with their values
	data := make(map[string]interface{}, len(matches))
	for i, m := range matches {
		var ends int
		if i == len(matches)-1 {
			ends = len(buf)
		} else {
			ends = matches[i+1].index[0]
		}

		value := strings.TrimSpace(string(buf[m.index[1]+1 : ends]))
		if value != "" {
			data[m.key] = value
		}
	}

	// find phids
	if v, ok := data["ownerPHID"]; ok {
		v, ok := v.(string)
		if !ok {
			fatalf("owner should be a string")
		}

		phids := getPHIDs(v, '@')
		if len(phids) != 1 {
			fatalf("you should specify just 1 owner got: %d", len(phids))
		}

		data["ownerPHID"] = phids[0]
	}

	if v, ok := data["projectPHIDs"]; ok {
		v, ok := v.(string)
		if !ok {
			fatal("projects should be a string (comma separated if multiple)")
		}

		data["projectPHIDs"] = getPHIDs(v, '#')
	}

	// prepare the json to send to conduit
	buf, err = json.Marshal(data)
	fatalIf(err)

	// the arguments if any to the conduit call
	args := append([]string{"call-conduit"},
		append(os.Args[1:], "maniphest.createtask")...,
	)

	// capture the output
	stdout := bytes.NewBuffer(nil)

	// execute the final command
	cmd = exec.Command("arc", args...)
	cmd.Stdout = stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = bytes.NewReader(buf)

	log.Print("Sending to conduit ...")
	err = cmd.Start()
	fatalIf(err)

	err = cmd.Wait()
	fatalIf(err)

	{ // decode finally the response
		var res struct {
			Error        string `json:"error"`
			ErrorMessage string `json:"errorMessage"`
			Response     struct {
				URI        string `json:"uri"`
				ObjectName string `json:"objectName"`
			} `json:"response"`
		}

		err := json.NewDecoder(stdout).
			Decode(&res)
		fatalIf(err)

		// if we got an error
		if res.Error != "" || res.ErrorMessage != "" {
			fatal(res.ErrorMessage)
		}

		log.Printf("Task successfully created at %s", res.Response.URI)
	}
}

func getPHIDs(value string, prefix byte) []string {
	// prepare the data
	objects := map[string][]string{
		"names": []string{},
	}

	for _, v := range strings.Split(value, ",") {
		v := strings.TrimSpace(v)
		if v[0] != prefix {
			v = string([]byte{prefix}) + v
		}
		objects["names"] = append(objects["names"], v)
	}

	data, err := json.Marshal(objects)
	fatalIf(err)

	stdout := bytes.NewBuffer(nil)
	cmd := exec.Command("arc", "call-conduit", "phid.lookup")
	cmd.Stdout = stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = bytes.NewReader(data)
	err = cmd.Start()
	fatalIf(err)
	err = cmd.Wait()
	fatalIf(err)

	var res struct {
		Error        string                       `json:"error"`
		ErrorMessage string                       `json:"errorMessage"`
		Response     map[string]map[string]string `json:"response"`
	}

	err = json.NewDecoder(stdout).Decode(&res)
	fatalIf(err)

	// if we got an error
	if res.Error != "" || res.ErrorMessage != "" {
		fatal(res.ErrorMessage)
	}

	phids := make([]string, len(res.Response))
	for i, o := range objects["names"] {
		v, ok := res.Response[o]
		if !ok {
			fatalf("unable to find the phid of %q", o)
		}
		phids[i] = v["phid"]
	}

	return phids
}

func fatalIf(err error) {
	if err == nil {
		return
	}
	fatalWithCaller(err)
}

func fatalf(format string, args ...interface{}) {
	err := fmt.Errorf(format, args...)
	fatalWithCaller(err)
}

func fatal(msg string) {
	err := errors.New(msg)
	fatalWithCaller(err)
}

func fatalWithCaller(err error) {
	fileline := "<unknown>"
	_, file, line, ok := runtime.Caller(2)
	if ok {
		fileline = fmt.Sprintf("%s:%d", filepath.Base(file), line)
	}
	log.Fatalf("%s %v", fileline, err)
}
<commit_msg>Add subscriber option<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
)

const tmpl = `Title:

Description:

Owner:

CC:

Projects:

Priority:

Points:
`

var keysToConduit = map[string]string{
	"title":       "title",
	"description": "description",
	"owner":       "ownerPHID",
	"cc":          "ccPHIDs",
	"priority":    "priority",
	"projects":    "projectPHIDs",
	"points":      "points",
}

var re = regexp.MustCompile(`(?m)^(\w+):`)

func main() {
	log.SetFlags(0)

	// prepare a temp file
	// TODO: add maybe extension
	f, err := ioutil.TempFile("", "task")
	fatalIf(err)

	// try to get the editor otherwise use a default one
	editor := os.Getenv("EDITOR")
	if editor == "" {
		editor = "vim"
	}

	// write our template in it
	_, err = f.WriteString(tmpl)
	fatalIf(err)

	err = f.Close()
	fatalIf(err)

	// open the file in the editor
	cmd := exec.Command(editor, f.Name())
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	log.Printf("Executing %s %s", editor, f.Name())
	err = cmd.Start()
	fatalIf(err)

	err = cmd.Wait()
	fatalIf(err)

	// sync and seek to 0 so we can read it again
	f, err = os.Open(f.Name())
	fatalIf(err)

	buf, err := ioutil.ReadAll(f)

	// parse the template
	res := re.FindAllIndex(buf, -1)

	// matches is the index where each key starts and its key
	type keyMatch struct {
		index [2]int // start/finish
		key   string
	}
	matches := []keyMatch{}
	for _, m := range res {
		if len(m) != 2 {
			log.Fatal("Invalid index length")
		}

		// get start and beginning and transform it to a string
		s, e := m[0], m[1]-1
		key := string(buf[s:e])

		// store its start and key map
		if key, ok := keysToConduit[strings.ToLower(key)]; ok {
			matches = append(matches, keyMatch{[2]int{s, e}, key})
		}
	}

	// now pair the keys with their values
	data := make(map[string]interface{}, len(matches))
	for i, m := range matches {
		var ends int
		if i == len(matches)-1 {
			ends = len(buf)
		} else {
			ends = matches[i+1].index[0]
		}

		value := strings.TrimSpace(string(buf[m.index[1]+1 : ends]))
		if value != "" {
			data[m.key] = value
		}
	}

	// find phids
	if v, ok := data["ownerPHID"]; ok {
		v, ok := v.(string)
		if !ok {
			fatalf("owner should be a string")
		}

		phids := getPHIDs(v, '@')
		if len(phids) != 1 {
			fatalf("you should specify just 1 owner got: %d", len(phids))
		}

		data["ownerPHID"] = phids[0]
	}

	if v, ok := data["ccPHIDs"]; ok {
		v, ok := v.(string)
		if !ok {
			fatalf("owner should be a string")
		}

		data["ccPHIDs"] = getPHIDs(v, '@')
	}

	if v, ok := data["projectPHIDs"]; ok {
		v, ok := v.(string)
		if !ok {
			fatal("projects should be a string (comma separated if multiple)")
		}

		data["projectPHIDs"] = getPHIDs(v, '#')
	}

	// prepare the json to send to conduit
	buf, err = json.Marshal(data)
	fatalIf(err)

	// the arguments if any to the conduit call
	args := append([]string{"call-conduit"},
		append(os.Args[1:], "maniphest.createtask")...,
	)

	// capture the output
	stdout := bytes.NewBuffer(nil)

	// execute the final command
	cmd = exec.Command("arc", args...)
	cmd.Stdout = stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = bytes.NewReader(buf)

	log.Print("Sending to conduit ...")
	err = cmd.Start()
	fatalIf(err)

	err = cmd.Wait()
	fatalIf(err)

	{ // decode finally the response
		var res struct {
			Error        string `json:"error"`
			ErrorMessage string `json:"errorMessage"`
			Response     struct {
				URI        string `json:"uri"`
				ObjectName string `json:"objectName"`
			} `json:"response"`
		}

		err := json.NewDecoder(stdout).
			Decode(&res)
		fatalIf(err)

		// if we got an error
		if res.Error != "" || res.ErrorMessage != "" {
			fatal(res.ErrorMessage)
		}

		log.Printf("Task successfully created at %s", res.Response.URI)
	}
}

func getPHIDs(value string, prefix byte) []string {
	// prepare the data
	objects := map[string][]string{
		"names": []string{},
	}

	for _, v := range strings.Split(value, ",") {
		v := strings.TrimSpace(v)
		if v[0] != prefix {
			v = string([]byte{prefix}) + v
		}
		objects["names"] = append(objects["names"], v)
	}

	data, err := json.Marshal(objects)
	fatalIf(err)

	stdout := bytes.NewBuffer(nil)
	cmd := exec.Command("arc", "call-conduit", "phid.lookup")
	cmd.Stdout = stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = bytes.NewReader(data)
	err = cmd.Start()
	fatalIf(err)
	err = cmd.Wait()
	fatalIf(err)

	var res struct {
		Error        string                       `json:"error"`
		ErrorMessage string                       `json:"errorMessage"`
		Response     map[string]map[string]string `json:"response"`
	}

	err = json.NewDecoder(stdout).Decode(&res)
	fatalIf(err)

	// if we got an error
	if res.Error != "" || res.ErrorMessage != "" {
		fatal(res.ErrorMessage)
	}

	phids := make([]string, len(res.Response))
	for i, o := range objects["names"] {
		v, ok := res.Response[o]
		if !ok {
			fatalf("unable to find the phid of %q", o)
		}
		phids[i] = v["phid"]
	}

	return phids
}

func fatalIf(err error) {
	if err == nil {
		return
	}
	fatalWithCaller(err)
}

func fatalf(format string, args ...interface{}) {
	err := fmt.Errorf(format, args...)
	fatalWithCaller(err)
}

func fatal(msg string) {
	err := errors.New(msg)
	fatalWithCaller(err)
}

func fatalWithCaller(err error) {
	fileline := "<unknown>"
	_, file, line, ok := runtime.Caller(2)
	if ok {
		fileline = fmt.Sprintf("%s:%d", filepath.Base(file), line)
	}
	log.Fatalf("%s %v", fileline, err)
}
<|endoftext|>