<commit_before>package nagiosplugin

import (
	"fmt"
	"os"
	"strings"
)

const (
	messageSeparator = ", "
)

// Standalone Exit function for simple checks without multiple results
// or perfdata.
func Exit(status Status, message string) {
	fmt.Printf("%v: %s\n", status, message)
	os.Exit(int(status))
}

// Represents the state of a Nagios check.
type Check struct {
	results  []Result
	perfdata []PerfDatum
	status   Status
}

// NewCheck returns an empty Check object.
func NewCheck() *Check {
	c := new(Check)
	return c
}

// AddResult adds a check result. This will not terminate the check. If
// status is the highest yet reported, this will update the check's
// final return status.
func (c *Check) AddResult(status Status, message string) {
	var result Result
	result.status = status
	result.message = message
	c.results = append(c.results, result)
	if result.status > c.status {
		c.status = result.status
	}
}

// AddPerfDatum adds a metric to the set output by the check. unit must
// be a valid Nagios unit of measurement (UOM): "us", "ms", "s",
// "%", "b", "kb", "mb", "gb", "tb", "c", or the empty string. UOMs are
// not case-sensitive.
//
// Zero or more of the thresholds min, max, warn and crit may be
// supplied; these must be of the same UOM as the value.
//
// A threshold may be positive or negative infinity, in which case it
// will be omitted in the check output. A value may not be either
// infinity.
//
// Returns error on invalid parameters.
func (c *Check) AddPerfDatum(label, unit string, value float64, thresholds ...float64) error {
	datum, err := NewPerfDatum(label, unit, value, thresholds...)
	if err != nil {
		return err
	}
	c.perfdata = append(c.perfdata, *datum)
	return nil
}

// exitInfoText returns the most important result text, formatted for
// the first line of plugin output.
//
// Returns joined string of (messageSeparator-separated) info text from
// results which have a status of at least c.status.
func (c Check) exitInfoText() string {
	importantMessages := make([]string, 0)
	for _, result := range c.results {
		if result.status == c.status {
			importantMessages = append(importantMessages, result.message)
		}
	}
	return strings.Join(importantMessages, messageSeparator)
}

// String representation of the check results, suitable for output and
// parsing by Nagios.
func (c Check) String() string {
	value := fmt.Sprintf("%v: %s", c.status, c.exitInfoText())
	value += RenderPerfdata(c.perfdata)
	return value
}

// Finish ends the check, prints its output (to stdout), and exits with
// the correct status.
func (c *Check) Finish() {
	if r := recover(); r != nil {
		c.Exitf(CRITICAL, "check panicked: %v", r)
	}
	if len(c.results) == 0 {
		c.AddResult(UNKNOWN, "no check result specified")
	}
	fmt.Println(c)
	os.Exit(int(c.status))
}

// Exitf takes a status plus a format string, and a list of
// parameters to pass to Sprintf. It then immediately outputs and exits.
func (c *Check) Exitf(status Status, format string, v ...interface{}) {
	info := fmt.Sprintf(format, v...)
	c.AddResult(status, info)
	c.Finish()
}

// Criticalf is a shorthand function which exits the check with status
// CRITICAL and the message provided.
// nagiosplugin.CRITICAL and the supplied format string.
func (c *Check) Criticalf(format string, v ...interface{}) {
	c.Exitf(CRITICAL, format, v...)
}

// Unknownf is a shorthand function which exits the check with status
// UNKNOWN and the message provided.
func (c *Check) Unknownf(format string, v ...interface{}) {
	c.Exitf(UNKNOWN, format, v...)
}
<commit_msg>check.AddResultf function for formatting info messages<commit_after>package nagiosplugin

import (
	"fmt"
	"os"
	"strings"
)

const (
	messageSeparator = ", "
)

// Standalone Exit function for simple checks without multiple results
// or perfdata.
func Exit(status Status, message string) {
	fmt.Printf("%v: %s\n", status, message)
	os.Exit(int(status))
}

// Represents the state of a Nagios check.
type Check struct {
	results  []Result
	perfdata []PerfDatum
	status   Status
}

// NewCheck returns an empty Check object.
func NewCheck() *Check {
	c := new(Check)
	return c
}

// AddResult adds a check result. This will not terminate the check. If
// status is the highest yet reported, this will update the check's
// final return status.
func (c *Check) AddResult(status Status, message string) {
	var result Result
	result.status = status
	result.message = message
	c.results = append(c.results, result)
	if result.status > c.status {
		c.status = result.status
	}
}

// AddResultf functions as AddResult, but takes a printf-style format
// string and arguments.
func (c *Check) AddResultf(status Status, format string, v ...interface{}) {
	msg := fmt.Sprintf(format, v...)
	c.AddResult(status, msg)
}

// AddPerfDatum adds a metric to the set output by the check. unit must
// be a valid Nagios unit of measurement (UOM): "us", "ms", "s",
// "%", "b", "kb", "mb", "gb", "tb", "c", or the empty string. UOMs are
// not case-sensitive.
//
// Zero or more of the thresholds min, max, warn and crit may be
// supplied; these must be of the same UOM as the value.
//
// A threshold may be positive or negative infinity, in which case it
// will be omitted in the check output. A value may not be either
// infinity.
//
// Returns error on invalid parameters.
func (c *Check) AddPerfDatum(label, unit string, value float64, thresholds ...float64) error {
	datum, err := NewPerfDatum(label, unit, value, thresholds...)
	if err != nil {
		return err
	}
	c.perfdata = append(c.perfdata, *datum)
	return nil
}

// exitInfoText returns the most important result text, formatted for
// the first line of plugin output.
//
// Returns joined string of (messageSeparator-separated) info text from
// results which have a status of at least c.status.
func (c Check) exitInfoText() string {
	importantMessages := make([]string, 0)
	for _, result := range c.results {
		if result.status == c.status {
			importantMessages = append(importantMessages, result.message)
		}
	}
	return strings.Join(importantMessages, messageSeparator)
}

// String representation of the check results, suitable for output and
// parsing by Nagios.
func (c Check) String() string {
	value := fmt.Sprintf("%v: %s", c.status, c.exitInfoText())
	value += RenderPerfdata(c.perfdata)
	return value
}

// Finish ends the check, prints its output (to stdout), and exits with
// the correct status.
func (c *Check) Finish() {
	if r := recover(); r != nil {
		c.Exitf(CRITICAL, "check panicked: %v", r)
	}
	if len(c.results) == 0 {
		c.AddResult(UNKNOWN, "no check result specified")
	}
	fmt.Println(c)
	os.Exit(int(c.status))
}

// Exitf takes a status plus a format string, and a list of
// parameters to pass to Sprintf. It then immediately outputs and exits.
func (c *Check) Exitf(status Status, format string, v ...interface{}) {
	info := fmt.Sprintf(format, v...)
	c.AddResult(status, info)
	c.Finish()
}

// Criticalf is a shorthand function which exits the check with status
// CRITICAL and the message provided.
// nagiosplugin.CRITICAL and the supplied format string.
func (c *Check) Criticalf(format string, v ...interface{}) {
	c.Exitf(CRITICAL, format, v...)
}

// Unknownf is a shorthand function which exits the check with status
// UNKNOWN and the message provided.
func (c *Check) Unknownf(format string, v ...interface{}) {
	c.Exitf(UNKNOWN, format, v...)
}
<|endoftext|>


<commit_before>package gosnowflake

import (
	"bytes"
	"fmt"
	"io"

	"unicode"
	"unicode/utf16"
	"unicode/utf8"
)

const (
	defaultChunkBufferSize  int64 = 8 << 10 // 8k
	defaultStringBufferSize int64 = 512
)

type largeChunkDecoder struct {
	r io.Reader

	rows  int // hint for number of rows
	cells int // hint for number of cells/row

	rem int // bytes remaining in rbuf
	ptr int // position in rbuf

	rbuf []byte
	sbuf *bytes.Buffer // buffer for decodeString

	ioError error
}

func decodeLargeChunk(r io.Reader, rowCount int, cellCount int) ([][]*string, error) {
	glog.V(2).Info("custom JSON Decoder")
	lcd := largeChunkDecoder{
		r, rowCount, cellCount,
		0, 0,
		make([]byte, defaultChunkBufferSize),
		bytes.NewBuffer(make([]byte, defaultStringBufferSize)),
		nil,
	}

	rows, err := lcd.decode()
	if lcd.ioError != nil && lcd.ioError != io.EOF {
		return nil, lcd.ioError
	} else if err != nil {
		return nil, err
	}

	return rows, nil
}

func (lcd *largeChunkDecoder) mkError(s string) error {
	return fmt.Errorf("corrupt chunk: %s", s)
}

func (lcd *largeChunkDecoder) decode() ([][]*string, error) {
	if '[' != lcd.nextByteNonWhitespace() {
		return nil, lcd.mkError("expected chunk to begin with '['")
	}

	rows := make([][]*string, 0, lcd.rows)
	if ']' == lcd.nextByteNonWhitespace() {
		return rows, nil // special case of an empty chunk
	}
	lcd.rewind(1)

OuterLoop:
	for {
		row, err := lcd.decodeRow()
		if err != nil {
			return nil, err
		}
		rows = append(rows, row)

		switch c := lcd.nextByteNonWhitespace(); {
		case c == ',':
			continue // more elements in the array
		case c == ']':
			return rows, nil // we've scanned the whole chunk
		default:
			break OuterLoop
		}
	}
	return nil, lcd.mkError("invalid row boundary")
}

func (lcd *largeChunkDecoder) decodeRow() ([]*string, error) {
	if '[' != lcd.nextByteNonWhitespace() {
		return nil, lcd.mkError("expected row to begin with '['")
	}

	row := make([]*string, 0, lcd.cells)
	if ']' == lcd.nextByteNonWhitespace() {
		return row, nil // special case of an empty row
	}
	lcd.rewind(1)

OuterLoop:
	for {
		cell, err := lcd.decodeCell()
		if err != nil {
			return nil, err
		}
		row = append(row, cell)

		switch c := lcd.nextByteNonWhitespace(); {
		case c == ',':
			continue // more elements in the array
		case c == ']':
			return row, nil // we've scanned the whole row
		default:
			break OuterLoop
		}
	}
	return nil, lcd.mkError("invalid cell boundary")
}

func (lcd *largeChunkDecoder) decodeCell() (*string, error) {
	c := lcd.nextByteNonWhitespace()
	if c == '"' {
		s, err := lcd.decodeString()
		return &s, err
	} else if c == 'n' {
		if 'u' == lcd.nextByte() &&
			'l' == lcd.nextByte() &&
			'l' == lcd.nextByte() {
			return nil, nil
		}
	}
	return nil, lcd.mkError("cell begins with unexpected byte")
}

// TODO we can optimize this further by optimistically searching
// the read buffer for the next string. If it's short enough and
// doesn't contain any escaped characters, we can construct the
// return string directly without writing to the sbuf
func (lcd *largeChunkDecoder) decodeString() (string, error) {
	lcd.sbuf.Reset()
	for {
		// NOTE if you make changes here, ensure this
		// variable does not escape to the heap
		c := lcd.nextByte()
		if c == '"' {
			break
		} else if c == '\\' {
			if err := lcd.decodeEscaped(); err != nil {
				return "", err
			}
		} else if c < ' ' {
			return "", lcd.mkError("unexpected control character")
		} else if c < utf8.RuneSelf {
			lcd.sbuf.WriteByte(c)
		} else {
			lcd.rewind(1)
			lcd.sbuf.WriteRune(lcd.readRune())
		}
	}
	return lcd.sbuf.String(), nil
}

func (lcd *largeChunkDecoder) decodeEscaped() error {
	// NOTE if you make changes here, ensure this
	// variable does not escape to the heap
	c := lcd.nextByte()

	switch c {
	case '"', '\\', '/', '\'':
		lcd.sbuf.WriteByte(c)
	case 'b':
		lcd.sbuf.WriteByte('\b')
	case 'f':
		lcd.sbuf.WriteByte('\f')
	case 'n':
		lcd.sbuf.WriteByte('\n')
	case 'r':
		lcd.sbuf.WriteByte('\r')
	case 't':
		lcd.sbuf.WriteByte('\t')
	case 'u':
		rr := lcd.getu4()
		if rr < 0 {
			return lcd.mkError("invalid escape sequence")
		}
		if utf16.IsSurrogate(rr) {
			rr1, size := lcd.getu4WithPrefix()
			if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar {
				// A valid pair; consume.
				lcd.sbuf.WriteRune(dec)
				break
			}
			// Invalid surrogate; fall back to replacement rune.
			lcd.rewind(size)
			rr = unicode.ReplacementChar
		}
		lcd.sbuf.WriteRune(rr)
	default:
		return lcd.mkError("invalid escape sequence: " + string(c))
	}
	return nil
}

func (lcd *largeChunkDecoder) readRune() rune {
	lcd.ensureBytes(4)
	r, size := utf8.DecodeRune(lcd.rbuf[lcd.ptr:])
	lcd.ptr += size
	lcd.rem -= size
	return r
}

func (lcd *largeChunkDecoder) getu4WithPrefix() (rune, int) {
	lcd.ensureBytes(6)

	// NOTE take a snapshot of the cursor state. If this
	// is not a valid rune, then we need to roll back to
	// where we were before we began consuming bytes
	ptr := lcd.ptr

	if '\\' != lcd.nextByte() {
		return -1, lcd.ptr - ptr
	}
	if 'u' != lcd.nextByte() {
		return -1, lcd.ptr - ptr
	}
	r := lcd.getu4()
	return r, lcd.ptr - ptr
}

func (lcd *largeChunkDecoder) getu4() rune {
	var r rune
	for i := 0; i < 4; i++ {
		c := lcd.nextByte()
		switch {
		case '0' <= c && c <= '9':
			c = c - '0'
		case 'a' <= c && c <= 'f':
			c = c - 'a' + 10
		case 'A' <= c && c <= 'F':
			c = c - 'A' + 10
		default:
			return -1
		}
		r = r*16 + rune(c)
	}
	return r
}

