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

package sessions

import (
	"encoding/base32"
	"io"
	"net/http"
	"os"
	"strings"
	"sync"

	"github.com/gorilla/securecookie"
)

// Store is an interface for custom session stores.
//
// Get should return a cached session.
// New should create and return a new session.
// Save should persist session to the underlying store implementation.
//
// Note that New should never return a nul session, even in the case of an error
// if using the Registry infrastructure for caching of sessions in your store.
//
// See CookieStore and FilesystemStore for examples.
type Store interface {
	Get(r *http.Request, name string) (*Session, error)
	New(r *http.Request, name string) (*Session, error)
	Save(r *http.Request, w http.ResponseWriter, s *Session) error
}

// CookieStore ----------------------------------------------------------------

// NewCookieStore returns a new CookieStore.
//
// Keys are defined in pairs to allow key rotation, but the common case is
// to set a single authentication key and optionally an encryption key.
//
// The first key in a pair is used for authentication and the second for
// encryption. The encryption key can be set to nil or omitted in the last
// pair, but the authentication key is required in all pairs.
//
// It is recommended to use an authentication key with 32 or 64 bytes.
// The encryption key, if set, must be either 16, 24, or 32 bytes to select
// AES-128, AES-192, or AES-256 modes.
//
// Use the convenience function securecookie.GenerateRandomKey() to create
// strong keys.
func NewCookieStore(keyPairs ...[]byte) *CookieStore {
	return &CookieStore{
		Codecs: securecookie.CodecsFromPairs(keyPairs...),
		Options: &Options{
			Path:   "/",
			MaxAge: 86400 * 30,
		},
	}
}

// CookieStore stores sessions using secure cookies.
type CookieStore struct {
	Codecs  []securecookie.Codec
	Options *Options // default configuration
}

// Get returns a session for the given name after adding it to the registry.
//
// It returns a new session if the sessions doesn't exist. Access IsNew on
// the session to check if it is an existing session or a new one.
//
// It returns a new session and an error if the session exists but could
// not be decoded.
func (s *CookieStore) Get(r *http.Request, name string) (*Session, error) {
	return GetRegistry(r).Get(s, name)
}

// New returns a session for the given name without adding it to the registry.
//
// The difference between New() and Get() is that calling New() twice will
// decode the session data twice, while Get() registers and reuses the same
// decoded session after the first call.
func (s *CookieStore) New(r *http.Request, name string) (*Session, error) {
	session := NewSession(s, name)
	opts := *s.Options
	session.Options = &opts
	session.IsNew = true
	var err error
	if c, errCookie := r.Cookie(name); errCookie == nil {
		err = securecookie.DecodeMulti(name, c.Value, &session.Values,
			s.Codecs...)
		if err == nil {
			session.IsNew = false
		}
	}
	return session, err
}

// Save adds a single session to the response.
func (s *CookieStore) Save(r *http.Request, w http.ResponseWriter,
	session *Session) error {
	encoded, err := securecookie.EncodeMulti(session.Name(), session.Values,
		s.Codecs...)
	if err != nil {
		return err
	}
	http.SetCookie(w, NewCookie(session.Name(), encoded, session.Options))
	return nil
}

// FilesystemStore ------------------------------------------------------------

var fileMutex sync.RWMutex

// NewFilesystemStore returns a new FilesystemStore.
//
// The path argument is the directory where sessions will be saved. If empty
// it will use os.TempDir().
//
// See NewCookieStore() for a description of the other parameters.
func NewFilesystemStore(path string, keyPairs ...[]byte) *FilesystemStore {
	if path == "" {
		path = os.TempDir()
	}
	if path[len(path)-1] != '/' {
		path += "/"
	}
	return &FilesystemStore{
		Codecs: securecookie.CodecsFromPairs(keyPairs...),
		Options: &Options{
			Path:   "/",
			MaxAge: 86400 * 30,
		},
		path: path,
	}
}

// FilesystemStore stores sessions in the filesystem.
//
// It also serves as a referece for custom stores.
//
// This store is still experimental and not well tested. Feedback is welcome.
type FilesystemStore struct {
	Codecs  []securecookie.Codec
	Options *Options // default configuration
	path    string
}

// MaxLength restricts the maximum length of new sessions to l.
// If l is 0 there is no limit to the size of a session, use with caution.
// The default for a new FilesystemStore is 4096.
func (s *FilesystemStore) MaxLength(l int) {
	for _, c := range s.Codecs {
		if codec, ok := c.(*securecookie.SecureCookie); ok {
			codec.MaxLength(l)
		}
	}
}

// Get returns a session for the given name after adding it to the registry.
//
// See CookieStore.Get().
func (s *FilesystemStore) Get(r *http.Request, name string) (*Session, error) {
	return GetRegistry(r).Get(s, name)
}

// New returns a session for the given name without adding it to the registry.
//
// See CookieStore.New().
func (s *FilesystemStore) New(r *http.Request, name string) (*Session, error) {
	session := NewSession(s, name)
	opts := *s.Options
	session.Options = &opts
	session.IsNew = true
	var err error
	if c, errCookie := r.Cookie(name); errCookie == nil {
		err = securecookie.DecodeMulti(name, c.Value, &session.ID, s.Codecs...)
		if err == nil {
			err = s.load(session)
			if err == nil {
				session.IsNew = false
			}
		}
	}
	return session, err
}

// Save adds a single session to the response.
func (s *FilesystemStore) Save(r *http.Request, w http.ResponseWriter,
	session *Session) error {
	if session.ID == "" {
		// Because the ID is used in the filename, encode it to
		// use alphanumeric characters only.
		session.ID = strings.TrimRight(
			base32.StdEncoding.EncodeToString(
				securecookie.GenerateRandomKey(32)), "=")
	}
	if err := s.save(session); err != nil {
		return err
	}
	encoded, err := securecookie.EncodeMulti(session.Name(), session.ID,
		s.Codecs...)
	if err != nil {
		return err
	}
	http.SetCookie(w, NewCookie(session.Name(), encoded, session.Options))
	return nil
}

// save writes encoded session.Values to a file.
func (s *FilesystemStore) save(session *Session) error {
	encoded, err := securecookie.EncodeMulti(session.Name(), session.Values,
		s.Codecs...)
	if err != nil {
		return err
	}
	filename := s.path + "session_" + session.ID
	fileMutex.Lock()
	defer fileMutex.Unlock()
	fp, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	if _, err = fp.Write([]byte(encoded)); err != nil {
		return err
	}
	fp.Close()
	return nil
}

// load reads a file and decodes its content into session.Values.
func (s *FilesystemStore) load(session *Session) error {
	filename := s.path + "session_" + session.ID
	fp, err := os.OpenFile(filename, os.O_RDONLY, 0400)
	if err != nil {
		return err
	}
	defer fp.Close()
	var fdata []byte
	buf := make([]byte, 128)
	for {
		var n int
		n, err = fp.Read(buf[0:])
		fdata = append(fdata, buf[0:n]...)
		if err != nil {
			if err == io.EOF {
				break
			}
			return err
		}
	}
	if err = securecookie.DecodeMulti(session.Name(), string(fdata),
		&session.Values, s.Codecs...); err != nil {
		return err
	}
	return nil
}
<commit_msg>Improved Store interface comments.<commit_after>// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sessions

import (
	"encoding/base32"
	"io"
	"net/http"
	"os"
	"strings"
	"sync"

	"github.com/gorilla/securecookie"
)

// Store is an interface for custom session stores.
//
// See CookieStore and FilesystemStore for examples.
type Store interface {
	// Get should return a cached session.
	Get(r *http.Request, name string) (*Session, error)

	// New should create and return a new session.
	//
	// Note that New should never return a nil session, even in the case of
	// an error if using the Registry infrastructure to cache the session.
	New(r *http.Request, name string) (*Session, error)

	// Save should persist session to the underlying store implementation.
	Save(r *http.Request, w http.ResponseWriter, s *Session) error
}

// CookieStore ----------------------------------------------------------------

// NewCookieStore returns a new CookieStore.
//
// Keys are defined in pairs to allow key rotation, but the common case is
// to set a single authentication key and optionally an encryption key.
//
// The first key in a pair is used for authentication and the second for
// encryption. The encryption key can be set to nil or omitted in the last
// pair, but the authentication key is required in all pairs.
//
// It is recommended to use an authentication key with 32 or 64 bytes.
// The encryption key, if set, must be either 16, 24, or 32 bytes to select
// AES-128, AES-192, or AES-256 modes.
//
// Use the convenience function securecookie.GenerateRandomKey() to create
// strong keys.
func NewCookieStore(keyPairs ...[]byte) *CookieStore {
	return &CookieStore{
		Codecs: securecookie.CodecsFromPairs(keyPairs...),
		Options: &Options{
			Path:   "/",
			MaxAge: 86400 * 30,
		},
	}
}

// CookieStore stores sessions using secure cookies.
type CookieStore struct {
	Codecs  []securecookie.Codec
	Options *Options // default configuration
}

// Get returns a session for the given name after adding it to the registry.
//
// It returns a new session if the sessions doesn't exist. Access IsNew on
// the session to check if it is an existing session or a new one.
//
// It returns a new session and an error if the session exists but could
// not be decoded.
func (s *CookieStore) Get(r *http.Request, name string) (*Session, error) {
	return GetRegistry(r).Get(s, name)
}

// New returns a session for the given name without adding it to the registry.
//
// The difference between New() and Get() is that calling New() twice will
// decode the session data twice, while Get() registers and reuses the same
// decoded session after the first call.
func (s *CookieStore) New(r *http.Request, name string) (*Session, error) {
	session := NewSession(s, name)
	opts := *s.Options
	session.Options = &opts
	session.IsNew = true
	var err error
	if c, errCookie := r.Cookie(name); errCookie == nil {
		err = securecookie.DecodeMulti(name, c.Value, &session.Values,
			s.Codecs...)
		if err == nil {
			session.IsNew = false
		}
	}
	return session, err
}

// Save adds a single session to the response.
func (s *CookieStore) Save(r *http.Request, w http.ResponseWriter,
	session *Session) error {
	encoded, err := securecookie.EncodeMulti(session.Name(), session.Values,
		s.Codecs...)
	if err != nil {
		return err
	}
	http.SetCookie(w, NewCookie(session.Name(), encoded, session.Options))
	return nil
}

// FilesystemStore ------------------------------------------------------------

var fileMutex sync.RWMutex

// NewFilesystemStore returns a new FilesystemStore.
//
// The path argument is the directory where sessions will be saved. If empty
// it will use os.TempDir().
//
// See NewCookieStore() for a description of the other parameters.
func NewFilesystemStore(path string, keyPairs ...[]byte) *FilesystemStore {
	if path == "" {
		path = os.TempDir()
	}
	if path[len(path)-1] != '/' {
		path += "/"
	}
	return &FilesystemStore{
		Codecs: securecookie.CodecsFromPairs(keyPairs...),
		Options: &Options{
			Path:   "/",
			MaxAge: 86400 * 30,
		},
		path: path,
	}
}

// FilesystemStore stores sessions in the filesystem.
//
// It also serves as a referece for custom stores.
//
// This store is still experimental and not well tested. Feedback is welcome.
type FilesystemStore struct {
	Codecs  []securecookie.Codec
	Options *Options // default configuration
	path    string
}

// MaxLength restricts the maximum length of new sessions to l.
// If l is 0 there is no limit to the size of a session, use with caution.
// The default for a new FilesystemStore is 4096.
func (s *FilesystemStore) MaxLength(l int) {
	for _, c := range s.Codecs {
		if codec, ok := c.(*securecookie.SecureCookie); ok {
			codec.MaxLength(l)
		}
	}
}

// Get returns a session for the given name after adding it to the registry.
//
// See CookieStore.Get().
func (s *FilesystemStore) Get(r *http.Request, name string) (*Session, error) {
	return GetRegistry(r).Get(s, name)
}

// New returns a session for the given name without adding it to the registry.
//
// See CookieStore.New().
func (s *FilesystemStore) New(r *http.Request, name string) (*Session, error) {
	session := NewSession(s, name)
	opts := *s.Options
	session.Options = &opts
	session.IsNew = true
	var err error
	if c, errCookie := r.Cookie(name); errCookie == nil {
		err = securecookie.DecodeMulti(name, c.Value, &session.ID, s.Codecs...)
		if err == nil {
			err = s.load(session)
			if err == nil {
				session.IsNew = false
			}
		}
	}
	return session, err
}

// Save adds a single session to the response.
func (s *FilesystemStore) Save(r *http.Request, w http.ResponseWriter,
	session *Session) error {
	if session.ID == "" {
		// Because the ID is used in the filename, encode it to
		// use alphanumeric characters only.
		session.ID = strings.TrimRight(
			base32.StdEncoding.EncodeToString(
				securecookie.GenerateRandomKey(32)), "=")
	}
	if err := s.save(session); err != nil {
		return err
	}
	encoded, err := securecookie.EncodeMulti(session.Name(), session.ID,
		s.Codecs...)
	if err != nil {
		return err
	}
	http.SetCookie(w, NewCookie(session.Name(), encoded, session.Options))
	return nil
}