func (lcd *largeChunkDecoder) nextByteNonWhitespace() byte {
	for {
		c := lcd.nextByte()
		switch c {
		case ' ', '\t', '\n', '\r':
			continue
		default:
			return c
		}
	}
}

func (lcd *largeChunkDecoder) rewind(n int) {
	lcd.ptr -= n
	lcd.rem += n
}

func (lcd *largeChunkDecoder) nextByte() byte {
	if lcd.rem == 0 {
		if lcd.ioError != nil {
			return 0
		}

		lcd.ptr = 0
		lcd.rem = lcd.fillBuffer(lcd.rbuf)
		if lcd.rem == 0 {
			return 0
		}
	}

	b := lcd.rbuf[lcd.ptr]
	lcd.ptr++

	lcd.rem--
	return b
}

func (lcd *largeChunkDecoder) ensureBytes(n int) {
	if lcd.rem <= n {
		rbuf := make([]byte, defaultChunkBufferSize)
		off := copy(rbuf, lcd.rbuf[lcd.ptr:lcd.ptr+lcd.rem])
		add := lcd.fillBuffer(rbuf[off:])

		lcd.ptr = 0
		lcd.rem += add
		lcd.rbuf = rbuf
	}
}

func (lcd *largeChunkDecoder) fillBuffer(b []byte) int {
	n, err := lcd.r.Read(b)
	if err != nil && err != io.EOF {
		lcd.ioError = err
		return 0
	} else if n <= 0 {
		lcd.ioError = io.EOF
		return 0
	}
	return n
}
<commit_msg>address comments<commit_after>package gosnowflake

import (
	"bytes"
	"fmt"
	"io"

	"unicode"
	"unicode/utf16"
	"unicode/utf8"
)

const (
	defaultChunkBufferSize  int64 = 8 << 10 // 8k
	defaultStringBufferSize int64 = 512
)

type largeChunkDecoder struct {
	r io.Reader

	rows  int // hint for number of rows
	cells int // hint for number of cells/row

	rem int // bytes remaining in rbuf
	ptr int // position in rbuf

	rbuf []byte
	sbuf *bytes.Buffer // buffer for decodeString

	ioError error
}

func decodeLargeChunk(r io.Reader, rowCount int, cellCount int) ([][]*string, error) {
	glog.V(2).Info("custom JSON Decoder")
	lcd := largeChunkDecoder{
		r, rowCount, cellCount,
		0, 0,
		make([]byte, defaultChunkBufferSize),
		bytes.NewBuffer(make([]byte, defaultStringBufferSize)),
		nil,
	}

	rows, err := lcd.decode()
	if lcd.ioError != nil && lcd.ioError != io.EOF {
		return nil, lcd.ioError
	} else if err != nil {
		return nil, err
	}

	return rows, nil
}

func (lcd *largeChunkDecoder) mkError(s string) error {
	return fmt.Errorf("corrupt chunk: %s", s)
}

func (lcd *largeChunkDecoder) decode() ([][]*string, error) {
	if '[' != lcd.nextByteNonWhitespace() {
		return nil, lcd.mkError("expected chunk to begin with '['")
	}

	rows := make([][]*string, 0, lcd.rows)
	if ']' == lcd.nextByteNonWhitespace() {
		return rows, nil // special case of an empty chunk
	}
	lcd.rewind(1)

OuterLoop:
	for {
		row, err := lcd.decodeRow()
		if err != nil {
			return nil, err
		}
		rows = append(rows, row)

		switch c := lcd.nextByteNonWhitespace(); {
		case c == ',':
			continue // more elements in the array
		case c == ']':
			return rows, nil // we've scanned the whole chunk
		default:
			break OuterLoop
		}
	}
	return nil, lcd.mkError("invalid row boundary")
}

func (lcd *largeChunkDecoder) decodeRow() ([]*string, error) {
	if '[' != lcd.nextByteNonWhitespace() {
		return nil, lcd.mkError("expected row to begin with '['")
	}

	row := make([]*string, 0, lcd.cells)
	if ']' == lcd.nextByteNonWhitespace() {
		return row, nil // special case of an empty row
	}
	lcd.rewind(1)

OuterLoop:
	for {
		cell, err := lcd.decodeCell()
		if err != nil {
			return nil, err
		}
		row = append(row, cell)

		switch c := lcd.nextByteNonWhitespace(); {
		case c == ',':
			continue // more elements in the array
		case c == ']':
			return row, nil // we've scanned the whole row
		default:
			break OuterLoop
		}
	}
	return nil, lcd.mkError("invalid cell boundary")
}

func (lcd *largeChunkDecoder) decodeCell() (*string, error) {
	c := lcd.nextByteNonWhitespace()
	if c == '"' {
		s, err := lcd.decodeString()
		return &s, err
	} else if c == 'n' {
		if 'u' == lcd.nextByte() &&
			'l' == lcd.nextByte() &&
			'l' == lcd.nextByte() {
			return nil, nil
		}
	}
	return nil, lcd.mkError("cell begins with unexpected byte")
}

// TODO we can optimize this further by optimistically searching
// the read buffer for the next string. If it's short enough and
// doesn't contain any escaped characters, we can construct the
// return string directly without writing to the sbuf
func (lcd *largeChunkDecoder) decodeString() (string, error) {
	lcd.sbuf.Reset()
	for {
		// NOTE if you make changes here, ensure this
		// variable does not escape to the heap
		c := lcd.nextByte()
		if c == '"' {
			break
		} else if c == '\\' {
			if err := lcd.decodeEscaped(); err != nil {
				return "", err
			}
		} else if c < ' ' {
			return "", lcd.mkError("unexpected control character")
		} else if c < utf8.RuneSelf {
			lcd.sbuf.WriteByte(c)
		} else {
			lcd.rewind(1)
			lcd.sbuf.WriteRune(lcd.readRune())
		}
	}
	return lcd.sbuf.String(), nil
}

func (lcd *largeChunkDecoder) decodeEscaped() error {
	// NOTE if you make changes here, ensure this
	// variable does not escape to the heap
	c := lcd.nextByte()

	switch c {
	case '"', '\\', '/', '\'':
		lcd.sbuf.WriteByte(c)
	case 'b':
		lcd.sbuf.WriteByte('\b')
	case 'f':
		lcd.sbuf.WriteByte('\f')
	case 'n':
		lcd.sbuf.WriteByte('\n')
	case 'r':
		lcd.sbuf.WriteByte('\r')
	case 't':
		lcd.sbuf.WriteByte('\t')
	case 'u':
		rr := lcd.getu4()
		if rr < 0 {
			return lcd.mkError("invalid escape sequence")
		}
		if utf16.IsSurrogate(rr) {
			rr1, size := lcd.getu4WithPrefix()
			if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar {
				// A valid pair; consume.
				lcd.sbuf.WriteRune(dec)
				break
			}
			// Invalid surrogate; fall back to replacement rune.
			lcd.rewind(size)
			rr = unicode.ReplacementChar
		}
		lcd.sbuf.WriteRune(rr)
	default:
		return lcd.mkError("invalid escape sequence: " + string(c))
	}
	return nil
}

func (lcd *largeChunkDecoder) readRune() rune {
	lcd.ensureBytes(4)
	r, size := utf8.DecodeRune(lcd.rbuf[lcd.ptr:])
	lcd.ptr += size
	lcd.rem -= size
	return r
}

func (lcd *largeChunkDecoder) getu4WithPrefix() (rune, int) {
	lcd.ensureBytes(6)

	// NOTE take a snapshot of the cursor state. If this
	// is not a valid rune, then we need to roll back to
	// where we were before we began consuming bytes
	ptr := lcd.ptr

	if '\\' != lcd.nextByte() {
		return -1, lcd.ptr - ptr
	}
	if 'u' != lcd.nextByte() {
		return -1, lcd.ptr - ptr
	}
	r := lcd.getu4()
	return r, lcd.ptr - ptr
}

func (lcd *largeChunkDecoder) getu4() rune {
	var r rune
	for i := 0; i < 4; i++ {
		c := lcd.nextByte()
		switch {
		case '0' <= c && c <= '9':
			c = c - '0'
		case 'a' <= c && c <= 'f':
			c = c - 'a' + 10
		case 'A' <= c && c <= 'F':
			c = c - 'A' + 10
		default:
			return -1
		}
		r = r*16 + rune(c)
	}
	return r
}

func (lcd *largeChunkDecoder) nextByteNonWhitespace() byte {
	for {
		c := lcd.nextByte()
		switch c {
		case ' ', '\t', '\n', '\r':
			continue
		default:
			return c
		}
	}
}

func (lcd *largeChunkDecoder) rewind(n int) {
	lcd.ptr -= n
	lcd.rem += n
}

func (lcd *largeChunkDecoder) nextByte() byte {
	if lcd.rem == 0 {
		if lcd.ioError != nil {
			return 0
		}

		lcd.ptr = 0
		lcd.rem = lcd.fillBuffer(lcd.rbuf)
		if lcd.rem == 0 {
			return 0
		}
	}

	b := lcd.rbuf[lcd.ptr]
	lcd.ptr++

	lcd.rem--
	return b
}

func (lcd *largeChunkDecoder) ensureBytes(n int) {
	if lcd.rem <= n {
		rbuf := make([]byte, defaultChunkBufferSize)
		// NOTE when the buffer reads from the stream, there's no
		// guarantee that it will actually be filled. As such we
		// must use (ptr+rem) to compute the end of the slice.
		off := copy(rbuf, lcd.rbuf[lcd.ptr:lcd.ptr+lcd.rem])
		add := lcd.fillBuffer(rbuf[off:])

		lcd.ptr = 0
		lcd.rem += add
		lcd.rbuf = rbuf
	}
}

func (lcd *largeChunkDecoder) fillBuffer(b []byte) int {
	n, err := lcd.r.Read(b)
	if err != nil && err != io.EOF {
		lcd.ioError = err
		return 0
	} else if n <= 0 {
		lcd.ioError = io.EOF
		return 0
	}
	return n
}
<|endoftext|>


<commit_before>package apphandler

import "encoding/json"

type IReq interface {
	//ToJson() ([]byte, error)

    // Not supported: no possible to store value as keys (like nosql data)
    // 	ToXml() ([]byte, error)
    // Cannot convert from
    // - map[string]interface{}
    // - map[string]Master
    // - map[string]string
    // these types is not supported in xml.Marshal
}

// IClerr - interface, like error but only for client error
// (opposite of server errors)
type IClerr interface {
	ToJson() ([]byte, error)
}

type Clerr struct {
	ErrKey string			`json:"errkey"`
	Details interface {}	`json:"details"`
}

func (clerr *Clerr) ToJson() ([]byte, error) {
    return json.Marshal(clerr)
}<commit_msg>fix(clerr): add Error method<commit_after>package apphandler

import "encoding/json"

type IReq interface {
	//ToJson() ([]byte, error)

    // Not supported: no possible to store value as keys (like nosql data)
    // 	ToXml() ([]byte, error)
    // Cannot convert from
    // - map[string]interface{}
    // - map[string]Master
    // - map[string]string
    // these types is not supported in xml.Marshal
}

// IClerr - interface, like error but only for client error
// (opposite of server errors)
type IClerr interface {
	ToJson() ([]byte, error)
}

type Clerr struct {
	ErrKey string			`json:"errkey"`
	Details interface {}	`json:"details"`
}

func (clerr Clerr) ToJson() ([]byte, error) {
    return json.Marshal(clerr)
}

func (clerr Clerr) Error() string {
	return "client error: " + clerr.ErrKey
}
<|endoftext|>


<commit_before>package main

import (
	"appengine"
	"appengine/datastore"
	"fmt"
	"time"
)

type Entry struct {
	Id       int64
	Title    string // optional
	Content  string // Markdown
	Datetime time.Time
	Created  time.Time
	Modified time.Time
	Tags     []string
	// TODO(icco): Define a meta field that is a json hash of extra data
}

func NewEntry(title string, content string, datetime time.Time, tags []string) *Entry {
	e := new(Entry)

	// User supplied content
	e.Title = title
	e.Content = content
	e.Datetime = datetime
	e.Tags = tags

	// Computer generated content
	e.Created = time.Now()
	e.Modified = time.Now()

	return e
}

func GetEntry(c appengine.Context, id int64) (*Entry, error) {
	var entry Entry
	q := datastore.NewQuery("Entry").Filter("Id =", id)
	_, err := q.Run(c).Next(&entry)
	if err != nil {
		c.Warningf("Error getting entry %d", id)
		return nil, err
	}
	return &entry, nil
}

func MaxId(c appengine.Context) (int64, error) {
	var entry Entry
	q := datastore.NewQuery("Entry").Order("-Id").Limit(1)
	_, err := q.Run(c).Next(&entry)
	if err != nil {
		return 0, err
	}
	return entry.Id, nil
}

func (e *Entry) hasId() bool {
	return (e.Id <= 0)
}

func (e *Entry) save(c appengine.Context) error {
	var k *datastore.Key
	if e.hasId() {
		id, err := MaxId(c)
		if err != nil {
			return err
		}
		e.Id = id + 1
		k = datastore.NewIncompleteKey(c, "Entry", nil)
	} else {
		k = datastore.NewKey(c, "Entry", fmt.Sprintf("%d", e.Id), 0, nil)
	}

	_, err := datastore.Put(c, k, e)
	return err
}
<commit_msg>logging<commit_after>package main

import (
	"appengine"
	"appengine/datastore"
	"fmt"
	"time"
)

type Entry struct {
	Id       int64
	Title    string // optional
	Content  string // Markdown
	Datetime time.Time
	Created  time.Time
	Modified time.Time
	Tags     []string
	// TODO(icco): Define a meta field that is a json hash of extra data
}

func NewEntry(title string, content string, datetime time.Time, tags []string) *Entry {
	e := new(Entry)

	// User supplied content
	e.Title = title
	e.Content = content
	e.Datetime = datetime
	e.Tags = tags

	// Computer generated content
	e.Created = time.Now()
	e.Modified = time.Now()

	return e
}

func GetEntry(c appengine.Context, id int64) (*Entry, error) {
	var entry Entry
	q := datastore.NewQuery("Entry").Filter("Id =", id)
	_, err := q.Run(c).Next(&entry)
	if err != nil {
		c.Warningf("Error getting entry %d", id)
		return nil, err
	}
	return &entry, nil
}

func MaxId(c appengine.Context) (int64, error) {
	var entry Entry
	q := datastore.NewQuery("Entry").Order("-Id").Limit(1)
	_, err := q.Run(c).Next(&entry)
	if err != nil {
		return 0, err
	}
	return entry.Id, nil
}

func (e *Entry) hasId() bool {
	return (e.Id <= 0)
}

func (e *Entry) save(c appengine.Context) error {
	var k *datastore.Key
	if e.hasId() {
		id, err := MaxId(c)
		if err != nil {
			return err
		}
		e.Id = id + 1
		k = datastore.NewIncompleteKey(c, "Entry", nil)
	} else {
		k = datastore.NewKey(c, "Entry", fmt.Sprintf("%d", e.Id), 0, nil)
	}

	_, err := datastore.Put(c, k, e)
	if err == nil {
		c.Infof("Wrote %+v", e)
	} else {
		c.Warningf("Error writing entry: %v", e)
	}
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"io"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/dustin/seriesly/timelib"
)

var min = flag.String("min", "", "minimum timestamp (RFC3339)")

func maybeFatal(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func setupDb(u string) {
	req, err := http.NewRequest("PUT", u, nil)
	maybeFatal(err)
	res, err := http.DefaultClient.Do(req)
	maybeFatal(err)
	res.Body.Close()
}

func sendOne(u, k string, body []byte) {
	resp, err := http.DefaultClient.Post(u+"?ts="+k,
		"application/json", bytes.NewReader(body))
	maybeFatal(err)
	defer resp.Body.Close()
	if resp.StatusCode >= 300 || resp.StatusCode < 200 {
		log.Fatalf("HTTP Error on %v: %v", k, err)
	}
}

func parseMinTime() time.Time {
	tm, err := timelib.ParseTime(*min)
	if err != nil {
		tm = time.Time{}
	}
	return tm
}

func main() {
	flag.Parse()

	if flag.NArg() < 1 {
		log.Fatalf("Usage:  gzip -dc backup.gz | %v http://seriesly:3133/dbname",
			os.Args[0])
	}
	u := flag.Arg(0)
	setupDb(u)

	minTime := parseMinTime()

	t := time.Tick(5 * time.Second)
	i := 0

	d := json.NewDecoder(os.Stdin)
	for {
		kv := map[string]*json.RawMessage{}

		err := d.Decode(&kv)
		if err == io.EOF {
			log.Printf("Done!")
			break
		}
		maybeFatal(err)

		var latestKey string
		for k, v := range kv {
			if !minTime.IsZero() {
				thist, err := timelib.ParseTime(k)
				if err == nil && minTime.After(thist) {
					continue
				}
			}
			body := []byte(*v)
			sendOne(u, k, body)
			latestKey = k
		}

		i++
		select {
		case <-t:
			log.Printf("Processed %v items, latest was %v", i, latestKey)
		default:
		}
	}
}
<commit_msg>Track seriesly restores<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"io"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/dustin/httputil"
	"github.com/dustin/seriesly/timelib"
)

var min = flag.String("min", "", "minimum timestamp (RFC3339)")

func maybeFatal(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func setupDb(u string) {
	req, err := http.NewRequest("PUT", u, nil)
	maybeFatal(err)
	res, err := http.DefaultClient.Do(req)
	maybeFatal(err)
	res.Body.Close()
}

func sendOne(u, k string, body []byte) {
	resp, err := http.DefaultClient.Post(u+"?ts="+k,
		"application/json", bytes.NewReader(body))
	maybeFatal(err)
	defer resp.Body.Close()
	if resp.StatusCode >= 300 || resp.StatusCode < 200 {
		log.Fatalf("HTTP Error on %v: %v", k, err)
	}
}

func parseMinTime() time.Time {
	tm, err := timelib.ParseTime(*min)
	if err != nil {
		tm = time.Time{}
	}
	return tm
}

func main() {
	flag.Parse()

	if flag.NArg() < 1 {
		log.Fatalf("Usage:  gzip -dc backup.gz | %v http://seriesly:3133/dbname",
			os.Args[0])
	}

	httputil.InitHTTPTracker(false)

	u := flag.Arg(0)
	setupDb(u)

	minTime := parseMinTime()

	t := time.Tick(5 * time.Second)
	i := 0

	d := json.NewDecoder(os.Stdin)
	for {
		kv := map[string]*json.RawMessage{}

		err := d.Decode(&kv)
		if err == io.EOF {
			log.Printf("Done!")
			break
		}
		maybeFatal(err)

		var latestKey string
		for k, v := range kv {
			if !minTime.IsZero() {
				thist, err := timelib.ParseTime(k)
				if err == nil && minTime.After(thist) {
					continue
				}
			}
			body := []byte(*v)
			sendOne(u, k, body)
			latestKey = k
		}

		i++
		select {
		case <-t:
			log.Printf("Processed %v items, latest was %v", i, latestKey)
		default:
		}
	}
}
<|endoftext|>


<commit_before>// clock counts down to or up from a target time.
package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	target := time.Date(2016, 8, 25, 20, 57, 8, 0, time.UTC)
	motto := "Simplify"
	printTargetTime(target, motto)
	exitOnEnterKey()

	var previous time.Time
	for {
		now := time.Now()
		now = now.Add(time.Duration(-now.Nanosecond())) // truncate to second
		if now != previous {
			previous = now
			remaining := target.Sub(now)
			printTimeRemaining(now, remaining)
		}
		time.Sleep(50 * time.Millisecond)
	}
}

func exitOnEnterKey() {
	go func() {
		buf := make([]byte, 1)
		_, _ = os.Stdin.Read(buf)
		os.Exit(0)
	}()
}

const (
	indent         = "\t"
	highlightStart = "\x1b[1;35m"
	highlightEnd   = "\x1b[0m"
)

func printTargetTime(target time.Time, motto string) {
	fmt.Print(indent, highlightStart, motto, highlightEnd, "\n")
	fmt.Print(indent, target.Format(time.UnixDate), "\n")
}

func printTimeRemaining(now time.Time, remaining time.Duration) {
	var sign string
	if remaining > 0 {
		sign = "-" // countdown is "T minus..."
	} else {
		sign = "+" // count up is "T plus..."
		remaining = -remaining
	}

	var days int
	if remaining >= 24*time.Hour {
		days = int(remaining / (24 * time.Hour))
		remaining = remaining % (24 * time.Hour)
	}

	fmt.Print(indent, now.Format(time.UnixDate), "  ", sign)
	if days > 0 {
		fmt.Print(days, "d")
	}
	fmt.Print(remaining, "          \r")
	os.Stdout.Sync()
}
<commit_msg>Late Summer Bank Holiday<commit_after>// clock counts down to or up from a target time.
package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	target := time.Date(2016, 8, 29, 20, 0, 0, 0, time.Local)
	motto := "Simplify"
	printTargetTime(target, motto)
	exitOnEnterKey()

	var previous time.Time
	for {
		now := time.Now()
		now = now.Add(time.Duration(-now.Nanosecond())) // truncate to second
		if now != previous {
			previous = now
			remaining := target.Sub(now)
			printTimeRemaining(now, remaining)
		}
		time.Sleep(50 * time.Millisecond)
	}
}

func exitOnEnterKey() {
	go func() {
		buf := make([]byte, 1)
		_, _ = os.Stdin.Read(buf)
		os.Exit(0)
	}()
}

const (
	indent         = "\t"
	highlightStart = "\x1b[1;35m"
	highlightEnd   = "\x1b[0m"
)

func printTargetTime(target time.Time, motto string) {
	fmt.Print(indent, highlightStart, motto, highlightEnd, "\n")
	fmt.Print(indent, target.Format(time.UnixDate), "\n")
}

func printTimeRemaining(now time.Time, remaining time.Duration) {
	var sign string
	if remaining > 0 {
		sign = "-" // countdown is "T minus..."
	} else {
		sign = "+" // count up is "T plus..."
		remaining = -remaining
	}

	var days int
	if remaining >= 24*time.Hour {
		days = int(remaining / (24 * time.Hour))
		remaining = remaining % (24 * time.Hour)
	}

	fmt.Print(indent, now.Format(time.UnixDate), "  ", sign)
	if days > 0 {
		fmt.Print(days, "d")
	}
	fmt.Print(remaining, "          \r")
	os.Stdout.Sync()
}
<|endoftext|>


<commit_before>// Copyright 2016 Sam Dukhovni <dukhovni@mit.edu>
//
// Adapted from clyde.pl by cat@mit.edu
//
// Licensed under the MIT License
// (https://opensource.org/licenses/MIT)
//
// Some code snippets copied from the zephyr-go library
// (https://github.com/zephyr-im/zephyr-go), (c) 2014 The zephyr-go
// authors, licensed under the Apache License, Version 2.0
// (http://www.apache.org/licenses/LICENSE-2.0)
//
//
// clyde is a markov-chain-based zephyr chatbot; this library defines
// structures and methods for running an instance of clyde.

package clyde

import (
	"strings"
	"log"
	"time"
	"path"
	"os"
	"encoding/json"
	"github.com/zephyr-im/krb5-go"
	"github.com/zephyr-im/zephyr-go"
	"github.com/sdukhovni/clyde-go/markov"
)

type ClassPolicy uint8

const (
	LISTEN ClassPolicy = 1
	REPLYHOME ClassPolicy = 2
	FULL ClassPolicy = 3
)

// Clyde (the struct) holds all of the internal state needed for Clyde
// (the zephyrbot) to send and receive zephyrs, generate text, and
// load/save persistent state data.
type Clyde struct {
	Chain *markov.Chain
	homeDir string
	session *zephyr.Session
	ctx *krb5.Context
	subs map[string]ClassPolicy
}

// LoadClyde initializes a Clyde by loading data files found in the
// given directory, returning an error if the directory does not
// exist and cannot be created.
func LoadClyde(dir string) (*Clyde, error) {
	err := os.MkdirAll(dir, 0755)
	if err != nil {
		return nil, err
	}

	c := &Clyde{}

	c.homeDir = dir

	// Set up zephyr session
	c.session, err = zephyr.DialSystemDefault()
	if err != nil {
		return nil, err
	}

	// Create krb5 context for subscriptions
	c.ctx, err = krb5.NewContext()
	if err != nil {
		return nil, err
	}

	// Create markov chain, and try to load saved chain
	c.Chain = markov.NewChain(prefixLen)
	err = c.Chain.Load(c.Path(chainFile))
	if err != nil && !os.IsNotExist(err) {
		return nil, err
	}

	c.session.SendSubscribeNoDefaults(c.ctx, []zephyr.Subscription{{Class: homeClass, Instance: homeInstance, Recipient: ""}})
	c.subs = make(map[string]ClassPolicy)
	err = c.LoadSubs()
	if err != nil && !os.IsNotExist(err) {
		return nil, err
	}

	return c, nil
}

// Listen receives and handles zephyrs on classes Clyde is subscribed
// to, and never returns until Clyde is shut down.
func (c *Clyde) Listen() {
	for r := range c.session.Messages() {
		c.handleMessage(r)
	}
}

// Subscribe subscribes Clyde to a new zephyr class.
func (c *Clyde) Subscribe(class string, policy ClassPolicy) {
	if c.subs[class] != 0 {
		return
	}
	c.session.SendSubscribeNoDefaults(c.ctx, []zephyr.Subscription{{Class: class, Instance: "*", Recipient: ""}})
	c.subs[class] = policy
}

// Send sends a zephyr from Clyde with the given body to the given
// class and instance.
func (c *Clyde) Send(class, instance, body string) {
	uid := c.session.MakeUID(time.Now())
	msg := &zephyr.Message{
		Header: zephyr.Header{
			Kind:	zephyr.ACKED,
			UID:	uid,
			Port:	c.session.Port(),
			Class:	class, Instance: instance, OpCode: "",
			Sender:		sender,
			Recipient:	"",
			DefaultFormat:	"http://mit.edu/df/",
			SenderAddress:	c.session.LocalAddr().IP,
			Charset:	zephyr.CharsetUTF8,
			OtherFields:	nil,
		},
		Body: []string{zsig, body},
	}
	_, err := c.session.SendMessageUnauth(msg)
	if err != nil {
		log.Printf("Send error: %v", err)
	}
}

// Shutdown saves Clyde's persistent state to Clyde's home directory,
// closes Clyde's zephyr session, and performs any necessary cleanup
// for Clyde to shut down. Any program that uses a Clyde must call
// this method to cleanly shutdown Clyde before exiting.
func (c *Clyde) Shutdown() error {
	var err error

	err = c.Chain.Save(c.Path(chainFile))
	if err != nil {
		return err
	}

	err = c.SaveSubs()
	if err != nil {
		return err
	}

	_, err = c.session.SendCancelSubscriptions(c.ctx)
	if err != nil {
		return err
	}

	c.ctx.Free()

	err = c.session.Close()
	if err != nil {
		return err
	}

	return nil
}

func (c *Clyde) Path(filename string) string {
	return path.Join(c.homeDir, filename)
}

const homeClass = "ztoys-dev"
const homeInstance = "clyde"

const chainFile = "chain.json"
const subsFile = "subs.json"

const sender = "clyde"
const zsig = "Clyde"
const prefixLen = 2