// save writes encoded session.Values to a file.
func (s *FilesystemStore) save(session *Session) error {
	encoded, err := securecookie.EncodeMulti(session.Name(), session.Values,
		s.Codecs...)
	if err != nil {
		return err
	}
	filename := s.path + "session_" + session.ID
	fileMutex.Lock()
	defer fileMutex.Unlock()
	fp, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	if _, err = fp.Write([]byte(encoded)); err != nil {
		return err
	}
	fp.Close()
	return nil
}

// load reads a file and decodes its content into session.Values.
func (s *FilesystemStore) load(session *Session) error {
	filename := s.path + "session_" + session.ID
	fp, err := os.OpenFile(filename, os.O_RDONLY, 0400)
	if err != nil {
		return err
	}
	defer fp.Close()
	var fdata []byte
	buf := make([]byte, 128)
	for {
		var n int
		n, err = fp.Read(buf[0:])
		fdata = append(fdata, buf[0:n]...)
		if err != nil {
			if err == io.EOF {
				break
			}
			return err
		}
	}
	if err = securecookie.DecodeMulti(session.Name(), string(fdata),
		&session.Values, s.Codecs...); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package crud

import "strconv"
import "fmt"
import "strings"
import "errors"

type Table struct {
	*CRUD
	tableName string
}

// 返回这张表所有数据
func (t *Table) All() []map[string]string {
	return t.Query("SELECT * FROM " + t.tableName).RawsMap()
}

// 返回表有多少条数据
func (t *Table) Count() (count int) {
	t.Query("SELECT COUNT(*) FROM " + t.tableName).Scan(&count)
	return
}

// 查找表的更新时间
func (t *Table) UpdateTime() (updateTime string) {
	t.Query("SELECT `UPDATE_TIME` FROM  INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA =(select database()) AND TABLE_NAME = '" + t.tableName + "';").Scan(&updateTime)
	return
}

// 查找表的自增ID的值
func (t *Table) AutoIncrement() (id int) {
	t.Query("SELECT `AUTO_INCREMENT` FROM  INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA =(select database()) AND TABLE_NAME = '" + t.tableName + "';").Scan(&id)
	return
}

// 设置自动增长ID
func (t *Table) SetAutoIncrement(id int) error {
	return t.Exec("ALTER TABLE `" + t.tableName + "` AUTO_INCREMENT = " + strconv.Itoa(id)).err
}

// 查找表的最大ID，如果为NULL的话则为0
func (t *Table) MaxID() (maxid int) {
	t.Query("SELECT IFNULL(MAX(id), 0) as id FROM `" + t.tableName + "`").Scan(&maxid)
	return
}

/*
	创建
	check 如果有，则会判断表里面以这几个字段为唯一的话，数据库是否存在此条数据，如果有就不插入了。
*/
func (t *Table) Create(m map[string]interface{}, checks ...string) error {
	//INSERT INTO `feedback` (`task_id`, `template_question_id`, `question_options_id`, `suggestion`, `member_id`) VALUES ('1', '1', '1', '1', '1')
	if len(checks) > 0 {
		names := []string{}
		values := []interface{}{}
		for _, check := range checks {
			names = append(names, "`"+check+"`"+" = ? ")
			values = append(values, m[check])
		}
		// SELECT COUNT(*) FROM `feedback` WHERE `task_id` = ? AND `member_id` = ?
		if t.Query(fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE %s", t.tableName, strings.Join(names, "AND")), values...).Int() > 0 {
			return errors.New("重复插入")
		}
	}
	ks, vs := ksvs(m)
	e, err := t.Exec(fmt.Sprintf("INSERT INTO `%s` (%s) VALUES (%s)", t.tableName, strings.Join(ks, ","), argslice(len(ks))), vs...).Effected()
	if err != nil {
		return errors.New("SQL语句异常")
	}
	if e <= 0 {
		return errors.New("插入数据库异常")
	}
	return nil
}

func (t *Table) Update(m map[string]interface{}, keys ...string) error {
	if len(keys) == 0 {
		keys = append(keys, "id")
	}
	keysValue := []interface{}{}
	whereks := []string{}
	for _, key := range keys {
		val, ok := m[key]
		if !ok {
			return errors.New("没有更新主键")
		}
		keysValue = append(keysValue, val)
		delete(m, key)
		whereks = append(whereks, "`"+key+"` = ? ")
	}
	//因为在更新的时候最好不要更新ID，而有时候又会将ID传入进来，所以id每次都会被删除，如果要更新id的话使用Exec()
	delete(m, "id")
	ks, vs := ksvs(m, " = ? ")
	for _, val := range keysValue {
		vs = append(vs, val)
	}
	_, err := t.Exec(fmt.Sprintf("UPDATE `%s` SET %s WHERE %s LIMIT 1", t.tableName, strings.Join(ks, ","), strings.Join(whereks, "AND")), vs...).Effected()
	if err != nil {
		return errors.New("SQL语句异常")
	}
	return nil
}

func (t *Table) Delete(m map[string]interface{}) error {
	return nil
}
<commit_msg>Add Table IDIn<commit_after>package crud

import "strconv"
import "fmt"
import "strings"
import "errors"

// Table 是对CRUD进一层的封装
type Table struct {
	*CRUD
	tableName string
}

// All 返回这张表所有数据
func (t *Table) All() []map[string]string {
	return t.Query("SELECT * FROM " + t.tableName).RawsMap()
}

// Count 返回表有多少条数据
func (t *Table) Count() (count int) {
	t.Query("SELECT COUNT(*) FROM " + t.tableName).Scan(&count)
	return
}

// UpdateTime 查找表的更新时间
func (t *Table) UpdateTime() (updateTime string) {
	t.Query("SELECT `UPDATE_TIME` FROM  INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA =(select database()) AND TABLE_NAME = '" + t.tableName + "';").Scan(&updateTime)
	return
}

// AutoIncrement 查找表的自增ID的值
func (t *Table) AutoIncrement() (id int) {
	t.Query("SELECT `AUTO_INCREMENT` FROM  INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA =(select database()) AND TABLE_NAME = '" + t.tableName + "';").Scan(&id)
	return
}

// SetAutoIncrement 设置自动增长ID
func (t *Table) SetAutoIncrement(id int) error {
	return t.Exec("ALTER TABLE `" + t.tableName + "` AUTO_INCREMENT = " + strconv.Itoa(id)).err
}

// MaxID 查找表的最大ID，如果为NULL的话则为0
func (t *Table) MaxID() (maxid int) {
	t.Query("SELECT IFNULL(MAX(id), 0) as id FROM `" + t.tableName + "`").Scan(&maxid)
	return
}

// IDIn 查找多个ID对应的列
func (t *Table) IDIn(ids ...interface{}) *SQLRows {
	if len(ids) == 0 {
		return &SQLRows{}
	}
	return t.Query(fmt.Sprintf("SELECT * FROM %s WHERE id in (%s)", t.tableName, argslice(len(ids))), ids...)
}

// Create 创建
// check 如果有，则会判断表里面以这几个字段为唯一的话，数据库是否存在此条数据，如果有就不插入了。
//
func (t *Table) Create(m map[string]interface{}, checks ...string) error {
	//INSERT INTO `feedback` (`task_id`, `template_question_id`, `question_options_id`, `suggestion`, `member_id`) VALUES ('1', '1', '1', '1', '1')
	if len(checks) > 0 {
		names := []string{}
		values := []interface{}{}
		for _, check := range checks {
			names = append(names, "`"+check+"`"+" = ? ")
			values = append(values, m[check])
		}
		// SELECT COUNT(*) FROM `feedback` WHERE `task_id` = ? AND `member_id` = ?
		if t.Query(fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE %s", t.tableName, strings.Join(names, "AND")), values...).Int() > 0 {
			return errors.New("重复插入")
		}
	}
	ks, vs := ksvs(m)
	e, err := t.Exec(fmt.Sprintf("INSERT INTO `%s` (%s) VALUES (%s)", t.tableName, strings.Join(ks, ","), argslice(len(ks))), vs...).Effected()
	if err != nil {
		return errors.New("SQL语句异常")
	}
	if e <= 0 {
		return errors.New("插入数据库异常")
	}
	return nil
}

func (t *Table) Update(m map[string]interface{}, keys ...string) error {
	if len(keys) == 0 {
		keys = append(keys, "id")
	}
	keysValue := []interface{}{}
	whereks := []string{}
	for _, key := range keys {
		val, ok := m[key]
		if !ok {
			return errors.New("没有更新主键")
		}
		keysValue = append(keysValue, val)
		delete(m, key)
		whereks = append(whereks, "`"+key+"` = ? ")
	}
	//因为在更新的时候最好不要更新ID，而有时候又会将ID传入进来，所以id每次都会被删除，如果要更新id的话使用Exec()
	delete(m, "id")
	ks, vs := ksvs(m, " = ? ")
	for _, val := range keysValue {
		vs = append(vs, val)
	}
	_, err := t.Exec(fmt.Sprintf("UPDATE `%s` SET %s WHERE %s LIMIT 1", t.tableName, strings.Join(ks, ","), strings.Join(whereks, "AND")), vs...).Effected()
	if err != nil {
		return errors.New("SQL语句异常")
	}
	return nil
}

func (t *Table) Delete(m map[string]interface{}) error {
	return nil
}
<|endoftext|>


<commit_before>package termo

import (
	"errors"
	"fmt"
	"syscall"
	"unicode/utf8"

	"github.com/jonvaldes/termo/terminal"
)

// NotATerminal is the error returned when running
// termo in an unsupported environment
var NotATerminal error = errors.New("not running in a terminal")

var oldTermState *terminal.State

// Init initializes termo to work with the terminal
func Init() error {
	if !terminal.IsTerminal(syscall.Stdin) {
		return NotATerminal
	}
	var err error
	oldTermState, err = terminal.MakeRaw(syscall.Stdin)
	if err != nil {
		panic(err)
	}
	return nil
}

// Stop restores the terminal to its original state
func Stop() {
	terminal.Restore(syscall.Stdin, oldTermState)
}

// Size returns the current size of the terminal
func Size() (int, int, error) {
	return terminal.GetSize(syscall.Stdin)
}

// ScanCode contains data for a terminal keypress
type ScanCode []byte

// IsEscapeCode returns true if the terminal
// considers it an escape code
func (s ScanCode) IsEscapeCode() bool {
	return s[0] == 27 && s[1] == 91
}

// EscapeCode returns the escape code for a keypress
func (s ScanCode) EscapeCode() byte {
	return s[2]
}

// Rune returns the actual key pressed (only for
// non-escapecode keypresses)
func (s ScanCode) Rune() rune {
	r, _ := utf8.DecodeRune(s)
	return r
}

// ReadScanCode reads a keypress from stdin.
// It will block until it can read something
func ReadScanCode() (ScanCode, error) {
	s := ScanCode{0, 0, 0, 0, 0, 0}
	_, err := syscall.Read(syscall.Stdin, s)
	return s, err
}

type Attribute int

const (
	AttrNone  Attribute = 0
	AttrBold  Attribute = 1
	AttrDim   Attribute = 2
	AttrUnder Attribute = 4
	AttrBlink Attribute = 5
	AttrRev   Attribute = 7
	AttrHid   Attribute = 8
)

type Color int

const (
	ColorBlack Color = 30 + iota
	ColorRed
	ColorGreen
	ColorYellow
	ColorBlue
	ColorMagenta
	ColorCyan
	ColorGray
	ColorDefault Color = 39
)

func (c Color) Light() Color {
	return c + 60
}

func background(c Color) Color {
	return c + 10
}

type CellState struct {
	Attrib  Attribute
	FGColor Color
	BGColor Color
}

type cell struct {
	state CellState
	r     rune
}

// Framebuffer contains the runes to draw
// in the terminal
type Framebuffer struct {
	w, h  int
	chars []cell
}

// NewFramebuffer creates a Framebuffer with the specified size
// and initializes it filling it with blank spaces
func NewFramebuffer(w, h int) *Framebuffer {
	result := &Framebuffer{w, h, make([]cell, w*h)}
	result.Clear()
	return result
}

// Get returns the rune stored in the [x,y] position.
// If coords are outside the framebuffer size, it returns ' '
func (f *Framebuffer) Get(x, y int) (rune, CellState) {
	if x < 0 || y < 0 || x >= f.w || y >= f.h {
		return ' ', CellState{AttrNone, ColorDefault, ColorDefault}
	}
	c := f.chars[x+y*f.w]
	return c.r, c.state
}

// Put sets a rune in the specified position
func (f *Framebuffer) Put(x, y int, s CellState, r rune) {
	if x < 0 || y < 0 || x >= f.w || y >= f.h {
		return
	}
	f.chars[x+y*f.w].r = r
	f.chars[x+y*f.w].state = s
}

// PutRect fills a rectangular region with a rune
func (f *Framebuffer) PutRect(x0, y0, w, h int, s CellState, r rune) {
	for y := y0; y < y0+h; y++ {
		for x := x0; x < x0+w; x++ {
			f.Put(x, y, s, r)
		}
	}
}

// PutText draws a string from left to right, starting at x0,y0
// There is no wrapping mechanism, and parts of the text outside
// the framebuffer will be ignored.
func (f *Framebuffer) PutText(x0, y0 int, s CellState, t string) {
	i := 0
	for _, runeValue := range t {
		f.Put(x0+i, y0, s, runeValue)
		i++
	}
}

// Clear fills the framebuffer with blank spaces
func (f *Framebuffer) Clear() {
	f.PutRect(0, 0, f.w, f.h, CellState{Attrib: AttrNone, FGColor: ColorDefault, BGColor: ColorDefault}, ' ')
}

// Flush pushes the current state of the framebuffer to the terminal
func (f *Framebuffer) Flush() {
	fmt.Printf("\033[0;0H")
	for y := 0; y < f.h; y++ {
		if y != 0 {
			fmt.Print("\n")
		}
		for x := 0; x < f.w; x++ {
			c := f.chars[y*f.w+x]
			fmt.Printf("\033[%d;%d;%dm%c\033[0m", c.state.Attrib, c.state.FGColor, background(c.state.BGColor), c.r)
		}
	}
	fmt.Printf("\033[0m")
}
<commit_msg>Added simpler way to get key input<commit_after>package termo

import (
	"errors"
	"fmt"
	"syscall"
	"unicode/utf8"

	"github.com/jonvaldes/termo/terminal"
)

// NotATerminal is the error returned when running
// termo in an unsupported environment
var NotATerminal error = errors.New("not running in a terminal")

var oldTermState *terminal.State

// Init initializes termo to work with the terminal
func Init() error {
	if !terminal.IsTerminal(syscall.Stdin) {
		return NotATerminal
	}
	var err error
	oldTermState, err = terminal.MakeRaw(syscall.Stdin)
	if err != nil {
		panic(err)
	}
	return nil
}

// Stop restores the terminal to its original state
func Stop() {
	terminal.Restore(syscall.Stdin, oldTermState)
}

// Size returns the current size of the terminal
func Size() (int, int, error) {
	return terminal.GetSize(syscall.Stdin)
}

// ScanCode contains data for a terminal keypress
type ScanCode []byte

// IsEscapeCode returns true if the terminal
// considers it an escape code
func (s ScanCode) IsEscapeCode() bool {
	return s[0] == 27 && s[1] == 91
}

// EscapeCode returns the escape code for a keypress
func (s ScanCode) EscapeCode() byte {
	return s[2]
}

// Rune returns the actual key pressed (only for
// non-escapecode keypresses)
func (s ScanCode) Rune() rune {
	r, _ := utf8.DecodeRune(s)
	return r
}

// ReadScanCode reads a keypress from stdin.
// It will block until it can read something
func ReadScanCode() (ScanCode, error) {
	s := ScanCode{0, 0, 0, 0, 0, 0}
	_, err := syscall.Read(syscall.Stdin, s)
	return s, err
}

func StartKeyReadLoop(keyChan chan<- ScanCode, errChan chan<- error) {
	go func() {
		for {
			s, err := ReadScanCode()
			if err != nil {
				errChan <- err
				return
			}
			keyChan <- s
		}
	}()
}

type Attribute int

const (
	AttrNone  Attribute = 0
	AttrBold  Attribute = 1
	AttrDim   Attribute = 2
	AttrUnder Attribute = 4
	AttrBlink Attribute = 5
	AttrRev   Attribute = 7
	AttrHid   Attribute = 8
)

type Color int

const (
	ColorBlack Color = 30 + iota
	ColorRed
	ColorGreen
	ColorYellow
	ColorBlue
	ColorMagenta
	ColorCyan
	ColorGray
	ColorDefault Color = 39
)

func (c Color) Light() Color {
	return c + 60
}

func background(c Color) Color {
	return c + 10
}

type CellState struct {
	Attrib  Attribute
	FGColor Color
	BGColor Color
}

type cell struct {
	state CellState
	r     rune
}

// Framebuffer contains the runes to draw
// in the terminal
type Framebuffer struct {
	w, h  int
	chars []cell
}

// NewFramebuffer creates a Framebuffer with the specified size
// and initializes it filling it with blank spaces
func NewFramebuffer(w, h int) *Framebuffer {
	result := &Framebuffer{w, h, make([]cell, w*h)}
	result.Clear()
	return result
}

// Get returns the rune stored in the [x,y] position.
// If coords are outside the framebuffer size, it returns ' '
func (f *Framebuffer) Get(x, y int) (rune, CellState) {
	if x < 0 || y < 0 || x >= f.w || y >= f.h {
		return ' ', CellState{AttrNone, ColorDefault, ColorDefault}
	}
	c := f.chars[x+y*f.w]
	return c.r, c.state
}

// Put sets a rune in the specified position
func (f *Framebuffer) Put(x, y int, s CellState, r rune) {
	if x < 0 || y < 0 || x >= f.w || y >= f.h {
		return
	}
	f.chars[x+y*f.w].r = r
	f.chars[x+y*f.w].state = s
}

// PutRect fills a rectangular region with a rune
func (f *Framebuffer) PutRect(x0, y0, w, h int, s CellState, r rune) {
	for y := y0; y < y0+h; y++ {
		for x := x0; x < x0+w; x++ {
			f.Put(x, y, s, r)
		}
	}
}

// PutText draws a string from left to right, starting at x0,y0
// There is no wrapping mechanism, and parts of the text outside
// the framebuffer will be ignored.
func (f *Framebuffer) PutText(x0, y0 int, s CellState, t string) {
	i := 0
	for _, runeValue := range t {
		f.Put(x0+i, y0, s, runeValue)
		i++
	}
}

// Clear fills the framebuffer with blank spaces
func (f *Framebuffer) Clear() {
	f.PutRect(0, 0, f.w, f.h, CellState{Attrib: AttrNone, FGColor: ColorDefault, BGColor: ColorDefault}, ' ')
}

// Flush pushes the current state of the framebuffer to the terminal
func (f *Framebuffer) Flush() {
	fmt.Printf("\033[0;0H")
	for y := 0; y < f.h; y++ {
		if y != 0 {
			fmt.Print("\n")
		}
		for x := 0; x < f.w; x++ {
			c := f.chars[y*f.w+x]
			fmt.Printf("\033[%d;%d;%dm%c\033[0m", c.state.Attrib, c.state.FGColor, background(c.state.BGColor), c.r)
		}
	}
	fmt.Printf("\033[0m")
}
<|endoftext|>


<commit_before>package statuscake

import (
	"encoding/json"
	"fmt"
	"net/url"
	"reflect"
	"strings"
)

const queryStringTag = "querystring"

// Test represents a statuscake Test
type Test struct {
	// TestID is an int, use this to get more details about this test. If not provided will insert a new check, else will update
	TestID int `json:"TestID" querystring:"TestID" querystringoptions:"omitempty"`

	// Sent tfalse To Unpause and true To Pause.
	Paused bool `json:"Paused" querystring:"Paused"`

	// Website name. Tags are stripped out
	WebsiteName string `json:"WebsiteName" querystring:"WebsiteName"`

	// CustomHeader. A special header that will be sent along with the HTTP tests.
	CustomHeader string `json:"CustomHeader" querystring:"CustomHeader"`

	// Use to populate the test with a custom user agent
	UserAgent string `json:"UserAgent" queryString:"UserAgent"`

	// Test location, either an IP (for TCP and Ping) or a fully qualified URL for other TestTypes
	WebsiteURL string `json:"WebsiteURL" querystring:"WebsiteURL"`

	// A Port to use on TCP Tests
	Port int `json:"Port" querystring:"Port"`

	// Contact group ID - deprecated in favor of ContactGroup but still provided in the API detail response
	ContactID int `json:"ContactID"`

	// Contact group IDs - will return list of ints or empty if not provided
	ContactGroup []string `json:"ContactGroup" querystring:"ContactGroup"`

	// Current status at last test
	Status string `json:"Status"`

	// 7 Day Uptime
	Uptime float64 `json:"Uptime"`

	// Any test locations seperated by a comma (using the Node Location IDs)
	NodeLocations []string `json:"NodeLocations" querystring:"NodeLocations"`

	// Timeout in an int form representing seconds.
	Timeout int `json:"Timeout" querystring:"Timeout"`

	// A URL to ping if a site goes down.
	PingURL string `json:"PingURL" querystring:"PingURL"`

	Confirmation int `json:"Confirmation,string" querystring:"Confirmation"`

	// The number of seconds between checks.
	CheckRate int `json:"CheckRate" querystring:"CheckRate"`

	// A Basic Auth User account to use to login
	BasicUser string `json:"BasicUser" querystring:"BasicUser"`

	// If BasicUser is set then this should be the password for the BasicUser
	BasicPass string `json:"BasicPass" querystring:"BasicPass"`

	// Set 1 to enable public reporting, 0 to disable
	Public int `json:"Public" querystring:"Public"`

	// A URL to a image to use for public reporting
	LogoImage string `json:"LogoImage" querystring:"LogoImage"`

	// Set to 0 to use branding (default) or 1 to disable public reporting branding
	Branding int `json:"Branding" querystring:"Branding"`

	// Used internally by the statuscake API
	WebsiteHost string `json:"WebsiteHost" querystring:"WebsiteHost"`

	// Enable virus checking or not. 1 to enable
	Virus int `json:"Virus" querystring:"Virus"`

	// A string that should either be found or not found.
	FindString string `json:"FindString" querystring:"FindString"`

	// If the above string should be found to trigger a alert. true will trigger if FindString found
	DoNotFind bool `json:"DoNotFind" querystring:"DoNotFind"`

	// What type of test type to use. Accepted values are HTTP, TCP, PING
	TestType string `json:"TestType" querystring:"TestType"`

	// Use 1 to TURN OFF real browser testing
	RealBrowser int `json:"RealBrowser" querystring:"RealBrowser"`

	// How many minutes to wait before sending an alert
	TriggerRate int `json:"TriggerRate" querystring:"TriggerRate"`

	// Tags should be seperated by a comma - no spacing between tags (this,is,a set,of,tags)
	TestTags []string `json:"TestTags" querystring:"TestTags"`

	// Comma Seperated List of StatusCodes to Trigger Error on (on Update will replace, so send full list each time)
	StatusCodes string `json:"StatusCodes" querystring:"StatusCodes"`

	// Set to 1 to enable the Cookie Jar. Required for some redirects.
	UseJar int `json:"UseJar" querystring:"UseJar"`

	// Raw POST data seperated by an ampersand
	PostRaw string `json:"PostRaw" querystring:"PostRaw"`

	// Use to specify the expected Final URL in the testing process
	FinalEndpoint string `json:"FinalEndpoint" querystring:"FinalEndpoint"`

	// Use to specify whether redirects should be followed
	FollowRedirect bool `json:"FollowRedirect" querystring:"FollowRedirect"`
}

// Validate checks if the Test is valid. If it's invalid, it returns a ValidationError with all invalid fields. It returns nil otherwise.
func (t *Test) Validate() error {
	e := make(ValidationError)

	if t.WebsiteName == "" {
		e["WebsiteName"] = "is required"
	}

	if t.WebsiteURL == "" {
		e["WebsiteURL"] = "is required"
	}

	if t.Timeout != 0 && (t.Timeout < 6 || t.Timeout > 99) {
		e["Timeout"] = "must be 0 or between 6 and 99"
	}

	if t.Confirmation < 0 || t.Confirmation > 9 {
		e["Confirmation"] = "must be between 0 and 9"
	}

	if t.CheckRate < 0 || t.CheckRate > 23999 {
		e["CheckRate"] = "must be between 0 and 23999"
	}

	if t.Public < 0 || t.Public > 1 {
		e["Public"] = "must be 0 or 1"
	}

	if t.Virus < 0 || t.Virus > 1 {
		e["Virus"] = "must be 0 or 1"
	}

	if t.TestType != "HTTP" && t.TestType != "TCP" && t.TestType != "PING" {
		e["TestType"] = "must be HTTP, TCP, or PING"
	}

	if t.RealBrowser < 0 || t.RealBrowser > 1 {
		e["RealBrowser"] = "must be 0 or 1"
	}

	if t.TriggerRate < 0 || t.TriggerRate > 59 {
		e["TriggerRate"] = "must be between 0 and 59"
	}

	if t.PostRaw != "" && t.TestType != "HTTP" {
		e["PostRaw"] = "must be HTTP to submit a POST request"
	}

	if t.FinalEndpoint != "" && t.TestType != "HTTP" {
		e["FinalEndpoint"] = "must be a Valid URL"
	}

	var jsonVerifiable map[string]interface{}
	if json.Unmarshal([]byte(t.CustomHeader), &jsonVerifiable) != nil {
		e["CustomHeader"] = "must be provided as json string"
	}

	if len(e) > 0 {
		return e
	}

	return nil
}

// ToURLValues returns url.Values of all fields required to create/update a Test.
func (t Test) ToURLValues() url.Values {
	values := make(url.Values)
	st := reflect.TypeOf(t)
	sv := reflect.ValueOf(t)
	for i := 0; i < st.NumField(); i++ {
		sf := st.Field(i)
		tag := sf.Tag.Get(queryStringTag)
		ft := sf.Type
		if ft.Name() == "" && ft.Kind() == reflect.Ptr {
			// Follow pointer.
			ft = ft.Elem()
		}

		v := sv.Field(i)
		options := sf.Tag.Get("querystringoptions")
		omit := options == "omitempty" && isEmptyValue(v)

		if tag != "" && !omit {
			values.Set(tag, valueToQueryStringValue(v))
		}
	}

	return values
}

func isEmptyValue(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		return v.Len() == 0
	case reflect.Bool:
		return !v.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Interface, reflect.Ptr:
		return v.IsNil()
	}

	return false
}