func (c *Clyde) handleMessage(r zephyr.MessageReaderResult) {
	// Ignore our own messages
	if r.Message.Header.Sender == sender {
		return
	}

	c.Chain.Build(strings.NewReader(r.Message.Body[1]))

	// Perform the first behavior that triggers, and exit
	for _, b := range Behaviors {
		if b(c, r) {
			return
		}
	}
}

// LoadSubs attempts to load and subscribe to a list of subscriptions
// in JSON format from a file in Clyde's home directory.
func (c *Clyde) LoadSubs() error {
	f, err := os.Open(c.Path(subsFile))
	if err != nil {
		return err
	}
	defer f.Close()

	dec := json.NewDecoder(f)
	err = dec.Decode(&(c.subs))
	if err != nil {
		return err
	}

	var subList []zephyr.Subscription
	for class, policy := range c.subs {
		if policy != 0 {
			subList = append(subList, zephyr.Subscription{Class: class, Instance: "*", Recipient: ""})
		}
	}

	c.session.SendSubscribeNoDefaults(c.ctx, subList)

	return nil
}

// SaveSubs saves Clyde's subscriptions to a file in JSON format in
// Clyde's home directory.
func (c *Clyde) SaveSubs() error {
	f, err := os.Create(c.Path(subsFile))
	if err != nil {
		return err
	}
	defer f.Close()

	enc := json.NewEncoder(f)
	err = enc.Encode(c.subs)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Generate zsigs with chainer too<commit_after>// Copyright 2016 Sam Dukhovni <dukhovni@mit.edu>
//
// Adapted from clyde.pl by cat@mit.edu
//
// Licensed under the MIT License
// (https://opensource.org/licenses/MIT)
//
// Some code snippets copied from the zephyr-go library
// (https://github.com/zephyr-im/zephyr-go), (c) 2014 The zephyr-go
// authors, licensed under the Apache License, Version 2.0
// (http://www.apache.org/licenses/LICENSE-2.0)
//
//
// clyde is a markov-chain-based zephyr chatbot; this library defines
// structures and methods for running an instance of clyde.

package clyde

import (
	"strings"
	"log"
	"time"
	"math/rand"
	"path"
	"os"
	"encoding/json"
	"github.com/zephyr-im/krb5-go"
	"github.com/zephyr-im/zephyr-go"
	"github.com/sdukhovni/clyde-go/markov"
)

type ClassPolicy uint8

const (
	LISTEN ClassPolicy = 1
	REPLYHOME ClassPolicy = 2
	FULL ClassPolicy = 3
)

// Clyde (the struct) holds all of the internal state needed for Clyde
// (the zephyrbot) to send and receive zephyrs, generate text, and
// load/save persistent state data.
type Clyde struct {
	Chain *markov.Chain
	zsigChain *markov.Chain
	homeDir string
	session *zephyr.Session
	ctx *krb5.Context
	subs map[string]ClassPolicy
}

// LoadClyde initializes a Clyde by loading data files found in the
// given directory, returning an error if the directory does not
// exist and cannot be created.
func LoadClyde(dir string) (*Clyde, error) {
	err := os.MkdirAll(dir, 0755)
	if err != nil {
		return nil, err
	}

	c := &Clyde{}

	c.homeDir = dir

	// Set up zephyr session
	c.session, err = zephyr.DialSystemDefault()
	if err != nil {
		return nil, err
	}

	// Create krb5 context for subscriptions
	c.ctx, err = krb5.NewContext()
	if err != nil {
		return nil, err
	}

	// Create markov chain, and try to load saved chain
	c.Chain = markov.NewChain(prefixLen)
	err = c.Chain.Load(c.Path(chainFile))
	if err != nil && !os.IsNotExist(err) {
		return nil, err
	}

	// Create zsig markov chain, and try to load saved chain
	c.zsigChain = markov.NewChain(zsigPrefixLen)
	err = c.zsigChain.Load(c.Path(zsigChainFile))
	if err != nil && !os.IsNotExist(err) {
		return nil, err
	}

	c.session.SendSubscribeNoDefaults(c.ctx, []zephyr.Subscription{{Class: homeClass, Instance: homeInstance, Recipient: ""}})
	c.subs = make(map[string]ClassPolicy)
	err = c.LoadSubs()
	if err != nil && !os.IsNotExist(err) {
		return nil, err
	}

	return c, nil
}

// Listen receives and handles zephyrs on classes Clyde is subscribed
// to, and never returns until Clyde is shut down.
func (c *Clyde) Listen() {
	for r := range c.session.Messages() {
		c.handleMessage(r)
	}
}

// Subscribe subscribes Clyde to a new zephyr class.
func (c *Clyde) Subscribe(class string, policy ClassPolicy) {
	if c.subs[class] != 0 {
		return
	}
	c.session.SendSubscribeNoDefaults(c.ctx, []zephyr.Subscription{{Class: class, Instance: "*", Recipient: ""}})
	c.subs[class] = policy
}

// Send sends a zephyr from Clyde with the given body to the given
// class and instance.
func (c *Clyde) Send(class, instance, body string) {
	uid := c.session.MakeUID(time.Now())
	zsig := c.zsigChain.Generate("", 1, rand.Intn(6)+2)
	msg := &zephyr.Message{
		Header: zephyr.Header{
			Kind:	zephyr.ACKED,
			UID:	uid,
			Port:	c.session.Port(),
			Class:	class, Instance: instance, OpCode: "",
			Sender:		sender,
			Recipient:	"",
			DefaultFormat:	"http://mit.edu/df/",
			SenderAddress:	c.session.LocalAddr().IP,
			Charset:	zephyr.CharsetUTF8,
			OtherFields:	nil,
		},
		Body: []string{zsig, body},
	}
	_, err := c.session.SendMessageUnauth(msg)
	if err != nil {
		log.Printf("Send error: %v", err)
	}
}

// Shutdown saves Clyde's persistent state to Clyde's home directory,
// closes Clyde's zephyr session, and performs any necessary cleanup
// for Clyde to shut down. Any program that uses a Clyde must call
// this method to cleanly shutdown Clyde before exiting.
func (c *Clyde) Shutdown() error {
	var err error

	err = c.Chain.Save(c.Path(chainFile))
	if err != nil {
		return err
	}

	err = c.zsigChain.Save(c.Path(zsigChainFile))
	if err != nil {
		return err
	}

	err = c.SaveSubs()
	if err != nil {
		return err
	}

	_, err = c.session.SendCancelSubscriptions(c.ctx)
	if err != nil {
		return err
	}

	c.ctx.Free()

	err = c.session.Close()
	if err != nil {
		return err
	}

	return nil
}

func (c *Clyde) Path(filename string) string {
	return path.Join(c.homeDir, filename)
}

const homeClass = "ztoys-dev"
const homeInstance = "clyde"

const chainFile = "chain.json"
const zsigChainFile = "zsigChain.json"
const subsFile = "subs.json"

const sender = "clyde"
const prefixLen = 2
const zsigPrefixLen = 1 // Be more creative with less input data

func (c *Clyde) handleMessage(r zephyr.MessageReaderResult) {
	// Ignore our own messages
	if r.Message.Header.Sender == sender {
		return
	}

	c.Chain.Build(strings.NewReader(r.Message.Body[1]))
	c.zsigChain.Build(strings.NewReader(r.Message.Body[0]))

	// Perform the first behavior that triggers, and exit
	for _, b := range Behaviors {
		if b(c, r) {
			return
		}
	}
}

// LoadSubs attempts to load and subscribe to a list of subscriptions
// in JSON format from a file in Clyde's home directory.
func (c *Clyde) LoadSubs() error {
	f, err := os.Open(c.Path(subsFile))
	if err != nil {
		return err
	}
	defer f.Close()

	dec := json.NewDecoder(f)
	err = dec.Decode(&(c.subs))
	if err != nil {
		return err
	}

	var subList []zephyr.Subscription
	for class, policy := range c.subs {
		if policy != 0 {
			subList = append(subList, zephyr.Subscription{Class: class, Instance: "*", Recipient: ""})
		}
	}

	c.session.SendSubscribeNoDefaults(c.ctx, subList)

	return nil
}

// SaveSubs saves Clyde's subscriptions to a file in JSON format in
// Clyde's home directory.
func (c *Clyde) SaveSubs() error {
	f, err := os.Create(c.Path(subsFile))
	if err != nil {
		return err
	}
	defer f.Close()

	enc := json.NewEncoder(f)
	err = enc.Encode(c.subs)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package triplestore

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"sync"
)

type Encoder interface {
	Encode(tris ...Triple) error
}

type Decoder interface {
	Decode() ([]Triple, error)
}

type datasetDecoder struct {
	newDecoderFunc func(io.Reader) Decoder
	rs             []io.Reader
}

func NewDatasetDecoder(fn func(io.Reader) Decoder, readers ...io.Reader) Decoder {
	return &datasetDecoder{newDecoderFunc: fn, rs: readers}
}

func (dec *datasetDecoder) Decode() ([]Triple, error) {
	type result struct {
		err  error
		tris []Triple
	}

	results := make(chan *result, len(dec.rs))
	done := make(chan struct{})
	defer close(done)

	var wg sync.WaitGroup
	for _, reader := range dec.rs {
		wg.Add(1)
		go func(r io.Reader) {
			defer wg.Done()
			tris, err := dec.newDecoderFunc(r).Decode()
			select {
			case results <- &result{tris: tris, err: err}:
			case <-done:
				return
			}
		}(reader)
	}

	go func() {
		wg.Wait()
		close(results)
	}()

	var all []Triple
	for r := range results {
		if r.err != nil {
			return all, r.err
		}
		all = append(all, r.tris...)
	}

	return all, nil
}

type binaryEncoder struct {
	w io.Writer
}

type wordLength uint32

const (
	resourceTypeEncoding = uint8(0)
	literalTypeEncoding  = uint8(1)
)

func NewBinaryEncoder(w io.Writer) Encoder {
	return &binaryEncoder{w}
}

func (enc *binaryEncoder) Encode(tris ...Triple) error {
	for _, t := range tris {
		b, err := encodeTriple(t)
		if err != nil {
			return err
		}

		if _, err := enc.w.Write(b); err != nil {
			return err
		}
	}

	return nil
}

func encodeTriple(t Triple) ([]byte, error) {
	sub, pred := t.Subject(), t.Predicate()

	var buff bytes.Buffer

	binary.Write(&buff, binary.BigEndian, wordLength(len(sub)))
	buff.WriteString(sub)

	binary.Write(&buff, binary.BigEndian, wordLength(len(pred)))
	buff.WriteString(pred)

	obj := t.Object()
	if lit, isLit := obj.Literal(); isLit {
		binary.Write(&buff, binary.BigEndian, literalTypeEncoding)
		typ := lit.Type()
		binary.Write(&buff, binary.BigEndian, wordLength(len(typ)))
		buff.WriteString(string(typ))

		litVal := lit.Value()
		binary.Write(&buff, binary.BigEndian, wordLength(len(litVal)))
		buff.WriteString(litVal)
	} else {
		binary.Write(&buff, binary.BigEndian, resourceTypeEncoding)
		resID, _ := obj.ResourceID()
		binary.Write(&buff, binary.BigEndian, wordLength(len(resID)))
		buff.WriteString(resID)
	}

	return buff.Bytes(), nil
}

type binaryDecoder struct {
	r       io.Reader
	triples []Triple
}

func NewBinaryDecoder(r io.Reader) Decoder {
	return &binaryDecoder{r: r}
}

func (dec *binaryDecoder) Decode() ([]Triple, error) {
	for {
		done, err := dec.decodeTriple()
		if done {
			break
		} else if err != nil {
			return nil, err
		}
	}

	return dec.triples, nil
}

func (dec *binaryDecoder) decodeTriple() (bool, error) {
	sub, err := dec.readWord()
	if err == io.EOF {
		return true, nil
	} else if err != nil {
		return false, fmt.Errorf("subject: %s", err)
	}

	pred, err := dec.readWord()
	if err != nil {
		return false, fmt.Errorf("predicate: %s", err)
	}

	var objType uint8
	if err := binary.Read(dec.r, binary.BigEndian, &objType); err != nil {
		return false, fmt.Errorf("object type: %s", err)
	}

	var decodedObj object
	if objType == resourceTypeEncoding {
		resource, err := dec.readWord()
		if err != nil {
			return false, fmt.Errorf("resource: %s", err)
		}
		decodedObj.resourceID = string(resource)

	} else {
		decodedObj.isLit = true
		var decodedLiteral literal

		litType, err := dec.readWord()
		if err != nil {
			return false, fmt.Errorf("literate type: %s", err)
		}
		decodedLiteral.typ = XsdType(litType)

		val, err := dec.readWord()
		if err != nil {
			return false, fmt.Errorf("literate: %s", err)
		}

		decodedLiteral.val = string(val)
		decodedObj.lit = decodedLiteral
	}

	dec.triples = append(dec.triples, &triple{
		sub:  subject(string(sub)),
		pred: predicate(string(pred)),
		obj:  decodedObj,
	})

	return false, nil
}

func (dec *binaryDecoder) readWord() ([]byte, error) {
	var len wordLength
	if err := binary.Read(dec.r, binary.BigEndian, &len); err != nil {
		return nil, err
	}

	word := make([]byte, len)
	if _, err := io.ReadFull(dec.r, word); err != nil {
		return nil, errors.New("triplestore: binary: cannot decode word")
	}

	return word, nil
}

type ntriplesEncoder struct {
	w io.Writer
}

func NewNTriplesEncoder(w io.Writer) Encoder {
	return &ntriplesEncoder{w}
}

func (enc *ntriplesEncoder) Encode(tris ...Triple) error {
	var buff bytes.Buffer
	for _, t := range tris {
		buff.WriteString(fmt.Sprintf("<%s> <%s> ", t.Subject(), t.Predicate()))
		if rid, ok := t.Object().ResourceID(); ok {
			buff.WriteString(fmt.Sprintf("<%s>", rid))
		}
		if lit, ok := t.Object().Literal(); ok {
			var namespace string
			switch lit.Type() {
			case XsdString:
				// namespace empty as per spec
			default:
				namespace = lit.Type().NTriplesNamespaced()
			}

			buff.WriteString(fmt.Sprintf("\"%s\"%s", lit.Value(), namespace))
		}
		buff.WriteString(" .\n")
	}

	_, err := enc.w.Write(buff.Bytes())
	return err
}
<commit_msg>Better display parsing errors<commit_after>package triplestore

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"os"
	"sync"
)

type Encoder interface {
	Encode(tris ...Triple) error
}

type Decoder interface {
	Decode() ([]Triple, error)
}

type datasetDecoder struct {
	newDecoderFunc func(io.Reader) Decoder
	rs             []io.Reader
}

func NewDatasetDecoder(fn func(io.Reader) Decoder, readers ...io.Reader) Decoder {
	return &datasetDecoder{newDecoderFunc: fn, rs: readers}
}

func (dec *datasetDecoder) Decode() ([]Triple, error) {
	type result struct {
		err    error
		tris   []Triple
		reader io.Reader
	}

	results := make(chan *result, len(dec.rs))
	done := make(chan struct{})
	defer close(done)

	var wg sync.WaitGroup
	for _, reader := range dec.rs {
		wg.Add(1)
		go func(r io.Reader) {
			defer wg.Done()
			tris, err := dec.newDecoderFunc(r).Decode()
			select {
			case results <- &result{tris: tris, err: err, reader: r}:
			case <-done:
				return
			}
		}(reader)
	}

	go func() {
		wg.Wait()
		close(results)
	}()

	var all []Triple
	for r := range results {
		if r.err != nil {
			switch rr := r.reader.(type) {
			case *os.File:
				return all, fmt.Errorf("file '%s': %s", rr.Name(), r.err)
			default:
				return all, r.err
			}
		}
		all = append(all, r.tris...)
	}

	return all, nil
}

type binaryEncoder struct {
	w io.Writer
}

type wordLength uint32

const (
	resourceTypeEncoding = uint8(0)
	literalTypeEncoding  = uint8(1)
)

func NewBinaryEncoder(w io.Writer) Encoder {
	return &binaryEncoder{w}
}

func (enc *binaryEncoder) Encode(tris ...Triple) error {
	for _, t := range tris {
		b, err := encodeTriple(t)
		if err != nil {
			return err
		}

		if _, err := enc.w.Write(b); err != nil {
			return err
		}
	}

	return nil
}

func encodeTriple(t Triple) ([]byte, error) {
	sub, pred := t.Subject(), t.Predicate()

	var buff bytes.Buffer

	binary.Write(&buff, binary.BigEndian, wordLength(len(sub)))
	buff.WriteString(sub)

	binary.Write(&buff, binary.BigEndian, wordLength(len(pred)))
	buff.WriteString(pred)

	obj := t.Object()
	if lit, isLit := obj.Literal(); isLit {
		binary.Write(&buff, binary.BigEndian, literalTypeEncoding)
		typ := lit.Type()
		binary.Write(&buff, binary.BigEndian, wordLength(len(typ)))
		buff.WriteString(string(typ))

		litVal := lit.Value()
		binary.Write(&buff, binary.BigEndian, wordLength(len(litVal)))
		buff.WriteString(litVal)
	} else {
		binary.Write(&buff, binary.BigEndian, resourceTypeEncoding)
		resID, _ := obj.ResourceID()
		binary.Write(&buff, binary.BigEndian, wordLength(len(resID)))
		buff.WriteString(resID)
	}

	return buff.Bytes(), nil
}

type binaryDecoder struct {
	r       io.Reader
	triples []Triple
}

func NewBinaryDecoder(r io.Reader) Decoder {
	return &binaryDecoder{r: r}
}

func (dec *binaryDecoder) Decode() ([]Triple, error) {
	for {
		done, err := dec.decodeTriple()
		if done {
			break
		} else if err != nil {
			return nil, err
		}
	}

	return dec.triples, nil
}

func (dec *binaryDecoder) decodeTriple() (bool, error) {
	sub, err := dec.readWord()
	if err == io.EOF {
		return true, nil
	} else if err != nil {
		return false, fmt.Errorf("subject: %s", err)
	}

	pred, err := dec.readWord()
	if err != nil {
		return false, fmt.Errorf("predicate: %s", err)
	}

	var objType uint8
	if err := binary.Read(dec.r, binary.BigEndian, &objType); err != nil {
		return false, fmt.Errorf("object type: %s", err)
	}

	var decodedObj object
	if objType == resourceTypeEncoding {
		resource, err := dec.readWord()
		if err != nil {
			return false, fmt.Errorf("resource: %s", err)
		}
		decodedObj.resourceID = string(resource)

	} else {
		decodedObj.isLit = true
		var decodedLiteral literal

		litType, err := dec.readWord()
		if err != nil {
			return false, fmt.Errorf("literate type: %s", err)
		}
		decodedLiteral.typ = XsdType(litType)

		val, err := dec.readWord()
		if err != nil {
			return false, fmt.Errorf("literate: %s", err)
		}

		decodedLiteral.val = string(val)
		decodedObj.lit = decodedLiteral
	}

	dec.triples = append(dec.triples, &triple{
		sub:  subject(string(sub)),
		pred: predicate(string(pred)),
		obj:  decodedObj,
	})

	return false, nil
}

func (dec *binaryDecoder) readWord() ([]byte, error) {
	var len wordLength
	if err := binary.Read(dec.r, binary.BigEndian, &len); err != nil {
		return nil, err
	}

	word := make([]byte, len)
	if _, err := io.ReadFull(dec.r, word); err != nil {
		return nil, fmt.Errorf("triplestore: binary: cannot decode word of length %d bytes: %s", len, err)
	}

	return word, nil
}

type ntriplesEncoder struct {
	w io.Writer
}

func NewNTriplesEncoder(w io.Writer) Encoder {
	return &ntriplesEncoder{w}
}

func (enc *ntriplesEncoder) Encode(tris ...Triple) error {
	var buff bytes.Buffer
	for _, t := range tris {
		buff.WriteString(fmt.Sprintf("<%s> <%s> ", t.Subject(), t.Predicate()))
		if rid, ok := t.Object().ResourceID(); ok {
			buff.WriteString(fmt.Sprintf("<%s>", rid))
		}
		if lit, ok := t.Object().Literal(); ok {
			var namespace string
			switch lit.Type() {
			case XsdString:
				// namespace empty as per spec
			default:
				namespace = lit.Type().NTriplesNamespaced()
			}

			buff.WriteString(fmt.Sprintf("\"%s\"%s", lit.Value(), namespace))
		}
		buff.WriteString(" .\n")
	}

	_, err := enc.w.Write(buff.Bytes())
	return err
}
<|endoftext|>


<commit_before>package rest

import (
	"encoding/json"
	"mime"
	"strings"
)

// JSON позволяет быстро описать данные в одноименном формате.
type JSON map[string]interface{}

// Coder описывает интерфейс для поддержки разбора запроса и кодирования ответа.
type Coder interface {
	Bind(*Context, interface{}) error
	Encode(*Context, interface{}) error
}

// JSONCoder осуществляет разбор запроса и кодирование ответа в формате JSON.
type JSONCoder struct {
	MaxBody int64 // максимально допустимый размер запроса
	Indent  bool  // флаг форматированного вывода  JSON
}

// NewJSONCoder возвращает новый инициализированный Coder, поддерживающий
// формат JSON.
func NewJSONCoder(maxSize int64, indent bool) *JSONCoder {
	return &JSONCoder{MaxBody: maxSize, Indent: indent}
}

// Bind разбирает данные запроса в формате JSON и заполняет ими указанный в
// параметре объект.
//
// Если Content-Type запроса не соответствует "application/json", то
// возвращается ошибка ErrUnsupportedMediaType. Так же может возвращать ошибку
// ErrLengthRequired, если не указана длина запроса, ErrRequestEntityTooLarge —
// если запрос превышает значение MaxBody, и ErrBadRequest — если не смогли
// разобрать запрос и поместить результат разбора в объект obj. Все эти ошибки
// поддерживаются методом Send и отдают соответствующий статус ответа на запрос.
func (j JSONCoder) Bind(c *Context, obj interface{}) error {
	r := c.Request // запрос
	// разбираем заголовок с типом информации в запросе
	mediatype, params, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
	charset, ok := params["charset"]
	if !ok {
		charset = "UTF-8"
	}
	// если запрос не является JSON, то возвращаем ошибку
	if mediatype != "application/json" || strings.ToUpper(charset) != "UTF-8" {
		return ErrUnsupportedMediaType
	}
	// если запрос превышает допустимый объем, то возвращаем ошибку
	if j.MaxBody > 0 {
		if r.ContentLength == 0 {
			return ErrLengthRequired
		} else if r.ContentLength > j.MaxBody {
			return ErrRequestEntityTooLarge
		}
	}
	// разбираем данные из запроса
	if err := json.NewDecoder(r.Body).Decode(obj); err != nil {
		return ErrBadRequest
	}
	return nil
}

// Encode кодирует и отправляет ответ с содержимым obj в формате JSON.
func (j JSONCoder) Encode(c *Context, obj interface{}) error {
	if c.ContentType == "" {
		c.ContentType = "application/json; charset=utf-8"
	}
	enc := json.NewEncoder(c)
	if j.Indent {
		enc.SetIndent("", "  ")
	}
	return enc.Encode(obj)
}
<commit_msg>set JSON indent<commit_after>package rest

import (
	"encoding/json"
	"mime"
	"strings"
)

// JSON позволяет быстро описать данные в одноименном формате.
type JSON map[string]interface{}

// Coder описывает интерфейс для поддержки разбора запроса и кодирования ответа.
type Coder interface {
	Bind(*Context, interface{}) error
	Encode(*Context, interface{}) error
}

// JSONCoder осуществляет разбор запроса и кодирование ответа в формате JSON.
type JSONCoder struct {
	MaxBody int64 // максимально допустимый размер запроса
	Indent  bool  // флаг форматированного вывода  JSON
}

// NewJSONCoder возвращает новый инициализированный Coder, поддерживающий
// формат JSON.
func NewJSONCoder(maxSize int64, indent bool) *JSONCoder {
	return &JSONCoder{MaxBody: maxSize, Indent: indent}
}

// Bind разбирает данные запроса в формате JSON и заполняет ими указанный в
// параметре объект.
//
// Если Content-Type запроса не соответствует "application/json", то
// возвращается ошибка ErrUnsupportedMediaType. Так же может возвращать ошибку
// ErrLengthRequired, если не указана длина запроса, ErrRequestEntityTooLarge —
// если запрос превышает значение MaxBody, и ErrBadRequest — если не смогли
// разобрать запрос и поместить результат разбора в объект obj. Все эти ошибки
// поддерживаются методом Send и отдают соответствующий статус ответа на запрос.
func (j JSONCoder) Bind(c *Context, obj interface{}) error {
	r := c.Request // запрос
	// разбираем заголовок с типом информации в запросе
	mediatype, params, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
	charset, ok := params["charset"]
	if !ok {
		charset = "UTF-8"
	}
	// если запрос не является JSON, то возвращаем ошибку
	if mediatype != "application/json" || strings.ToUpper(charset) != "UTF-8" {
		return ErrUnsupportedMediaType
	}
	// если запрос превышает допустимый объем, то возвращаем ошибку
	if j.MaxBody > 0 {
		if r.ContentLength == 0 {
			return ErrLengthRequired
		} else if r.ContentLength > j.MaxBody {
			return ErrRequestEntityTooLarge
		}
	}
	// разбираем данные из запроса
	if err := json.NewDecoder(r.Body).Decode(obj); err != nil {
		return ErrBadRequest
	}
	return nil
}

// Encode кодирует и отправляет ответ с содержимым obj в формате JSON.
func (j JSONCoder) Encode(c *Context, obj interface{}) error {
	if c.ContentType == "" {
		c.ContentType = "application/json; charset=utf-8"
	}
	enc := json.NewEncoder(c)
	if j.Indent {
		enc.SetIndent("", "    ")
	}
	return enc.Encode(obj)
}
<|endoftext|>


<commit_before>package notary

import (
	"os"
	"syscall"
	"time"
)

// application wide constants
const (
	// MaxDownloadSize is the maximum size we'll download for metadata if no limit is given
	MaxDownloadSize int64 = 100 << 20
	// MaxTimestampSize is the maximum size of timestamp metadata - 1MiB.
	MaxTimestampSize int64 = 1 << 20
	// MinRSABitSize is the minimum bit size for RSA keys allowed in notary
	MinRSABitSize = 2048
	// MinThreshold requires a minimum of one threshold for roles; currently we do not support a higher threshold
	MinThreshold = 1
	// PrivKeyPerms are the file permissions to use when writing private keys to disk
	PrivKeyPerms = 0700
	// PubCertPerms are the file permissions to use when writing public certificates to disk
	PubCertPerms = 0755
	// Sha256HexSize is how big a Sha256 hex is in number of characters
	Sha256HexSize = 64
	// Sha512HexSize is how big a Sha512 hex is in number of characters
	Sha512HexSize = 128
	// SHA256 is the name of SHA256 hash algorithm
	SHA256 = "sha256"
	// SHA512 is the name of SHA512 hash algorithm
	SHA512 = "sha512"
	// TrustedCertsDir is the directory, under the notary repo base directory, where trusted certs are stored
	TrustedCertsDir = "trusted_certificates"
	// PrivDir is the directory, under the notary repo base directory, where private keys are stored
	PrivDir = "private"
	// RootKeysSubdir is the subdirectory under PrivDir where root private keys are stored
	RootKeysSubdir = "root_keys"
	// NonRootKeysSubdir is the subdirectory under PrivDir where non-root private keys are stored
	NonRootKeysSubdir = "tuf_keys"

	// Day is a duration of one day
	Day  = 24 * time.Hour
	Year = 365 * Day

	// NotaryRootExpiry is the duration representing the expiry time of the Root role
	NotaryRootExpiry      = 10 * Year
	NotaryTargetsExpiry   = 3 * Year
	NotarySnapshotExpiry  = 3 * Year
	NotaryTimestampExpiry = 14 * Day

	ConsistentMetadataCacheMaxAge = 30 * Day
	CurrentMetadataCacheMaxAge    = 5 * time.Minute
	// CacheMaxAgeLimit is the generally recommended maximum age for Cache-Control headers
	// (one year, in seconds, since one year is forever in terms of internet
	// content)
	CacheMaxAgeLimit = 1 * Year

	MySQLBackend     = "mysql"
	MemoryBackend    = "memory"
	SQLiteBackend    = "sqlite3"
	RethinkDBBackend = "rethinkdb"
)