func valueToQueryStringValue(v reflect.Value) string {
	if v.Type().Name() == "bool" {
		if v.Bool() {
			return "1"
		}

		return "0"
	}

	if v.Type().Kind() == reflect.Slice {
		if ss, ok := v.Interface().([]string); ok {
			return strings.Join(ss, ",")
		}
	}

	return fmt.Sprint(v)
}

// Tests is a client that implements the `Tests` API.
type Tests interface {
	All() ([]*Test, error)
	AllWithFilter(url.Values) ([]*Test, error)
	Detail(int) (*Test, error)
	Update(*Test) (*Test, error)
	Delete(TestID int) error
}

type tests struct {
	client apiClient
}

func newTests(c apiClient) Tests {
	return &tests{
		client: c,
	}
}

func (tt *tests) All() ([]*Test, error) {
	resp, err := tt.client.get("/Tests", nil)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var tests []*Test
	err = json.NewDecoder(resp.Body).Decode(&tests)

	return tests, err
}

func (tt *tests) AllWithFilter(filterOptions url.Values) ([]*Test, error) {
	resp, err := tt.client.get("/Tests", filterOptions)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var tests []*Test
	err = json.NewDecoder(resp.Body).Decode(&tests)

	return tests, err
}

func (tt *tests) Update(t *Test) (*Test, error) {
	resp, err := tt.client.put("/Tests/Update", t.ToURLValues())
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var ur updateResponse
	err = json.NewDecoder(resp.Body).Decode(&ur)
	if err != nil {
		return nil, err
	}

	if !ur.Success {
		return nil, &updateError{Issues: ur.Issues, Message: ur.Message}
	}

	t2 := *t
	t2.TestID = ur.InsertID

	return &t2, err
}

func (tt *tests) Delete(testID int) error {
	resp, err := tt.client.delete("/Tests/Details", url.Values{"TestID": {fmt.Sprint(testID)}})
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	var dr deleteResponse
	err = json.NewDecoder(resp.Body).Decode(&dr)
	if err != nil {
		return err
	}

	if !dr.Success {
		return &deleteError{Message: dr.Error}
	}

	return nil
}

func (tt *tests) Detail(testID int) (*Test, error) {
	resp, err := tt.client.get("/Tests/Details", url.Values{"TestID": {fmt.Sprint(testID)}})
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var dr *detailResponse
	err = json.NewDecoder(resp.Body).Decode(&dr)
	if err != nil {
		return nil, err
	}

	return dr.test(), nil
}
<commit_msg>Uptime received from /Tests/Detail is only 1 day<commit_after>package statuscake

import (
	"encoding/json"
	"fmt"
	"net/url"
	"reflect"
	"strings"
)

const queryStringTag = "querystring"

// Test represents a statuscake Test
type Test struct {
	// TestID is an int, use this to get more details about this test. If not provided will insert a new check, else will update
	TestID int `json:"TestID" querystring:"TestID" querystringoptions:"omitempty"`

	// Sent tfalse To Unpause and true To Pause.
	Paused bool `json:"Paused" querystring:"Paused"`

	// Website name. Tags are stripped out
	WebsiteName string `json:"WebsiteName" querystring:"WebsiteName"`

	// CustomHeader. A special header that will be sent along with the HTTP tests.
	CustomHeader string `json:"CustomHeader" querystring:"CustomHeader"`

	// Use to populate the test with a custom user agent
	UserAgent string `json:"UserAgent" queryString:"UserAgent"`

	// Test location, either an IP (for TCP and Ping) or a fully qualified URL for other TestTypes
	WebsiteURL string `json:"WebsiteURL" querystring:"WebsiteURL"`

	// A Port to use on TCP Tests
	Port int `json:"Port" querystring:"Port"`

	// Contact group ID - deprecated in favor of ContactGroup but still provided in the API detail response
	ContactID int `json:"ContactID"`

	// Contact group IDs - will return list of ints or empty if not provided
	ContactGroup []string `json:"ContactGroup" querystring:"ContactGroup"`

	// Current status at last test
	Status string `json:"Status"`

	// 1 Day Uptime
	Uptime float64 `json:"Uptime"`

	// Any test locations seperated by a comma (using the Node Location IDs)
	NodeLocations []string `json:"NodeLocations" querystring:"NodeLocations"`

	// Timeout in an int form representing seconds.
	Timeout int `json:"Timeout" querystring:"Timeout"`

	// A URL to ping if a site goes down.
	PingURL string `json:"PingURL" querystring:"PingURL"`

	Confirmation int `json:"Confirmation,string" querystring:"Confirmation"`

	// The number of seconds between checks.
	CheckRate int `json:"CheckRate" querystring:"CheckRate"`

	// A Basic Auth User account to use to login
	BasicUser string `json:"BasicUser" querystring:"BasicUser"`

	// If BasicUser is set then this should be the password for the BasicUser
	BasicPass string `json:"BasicPass" querystring:"BasicPass"`

	// Set 1 to enable public reporting, 0 to disable
	Public int `json:"Public" querystring:"Public"`

	// A URL to a image to use for public reporting
	LogoImage string `json:"LogoImage" querystring:"LogoImage"`

	// Set to 0 to use branding (default) or 1 to disable public reporting branding
	Branding int `json:"Branding" querystring:"Branding"`

	// Used internally by the statuscake API
	WebsiteHost string `json:"WebsiteHost" querystring:"WebsiteHost"`

	// Enable virus checking or not. 1 to enable
	Virus int `json:"Virus" querystring:"Virus"`

	// A string that should either be found or not found.
	FindString string `json:"FindString" querystring:"FindString"`

	// If the above string should be found to trigger a alert. true will trigger if FindString found
	DoNotFind bool `json:"DoNotFind" querystring:"DoNotFind"`

	// What type of test type to use. Accepted values are HTTP, TCP, PING
	TestType string `json:"TestType" querystring:"TestType"`

	// Use 1 to TURN OFF real browser testing
	RealBrowser int `json:"RealBrowser" querystring:"RealBrowser"`

	// How many minutes to wait before sending an alert
	TriggerRate int `json:"TriggerRate" querystring:"TriggerRate"`

	// Tags should be seperated by a comma - no spacing between tags (this,is,a set,of,tags)
	TestTags []string `json:"TestTags" querystring:"TestTags"`

	// Comma Seperated List of StatusCodes to Trigger Error on (on Update will replace, so send full list each time)
	StatusCodes string `json:"StatusCodes" querystring:"StatusCodes"`

	// Set to 1 to enable the Cookie Jar. Required for some redirects.
	UseJar int `json:"UseJar" querystring:"UseJar"`

	// Raw POST data seperated by an ampersand
	PostRaw string `json:"PostRaw" querystring:"PostRaw"`

	// Use to specify the expected Final URL in the testing process
	FinalEndpoint string `json:"FinalEndpoint" querystring:"FinalEndpoint"`

	// Use to specify whether redirects should be followed
	FollowRedirect bool `json:"FollowRedirect" querystring:"FollowRedirect"`
}

// Validate checks if the Test is valid. If it's invalid, it returns a ValidationError with all invalid fields. It returns nil otherwise.
func (t *Test) Validate() error {
	e := make(ValidationError)

	if t.WebsiteName == "" {
		e["WebsiteName"] = "is required"
	}

	if t.WebsiteURL == "" {
		e["WebsiteURL"] = "is required"
	}

	if t.Timeout != 0 && (t.Timeout < 6 || t.Timeout > 99) {
		e["Timeout"] = "must be 0 or between 6 and 99"
	}

	if t.Confirmation < 0 || t.Confirmation > 9 {
		e["Confirmation"] = "must be between 0 and 9"
	}

	if t.CheckRate < 0 || t.CheckRate > 23999 {
		e["CheckRate"] = "must be between 0 and 23999"
	}

	if t.Public < 0 || t.Public > 1 {
		e["Public"] = "must be 0 or 1"
	}

	if t.Virus < 0 || t.Virus > 1 {
		e["Virus"] = "must be 0 or 1"
	}

	if t.TestType != "HTTP" && t.TestType != "TCP" && t.TestType != "PING" {
		e["TestType"] = "must be HTTP, TCP, or PING"
	}

	if t.RealBrowser < 0 || t.RealBrowser > 1 {
		e["RealBrowser"] = "must be 0 or 1"
	}

	if t.TriggerRate < 0 || t.TriggerRate > 59 {
		e["TriggerRate"] = "must be between 0 and 59"
	}

	if t.PostRaw != "" && t.TestType != "HTTP" {
		e["PostRaw"] = "must be HTTP to submit a POST request"
	}

	if t.FinalEndpoint != "" && t.TestType != "HTTP" {
		e["FinalEndpoint"] = "must be a Valid URL"
	}

	var jsonVerifiable map[string]interface{}
	if json.Unmarshal([]byte(t.CustomHeader), &jsonVerifiable) != nil {
		e["CustomHeader"] = "must be provided as json string"
	}

	if len(e) > 0 {
		return e
	}

	return nil
}

// ToURLValues returns url.Values of all fields required to create/update a Test.
func (t Test) ToURLValues() url.Values {
	values := make(url.Values)
	st := reflect.TypeOf(t)
	sv := reflect.ValueOf(t)
	for i := 0; i < st.NumField(); i++ {
		sf := st.Field(i)
		tag := sf.Tag.Get(queryStringTag)
		ft := sf.Type
		if ft.Name() == "" && ft.Kind() == reflect.Ptr {
			// Follow pointer.
			ft = ft.Elem()
		}

		v := sv.Field(i)
		options := sf.Tag.Get("querystringoptions")
		omit := options == "omitempty" && isEmptyValue(v)

		if tag != "" && !omit {
			values.Set(tag, valueToQueryStringValue(v))
		}
	}

	return values
}

func isEmptyValue(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		return v.Len() == 0
	case reflect.Bool:
		return !v.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Interface, reflect.Ptr:
		return v.IsNil()
	}

	return false
}

func valueToQueryStringValue(v reflect.Value) string {
	if v.Type().Name() == "bool" {
		if v.Bool() {
			return "1"
		}

		return "0"
	}

	if v.Type().Kind() == reflect.Slice {
		if ss, ok := v.Interface().([]string); ok {
			return strings.Join(ss, ",")
		}
	}

	return fmt.Sprint(v)
}

// Tests is a client that implements the `Tests` API.
type Tests interface {
	All() ([]*Test, error)
	AllWithFilter(url.Values) ([]*Test, error)
	Detail(int) (*Test, error)
	Update(*Test) (*Test, error)
	Delete(TestID int) error
}

type tests struct {
	client apiClient
}

func newTests(c apiClient) Tests {
	return &tests{
		client: c,
	}
}

func (tt *tests) All() ([]*Test, error) {
	resp, err := tt.client.get("/Tests", nil)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var tests []*Test
	err = json.NewDecoder(resp.Body).Decode(&tests)

	return tests, err
}

func (tt *tests) AllWithFilter(filterOptions url.Values) ([]*Test, error) {
	resp, err := tt.client.get("/Tests", filterOptions)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var tests []*Test
	err = json.NewDecoder(resp.Body).Decode(&tests)

	return tests, err
}