// NotaryDefaultExpiries is the construct used to configure the default expiry times of
// the various role files.
var NotaryDefaultExpiries = map[string]time.Duration{
	"root":      NotaryRootExpiry,
	"targets":   NotaryTargetsExpiry,
	"snapshot":  NotarySnapshotExpiry,
	"timestamp": NotaryTimestampExpiry,
}

// NotarySupportedSignals contains the signals we would like to capture:
// - SIGUSR1, indicates a increment of the log level.
// - SIGUSR2, indicates a decrement of the log level.
var NotarySupportedSignals = []os.Signal{syscall.SIGUSR1, syscall.SIGUSR2}
<commit_msg>[PATCH 5/8] Introduce a signal constant to reload the configuration.<commit_after>package notary

import (
	"os"
	"syscall"
	"time"
)

// application wide constants
const (
	// MaxDownloadSize is the maximum size we'll download for metadata if no limit is given
	MaxDownloadSize int64 = 100 << 20
	// MaxTimestampSize is the maximum size of timestamp metadata - 1MiB.
	MaxTimestampSize int64 = 1 << 20
	// MinRSABitSize is the minimum bit size for RSA keys allowed in notary
	MinRSABitSize = 2048
	// MinThreshold requires a minimum of one threshold for roles; currently we do not support a higher threshold
	MinThreshold = 1
	// PrivKeyPerms are the file permissions to use when writing private keys to disk
	PrivKeyPerms = 0700
	// PubCertPerms are the file permissions to use when writing public certificates to disk
	PubCertPerms = 0755
	// Sha256HexSize is how big a Sha256 hex is in number of characters
	Sha256HexSize = 64
	// Sha512HexSize is how big a Sha512 hex is in number of characters
	Sha512HexSize = 128
	// SHA256 is the name of SHA256 hash algorithm
	SHA256 = "sha256"
	// SHA512 is the name of SHA512 hash algorithm
	SHA512 = "sha512"
	// TrustedCertsDir is the directory, under the notary repo base directory, where trusted certs are stored
	TrustedCertsDir = "trusted_certificates"
	// PrivDir is the directory, under the notary repo base directory, where private keys are stored
	PrivDir = "private"
	// RootKeysSubdir is the subdirectory under PrivDir where root private keys are stored
	RootKeysSubdir = "root_keys"
	// NonRootKeysSubdir is the subdirectory under PrivDir where non-root private keys are stored
	NonRootKeysSubdir = "tuf_keys"

	// Day is a duration of one day
	Day  = 24 * time.Hour
	Year = 365 * Day

	// NotaryRootExpiry is the duration representing the expiry time of the Root role
	NotaryRootExpiry      = 10 * Year
	NotaryTargetsExpiry   = 3 * Year
	NotarySnapshotExpiry  = 3 * Year
	NotaryTimestampExpiry = 14 * Day

	ConsistentMetadataCacheMaxAge = 30 * Day
	CurrentMetadataCacheMaxAge    = 5 * time.Minute
	// CacheMaxAgeLimit is the generally recommended maximum age for Cache-Control headers
	// (one year, in seconds, since one year is forever in terms of internet
	// content)
	CacheMaxAgeLimit = 1 * Year

	MySQLBackend     = "mysql"
	MemoryBackend    = "memory"
	SQLiteBackend    = "sqlite3"
	RethinkDBBackend = "rethinkdb"
)

// NotaryDefaultExpiries is the construct used to configure the default expiry times of
// the various role files.
var NotaryDefaultExpiries = map[string]time.Duration{
	"root":      NotaryRootExpiry,
	"targets":   NotaryTargetsExpiry,
	"snapshot":  NotarySnapshotExpiry,
	"timestamp": NotaryTimestampExpiry,
}

// NotarySupportedSignals contains the signals we would like to capture:
// - SIGUSR1, indicates a increment of the log level.
// - SIGUSR2, indicates a decrement of the log level.
// - SIGHUP,  indicates a reloading of the configuration.
var NotarySupportedSignals = []os.Signal{
	syscall.SIGUSR1,
	syscall.SIGUSR2,
	syscall.SIGHUP,
}
<|endoftext|>


<commit_before>package main

const NGINX_BUILD_VERSION = "0.3.4"

// nginx
const (
	NGINX_VERSION             = "1.9.0"
	NGINX_DOWNLOAD_URL_PREFIX = "http://nginx.org/download"
)

// pcre
const (
	PCRE_VERSION             = "8.36"
	PCRE_DOWNLOAD_URL_PREFIX = "http://ftp.csx.cam.ac.uk/pub/software/programming/pcre"
)

// openssl
const (
	OPENSSL_VERSION             = "1.0.2a"
	OPENSSL_DOWNLOAD_URL_PREFIX = "http://www.openssl.org/source"
)

// zlib
const (
	ZLIB_VERSION             = "1.2.8"
	ZLIB_DOWNLOAD_URL_PREFIX = "http://zlib.net"
)

// openResty
const (
	OPENRESTY_VERSION             = "1.7.10.1"
	OPENRESTY_DOWNLOAD_URL_PREFIX = "http://openresty.org/download"
)

// tengine
const (
	TENGINE_VERSION             = "2.1.0"
	TENGINE_DOWNLOAD_URL_PREFIX = "http://tengine.taobao.org/download"
)

// component enumerations
const (
	COMPONENT_NGINX = iota
	COMPONENT_OPENRESTY
	COMPONENT_TENGINE
	COMPONENT_PCRE
	COMPONENT_OPENSSL
	COMPONENT_ZLIB
	COMPONENT_MAX
)
<commit_msg>bumped PCRE version to 8.37.<commit_after>package main

const NGINX_BUILD_VERSION = "0.3.4"

// nginx
const (
	NGINX_VERSION             = "1.9.0"
	NGINX_DOWNLOAD_URL_PREFIX = "http://nginx.org/download"
)

// pcre
const (
	PCRE_VERSION             = "8.37"
	PCRE_DOWNLOAD_URL_PREFIX = "http://ftp.csx.cam.ac.uk/pub/software/programming/pcre"
)

// openssl
const (
	OPENSSL_VERSION             = "1.0.2a"
	OPENSSL_DOWNLOAD_URL_PREFIX = "http://www.openssl.org/source"
)

// zlib
const (
	ZLIB_VERSION             = "1.2.8"
	ZLIB_DOWNLOAD_URL_PREFIX = "http://zlib.net"
)

// openResty
const (
	OPENRESTY_VERSION             = "1.7.10.1"
	OPENRESTY_DOWNLOAD_URL_PREFIX = "http://openresty.org/download"
)

// tengine
const (
	TENGINE_VERSION             = "2.1.0"
	TENGINE_DOWNLOAD_URL_PREFIX = "http://tengine.taobao.org/download"
)

// component enumerations
const (
	COMPONENT_NGINX = iota
	COMPONENT_OPENRESTY
	COMPONENT_TENGINE
	COMPONENT_PCRE
	COMPONENT_OPENSSL
	COMPONENT_ZLIB
	COMPONENT_MAX
)
<|endoftext|>


<commit_before>package	gearman // import "github.com/nathanaelle/gearman"

import	(
	"io"
	"sync"
	"bytes"
)

type	(
	Task	interface {
		Handle(p Packet)
		Value() ([]byte,error)
		Reader() (io.Reader,error)
		Packet() Packet
	}

	task	struct {
		packet		Packet
		solved		*sync.WaitGroup
		payload		bytes.Buffer
		err		error
	}

	nullTask struct{}

	echoTask	struct {
		packet		Packet
		solved		*sync.WaitGroup
		payload		bytes.Buffer
		err		error
	}

)

var	NilTask	Task	= &nullTask{}

func NewTask(cmd string, payload []byte) Task {
	r := &task {
		packet:	BuildPacket(SUBMIT_JOB, Opacify([]byte(cmd)), Opacify([]byte{}), Opacify(payload)),
		solved:	new(sync.WaitGroup),
	}

	r.solved.Add(1)
	return	r
}

func (r *task) Packet() Packet {
	return r.packet
}

func (r *task) Handle(p Packet) {
	switch p.Cmd() {
	case	WORK_COMPLETE:
		r.payload.Write(p.At(1).Bytes())
		r.solved.Done()

	case	WORK_FAIL:
		r.err = unknownError
		r.solved.Done()

	case	WORK_EXCEPTION:
		r.err = &ExceptionError { p.At(1).Bytes() }
		r.solved.Done()
	}
}

func (r *task) Value() ([]byte,error) {
	r.solved.Wait()

	return r.payload.Bytes(), r.err
}

func (r *task) Reader() (io.Reader,error) {
	r.solved.Wait()

	return bytes.NewReader( r.payload.Bytes() ), r.err
}

func (_ *nullTask) Handle(_ Packet) {
}

func (_ *nullTask) Value() ([]byte,error) {
	return []byte{},nil
}

func (_ *nullTask) Packet() Packet {
	return empty_echo_packet
}

func (_ *nullTask) Reader() (io.Reader,error) {
	return bytes.NewReader( []byte{} ), nil
}

func EchoTask(payload []byte) Task {
	r := &echoTask {
		packet:	BuildPacket(ECHO_REQ, Opacify(payload)),
		solved:	new(sync.WaitGroup),
	}

	r.solved.Add(1)
	return	r
}

func (r *echoTask) Handle(p Packet) {
	switch p.Cmd() {
	case	ECHO_RES:
		r.payload.Write(p.At(0).Bytes())
		r.solved.Done()

	default:
		r.err = unknownError
		r.solved.Done()
	}
}

func (r *echoTask) Value() ([]byte,error) {
	r.solved.Wait()

	return r.payload.Bytes(), r.err
}

func (r *echoTask) Packet() Packet {
	return r.packet
}

func (r *echoTask) Reader() (io.Reader,error) {
	r.solved.Wait()

	return bytes.NewReader( r.payload.Bytes() ), r.err
}
<commit_msg>adding High and Low priority task<commit_after>package	gearman // import "github.com/nathanaelle/gearman"

import	(
	"io"
	"sync"
	"bytes"
)

type	(
	Task	interface {
		Handle(p Packet)
		Value() ([]byte,error)
		Reader() (io.Reader,error)
		Packet() Packet
	}

	task	struct {
		packet		Packet
		solved		*sync.WaitGroup
		payload		bytes.Buffer
		err		error
		stat_num	int
		stat_den	int
	}

	nullTask struct{}

	echoTask	struct {
		packet		Packet
		solved		*sync.WaitGroup
		payload		bytes.Buffer
		err		error
	}

)

var	NilTask	Task	= &nullTask{}

func NewTask(cmd string, payload []byte) Task {
	r := &task {
		packet:	BuildPacket(SUBMIT_JOB, Opacify([]byte(cmd)), Opacify([]byte{}), Opacify(payload)),
		solved:	new(sync.WaitGroup),
	}

	r.solved.Add(1)
	return	r
}

func NewTaskLow(cmd string, payload []byte) Task {
	r := &task {
		packet:	BuildPacket(SUBMIT_JOB_LOW, Opacify([]byte(cmd)), Opacify([]byte{}), Opacify(payload)),
		solved:	new(sync.WaitGroup),
	}

	r.solved.Add(1)
	return	r
}

func NewTaskHigh(cmd string, payload []byte) Task {
	r := &task {
		packet:	BuildPacket(SUBMIT_JOB_HIGH, Opacify([]byte(cmd)), Opacify([]byte{}), Opacify(payload)),
		solved:	new(sync.WaitGroup),
	}

	r.solved.Add(1)
	return	r
}

func (r *task) Packet() Packet {
	return r.packet
}

func (r *task) Handle(p Packet) {
	switch p.Cmd() {
	case	WORK_COMPLETE:
		r.payload.Write(p.At(1).Bytes())
		r.solved.Done()

	case	WORK_FAIL:
		r.err = unknownError
		r.solved.Done()

	case	WORK_EXCEPTION:
		r.err = &ExceptionError { p.At(1).Bytes() }
		r.solved.Done()

	case	WORK_DATA:
		r.payload.Write(p.At(1).Bytes())

	case	WORK_STATUS:
		// TODO

	case	WORK_WARNING:
		// TODO

	}
}

func (r *task) Value() ([]byte,error) {
	r.solved.Wait()

	return r.payload.Bytes(), r.err
}

func (r *task) Reader() (io.Reader,error) {
	r.solved.Wait()

	return bytes.NewReader( r.payload.Bytes() ), r.err
}

func (_ *nullTask) Handle(_ Packet) {
}

func (_ *nullTask) Value() ([]byte,error) {
	return []byte{},nil
}

func (_ *nullTask) Packet() Packet {
	return empty_echo_packet
}

func (_ *nullTask) Reader() (io.Reader,error) {
	return bytes.NewReader( []byte{} ), nil
}

func EchoTask(payload []byte) Task {
	r := &echoTask {
		packet:	BuildPacket(ECHO_REQ, Opacify(payload)),
		solved:	new(sync.WaitGroup),
	}

	r.solved.Add(1)
	return	r
}

func (r *echoTask) Handle(p Packet) {
	switch p.Cmd() {
	case	ECHO_RES:
		r.payload.Write(p.At(0).Bytes())
		r.solved.Done()

	default:
		r.err = unknownError
		r.solved.Done()
	}
}

func (r *echoTask) Value() ([]byte,error) {
	r.solved.Wait()

	return r.payload.Bytes(), r.err
}

func (r *echoTask) Packet() Packet {
	return r.packet
}

func (r *echoTask) Reader() (io.Reader,error) {
	r.solved.Wait()

	return bytes.NewReader( r.payload.Bytes() ), r.err
}
<|endoftext|>


<commit_before>package main

import "fmt"
import "log"
import "os"
import "errors"
import "strings"
import "unicode"
import "github.com/nlopes/slack"
import "github.com/tadgh/go-toggl"
import "encoding/gob"
import "time"
import "runtime"

const file = "./test.gob"

func Check(err error) {
	if err != nil {
		_, file, line, _ := runtime.Caller(1)
		fmt.Println(line, "\t", file, "\n", err)
		os.Exit(1)
	}
}

func pingTogglApi(apiKey string) error {
	ts := toggl.OpenSession(apiKey)
	_, err := ts.GetAccount()
	if err != nil {
		fmt.Println(os.Stderr, "Error: %s\n", err)
		return err
	}
	return nil
}

func Save(path string, object interface{}) error {
	file, err := os.Create(path)
	if err == nil {
		encoder := gob.NewEncoder(file)
		encoder.Encode(object)
	}
	file.Close()
	return err
}

func Load(path string, object interface{}) error {
	file, err := os.Open(path)
	if err == nil {
		decoder := gob.NewDecoder(file)
		err = decoder.Decode(object)
	}
	file.Close()
	return err
}

func createTimeEntry(apiKey, description string, start time.Time, duration time.Duration, pid, tid int) *toggl.TimeEntry {
	ts := toggl.OpenSession(apiKey)
	te, err := ts.CreateTimeEntry(pid, 0, start, duration, description)
	if err != nil {
		log.Fatal("Error uploading time entry! %v", err)
	}
	return &te
}

func stopTimer(apiKey string) (*toggl.TimeEntry, error) {
	ts := toggl.OpenSession(apiKey)
	te, err := ts.GetActiveTimeEntry()
	if err != nil {
		return nil, err
	}
	if te.ID <= 0 {
		return nil, errors.New("No timer is currently running!")
	}
	te, err = ts.StopTimeEntry(te)
	if err != nil {
		return nil, err
	}
	return &te, nil
}

func startTimer(apiKey, description string, pid int) *toggl.TimeEntry {
	ts := toggl.OpenSession(apiKey)
	te, err := ts.StartTimeEntryForProject(description, pid)

	if err != nil {
		fmt.Println(err)
	}
	sessionMap[apiKey] = te
	return &te
}

func getProjectWithName(apiKey, projectName string) int {
	ts := toggl.OpenSession(apiKey)
	acc, err := ts.GetAccount()
	var retVal int
	if err != nil {
		fmt.Println(err)
	}
	for _, project := range acc.Data.Projects {
		//case insensitive string comparison
		if strings.EqualFold(project.Name, projectName) {
			retVal = project.ID
		}
	}
	return retVal
}

type BotCommand struct {
	Channel string
	Event   *slack.MessageEvent
	UserId  string
}

type ReplyChannel struct {
	Channel      string
	Attachment   *slack.Attachment
	DisplayTitle string
}

var (
	api               *slack.Client
	botCommandChannel chan *BotCommand
	botReplyChannel   chan ReplyChannel
	botId             string
	userMap           map[string]string
	sessionMap        map[string]toggl.TimeEntry
)

func handleBotCommands(replyChannel chan ReplyChannel) {
	commands := map[string]string{
		"register": "Register yourself with togglbot. `@togglbot register MY_TOGGL_API_KEY`",
		"start":    "Start a timer for a given project and description. `@togglbot start <PROJECT_NAME> <EVERYTHING_ELSE_IS_DESCRIPTION>`",
		"stop":     "Stops any current timer session. `@togglbot stop`",
		"track":    "adds a toggl entry to a project for a given time range. `@togglbot track icancope 9am-5pm`",
	}

	for {
		incomingCommand := <-botCommandChannel

		commandArray := strings.Fields(strings.ToLower(incomingCommand.Event.Text))
		if strings.EqualFold(commandArray[0], "<@"+botId+">") {
			commandArray = commandArray[1:]
		}
		var reply ReplyChannel
		reply.Channel = incomingCommand.Channel

		switch commandArray[0] {
		case "help":
			reply.DisplayTitle = "Help!"
			fields := make([]slack.AttachmentField, 0)
			for k, v := range commands {
				fields = append(fields, slack.AttachmentField{
					Title: "<bot> " + k,
					Value: v,
				})
			}
			attachment := &slack.Attachment{
				Pretext:    "TogglBot Command List",
				Color:      "#B733FF",
				Fields:     fields,
				MarkdownIn: []string{"fields"},
			}
			reply.Attachment = attachment
			replyChannel <- reply
		case "register":
			togglApiKey := commandArray[1]
			err := pingTogglApi(togglApiKey)
			if err != nil {
				reply.DisplayTitle = "Failed to register. Bad api key?"
			} else {
				userMap[incomingCommand.Event.User] = togglApiKey
				err := Save(file, userMap)
				Check(err)
				reply.DisplayTitle = "Successfully registered!"
			}
			replyChannel <- reply
		}

		if reply.DisplayTitle != "" {
			continue
		}
		togglApiKey, ok := userMap[incomingCommand.Event.User]
		if !ok {
			reply.DisplayTitle = "You have not registered with togglbot yet. Try @togglbot register API_KEY_HERE"
			replyChannel <- reply
			continue
		}

		switch commandArray[0] {
		case "start":
			if len(commandArray) <= 2 {
				reply.DisplayTitle = "Please provide a project name and description! `@togglbot start PROJECT_NAME DESCRIPTION`"
				replyChannel <- reply
				break
			}
			project := commandArray[1]
			description := strings.Join(commandArray[2:], " ")
			pid := getProjectWithName(togglApiKey, project)
			fmt.Printf("%v", pid)
			startTimer(togglApiKey, description, pid)
			reply.DisplayTitle = "Timer started! *get back to work peon*"
			replyChannel <- reply
		case "stop":
			te, err := stopTimer(togglApiKey)
			if err != nil {
				reply.DisplayTitle = "couldn't stop timer: " + err.Error()
				replyChannel <- reply
				break
			}
			dur, err := time.ParseDuration(fmt.Sprintf("%vs", te.Duration))
			if err != nil {
				log.Fatal("Unparseable duration! %v", te.Duration)
			}
			reply.DisplayTitle = fmt.Sprintf("Timer Stopped. Worked for %v.", dur.String())
			replyChannel <- reply
		case "track":
			if len(commandArray) < 3 {
				reply.DisplayTitle = "Sorry, I don't have enough information to make an event for you. try `@togglbot track PROJECT_NAME 9:00AM-5:00PM TASK_DESCRIPTION`"
				replyChannel <- reply
				break
			}
			projectName := commandArray[1]
			pid := getProjectWithName(togglApiKey, projectName)
			timeRange := commandArray[2]

			parsedDate := parseDate(commandArray[3])

			description := "no description provided"
			if len(commandArray) > 4 {
				description = strings.Join(commandArray[4:], " ")
			}

			startTime, duration, err := parseTimeRange(timeRange, parsedDate)
			if err != nil {
				reply.DisplayTitle = err.Error()
				replyChannel <- reply
				break
			}
			createTimeEntry(togglApiKey, description, *startTime, *duration, pid, 0)
			reply.DisplayTitle = "Time entry created!"
			replyChannel <- reply
		default:
			reply.DisplayTitle = "Sorry, i don't understand that command. Try `@Togglbot help`"
			replyChannel <- reply
		}
	}
}

func parseDate(readingDate string) (*time.Date, error) {
	parsedDate, err := time.Parse("2006/01/02", readingDate)
	if err != nil {
		return nil, errors.New("Your date is incorrectly formatted! Try something like: 2017/08/11. The ISO 8601 Standard 😉")
	}

	return parsedDate
}

func parseTimeRange(timeRange string, parsedDate time.Date) (*time.Time, *time.Duration, error) {
	timeRange = strings.ToUpper(timeRange)
	fields := strings.Split(timeRange, "-")
	if len(fields) != 2 {
		return nil, nil, errors.New("Your date range is incorrectly formatted! Try something like: 9:00AM-5:00PM")
	}

	startTime, err := time.Parse(time.Kitchen, fields[0])
	if err != nil {
		return nil, nil, errors.New("Your date range is incorrectly formatted! Try something like: 9:00AM-5:00PM")
	}

	endTime, err := time.Parse(time.Kitchen, fields[1])
	if err != nil {
		return nil, nil, errors.New("Your date range is incorrectly formatted! Try something like: 9:00AM-5:00PM")
	}

	duration := endTime.Sub(startTime)

	if parsedDate == nil {
		dateToInput := time.Now()
	} else {
		dateToInput := parsedDate
	}

	// Kitchen time has only hours and PM/AM. Drop in today's date.
	fmt.Println("DATE:\t", dateToInput)
	startTime = time.Date(dateToInput.Year(), dateToInput.Month(), dateToInput.Day(), startTime.Hour(), startTime.Minute(), startTime.Second(), startTime.Nanosecond(), now.Location())
	fmt.Println("START TIME:\t", startTime)
	return &startTime, &duration, nil
}

func handleBotReplies() {
	for {
		reply := <-botReplyChannel
		params := slack.PostMessageParameters{}
		params.AsUser = true
		if reply.Attachment != nil {
			params.Attachments = []slack.Attachment{*reply.Attachment}
		}
		_, _, err := api.PostMessage(reply.Channel, reply.DisplayTitle, params)
		if err != nil {
			fmt.Println("FATAL SHIT")
			log.Fatal(err)
		}
	}
}

func main() {

	if len(os.Args) != 2 {
		fmt.Printf("usage: togglbot slack-bot-token")
		os.Exit(1)
	}

	//First attempt to deserialize a saved registration file, otherwise
	//create new
	err := Load(file, &userMap)
	if err != nil {
		fmt.Println("ERROR WAS DETECTED")
		log.Fatal(err)
		userMap = make(map[string]string)
	}

	sessionMap = make(map[string]toggl.TimeEntry)
	token := os.Args[1]
	api = slack.New(token)
	rtm := api.NewRTM()
	botCommandChannel = make(chan *BotCommand)
	botReplyChannel = make(chan ReplyChannel)
	go rtm.ManageConnection()
	go handleBotCommands(botReplyChannel)
	go handleBotReplies()
	go fmt.Println("TogglBot ready, ^C exits")
Loop:
	for {
		select {
		case msg := <-rtm.IncomingEvents:
			switch event := msg.Data.(type) {
			case *slack.ConnectedEvent:
				botId = event.Info.User.ID
			case *slack.MessageEvent:

				botCommand := &BotCommand{
					Channel: event.Channel,
					Event:   event,
					UserId:  event.User,
				}

				if isValidMessageEvent(event) {
					fmt.Println("Received event: ", event)
					botCommandChannel <- botCommand
				}
			case *slack.RTMError:
				fmt.Printf("ERROR: %s\n", event.Error())
			case *slack.InvalidAuthEvent:
				fmt.Printf("Invalid credentials")
				break Loop
			}
		}
	}

}

func isValidMessageEvent(event *slack.MessageEvent) bool {
	if event.Type != "message" {
		return false
	}
	if event.User == botId {
		return false
	}
	if strings.HasPrefix(event.Text, "<@"+botId+">") {
		return true
	}
	if strings.HasPrefix(event.Channel, "D") {
		return true
	}
	return false
}
<commit_msg>fixed stuff<commit_after>package main

import "fmt"
import "log"
import "os"
import "errors"
import "strings"
import "unicode"
import "github.com/nlopes/slack"
import "github.com/tadgh/go-toggl"
import "encoding/gob"
import "time"
import "runtime"

const file = "./test.gob"

func Check(err error) {
	if err != nil {
		_, file, line, _ := runtime.Caller(1)
		fmt.Println(line, "\t", file, "\n", err)
		os.Exit(1)
	}
}

func pingTogglApi(apiKey string) error {
	ts := toggl.OpenSession(apiKey)
	_, err := ts.GetAccount()
	if err != nil {
		fmt.Println(os.Stderr, "Error: %s\n", err)
		return err
	}
	return nil
}

func Save(path string, object interface{}) error {
	file, err := os.Create(path)
	if err == nil {
		encoder := gob.NewEncoder(file)
		encoder.Encode(object)
	}
	file.Close()
	return err
}

func Load(path string, object interface{}) error {
	file, err := os.Open(path)
	if err == nil {
		decoder := gob.NewDecoder(file)
		err = decoder.Decode(object)
	}
	file.Close()
	return err
}

func createTimeEntry(apiKey, description string, start time.Time, duration time.Duration, pid, tid int) *toggl.TimeEntry {
	ts := toggl.OpenSession(apiKey)
	te, err := ts.CreateTimeEntry(pid, 0, start, duration, description)
	if err != nil {
		log.Fatal("Error uploading time entry! %v", err)
	}
	return &te
}

func stopTimer(apiKey string) (*toggl.TimeEntry, error) {
	ts := toggl.OpenSession(apiKey)
	te, err := ts.GetActiveTimeEntry()
	if err != nil {
		return nil, err
	}
	if te.ID <= 0 {
		return nil, errors.New("No timer is currently running!")
	}
	te, err = ts.StopTimeEntry(te)
	if err != nil {
		return nil, err
	}
	return &te, nil
}

func startTimer(apiKey, description string, pid int) *toggl.TimeEntry {
	ts := toggl.OpenSession(apiKey)
	te, err := ts.StartTimeEntryForProject(description, pid)

	if err != nil {
		fmt.Println(err)
	}
	sessionMap[apiKey] = te
	return &te
}