func (tt *tests) Update(t *Test) (*Test, error) {
	resp, err := tt.client.put("/Tests/Update", t.ToURLValues())
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var ur updateResponse
	err = json.NewDecoder(resp.Body).Decode(&ur)
	if err != nil {
		return nil, err
	}

	if !ur.Success {
		return nil, &updateError{Issues: ur.Issues, Message: ur.Message}
	}

	t2 := *t
	t2.TestID = ur.InsertID

	return &t2, err
}

func (tt *tests) Delete(testID int) error {
	resp, err := tt.client.delete("/Tests/Details", url.Values{"TestID": {fmt.Sprint(testID)}})
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	var dr deleteResponse
	err = json.NewDecoder(resp.Body).Decode(&dr)
	if err != nil {
		return err
	}

	if !dr.Success {
		return &deleteError{Message: dr.Error}
	}

	return nil
}

func (tt *tests) Detail(testID int) (*Test, error) {
	resp, err := tt.client.get("/Tests/Details", url.Values{"TestID": {fmt.Sprint(testID)}})
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var dr *detailResponse
	err = json.NewDecoder(resp.Body).Decode(&dr)
	if err != nil {
		return nil, err
	}

	return dr.test(), nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

func goimports(paths []string, verbose bool) error {
	args := []string{"-l", "-w"}
	for _, path := range paths {
		args = append(args, path)
	}
	if verbose {
		fmt.Println("goimports", strings.Join(args, " "))
	}
	cmd := exec.Command("goimports", args...)
	var outbuf bytes.Buffer
	cmd.Stdout = &outbuf
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		return err
	}
	if outbuf.String() != "" {
		return fmt.Errorf("goimports -l -w:\n%s", strings.TrimSpace(outbuf.String()))
	}
	return nil
}

func gofmt(paths []string, verbose bool) error {
	args := []string{"-l", "-w", "-s"}
	for _, path := range paths {
		args = append(args, path)
	}
	if verbose {
		fmt.Println("gofmt", strings.Join(args, " "))
	}
	cmd := exec.Command("gofmt", args...)
	var outbuf bytes.Buffer
	cmd.Stdout = &outbuf
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		return err
	}
	if outbuf.String() != "" {
		return fmt.Errorf("gofmt -l -w -s:\n%s", strings.TrimSpace(outbuf.String()))
	}
	return nil
}

func golint(paths []string, verbose bool) error {
	if verbose {
		fmt.Println("golint", strings.Join(paths, " "))
	}
	cmd := exec.Command("golint", paths...)
	var outbuf bytes.Buffer
	cmd.Stdout = &outbuf
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		return err
	}
	if outbuf.String() != "" {
		return fmt.Errorf("golint:\n%s", strings.TrimSpace(outbuf.String()))
	}
	return nil
}

func gotoolvet(paths []string, verbose bool) error {
	if verbose {
		fmt.Println("go tool vet", strings.Join(paths, " "))
	}
	args := []string{"tool", "vet"}
	args = append(args, paths...)
	cmd := exec.Command("go", args...)
	var errbuf bytes.Buffer
	cmd.Stdout = os.Stdout
	cmd.Stderr = &errbuf
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("%s: go tool vet:\n%s", err,
			strings.TrimSpace(errbuf.String()))
	}
	return nil
}

func gotest(path string, coverage, verbose bool) error {
	args := []string{"test"}
	if coverage {
		args = append(args, "-cover")
	}
	args = append(args, path)
	if verbose {
		fmt.Println("go", strings.Join(args, " "))
	}
	cmd := exec.Command("go", args...)
	var errbuf bytes.Buffer
	cmd.Stdout = os.Stdout
	cmd.Stderr = &errbuf
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("%s: go test:\n%s", err,
			strings.TrimSpace(errbuf.String()))
	}
	return nil
}
<commit_msg>make sure golint is executed everywhere<commit_after>package main

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

func goimports(paths []string, verbose bool) error {
	args := []string{"-l", "-w"}
	for _, path := range paths {
		args = append(args, path)
	}
	if verbose {
		fmt.Println("goimports", strings.Join(args, " "))
	}
	cmd := exec.Command("goimports", args...)
	var outbuf bytes.Buffer
	cmd.Stdout = &outbuf
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		return err
	}
	if outbuf.String() != "" {
		return fmt.Errorf("goimports -l -w:\n%s", strings.TrimSpace(outbuf.String()))
	}
	return nil
}

func gofmt(paths []string, verbose bool) error {
	args := []string{"-l", "-w", "-s"}
	for _, path := range paths {
		args = append(args, path)
	}
	if verbose {
		fmt.Println("gofmt", strings.Join(args, " "))
	}
	cmd := exec.Command("gofmt", args...)
	var outbuf bytes.Buffer
	cmd.Stdout = &outbuf
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		return err
	}
	if outbuf.String() != "" {
		return fmt.Errorf("gofmt -l -w -s:\n%s", strings.TrimSpace(outbuf.String()))
	}
	return nil
}

func golint(paths []string, verbose bool) error {
	var pathsWithSubDirs []string
	for _, path := range paths {
		fi, err := os.Stat(path)
		if err != nil {
			return err
		}
		if fi.IsDir() {
			pathsWithSubDirs = append(pathsWithSubDirs, filepath.Join(path, "..."))
		} else {
			pathsWithSubDirs = append(pathsWithSubDirs, path)
		}

	}
	if verbose {
		fmt.Println("golint", strings.Join(pathsWithSubDirs, " "))
	}
	cmd := exec.Command("golint", pathsWithSubDirs...)
	var outbuf bytes.Buffer
	cmd.Stdout = &outbuf
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		return err
	}
	if outbuf.String() != "" {
		return fmt.Errorf("golint:\n%s", strings.TrimSpace(outbuf.String()))
	}
	return nil
}

func gotoolvet(paths []string, verbose bool) error {
	if verbose {
		fmt.Println("go tool vet", strings.Join(paths, " "))
	}
	args := []string{"tool", "vet"}
	args = append(args, paths...)
	cmd := exec.Command("go", args...)
	var errbuf bytes.Buffer
	cmd.Stdout = os.Stdout
	cmd.Stderr = &errbuf
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("%s: go tool vet:\n%s", err,
			strings.TrimSpace(errbuf.String()))
	}
	return nil
}

func gotest(path string, coverage, verbose bool) error {
	args := []string{"test"}
	if coverage {
		args = append(args, "-cover")
	}
	args = append(args, path)
	if verbose {
		fmt.Println("go", strings.Join(args, " "))
	}
	cmd := exec.Command("go", args...)
	var errbuf bytes.Buffer
	cmd.Stdout = os.Stdout
	cmd.Stderr = &errbuf
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("%s: go test:\n%s", err,
			strings.TrimSpace(errbuf.String()))
	}
	return nil
}
<|endoftext|>


<commit_before>package holux

import (
	"bytes"
	"fmt"
	"time"
)

const (
	Y2000     = 946684800
	TRACKSIZE = 32
	INDEXSIZE = 64
	TRKPTTIME = "2006-01-02 15:04:05Z07:00"
)

type Trackpoint struct {
	RawTime  MTKTime
	Lat      float32 // North Positive
	Lon      float32 // East Positive
	Height   int16
	Speed    uint16
	_        byte
	Flags    byte
	HR       uint16
	Alt      int16
	Heading  uint16
	Distance uint32
	_        uint32 // Cadence?
}

type Track []Trackpoint

func (t Trackpoint) IsPOI() bool {
	return t.Flags&0x10 == 1
}

func (t Trackpoint) Time() time.Time {
	return t.RawTime.Value()
}

// TODO: Add more fields, perhaps?
func (t Trackpoint) String() string {
	var out bytes.Buffer

	fmt.Fprintf(&out, t.Time().Format(TRKPTTIME))
	fmt.Fprintf(&out, " %s, %s",
		fmtCoordinate(t.Lat, "N", "S"),
		fmtCoordinate(t.Lon, "E", "W"))
	return out.String()
}

func fmtCoordinate(v float32, pos, neg string) string {
	switch {
	case v > 0:
		return fmt.Sprintf("%0.5f °%s", v, pos)
	case v < 0:
		return fmt.Sprintf("%0.5f °%s", -v, neg)
	}
	return "0 °"
}

// FF 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF
// 52 08 B6 17 FD 0B 00 00 3F 04 00 00 00 00 00 00
// |--time---|             |distance-| |-offset--|
// 37 00 00 00 47 00 0C 00 2E 00 02 00 02 00 00 00
// |--size---| |smx| |sav| |cal|             HM HA
// 00 00 00 00 E6 00 00 00 02 00 00 00 00 00 00 00
type Index struct {
	F00F        [4]byte // TODO double check
	RawName     [10]byte
	Unk         [2]byte // First byte can be \0 for C strings
	RawTime     MTKTime // MKTTime
	RawDuration uint32  // seconds
	Distance    uint32  // meters

	Offset uint32 // LIST_MEM_START_OFFSET=28
	Size   uint32 // LIST_MEM_LENGTH_OFFSET=32

	SpeedMax uint16 // 35.6 km/h = 356.
	SpeedAvg uint16
	Calories uint16
	Unk1     [4]byte
	HRMMax   byte // BPM
	HRMAvg   byte
	Unk2     [16]byte
}

func (i Index) Name() string {
	if i.IsNameSet() {
		return string(i.RawName[:])
	}
	return ""
}

func (i Index) IsNameSet() bool {
	return i.RawName[0] != 0
}

func (i Index) Duration() time.Duration {
	return time.Duration(i.RawDuration) * time.Second
}

func (i Index) Time() time.Time {
	return i.RawTime.Value()
}

func (i Index) String() string {
	s := `[FF0000FF: %02x] [Name: % 02x (%s)] [Unk: %02x]
	Time: %v: Distance: %d m, Duration: %v
	Offset: %d points (%d B), Size: %d points (%d B)
	SPDMAX: %.1f km/h, SPDAVG: %.1f km/h, CAL: %d
	[% 02x]
	HRMMax: %d, HRMAvg: %d
	[% 02x]
	`
	return fmt.Sprintf(s, i.F00F, i.RawName, i.Name(), i.Unk,
		i.Time(), i.Distance, i.Duration(),
		i.Offset, i.Offset*32, i.Size, i.Size*32,
		float32(i.SpeedMax)/10, float32(i.SpeedAvg)/10, i.Calories,
		i.Unk1,
		i.HRMMax, i.HRMAvg,
		i.Unk2)
}

type MTKTime uint32

func (t MTKTime) Value() time.Time {
	return time.Unix(int64(t)+Y2000, 0)
}
<commit_msg>Improve index struct<commit_after>package holux

import (
	"bytes"
	"fmt"
	"time"
)

const (
	Y2000     = 946684800
	TRACKSIZE = 32
	INDEXSIZE = 64
	TRKPTTIME = "2006-01-02 15:04:05Z07:00"
)

type Trackpoint struct {
	RawTime  MTKTime
	Lat      float32 // North Positive
	Lon      float32 // East Positive
	Height   int16
	Speed    uint16
	_        byte
	Flags    byte
	HR       uint16
	Alt      int16
	Heading  uint16
	Distance uint32
	_        uint32 // Cadence?
}

type Track []Trackpoint

func (t Trackpoint) IsPOI() bool {
	return t.Flags&0x10 == 1
}

func (t Trackpoint) Time() time.Time {
	return t.RawTime.Value()
}

// TODO: Add more fields, perhaps?
func (t Trackpoint) String() string {
	var out bytes.Buffer

	fmt.Fprintf(&out, t.Time().Format(TRKPTTIME))
	fmt.Fprintf(&out, " %s, %s",
		fmtCoordinate(t.Lat, "N", "S"),
		fmtCoordinate(t.Lon, "E", "W"))
	return out.String()
}

func fmtCoordinate(v float32, pos, neg string) string {
	switch {
	case v > 0:
		return fmt.Sprintf("%0.5f °%s", v, pos)
	case v < 0:
		return fmt.Sprintf("%0.5f °%s", -v, neg)
	}
	return "0 °"
}

// FF 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF
//          01 jos favourite, muuten FF
// 52 08 B6 17 FD 0B 00 00 3F 04 00 00 00 00 00 00
// |--time---|             |distance-| |-offset--|
// 37 00 00 00 47 00 0C 00 2E 00 02 00 02 00 00 00
// |--size---| |smx| |sav| |cal|             HM HA
// 00 00 00 00 E6 00 00 00 02 00 00 00 00 00 00 00
// [pois] ?? ]
type Index struct {
	F00         [3]byte // TODO double check
	UnkFlag     byte    // FF when not favourite, 01 when fav
	RawName     [10]byte
	Unk         [2]byte // First byte can be \0 for C strings
	RawTime     MTKTime // MKTTime
	RawDuration uint32  // seconds
	Distance    uint32  // meters

	Offset uint32 // LIST_MEM_START_OFFSET=28
	Size   uint32 // LIST_MEM_LENGTH_OFFSET=32

	SpeedMax uint16 // 35.6 km/h = 356.
	SpeedAvg uint16
	Calories uint16
	Unk1     [2]byte
	CO2      uint16 // hectograms. 1 hg = 100 g
	HRMMax   byte   // BPM
	HRMAvg   byte
	POIs     byte // Can be uint16 or 32 as well.
	Unk2     [15]byte
}