func getProjectWithName(apiKey, projectName string) int {
	ts := toggl.OpenSession(apiKey)
	acc, err := ts.GetAccount()
	var retVal int
	if err != nil {
		fmt.Println(err)
	}
	for _, project := range acc.Data.Projects {
		//case insensitive string comparison
		if strings.EqualFold(project.Name, projectName) {
			retVal = project.ID
		}
	}
	return retVal
}

type BotCommand struct {
	Channel string
	Event   *slack.MessageEvent
	UserId  string
}

type ReplyChannel struct {
	Channel      string
	Attachment   *slack.Attachment
	DisplayTitle string
}

var (
	api               *slack.Client
	botCommandChannel chan *BotCommand
	botReplyChannel   chan ReplyChannel
	botId             string
	userMap           map[string]string
	sessionMap        map[string]toggl.TimeEntry
)

func handleBotCommands(replyChannel chan ReplyChannel) {
	commands := map[string]string{
		"register": "Register yourself with togglbot. `@togglbot register MY_TOGGL_API_KEY`",
		"start":    "Start a timer for a given project and description. `@togglbot start <PROJECT_NAME> <EVERYTHING_ELSE_IS_DESCRIPTION>`",
		"stop":     "Stops any current timer session. `@togglbot stop`",
		"track":    "adds a toggl entry to a project for a given time range. `@togglbot track icancope 9am-5pm`",
	}

	for {
		incomingCommand := <-botCommandChannel

		commandArray := strings.Fields(strings.ToLower(incomingCommand.Event.Text))
		if strings.EqualFold(commandArray[0], "<@"+botId+">") {
			commandArray = commandArray[1:]
		}
		var reply ReplyChannel
		reply.Channel = incomingCommand.Channel

		switch commandArray[0] {
		case "help":
			reply.DisplayTitle = "Help!"
			fields := make([]slack.AttachmentField, 0)
			for k, v := range commands {
				fields = append(fields, slack.AttachmentField{
					Title: "<bot> " + k,
					Value: v,
				})
			}
			attachment := &slack.Attachment{
				Pretext:    "TogglBot Command List",
				Color:      "#B733FF",
				Fields:     fields,
				MarkdownIn: []string{"fields"},
			}
			reply.Attachment = attachment
			replyChannel <- reply
		case "register":
			togglApiKey := commandArray[1]
			err := pingTogglApi(togglApiKey)
			if err != nil {
				reply.DisplayTitle = "Failed to register. Bad api key?"
			} else {
				userMap[incomingCommand.Event.User] = togglApiKey
				err := Save(file, userMap)
				Check(err)
				reply.DisplayTitle = "Successfully registered!"
			}
			replyChannel <- reply
		}

		if reply.DisplayTitle != "" {
			continue
		}
		togglApiKey, ok := userMap[incomingCommand.Event.User]
		if !ok {
			reply.DisplayTitle = "You have not registered with togglbot yet. Try @togglbot register API_KEY_HERE"
			replyChannel <- reply
			continue
		}

		switch commandArray[0] {
		case "start":
			if len(commandArray) <= 2 {
				reply.DisplayTitle = "Please provide a project name and description! `@togglbot start PROJECT_NAME DESCRIPTION`"
				replyChannel <- reply
				break
			}
			project := commandArray[1]
			description := strings.Join(commandArray[2:], " ")
			pid := getProjectWithName(togglApiKey, project)
			fmt.Printf("%v", pid)
			startTimer(togglApiKey, description, pid)
			reply.DisplayTitle = "Timer started! *get back to work peon*"
			replyChannel <- reply
		case "stop":
			te, err := stopTimer(togglApiKey)
			if err != nil {
				reply.DisplayTitle = "couldn't stop timer: " + err.Error()
				replyChannel <- reply
				break
			}
			dur, err := time.ParseDuration(fmt.Sprintf("%vs", te.Duration))
			if err != nil {
				log.Fatal("Unparseable duration! %v", te.Duration)
			}
			reply.DisplayTitle = fmt.Sprintf("Timer Stopped. Worked for %v.", dur.String())
			replyChannel <- reply
		case "track":
			if len(commandArray) < 3 {
				reply.DisplayTitle = "Sorry, I don't have enough information to make an event for you. try `@togglbot track PROJECT_NAME 9:00AM-5:00PM TASK_DESCRIPTION`"
				replyChannel <- reply
				break
			}
			projectName := commandArray[1]
			pid := getProjectWithName(togglApiKey, projectName)
			timeRange := commandArray[2]

			parsedDate := parseDate(commandArray[3])

			description := "no description provided"
			if len(commandArray) > 4 {
				description = strings.Join(commandArray[4:], " ")
			}

			startTime, duration, err := parseTimeRange(timeRange, parsedDate)
			if err != nil {
				reply.DisplayTitle = err.Error()
				replyChannel <- reply
				break
			}
			createTimeEntry(togglApiKey, description, *startTime, *duration, pid, 0)
			reply.DisplayTitle = "Time entry created!"
			replyChannel <- reply
		default:
			reply.DisplayTitle = "Sorry, i don't understand that command. Try `@Togglbot help`"
			replyChannel <- reply
		}
	}
}

func parseDate(readingDate string) (*time.Date, error) {
	parsedDate, err := time.Parse("2006/01/02", readingDate)
	if err != nil {
		return nil, errors.New("Your date is incorrectly formatted! Try something like: 2017/08/11. The ISO 8601 Standard 😉")
	}

	return parsedDate
}

func parseTimeRange(timeRange string, parsedDate time.Date) (*time.Time, *time.Duration, error) {
	timeRange = strings.ToUpper(timeRange)
	fields := strings.Split(timeRange, "-")
	if len(fields) != 2 {
		return nil, nil, errors.New("Your date range is incorrectly formatted! Try something like: 9:00AM-5:00PM")
	}

	startTime, err := time.Parse(time.Kitchen, fields[0])
	if err != nil {
		return nil, nil, errors.New("Your date range is incorrectly formatted! Try something like: 9:00AM-5:00PM")
	}

	endTime, err := time.Parse(time.Kitchen, fields[1])
	if err != nil {
		return nil, nil, errors.New("Your date range is incorrectly formatted! Try something like: 9:00AM-5:00PM")
	}

	duration := endTime.Sub(startTime)

	if parsedDate == nil {
		dateToInput := time.Now()
	} else {
		dateToInput := parsedDate
	}

	// Kitchen time has only hours and PM/AM. Drop in today's date.
	fmt.Println("DATE:\t", dateToInput)
	startTime = time.Date(dateToInput.Year(), dateToInput.Month(), dateToInput.Day(), startTime.Hour(), startTime.Minute(), startTime.Second(), startTime.Nanosecond(), now.Location())
	fmt.Println("START TIME:\t", startTime)
	return &startTime, &duration, nil
}

func handleBotReplies() {
	for {
		reply := <-botReplyChannel
		params := slack.PostMessageParameters{}
		params.AsUser = true
		if reply.Attachment != nil {
			params.Attachments = []slack.Attachment{*reply.Attachment}
		}
		_, _, err := api.PostMessage(reply.Channel, reply.DisplayTitle, params)
		if err != nil {
			fmt.Println("FATAL SHIT")
			log.Fatal(err)
		}
	}
}

func main() {

	if len(os.Args) != 2 {
		fmt.Printf("usage: togglbot slack-bot-token")
		os.Exit(1)
	}

	//First attempt to deserialize a saved registration file, otherwise
	//create new
	err := Load(file, &userMap)
	if err != nil {
		fmt.Println("ERROR WAS DETECTED")
		log.Fatal(err)
		userMap = make(map[string]string)
	}

	sessionMap = make(map[string]toggl.TimeEntry)
	token := os.Args[1]
	api = slack.New(token)
	rtm := api.NewRTM()
	botCommandChannel = make(chan *BotCommand)
	botReplyChannel = make(chan ReplyChannel)
	go rtm.ManageConnection()
	go handleBotCommands(botReplyChannel)
	go handleBotReplies()
	go fmt.Println("TogglBot ready, ^C exits")
Loop:
	for {
		select {
		case msg := <-rtm.IncomingEvents:
			switch event := msg.Data.(type) {
			case *slack.ConnectedEvent:
				botId = event.Info.User.ID
			case *slack.MessageEvent:

				botCommand := &BotCommand{
					Channel: event.Channel,
					Event:   event,
					UserId:  event.User,
				}

				if isValidMessageEvent(event) {
					fmt.Println("Received event: ", event)
					botCommandChannel <- botCommand
				}
			case *slack.RTMError:
				fmt.Printf("ERROR: %s\n", event.Error())
			case *slack.InvalidAuthEvent:
				fmt.Printf("Invalid credentials")
				break Loop
			}
		}
	}

}

func isValidMessageEvent(event *slack.MessageEvent) bool {
	if event.Type != "message" {
		return false
	}
	if event.User == botId {
		return false
	}
	if strings.HasPrefix(event.Text, "<@"+botId+">") {
		return true
	}
	if strings.HasPrefix(event.Channel, "D") {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package logberry

import (
	"bytes"
	"fmt"
	"runtime"
)

// Error is used to report a fault, capturing a human-oriented message
// describing the problem, structured data providing identifying
// details, the source code file name and line number location at
// which this Error was generated, and if appropriate a preceding
// error that caused this higher level fault.
type Error struct {
	Message string
	Data    D

	File string
	Line int

	Cause error
}

func newerror(msg string, data []interface{}) *Error {
	e := &Error{
		Message: msg,
		Data:    DAggregate(data),
	}
	return e
}

func wraperror(msg string, err error, data []interface{}) *Error {
	e := newerror(msg, data)
	e.Cause = err
	return e
}

// NewError generates a new Error capturing the given human-oriented
// message and optionally structured data associated with this fault.
// The source code position to be reported by this Error is the point
// at which NewError was called.
func NewError(msg string, data ...interface{}) *Error {
	e := newerror(msg, data)
	e.Locate(1)
	return e
}

// WrapError generates a new Error capturing the given human-oriented
// message, a preceding error which caused this higher level fault,
// and optionally structured data associated with this fault.  The
// source code position to be reported by this Error is the point at
// which WrapError was called.
func WrapError(msg string, err error, data ...interface{}) *Error {
	e := wraperror(msg, err, data)
	e.Locate(1)
	return e
}

// Locate sets the source code position to be reported with this error
// as that point where the Locate call is made.  In general it should
// not be necessary to invoke this manually.
func (e *Error) Locate(skip int) {
	_, file, line, ok := runtime.Caller(skip + 1)
	if ok {
		e.File = file
		e.Line = line
	}
}

// Error implements the standard Go error interface, returning a
// human-oriented text string serialization of the Error.
func (e *Error) Error() string {

	var buffer = new(bytes.Buffer)

	buffer.WriteString(e.Message)

	if e.File != "" {
		fmt.Fprintf(buffer, " [%v:%v]", e.File, e.Line)
	}

	if len(e.Data) > 0 {
		fmt.Fprintf(buffer, " %v", e.Data.String())
	}

	if e.Cause != nil {
		fmt.Fprintf(buffer, ": %v", e.Cause.Error())
	}

	return buffer.String()
}

// String returns a human-oriented text string serialization of the
// Error.
func (e *Error) String() string {
	return e.Error()
}
<commit_msg>Code.<commit_after>package logberry

import (
	"bytes"
	"fmt"
	"runtime"
)

// Error captures structured information about a fault.
type Error struct {

	// An optional identifier for differentiating classes of errors
	Code string

	// Human-oriented description of the fault
	Message string

	// Inputs, parameters, and other data associated with the fault
	Data    D

	// The source code file and line number where the error occurred
	File string
	Line int

	// Optional link to a preceding error underlying the fault
	Cause error

}

func newerror(msg string, data []interface{}) *Error {
	e := &Error{
		Message: msg,
		Data:    DAggregate(data),
	}
	return e
}

func wraperror(msg string, err error, data []interface{}) *Error {
	e := newerror(msg, data)
	e.Cause = err
	return e
}

// NewError generates a new Error capturing the given human-oriented
// message and optionally structured data associated with this fault.
// The source code position to be reported by this Error is the point
// at which NewError was called.
func NewError(msg string, data ...interface{}) *Error {
	e := newerror(msg, data)
	e.Locate(1)
	return e
}

// WrapError generates a new Error capturing the given human-oriented
// message, a preceding error which caused this higher level fault,
// and optionally structured data associated with this fault.  The
// source code position to be reported by this Error is the point at
// which WrapError was called.
func WrapError(msg string, err error, data ...interface{}) *Error {
	e := wraperror(msg, err, data)
	e.Locate(1)
	return e
}

// Locate sets the source code position to be reported with this error
// as that point where the Locate call is made.  It should not
// generally be necessary to invoke this manually when using Logberry.
func (e *Error) Locate(skip int) {
	_, file, line, ok := runtime.Caller(skip + 1)
	if ok {
		e.File = file
		e.Line = line
	}
}

// SetCode associates the error with a particular error class string.
func (e *Error) SetCode(code string) {
	e.Code = code
}

// IsCode checks if the error is tagged with any of the given codes.
func (e *Error) IsCode(code ...string) bool {

	for _,c := range(code) {
		if e.Code == c {
			return true
		}
	}

	return false

}

// Error returns a human-oriented serialization of the error.
func (e *Error) Error() string {

	var buffer = new(bytes.Buffer)

	buffer.WriteString(e.Message)

	if e.File != "" {
		fmt.Fprintf(buffer, " [%v:%v]", e.File, e.Line)
	}

	if len(e.Data) > 0 {
		fmt.Fprintf(buffer, " %v", e.Data.String())
	}

	/*
	if e.Cause != nil {
		fmt.Fprintf(buffer, ": %v", e.Cause.Error())
	}
	 */

	return buffer.String()
}

// String returns a human-oriented serialization of the error.
func (e *Error) String() string {
	return e.Error()
}
<|endoftext|>