func (i Index) Name() string {
	if i.IsNameSet() {
		return string(i.RawName[:])
	}
	return ""
}

func (i Index) IsNameSet() bool {
	return i.RawName[0] != 0xff
}

func (i Index) Duration() time.Duration {
	return time.Duration(i.RawDuration) * time.Second
}

func (i Index) Time() time.Time {
	return i.RawTime.Value()
}

func (i Index) IsFavorite() bool {
	return i.UnkFlag == 0x01
}

func (i Index) String() string {
	s := `[FF0000: %02x] Favorite: %v [Name: % 02x (%s)] [Unk: %02x]
	Time: %v: Distance: %d m, Duration: %v
	Offset: %d points (%d B), Size: %d points (%d B)
	SPDMAX: %.1f km/h, SPDAVG: %.1f km/h, CAL: %d
	[% 02x]
	CO2 %.1f kg
	HRMMax: %d, HRMAvg: %d
	[% 02x] (starts with # of POIs, length?)
	`
	return fmt.Sprintf(s, i.F00, i.IsFavorite(), i.RawName, i.Name(), i.Unk,
		i.Time(), i.Distance, i.Duration(),
		i.Offset, i.Offset*32, i.Size, i.Size*32,
		float32(i.SpeedMax)/10, float32(i.SpeedAvg)/10, i.Calories,
		i.Unk1,
		float32(i.CO2)/10,
		i.HRMMax, i.HRMAvg,
		i.Unk2)
}

type MTKTime uint32

func (t MTKTime) Value() time.Time {
	return time.Unix(int64(t)+Y2000, 0)
}
<|endoftext|>


<commit_before>package cmdline

import (
	"github.com/zxh0/jvm.go/jvmgo/classpath"
	"strconv"
	"strings"
)

const (
	_1k = 1024
	_1m = _1k * _1k
	_1g = _1k * _1m
)

type Options struct {
	classpath    *classpath.ClassPath
	verboseClass bool
	xss          int
	Xcpuprofile  string
}

func newOptions() *Options {
	options := &Options{}
	options.xss = 16 * _1k
	return options
}

// getters
func (self *Options) Classpath() *classpath.ClassPath {
	if self.classpath == nil {
		self.classpath = classpath.ParseClassPath(".")
	}
	return self.classpath
}
func (self *Options) VerboseClass() bool {
	return self.verboseClass
}
func (self *Options) Xss() int {
	return self.xss
}

func parseOptions(args *CmdLineArgs) *Options {
	options := newOptions()

	for !args.isEmpty() && args.first()[0] == '-' {
		optionName := args.removeFirst()
		_ = options.parseClassPathOption(optionName, args) ||
			options.parseVerboseOption(optionName) ||
			options.parseXssOption(optionName) ||
			options.parseXcpuprofile(optionName, args)
		// todo
	}

	return options
}

func (self *Options) parseClassPathOption(optionName string, args *CmdLineArgs) bool {
	if optionName == "-classpath" || optionName == "-cp" {
		optionVal := args.removeFirst()
		self.classpath = classpath.ParseClassPath(optionVal)
		return true
	}
	return false
}

func (self *Options) parseVerboseOption(optionName string) bool {
	if optionName == "-verbose" || optionName == "-verbose:class" {
		self.verboseClass = true
		return true
	}
	return false
}

// -Xss<size>[g|G|m|M|k|K]
func (self *Options) parseXssOption(optionName string) bool {
	if strings.HasPrefix(optionName, "-Xss") {
		size := optionName[4:]
		switch size[len(size)-1] {
		case 'g', 'G':
			self.xss = _1g * parseInt(size[:len(size)-1])
		case 'm', 'M':
			self.xss = _1m * parseInt(size[:len(size)-1])
		case 'k', 'K':
			self.xss = _1k * parseInt(size[:len(size)-1])
		default:
			self.xss = parseInt(size)
		}
		return true
	}
	return false
}

func (self *Options) parseXcpuprofile(optionName string, args *CmdLineArgs) bool {
	if optionName == "-Xcpuprofile" {
		self.Xcpuprofile = args.removeFirst()
		return true
	}
	return false
}

func parseInt(str string) int {
	i, err := strconv.Atoi(str)
	if err != nil {
		panic(err.Error())
	}
	return i
}
<commit_msg>add cmd line option: -XuseJavaHome<commit_after>package cmdline

import (
	"github.com/zxh0/jvm.go/jvmgo/classpath"
	"strconv"
	"strings"
)

const (
	_1k = 1024
	_1m = _1k * _1k
	_1g = _1k * _1m
)

type Options struct {
	classpath    *classpath.ClassPath
	verboseClass bool
	xss          int
	Xcpuprofile  string
	XuseJavaHome bool
}

func newOptions() *Options {
	options := &Options{}
	options.xss = 16 * _1k
	return options
}

// getters
func (self *Options) Classpath() *classpath.ClassPath {
	if self.classpath == nil {
		self.classpath = classpath.ParseClassPath(".")
	}
	return self.classpath
}
func (self *Options) VerboseClass() bool {
	return self.verboseClass
}
func (self *Options) Xss() int {
	return self.xss
}

func parseOptions(args *CmdLineArgs) *Options {
	options := newOptions()

	for !args.isEmpty() && args.first()[0] == '-' {
		optionName := args.removeFirst()
		_ = options.parseClassPathOption(optionName, args) ||
			options.parseVerboseOption(optionName) ||
			options.parseXssOption(optionName) ||
			options.parseXcpuprofile(optionName, args) ||
			options.parseXuseJavaHome(optionName)
		// todo
	}

	return options
}

func (self *Options) parseClassPathOption(optionName string, args *CmdLineArgs) bool {
	if optionName == "-classpath" || optionName == "-cp" {
		optionVal := args.removeFirst()
		self.classpath = classpath.ParseClassPath(optionVal)
		return true
	}
	return false
}

func (self *Options) parseVerboseOption(optionName string) bool {
	if optionName == "-verbose" || optionName == "-verbose:class" {
		self.verboseClass = true
		return true
	}
	return false
}

// -Xss<size>[g|G|m|M|k|K]
func (self *Options) parseXssOption(optionName string) bool {
	if strings.HasPrefix(optionName, "-Xss") {
		size := optionName[4:]
		switch size[len(size)-1] {
		case 'g', 'G':
			self.xss = _1g * parseInt(size[:len(size)-1])
		case 'm', 'M':
			self.xss = _1m * parseInt(size[:len(size)-1])
		case 'k', 'K':
			self.xss = _1k * parseInt(size[:len(size)-1])
		default:
			self.xss = parseInt(size)
		}
		return true
	}
	return false
}

func (self *Options) parseXcpuprofile(optionName string, args *CmdLineArgs) bool {
	if optionName == "-Xcpuprofile" {
		self.Xcpuprofile = args.removeFirst()
		return true
	}
	return false
}

func (self *Options) parseXuseJavaHome(optionName string) bool {
	if optionName == "-XuseJavaHome" {
		self.XuseJavaHome = true
		return true
	}
	return false
}

func parseInt(str string) int {
	i, err := strconv.Atoi(str)
	if err != nil {
		panic(err.Error())
	}
	return i
}
<|endoftext|>


<commit_before>package leetcode

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func Test_kthSmallest(t *testing.T) {
	assert := assert.New(t)

	/*
	         4
	       /   \
	     2      5
	    / \
	   1   3
	*/
	root := &TreeNode{Val: 4, Left: &TreeNode{Val: 2, Left: &TreeNode{Val: 1}, Right: &TreeNode{Val: 3}}, Right: &TreeNode{Val: 5}}
	for i := 1; i <= 5; i++ {
		assert.Equal(i, kthSmallest(root, i))
	}

}
<commit_msg>add panic test<commit_after>package leetcode

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func Test_kthSmallest(t *testing.T) {
	assert := assert.New(t)

	/*
	         4
	       /   \
	     2      5
	    / \
	   1   3
	*/
	root := &TreeNode{Val: 4, Left: &TreeNode{Val: 2, Left: &TreeNode{Val: 1}, Right: &TreeNode{Val: 3}}, Right: &TreeNode{Val: 5}}
	for i := 1; i <= 5; i++ {
		assert.Equal(i, kthSmallest(root, i))
	}

	assert.Panicsf(func() { kthSmallest(root, 100) }, "error occurred")
}
<|endoftext|>


<commit_before>package main

import (
	"compress/gzip"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

var logger = log.New(os.Stderr, "", 0)

func main() {
	if err := run(); err != nil {
		logger.Printf(err.Error())
		flag.Usage()
		os.Exit(1)
	}
}

var (
	address   = flag.String("a", "http://127.0.0.1:9200", "Address")
	index     = flag.String("i", "", "Index Name")
	out       = flag.String("o", "", "Output file")
	batchSize = flag.Int("b", 1000, "Batch Size")
)

func run() error {
	flag.Parse()
	if *address == "" {
		return errors.New("Address must be set")
	}
	if *index == "" {
		return errors.New("Index Name must be set")
	}

	if *out == "" {
		return errors.New("Output file must be set")
	}

	f, err := os.Create(*out)
	if err != nil {
		return err
	}
	defer f.Close()
	gz := gzip.NewWriter(f)
	defer gz.Close()

	docs, err := iterateIndex(*address, *index, *batchSize)
	if err != nil {
		return err
	}

	c, wg := progress()
	for d := range docs {
		if _, err = io.WriteString(gz, string(d)+"\n"); err != nil {
			return err
		}
		c <- struct{}{}
	}
	close(c)
	wg.Wait()
	return nil
}

func progress() (chan struct{}, *sync.WaitGroup) {
	wg := &sync.WaitGroup{}
	wg.Add(1)
	c := make(chan struct{})
	go func() {
		defer wg.Done()
		t := time.Tick(1 * time.Second)
		started := time.Now()
		cnt := 0

		printStatus := func() {
			diff := time.Since(started).Seconds()
			perSecond := float64(cnt) / diff
			logger.Printf("cnt=%d time=%.01f per_second=%.1f/second", cnt, diff, perSecond)
		}
		for {
			select {
			case _, ok := <-c:
				if !ok {
					printStatus()
					return
				}
				cnt++
			case <-t:
				printStatus()
			}

		}
	}()
	return c, wg
}

func iterateIndex(addr, name string, size int) (chan json.RawMessage, error) {
	scrollID, err := openIndex(addr, name, size, "1m")
	if err != nil {
		return nil, err
	}
	c := make(chan json.RawMessage)
	var docs []json.RawMessage
	go func() {
		defer close(c)
		for {
			scrollID, docs, err = loadDocumentsWithScroll(addr, scrollID)
			if err != nil {
				logger.Printf("err=%q", err)
				return
			} else if len(docs) == 0 {
				return
			}
			for _, d := range docs {
				c <- d
			}
		}
	}()
	return c, nil
}

type scrollResponse struct {
	ScrollID string `json:"_scroll_id"`
	Hits     struct {
		Hits []json.RawMessage `json:"hits"`
	} `json:"hits"`
}

func loadDocumentsWithScroll(addr string, id string) (string, []json.RawMessage, error) {
	req, err := http.NewRequest("GET", addr+"/_search/scroll?scroll=1m", strings.NewReader(id))
	if err != nil {
		return "", nil, err
	}
	rsp, err := http.DefaultClient.Do(req)
	if err != nil {
		return "", nil, err
	}
	defer rsp.Body.Close()
	switch rsp.StatusCode {
	case 404:
		b, _ := ioutil.ReadAll(rsp.Body)
		logger.Printf("%s", string(b))
		return "", nil, nil
	case 200:
		var rr *scrollResponse
		err = json.NewDecoder(rsp.Body).Decode(&rr)
		if err != nil {
			return "", nil, err
		}
		return rr.ScrollID, rr.Hits.Hits, nil
	default:
		b, _ := ioutil.ReadAll(rsp.Body)
		return "", nil, fmt.Errorf("got status %s but expected 2x. body=%s", rsp.Status, string(b))
	}
}

func openIndex(addr, name string, size int, scroll string) (scrollID string, err error) {
	rsp, err := http.Post(addr+"/"+name+"/_search?search_type=scan&scroll="+scroll,
		"application/json",
		strings.NewReader(`{"query": {"match_all": {} }, "size": `+strconv.Itoa(size)+`}`),
	)
	if err != nil {
		return "", err
	}
	defer rsp.Body.Close()
	if rsp.Status[0] != '2' {
		b, _ := ioutil.ReadAll(rsp.Body)
		return "", fmt.Errorf("expected status 2xx, got %s: %s", rsp.Status, string(b))
	}
	var s *scrollResponse
	err = json.NewDecoder(rsp.Body).Decode(&s)
	if err != nil {
		return "", err
	}
	return s.ScrollID, nil
}
<commit_msg>allow custom scroll interval<commit_after>package main

import (
	"compress/gzip"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

var logger = log.New(os.Stderr, "", 0)

func main() {
	if err := run(); err != nil {
		logger.Printf(err.Error())
		flag.Usage()
		os.Exit(1)
	}
}

var (
	address   = flag.String("a", "http://127.0.0.1:9200", "Address")
	index     = flag.String("i", "", "Index Name")
	out       = flag.String("o", "", "Output file")
	batchSize = flag.Int("b", 1000, "Batch Size")
	scroll    = flag.String("s", "1m", "Scroll duration")
)

func run() error {
	flag.Parse()
	if *address == "" {
		return errors.New("Address must be set")
	}
	if *index == "" {
		return errors.New("Index Name must be set")
	}

	if *out == "" {
		return errors.New("Output file must be set")
	}

	f, err := os.Create(*out)
	if err != nil {
		return err
	}
	defer f.Close()
	gz := gzip.NewWriter(f)
	defer gz.Close()

	docs, err := iterateIndex(*address, *index, *batchSize, *scroll)
	if err != nil {
		return err
	}

	c, wg := progress()
	for d := range docs {
		if _, err = io.WriteString(gz, string(d)+"\n"); err != nil {
			return err
		}
		c <- struct{}{}
	}
	close(c)
	wg.Wait()
	return nil
}

func progress() (chan struct{}, *sync.WaitGroup) {
	wg := &sync.WaitGroup{}
	wg.Add(1)
	c := make(chan struct{})
	go func() {
		defer wg.Done()
		t := time.Tick(1 * time.Second)
		started := time.Now()
		cnt := 0

		printStatus := func() {
			diff := time.Since(started).Seconds()
			perSecond := float64(cnt) / diff
			logger.Printf("cnt=%d time=%.01f per_second=%.1f/second", cnt, diff, perSecond)
		}
		for {
			select {
			case _, ok := <-c:
				if !ok {
					printStatus()
					return
				}
				cnt++
			case <-t:
				printStatus()
			}

		}
	}()
	return c, wg
}

func iterateIndex(addr, name string, size int, scroll string) (chan json.RawMessage, error) {
	scrollID, err := openIndex(addr, name, size, scroll)
	if err != nil {
		return nil, err
	}
	c := make(chan json.RawMessage)
	var docs []json.RawMessage
	go func() {
		defer close(c)
		for {
			scrollID, docs, err = loadDocumentsWithScroll(addr, scrollID)
			if err != nil {
				logger.Printf("err=%q", err)
				return
			} else if len(docs) == 0 {
				return
			}
			for _, d := range docs {
				c <- d
			}
		}
	}()
	return c, nil
}

type scrollResponse struct {
	ScrollID string `json:"_scroll_id"`
	Hits     struct {
		Hits []json.RawMessage `json:"hits"`
	} `json:"hits"`
}

func loadDocumentsWithScroll(addr string, id string) (string, []json.RawMessage, error) {
	req, err := http.NewRequest("GET", addr+"/_search/scroll?scroll=1m", strings.NewReader(id))
	if err != nil {
		return "", nil, err
	}
	rsp, err := http.DefaultClient.Do(req)
	if err != nil {
		return "", nil, err
	}
	defer rsp.Body.Close()
	switch rsp.StatusCode {
	case 404:
		b, _ := ioutil.ReadAll(rsp.Body)
		logger.Printf("%s", string(b))
		return "", nil, nil
	case 200:
		var rr *scrollResponse
		err = json.NewDecoder(rsp.Body).Decode(&rr)
		if err != nil {
			return "", nil, err
		}
		return rr.ScrollID, rr.Hits.Hits, nil
	default:
		b, _ := ioutil.ReadAll(rsp.Body)
		return "", nil, fmt.Errorf("got status %s but expected 2x. body=%s", rsp.Status, string(b))
	}
}

func openIndex(addr, name string, size int, scroll string) (scrollID string, err error) {
	rsp, err := http.Post(addr+"/"+name+"/_search?search_type=scan&scroll="+scroll,
		"application/json",
		strings.NewReader(`{"query": {"match_all": {} }, "size": `+strconv.Itoa(size)+`}`),
	)
	if err != nil {
		return "", err
	}
	defer rsp.Body.Close()
	if rsp.Status[0] != '2' {
		b, _ := ioutil.ReadAll(rsp.Body)
		return "", fmt.Errorf("expected status 2xx, got %s: %s", rsp.Status, string(b))
	}
	var s *scrollResponse
	err = json.NewDecoder(rsp.Body).Decode(&s)
	if err != nil {
		return "", err
	}
	return s.ScrollID, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"fmt"
	"net"

	"github.com/lucas-clemente/quic-go"
	"github.com/lucas-clemente/quic-go/crypto"
)

func main() {
	addr, err := net.ResolveUDPAddr("udp", "localhost:6121")
	if err != nil {
		panic(err)
	}

	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		panic(err)
	}

	data := make([]byte, 0x10000)
	n, remoteAddr, err := conn.ReadFromUDP(data)
	if err != nil {
		panic(err)
	}
	data = data[:n]
	r := bytes.NewReader(data)

	fmt.Printf("Number of bytes: %d\n", n)
	fmt.Printf("Remote addr: %v\n", remoteAddr)

	publicHeader, err := quic.ParsePublicHeader(r)
	if err != nil {
		panic(err)
	}

	if publicHeader.VersionFlag && publicHeader.QuicVersion != 0x51303330 {
		panic("only version Q030 supported")
	}

	nullAEAD := &crypto.NullAEAD{}
	r, err = nullAEAD.Open(data[0:int(r.Size())-r.Len()], r)
	if err != nil {
		panic(err)
	}

	privateFlag, err := r.ReadByte()
	if err != nil {
		panic(err)
	}

	if privateFlag&0x02 > 0 || privateFlag&0x04 > 0 {
		panic(errors.New("FEC packets are not implemented"))
	}

	frame, err := quic.ParseStreamFrame(r)
	if err != nil {
		panic(err)
	}

	messageTag, cryptoData, err := quic.ParseCryptoMessage(frame.Data)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Tag: %d\n", messageTag)
	fmt.Printf("Talking to: %s\n", string(cryptoData[quic.TagUAID]))

	serverConfig := &bytes.Buffer{}
	quic.WriteCryptoMessage(serverConfig, quic.TagSCFG, map[quic.Tag][]byte{
		quic.TagSCID: []byte{0xC5, 0x1C, 0x73, 0x6B, 0x8F, 0x48, 0x49, 0xAE, 0xB3, 0x00, 0xA2, 0xD4, 0x4B, 0xA0, 0xCF, 0xDF},
		quic.TagKEXS: []byte("C255"),
		quic.TagAEAD: []byte("AESG"),
		quic.TagPUBS: []byte{},
		quic.TagORBT: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7},
		quic.TagEXPY: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
		quic.TagVER:  []byte("Q030"),
	})

	serverReply := &bytes.Buffer{}
	quic.WriteCryptoMessage(serverReply, quic.TagREJ, map[quic.Tag][]byte{
		quic.TagSCFG: serverConfig.Bytes(),
	})

	replyFrame := &bytes.Buffer{}
	replyFrame.WriteByte(0) // Private header
	quic.WriteStreamFrame(replyFrame, &quic.StreamFrame{
		StreamID: 1,
		Data:     serverReply.Bytes(),
	})

	fullReply := &bytes.Buffer{}
	quic.WritePublicHeader(fullReply, &quic.PublicHeader{
		ConnectionID: publicHeader.ConnectionID,
		PacketNumber: 1,
	})

	nullAEAD.Seal(fullReply, fullReply.Bytes(), replyFrame.Bytes())

	conn.WriteToUDP(fullReply.Bytes(), remoteAddr)

	n, remoteAddr, err = conn.ReadFromUDP(data)
	if err != nil {
		panic(err)
	}
	data = data[:n]
	r = bytes.NewReader(data)

	fmt.Printf("%v\n", data)

	publicHeader, err = quic.ParsePublicHeader(r)
	if err != nil {
		panic(err)
	}
	fmt.Printf("%#v\n", publicHeader)
}
<commit_msg>improve version check in example server<commit_after>package main

import (
	"bytes"
	"errors"
	"fmt"
	"net"

	"github.com/lucas-clemente/quic-go"
	"github.com/lucas-clemente/quic-go/crypto"
)

const (
	// QuicVersion32 is Q032
	QuicVersion32 uint32 = 'Q' + '0'<<8 + '3'<<16 + '2'<<24
)

func main() {
	addr, err := net.ResolveUDPAddr("udp", "localhost:6121")
	if err != nil {
		panic(err)
	}

	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		panic(err)
	}

	data := make([]byte, 0x10000)
	n, remoteAddr, err := conn.ReadFromUDP(data)
	if err != nil {
		panic(err)
	}
	data = data[:n]
	r := bytes.NewReader(data)

	fmt.Printf("Number of bytes: %d\n", n)
	fmt.Printf("Remote addr: %v\n", remoteAddr)

	publicHeader, err := quic.ParsePublicHeader(r)
	if err != nil {
		panic(err)
	}

	if publicHeader.VersionFlag && publicHeader.QuicVersion < QuicVersion32 {
		println(publicHeader.QuicVersion)
		panic("only versions >= Q032 supported")
	}

	nullAEAD := &crypto.NullAEAD{}
	r, err = nullAEAD.Open(data[0:int(r.Size())-r.Len()], r)
	if err != nil {
		panic(err)
	}

	privateFlag, err := r.ReadByte()
	if err != nil {
		panic(err)
	}

	if privateFlag&0x02 > 0 || privateFlag&0x04 > 0 {
		panic(errors.New("FEC packets are not implemented"))
	}

	frame, err := quic.ParseStreamFrame(r)
	if err != nil {
		panic(err)
	}

	messageTag, cryptoData, err := quic.ParseCryptoMessage(frame.Data)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Tag: %d\n", messageTag)
	fmt.Printf("Talking to: %s\n", string(cryptoData[quic.TagUAID]))

	serverConfig := &bytes.Buffer{}
	quic.WriteCryptoMessage(serverConfig, quic.TagSCFG, map[quic.Tag][]byte{
		quic.TagSCID: []byte{0xC5, 0x1C, 0x73, 0x6B, 0x8F, 0x48, 0x49, 0xAE, 0xB3, 0x00, 0xA2, 0xD4, 0x4B, 0xA0, 0xCF, 0xDF},
		quic.TagKEXS: []byte("C255"),
		quic.TagAEAD: []byte("AESG"),
		quic.TagPUBS: []byte{},
		quic.TagORBT: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7},
		quic.TagEXPY: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
		quic.TagVER:  []byte("Q030"),
	})

	serverReply := &bytes.Buffer{}
	quic.WriteCryptoMessage(serverReply, quic.TagREJ, map[quic.Tag][]byte{
		quic.TagSCFG: serverConfig.Bytes(),
	})

	replyFrame := &bytes.Buffer{}
	replyFrame.WriteByte(0) // Private header
	quic.WriteStreamFrame(replyFrame, &quic.StreamFrame{
		StreamID: 1,
		Data:     serverReply.Bytes(),
	})

	fullReply := &bytes.Buffer{}
	quic.WritePublicHeader(fullReply, &quic.PublicHeader{
		ConnectionID: publicHeader.ConnectionID,
		PacketNumber: 1,
	})

	nullAEAD.Seal(fullReply, fullReply.Bytes(), replyFrame.Bytes())

	conn.WriteToUDP(fullReply.Bytes(), remoteAddr)

	n, remoteAddr, err = conn.ReadFromUDP(data)
	if err != nil {
		panic(err)
	}
	data = data[:n]
	r = bytes.NewReader(data)

	fmt.Printf("%v\n", data)

	publicHeader, err = quic.ParsePublicHeader(r)
	if err != nil {
		panic(err)
	}
	fmt.Printf("%#v\n", publicHeader)
}
<|endoftext|>


<commit_before>package fdcache

import (
	"io/ioutil"
	"os"
	"sync"

	"testing"
)

func TestSingleFileEviction(t *testing.T) {
	c := NewFileCache(1, 1)

	wg := sync.WaitGroup{}

	fd, err := ioutil.TempFile("", "fdcache")
	if err != nil {
		t.Fatal(err)
		return
	}
	fd.Close()

	for k := 0; k < 100; k++ {
		wg.Add(1)
		go func() {
			defer wg.Done()

			cfd, err := c.Open(fd.Name())
			if err != nil {
				t.Fatal(err)
				return
			}
			defer cfd.Close()

			_, err = cfd.ReadAt([]byte{}, 0)
			if err != nil {
				t.Fatal(err)
			}
		}()
	}

	wg.Wait()
}

func TestMultifileEviction(t *testing.T) {
	c := NewFileCache(1, 1)

	wg := sync.WaitGroup{}

	for k := 0; k < 100; k++ {
		wg.Add(1)
		go func() {
			defer wg.Done()

			fd, err := ioutil.TempFile("", "fdcache")
			if err != nil {
				t.Fatal(err)
				return
			}
			fd.Close()
			defer os.Remove(fd.Name())

			cfd, err := c.Open(fd.Name())
			if err != nil {
				t.Fatal(err)
				return
			}
			defer cfd.Close()

			_, err = cfd.ReadAt([]byte{}, 0)
			if err != nil {
				t.Fatal(err)
			}
		}()
	}

	wg.Wait()
}

func TestMixedEviction(t *testing.T) {
	c := NewFileCache(1, 1)

	wg := sync.WaitGroup{}
	for i := 0; i < 100; i++ {
		go func() {
			fd, err := ioutil.TempFile("", "fdcache")
			if err != nil {
				t.Fatal(err)
				return
			}
			fd.Close()

			for k := 0; k < 100; k++ {
				wg.Add(1)
				go func() {
					defer wg.Done()

					cfd, err := c.Open(fd.Name())
					if err != nil {
						t.Fatal(err)
						return
					}
					defer cfd.Close()

					_, err = cfd.ReadAt([]byte{}, 0)
					if err != nil {
						t.Fatal(err)
					}
				}()
			}
		}()
	}

	wg.Wait()
}
<commit_msg>Make sure tests actually test<commit_after>package fdcache

import (
	"io/ioutil"
	"os"
	"sync"

	"testing"
)

func TestNoopReadFailsOnClosed(t *testing.T) {
	fd, err := ioutil.TempFile("", "fdcache")
	if err != nil {
		t.Fatal(err)
		return
	}
	fd.WriteString("test")
	fd.Close()
	buf := make([]byte, 4)
	_, err = fd.ReadAt(buf, 0)
	if err == nil {
		t.Fatal("Expected error")
	}
}

func TestSingleFileEviction(t *testing.T) {
	c := NewFileCache(1, 1)

	wg := sync.WaitGroup{}

	fd, err := ioutil.TempFile("", "fdcache")
	if err != nil {
		t.Fatal(err)
		return
	}
	fd.WriteString("test")
	fd.Close()
	buf := make([]byte, 4)

	for k := 0; k < 100; k++ {
		wg.Add(1)
		go func() {
			defer wg.Done()

			cfd, err := c.Open(fd.Name())
			if err != nil {
				t.Fatal(err)
				return
			}
			defer cfd.Close()

			_, err = cfd.ReadAt(buf, 0)
			if err != nil {
				t.Fatal(err)
			}
		}()
	}

	wg.Wait()
}

func TestMultifileEviction(t *testing.T) {
	c := NewFileCache(1, 1)

	wg := sync.WaitGroup{}

	for k := 0; k < 100; k++ {
		wg.Add(1)
		go func() {
			defer wg.Done()

			fd, err := ioutil.TempFile("", "fdcache")
			if err != nil {
				t.Fatal(err)
				return
			}
			fd.WriteString("test")
			fd.Close()
			buf := make([]byte, 4)
			defer os.Remove(fd.Name())

			cfd, err := c.Open(fd.Name())
			if err != nil {
				t.Fatal(err)
				return
			}
			defer cfd.Close()

			_, err = cfd.ReadAt(buf, 0)
			if err != nil {
				t.Fatal(err)
			}
		}()
	}

	wg.Wait()
}

func TestMixedEviction(t *testing.T) {
	c := NewFileCache(1, 1)

	wg := sync.WaitGroup{}
	for i := 0; i < 100; i++ {
		go func() {
			fd, err := ioutil.TempFile("", "fdcache")
			if err != nil {
				t.Fatal(err)
				return
			}
			fd.WriteString("test")
			fd.Close()
			buf := make([]byte, 4)

			for k := 0; k < 100; k++ {
				wg.Add(1)
				go func() {
					defer wg.Done()

					cfd, err := c.Open(fd.Name())
					if err != nil {
						t.Fatal(err)
						return
					}
					defer cfd.Close()

					_, err = cfd.ReadAt(buf, 0)
					if err != nil {
						t.Fatal(err)
					}
				}()
			}
		}()
	}

	wg.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/TheJumpCloud/jcapi"
	"os"
)

const (
	apiUrl string = "https://console.jumpcloud.com/api"
)

func outFirst(data string) {
	fmt.Printf("\"%s\"", data)
}

func out(data string) {
	fmt.Printf(",\"%s\"", data)
}

func endLine() {
	fmt.Printf("\n")
}

func main() {
	apiKey := os.Getenv("JUMPCLOUD_APIKEY")
	if apiKey == "" {
		fmt.Printf("%s: Please run:\n\n\texport JUMPCLOUD_APIKEY=<your-JumpCloud-API-key>\n", os.Args[0])
		os.Exit(1)
	}

	jc := jcapi.NewJCAPI(apiKey, apiUrl)

	// Grab all systems with their tags
	systems, err := jc.GetSystems(true)
	if err != nil {
		fmt.Printf("Could not read systems, err='%s'\n", err)
		return
	}

	outFirst("Id")
	out("DisplayName")
	out("HostName")
	out("Active")
	out("Instance ID")
	out("OS")
	out("OSVersion")
	out("AgentVersion")
	out("CreatedDate")
	out("LastContactDate")
	endLine()

	for _, system := range systems {
		outFirst(system.Id)
		out(system.DisplayName)
		out(system.Hostname)
		out(fmt.Sprintf("%t", system.Active))
		out(system.AmazonInstanceID)
		out(system.Os)
		out(system.Version)
		out(system.AgentVersion)
		out(system.Created)
		out(system.LastContact)

		for _, tag := range system.Tags {
			out(tag.Name)
		}

		endLine()
	}
}
<commit_msg>Added heading for tags<commit_after>package main

import (
	"fmt"
	"github.com/TheJumpCloud/jcapi"
	"os"
)

const (
	apiUrl string = "https://console.jumpcloud.com/api"
)

func outFirst(data string) {
	fmt.Printf("\"%s\"", data)
}

func out(data string) {
	fmt.Printf(",\"%s\"", data)
}

func endLine() {
	fmt.Printf("\n")
}

func main() {
	apiKey := os.Getenv("JUMPCLOUD_APIKEY")
	if apiKey == "" {
		fmt.Printf("%s: Please run:\n\n\texport JUMPCLOUD_APIKEY=<your-JumpCloud-API-key>\n", os.Args[0])
		os.Exit(1)
	}

	jc := jcapi.NewJCAPI(apiKey, apiUrl)

	// Grab all systems with their tags
	systems, err := jc.GetSystems(true)
	if err != nil {
		fmt.Printf("Could not read systems, err='%s'\n", err)
		return
	}

	outFirst("Id")
	out("DisplayName")
	out("HostName")
	out("Active")
	out("Instance ID")
	out("OS")
	out("OSVersion")
	out("AgentVersion")
	out("CreatedDate")
	out("LastContactDate")
	out("Tags")
	endLine()

	for _, system := range systems {
		outFirst(system.Id)
		out(system.DisplayName)
		out(system.Hostname)
		out(fmt.Sprintf("%t", system.Active))
		out(system.AmazonInstanceID)
		out(system.Os)
		out(system.Version)
		out(system.AgentVersion)
		out(system.Created)
		out(system.LastContact)

		for _, tag := range system.Tags {
			out(tag.Name)
		}

		endLine()
	}
}
<|endoftext|>


<commit_before>package sshego

import (
	"fmt"
	"time"
)

// Verbose can be set to true for debug output. For production builds it
// should be set to false, the default.
const Verbose bool = true

// Ts gets the current timestamp for logging purposes.
func ts() string {
	return time.Now().Format("2006-01-02 15:04:05.999 -0700 MST")
}

// time-stamped fmt.Printf
func tSPrintf(format string, a ...interface{}) {
	fmt.Printf("\n%s ", ts())
	fmt.Printf(format+"\n", a...)
}

// VPrintf is like fmt.Printf, but only prints if Verbose is true. Uses TSPrint
// to mark each print with a timestamp.
func p(format string, a ...interface{}) {
	if Verbose {
		tSPrintf(format, a...)
	}
}

func pp(format string, a ...interface{}) {
	tSPrintf(format, a...)
}
<commit_msg>atg. with verbose false<commit_after>package sshego

import (
	"fmt"
	"time"
)

// Verbose can be set to true for debug output. For production builds it
// should be set to false, the default.
const Verbose bool = false

// Ts gets the current timestamp for logging purposes.
func ts() string {
	return time.Now().Format("2006-01-02 15:04:05.999 -0700 MST")
}

// time-stamped fmt.Printf
func tSPrintf(format string, a ...interface{}) {
	fmt.Printf("\n%s ", ts())
	fmt.Printf(format+"\n", a...)
}

// VPrintf is like fmt.Printf, but only prints if Verbose is true. Uses TSPrint
// to mark each print with a timestamp.
func p(format string, a ...interface{}) {
	if Verbose {
		tSPrintf(format, a...)
	}
}

func pp(format string, a ...interface{}) {
	tSPrintf(format, a...)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
)

const (
	VERSION = "2.0.unstable"
)

type Version struct{}

func (l *Version) Run(steward Steward) error {

	fmt.Printf("Vaulted v%s\n", VERSION)
	return nil
}
<commit_msg>Bump version to 2.1<commit_after>package main

import (
	"fmt"
)

const (
	VERSION = "2.1.unstable"
)

type Version struct{}

func (l *Version) Run(steward Steward) error {

	fmt.Printf("Vaulted v%s\n", VERSION)
	return nil
}
<|endoftext|>


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

package ach

// Version Number
const Version = "v1.6.0"
<commit_msg>Bump version for dev (#836)<commit_after>// Licensed to The Moov Authors under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. The Moov Authors licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

package ach

// Version Number
const Version = "v1.6.1-dev"
<|endoftext|>


<commit_before>package gf

const VERSION  = "v1.5.12"
const AUTHORS  = "john<john@goframe.org>"

<commit_msg>version updates<commit_after>package gf

const VERSION  = "v1.5.13"
const AUTHORS  = "john<john@goframe.org>"

<|endoftext|>


<commit_before>// nsq is the official Go package for https://github.com/bitly/nsq
//
// It provides high-level Reader and Writer types to implement consumers and
// producers as well as low-level functions to communicate over the NSQ protocol.
package nsq

const VERSION = "0.3.6"
<commit_msg>bump 0.3.7-alpha<commit_after>// nsq is the official Go package for https://github.com/bitly/nsq
//
// It provides high-level Reader and Writer types to implement consumers and
// producers as well as low-level functions to communicate over the NSQ protocol.
package nsq

const VERSION = "0.3.7-alpha"
<|endoftext|>


<commit_before>package main

import "github.com/tsaikd/KDGoLib/version"

func init() {
	version.VERSION = "0.0.13"
}
<commit_msg>0.1.0<commit_after>package main

import "github.com/tsaikd/KDGoLib/version"

func init() {
	version.VERSION = "0.1.0"
}
<|endoftext|>


<commit_before>package main

const VERSION = "1.0.1"
<commit_msg>v0.0.8<commit_after>package main

const VERSION = "0.0.8"
<|endoftext|>


<commit_before>package main

const VERSION = "0.6.2-alpha2"
<commit_msg>:+1: Bump up the version to 0.6.2-alpha3<commit_after>package main

const VERSION = "0.6.2-alpha3"
<|endoftext|>


<commit_before>// nsq is the official Go package for NSQ (http://nsq.io/)
//
// It provides high-level Consumer and Producer types as well as low-level
// functions to communicate over the NSQ protocol
package nsq

// VERSION
const VERSION = "1.0.3"
<commit_msg>bump v1.0.4-alpha<commit_after>// nsq is the official Go package for NSQ (http://nsq.io/)
//
// It provides high-level Consumer and Producer types as well as low-level
// functions to communicate over the NSQ protocol
package nsq

// VERSION
const VERSION = "1.0.4-alpha"
<|endoftext|>


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

package grpc

// Version is the current grpc version.
const Version = "1.24.0-dev"
<commit_msg>Change version to 1.25.0-dev (#3043)<commit_after>/*
 *
 * Copyright 2018 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package grpc

// Version is the current grpc version.
const Version = "1.25.0-dev"
<|endoftext|>


<commit_before>package main

const VERSION = "1.0"
<commit_msg>bump to alpha<commit_after>package main

const VERSION = "1.1-alpha"
<|endoftext|>


<commit_before>package main

const VERSION = "0.6.4"
<commit_msg>github-release 0.7.0<commit_after>package main

const VERSION = "0.7.0"
<|endoftext|>