<commit_before>// Package sql provides SQL implementations of the storage interface.
package sql

import (
	"database/sql"
	"github.com/dexidp/dex/pkg/log"
	"regexp"
	"time"

	// import third party drivers
	_ "github.com/lib/pq"
	_ "github.com/mattn/go-sqlite3"
)

// flavor represents a specific SQL implementation, and is used to translate query strings
// between different drivers. Flavors shouldn't aim to translate all possible SQL statements,
// only the specific queries used by the SQL storages.
type flavor struct {
	queryReplacers []replacer

	// Optional function to create and finish a transaction.
	executeTx func(db *sql.DB, fn func(*sql.Tx) error) error

	// Does the flavor support timezones?
	supportsTimezones bool
}

// A regexp with a replacement string.
type replacer struct {
	re   *regexp.Regexp
	with string
}

// Match a postgres query binds. E.g. "$1", "$12", etc.
var bindRegexp = regexp.MustCompile(`\$\d+`)

func matchLiteral(s string) *regexp.Regexp {
	return regexp.MustCompile(`\b` + regexp.QuoteMeta(s) + `\b`)
}

var (
	// The "github.com/lib/pq" driver is the default flavor. All others are
	// translations of this.
	flavorPostgres = flavor{
		// The default behavior for Postgres transactions is consistent reads, not consistent writes.
		// For each transaction opened, ensure it has the correct isolation level.
		//
		// See: https://www.postgresql.org/docs/9.3/static/sql-set-transaction.html
		//
		// NOTE(ericchiang): For some reason using `SET SESSION CHARACTERISTICS AS TRANSACTION` at a
		// session level didn't work for some edge cases. Might be something worth exploring.
		executeTx: func(db *sql.DB, fn func(sqlTx *sql.Tx) error) error {
			tx, err := db.Begin()
			if err != nil {
				return err
			}
			defer tx.Rollback()

			if _, err := tx.Exec(`SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;`); err != nil {
				return err
			}
			if err := fn(tx); err != nil {
				return err
			}
			return tx.Commit()
		},

		supportsTimezones: true,
	}

	flavorSQLite3 = flavor{
		queryReplacers: []replacer{
			{bindRegexp, "?"},
			// Translate for booleans to integers.
			{matchLiteral("true"), "1"},
			{matchLiteral("false"), "0"},
			{matchLiteral("boolean"), "integer"},
			// Translate other types.
			{matchLiteral("bytea"), "blob"},
			{matchLiteral("timestamptz"), "timestamp"},
			// SQLite doesn't have a "now()" method, replace with "date('now')"
			{regexp.MustCompile(`\bnow\(\)`), "date('now')"},
		},
	}
)

func (f flavor) translate(query string) string {
	// TODO(ericchiang): Heavy cashing.
	for _, r := range f.queryReplacers {
		query = r.re.ReplaceAllString(query, r.with)
	}
	return query
}

// translateArgs translates query parameters that may be unique to
// a specific SQL flavor. For example, standardizing "time.Time"
// types to UTC for clients that don't provide timezone support.
func (c *conn) translateArgs(args []interface{}) []interface{} {
	if c.flavor.supportsTimezones {
		return args
	}

	for i, arg := range args {
		if t, ok := arg.(time.Time); ok {
			args[i] = t.UTC()
		}
	}
	return args
}

// conn is the main database connection.
type conn struct {
	db                 *sql.DB
	flavor             flavor
	logger             log.Logger
	alreadyExistsCheck func(err error) bool
}

func (c *conn) Close() error {
	return c.db.Close()
}

// conn implements the same method signatures as encoding/sql.DB.

func (c *conn) Exec(query string, args ...interface{}) (sql.Result, error) {
	query = c.flavor.translate(query)
	return c.db.Exec(query, c.translateArgs(args)...)
}

func (c *conn) Query(query string, args ...interface{}) (*sql.Rows, error) {
	query = c.flavor.translate(query)
	return c.db.Query(query, c.translateArgs(args)...)
}

func (c *conn) QueryRow(query string, args ...interface{}) *sql.Row {
	query = c.flavor.translate(query)
	return c.db.QueryRow(query, c.translateArgs(args)...)
}

// ExecTx runs a method which operates on a transaction.
func (c *conn) ExecTx(fn func(tx *trans) error) error {
	if c.flavor.executeTx != nil {
		return c.flavor.executeTx(c.db, func(sqlTx *sql.Tx) error {
			return fn(&trans{sqlTx, c})
		})
	}

	sqlTx, err := c.db.Begin()
	if err != nil {
		return err
	}
	if err := fn(&trans{sqlTx, c}); err != nil {
		sqlTx.Rollback()
		return err
	}
	return sqlTx.Commit()
}

type trans struct {
	tx *sql.Tx
	c  *conn
}

// trans implements the same method signatures as encoding/sql.Tx.

func (t *trans) Exec(query string, args ...interface{}) (sql.Result, error) {
	query = t.c.flavor.translate(query)
	return t.tx.Exec(query, t.c.translateArgs(args)...)
}

func (t *trans) Query(query string, args ...interface{}) (*sql.Rows, error) {
	query = t.c.flavor.translate(query)
	return t.tx.Query(query, t.c.translateArgs(args)...)
}

func (t *trans) QueryRow(query string, args ...interface{}) *sql.Row {
	query = t.c.flavor.translate(query)
	return t.tx.QueryRow(query, t.c.translateArgs(args)...)
}
<commit_msg>Fix coding style<commit_after>// Package sql provides SQL implementations of the storage interface.
package sql

import (
	"database/sql"
	"regexp"
	"time"

	// import third party drivers
	_ "github.com/lib/pq"
	_ "github.com/mattn/go-sqlite3"

	"github.com/dexidp/dex/pkg/log"
)

// flavor represents a specific SQL implementation, and is used to translate query strings
// between different drivers. Flavors shouldn't aim to translate all possible SQL statements,
// only the specific queries used by the SQL storages.
type flavor struct {
	queryReplacers []replacer

	// Optional function to create and finish a transaction.
	executeTx func(db *sql.DB, fn func(*sql.Tx) error) error

	// Does the flavor support timezones?
	supportsTimezones bool
}

// A regexp with a replacement string.
type replacer struct {
	re   *regexp.Regexp
	with string
}

// Match a postgres query binds. E.g. "$1", "$12", etc.
var bindRegexp = regexp.MustCompile(`\$\d+`)

func matchLiteral(s string) *regexp.Regexp {
	return regexp.MustCompile(`\b` + regexp.QuoteMeta(s) + `\b`)
}

var (
	// The "github.com/lib/pq" driver is the default flavor. All others are
	// translations of this.
	flavorPostgres = flavor{
		// The default behavior for Postgres transactions is consistent reads, not consistent writes.
		// For each transaction opened, ensure it has the correct isolation level.
		//
		// See: https://www.postgresql.org/docs/9.3/static/sql-set-transaction.html
		//
		// NOTE(ericchiang): For some reason using `SET SESSION CHARACTERISTICS AS TRANSACTION` at a
		// session level didn't work for some edge cases. Might be something worth exploring.
		executeTx: func(db *sql.DB, fn func(sqlTx *sql.Tx) error) error {
			tx, err := db.Begin()
			if err != nil {
				return err
			}
			defer tx.Rollback()

			if _, err := tx.Exec(`SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;`); err != nil {
				return err
			}
			if err := fn(tx); err != nil {
				return err
			}
			return tx.Commit()
		},

		supportsTimezones: true,
	}

	flavorSQLite3 = flavor{
		queryReplacers: []replacer{
			{bindRegexp, "?"},
			// Translate for booleans to integers.
			{matchLiteral("true"), "1"},
			{matchLiteral("false"), "0"},
			{matchLiteral("boolean"), "integer"},
			// Translate other types.
			{matchLiteral("bytea"), "blob"},
			{matchLiteral("timestamptz"), "timestamp"},
			// SQLite doesn't have a "now()" method, replace with "date('now')"
			{regexp.MustCompile(`\bnow\(\)`), "date('now')"},
		},
	}
)

func (f flavor) translate(query string) string {
	// TODO(ericchiang): Heavy cashing.
	for _, r := range f.queryReplacers {
		query = r.re.ReplaceAllString(query, r.with)
	}
	return query
}

// translateArgs translates query parameters that may be unique to
// a specific SQL flavor. For example, standardizing "time.Time"
// types to UTC for clients that don't provide timezone support.
func (c *conn) translateArgs(args []interface{}) []interface{} {
	if c.flavor.supportsTimezones {
		return args
	}

	for i, arg := range args {
		if t, ok := arg.(time.Time); ok {
			args[i] = t.UTC()
		}
	}
	return args
}

// conn is the main database connection.
type conn struct {
	db                 *sql.DB
	flavor             flavor
	logger             log.Logger
	alreadyExistsCheck func(err error) bool
}

func (c *conn) Close() error {
	return c.db.Close()
}

// conn implements the same method signatures as encoding/sql.DB.

func (c *conn) Exec(query string, args ...interface{}) (sql.Result, error) {
	query = c.flavor.translate(query)
	return c.db.Exec(query, c.translateArgs(args)...)
}

func (c *conn) Query(query string, args ...interface{}) (*sql.Rows, error) {
	query = c.flavor.translate(query)
	return c.db.Query(query, c.translateArgs(args)...)
}

func (c *conn) QueryRow(query string, args ...interface{}) *sql.Row {
	query = c.flavor.translate(query)
	return c.db.QueryRow(query, c.translateArgs(args)...)
}

// ExecTx runs a method which operates on a transaction.
func (c *conn) ExecTx(fn func(tx *trans) error) error {
	if c.flavor.executeTx != nil {
		return c.flavor.executeTx(c.db, func(sqlTx *sql.Tx) error {
			return fn(&trans{sqlTx, c})
		})
	}

	sqlTx, err := c.db.Begin()
	if err != nil {
		return err
	}
	if err := fn(&trans{sqlTx, c}); err != nil {
		sqlTx.Rollback()
		return err
	}
	return sqlTx.Commit()
}

type trans struct {
	tx *sql.Tx
	c  *conn
}

// trans implements the same method signatures as encoding/sql.Tx.

func (t *trans) Exec(query string, args ...interface{}) (sql.Result, error) {
	query = t.c.flavor.translate(query)
	return t.tx.Exec(query, t.c.translateArgs(args)...)
}

func (t *trans) Query(query string, args ...interface{}) (*sql.Rows, error) {
	query = t.c.flavor.translate(query)
	return t.tx.Query(query, t.c.translateArgs(args)...)
}

func (t *trans) QueryRow(query string, args ...interface{}) *sql.Row {
	query = t.c.flavor.translate(query)
	return t.tx.QueryRow(query, t.c.translateArgs(args)...)
}
<|endoftext|>


<commit_before>package storage

import (
	"log"
	"sort"
	"strings"
	"time"

	"github.com/takama/whoisd/config"
	"github.com/takama/whoisd/mapper"
	"golang.org/x/net/idna"
)

// Storage - the interface for every implementation of storage
type Storage interface {
	Search(name string, query string) (map[string][]string, error)
	SearchRelated(typeTable string, name string, query string) (map[string][]string, error)
	SearchMultiple(typeTable string, name string, query string) (map[string][]string, error)
}

// Record - standard record (struct) for storage package
type Record struct {
	dataStore Storage
	mapper.Bundle
}

// New - returns new Storage instance
func New(conf *config.Record, bundle mapper.Bundle) *Record {
	switch strings.ToLower(conf.Storage.StorageType) {
	case "mysql":
		return &Record{
			&MysqlRecord{
				conf.Storage.Host,
				conf.Storage.Port,
				conf.Storage.IndexBase,
				conf.Storage.TypeTable,
			},
			bundle,
		}
	case "elasticsearch":
		return &Record{
			&ElasticsearchRecord{
				conf.Storage.Host,
				conf.Storage.Port,
				conf.Storage.IndexBase,
				conf.Storage.TypeTable,
			},
			bundle,
		}
	case "dummy":
		fallthrough
	default:
		return &Record{
			&DummyRecord{conf.Storage.TypeTable},
			bundle,
		}
	}
}

// Search and sort a data from the storage
func (storage *Record) Search(query string) (answer string, ok bool) {
	ok = false
	answer = "not found\n"
	log.Println("query:", query)
	if len(strings.TrimSpace(query)) == 0 {
		log.Println("Empty query")
	} else {
		entry, err := storage.request(strings.TrimSpace(query))
		if err != nil {
			log.Println("Query:", query, err.Error())
		} else {
			if entry == nil || len(entry.Fields) == 0 {
				return answer, ok
			}
			ok = true

			// get keys of a map and sort their
			keys := make([]string, 0, len(entry.Fields))
			for key := range entry.Fields {
				keys = append(keys, key)
			}
			sort.Strings(keys)
			answer = prepareAnswer(entry, keys)
		}
	}

	return answer, ok
}

// request - get and load bundle by query
func (storage *Record) request(query string) (*mapper.Entry, error) {
	TLD := detachTLD(query)
	if TLD == "" {
		return nil, nil
	}
	template := storage.Bundle.EntryByTLD(TLD)
	if template == nil {
		return nil, nil
	}

	var err error

	entry := new(mapper.Entry)
	entry.Fields = make(map[string]mapper.Field)
	baseField := make(map[string][]string)
	relatedField := make(map[string]map[string][]string)

	// Loads fields with constant values
	for index, field := range template.Fields {
		if len(field.Value) != 0 && len(field.Related) == 0 &&
			len(field.RelatedBy) == 0 && len(field.RelatedTo) == 0 {
			entry.Fields[index] = mapper.Field{
				Key:      field.Key,
				Value:    field.Value,
				Format:   field.Format,
				Multiple: field.Multiple,
				Hide:     field.Hide,
			}
		}
	}

	// Loads base fields (non related)
	for index, field := range template.Fields {
		// Detect base field
		if len(field.Value) == 0 && len(field.Related) != 0 &&
			(len(field.RelatedBy) == 0 || len(field.RelatedTo) == 0) {
			// if baseField not loaded, do it
			if len(baseField) == 0 {
				baseField, err = storage.dataStore.Search(field.Related, query)
				if err != nil {
					return nil, err
				}
				if len(baseField) == 0 {
					return nil, nil
				}
			}
			value := []string{}

			// collects all values into value
			for _, item := range field.Name {
				if result, ok := baseField[item]; ok {
					value = append(value, result...)
				}
			}

			entry.Fields[index] = mapper.Field{
				Key:      field.Key,
				Value:    value,
				Format:   field.Format,
				Multiple: field.Multiple,
				Hide:     field.Hide,
			}
		}
	}

	// Loads related records
	for index, field := range template.Fields {
		// Detect related fields
		if len(field.RelatedBy) != 0 && len(field.RelatedTo) != 0 && len(field.Related) != 0 {
			value := []string{}
			queryRelated := strings.Join(baseField[field.Related], "")

			// if non-related field from specified type/table
			if len(field.Value) != 0 {
				queryRelated = field.Value[0]
			}

			// if field not cached, do it
			if _, ok := relatedField[field.Related]; ok == false {
				if field.Multiple {
					relatedField[field.Related], err = storage.dataStore.SearchMultiple(
						field.RelatedTo,
						field.RelatedBy,
						queryRelated,
					)
					if err != nil {
						return nil, err
					}
				} else {
					relatedField[field.Related], err = storage.dataStore.SearchRelated(
						field.RelatedTo,
						field.RelatedBy,
						queryRelated,
					)
					if err != nil {
						return nil, err
					}
				}
			}
			// collects all values into value
			for _, item := range field.Name {
				if result, ok := relatedField[field.Related][item]; ok {
					value = append(value, result...)
				}
			}
			entry.Fields[index] = mapper.Field{
				Key:      field.Key,
				Value:    value,
				Format:   field.Format,
				Multiple: field.Multiple,
				Hide:     field.Hide,
			}
		}
	}

	return entry, nil
}

// detachTLD - isolates TLD part from a query
func detachTLD(query string) (TLD string) {
	parts := strings.Split(query, ".")
	if len(parts) > 1 {
		TLD = parts[len(parts)-1]
	}
	return
}

// prepares join and multiple actions in the answer
func prepareAnswer(entry *mapper.Entry, keys []string) (answer string) {
	for _, index := range keys {
		key := entry.Fields[index].Key
		if entry.Fields[index].Hide != true || len(entry.Fields[index].Value) > 0 {
			if strings.Contains(entry.Fields[index].Format, "{idn}") == true {
				entry.Fields[index] = decodeIDN(entry.Fields[index])
			}
			if entry.Fields[index].Multiple == true {
				for _, value := range entry.Fields[index].Value {
					answer = strings.Join([]string{answer, key, value, "\n"}, "")
				}
			} else {
				var value string
				if entry.Fields[index].Format != "" {
					value = loadTags(entry.Fields[index].Format, entry.Fields[index].Value)
				} else {
					value = strings.Join(entry.Fields[index].Value, " ")
				}
				answer = strings.Join([]string{answer, key, value, "\n"}, "")
			}
		}
	}

	return answer
}

// decodes IDN names to Unicode and adds it to value
func decodeIDN(field mapper.Field) mapper.Field {
	for _, item := range field.Value {
		idnItem, err := idna.ToUnicode(item)
		if err == nil && idnItem != item {
			field.Value = append(
				field.Value,
				strings.Replace(field.Format, "{idn}", idnItem, 1),
			)
		}
	}
	field.Format = ""
	return field
}

// loads all defined tags from value
func loadTags(format string, value []string) string {
	// template of date to parse
	var templateDateFormat = "2006-01-02 15:04:05"

	for _, item := range value {
		if strings.Contains(format, "{date}") == true {
			buildTime, err := time.Parse(templateDateFormat, item)
			if err != nil && len(strings.TrimSpace(item)) == 0 {
				buildTime = time.Now()
			}
			format = strings.Replace(format, "{date}", buildTime.Format(time.RFC3339), 1)
		}
		format = strings.Replace(format, "{string}", item, 1)
	}
	format = strings.Replace(format, "{string}", "", -1)

	return strings.Trim(format, ". ")
}
<commit_msg>add {shortdate} format, fix 'hide' property<commit_after>package storage

import (
	"log"
	"sort"
	"strings"
	"time"

	"github.com/takama/whoisd/config"
	"github.com/takama/whoisd/mapper"
	"golang.org/x/net/idna"
)

// Storage - the interface for every implementation of storage
type Storage interface {
	Search(name string, query string) (map[string][]string, error)
	SearchRelated(typeTable string, name string, query string) (map[string][]string, error)
	SearchMultiple(typeTable string, name string, query string) (map[string][]string, error)
}

// Record - standard record (struct) for storage package
type Record struct {
	dataStore Storage
	mapper.Bundle
}

// New - returns new Storage instance
func New(conf *config.Record, bundle mapper.Bundle) *Record {
	switch strings.ToLower(conf.Storage.StorageType) {
	case "mysql":
		return &Record{
			&MysqlRecord{
				conf.Storage.Host,
				conf.Storage.Port,
				conf.Storage.IndexBase,
				conf.Storage.TypeTable,
			},
			bundle,
		}
	case "elasticsearch":
		return &Record{
			&ElasticsearchRecord{
				conf.Storage.Host,
				conf.Storage.Port,
				conf.Storage.IndexBase,
				conf.Storage.TypeTable,
			},
			bundle,
		}
	case "dummy":
		fallthrough
	default:
		return &Record{
			&DummyRecord{conf.Storage.TypeTable},
			bundle,
		}
	}
}

// Search and sort a data from the storage
func (storage *Record) Search(query string) (answer string, ok bool) {
	ok = false
	answer = "not found\n"
	log.Println("query:", query)
	if len(strings.TrimSpace(query)) == 0 {
		log.Println("Empty query")
	} else {
		entry, err := storage.request(strings.TrimSpace(query))
		if err != nil {
			log.Println("Query:", query, err.Error())
		} else {
			if entry == nil || len(entry.Fields) == 0 {
				return answer, ok
			}
			ok = true

			// get keys of a map and sort their
			keys := make([]string, 0, len(entry.Fields))
			for key := range entry.Fields {
				keys = append(keys, key)
			}
			sort.Strings(keys)
			answer = prepareAnswer(entry, keys)
		}
	}

	return answer, ok
}

// request - get and load bundle by query
func (storage *Record) request(query string) (*mapper.Entry, error) {
	TLD := detachTLD(query)
	if TLD == "" {
		return nil, nil
	}
	template := storage.Bundle.EntryByTLD(TLD)
	if template == nil {
		return nil, nil
	}

	var err error

	entry := new(mapper.Entry)
	entry.Fields = make(map[string]mapper.Field)
	baseField := make(map[string][]string)
	relatedField := make(map[string]map[string][]string)

	// Loads fields with constant values
	for index, field := range template.Fields {
		if len(field.Value) != 0 && len(field.Related) == 0 &&
			len(field.RelatedBy) == 0 && len(field.RelatedTo) == 0 {
			entry.Fields[index] = mapper.Field{
				Key:      field.Key,
				Value:    field.Value,
				Format:   field.Format,
				Multiple: field.Multiple,
				Hide:     field.Hide,
			}
		}
	}

	// Loads base fields (non related)
	for index, field := range template.Fields {
		// Detect base field
		if len(field.Value) == 0 && len(field.Related) != 0 &&
			(len(field.RelatedBy) == 0 || len(field.RelatedTo) == 0) {
			// if baseField not loaded, do it
			if len(baseField) == 0 {
				baseField, err = storage.dataStore.Search(field.Related, query)
				if err != nil {
					return nil, err
				}
				if len(baseField) == 0 {
					return nil, nil
				}
			}
			value := []string{}

			// collects all values into value
			for _, item := range field.Name {
				if result, ok := baseField[item]; ok {
					value = append(value, result...)
				}
			}

			entry.Fields[index] = mapper.Field{
				Key:      field.Key,
				Value:    value,
				Format:   field.Format,
				Multiple: field.Multiple,
				Hide:     field.Hide,
			}
		}
	}

	// Loads related records
	for index, field := range template.Fields {
		// Detect related fields
		if len(field.RelatedBy) != 0 && len(field.RelatedTo) != 0 && len(field.Related) != 0 {
			value := []string{}
			queryRelated := strings.Join(baseField[field.Related], "")

			// if non-related field from specified type/table
			if len(field.Value) != 0 {
				queryRelated = field.Value[0]
			}

			// if field not cached, do it
			if _, ok := relatedField[field.Related]; ok == false {
				if field.Multiple {
					relatedField[field.Related], err = storage.dataStore.SearchMultiple(
						field.RelatedTo,
						field.RelatedBy,
						queryRelated,
					)
					if err != nil {
						return nil, err
					}
				} else {
					relatedField[field.Related], err = storage.dataStore.SearchRelated(
						field.RelatedTo,
						field.RelatedBy,
						queryRelated,
					)
					if err != nil {
						return nil, err
					}
				}
			}
			// collects all values into value
			for _, item := range field.Name {
				if result, ok := relatedField[field.Related][item]; ok {
					value = append(value, result...)
				}
			}
			entry.Fields[index] = mapper.Field{
				Key:      field.Key,
				Value:    value,
				Format:   field.Format,
				Multiple: field.Multiple,
				Hide:     field.Hide,
			}
		}
	}

	return entry, nil
}

// detachTLD - isolates TLD part from a query
func detachTLD(query string) (TLD string) {
	parts := strings.Split(query, ".")
	if len(parts) > 1 {
		TLD = parts[len(parts)-1]
	}
	return
}

// prepares join and multiple actions in the answer
func prepareAnswer(entry *mapper.Entry, keys []string) (answer string) {
	for _, index := range keys {
		key := entry.Fields[index].Key
		if strings.Contains(entry.Fields[index].Format, "{idn}") {
			entry.Fields[index] = decodeIDN(entry.Fields[index])
		}
		if entry.Fields[index].Multiple {
			for _, value := range entry.Fields[index].Value {
				if entry.Fields[index].Hide && value == "" {
					continue
				}
				if entry.Fields[index].Format != "" {
					value = handleTags(entry.Fields[index].Format, []string{value})
				}
				answer = strings.Join([]string{answer, key, value, "\n"}, "")
			}
		} else {
			var value string
			if entry.Fields[index].Format != "" {
				value = handleTags(entry.Fields[index].Format, entry.Fields[index].Value)
			} else {
				value = strings.Trim(strings.Join(entry.Fields[index].Value, " "), " ")
			}
			if entry.Fields[index].Hide && value == "" {
				continue
			}
			answer = strings.Join([]string{answer, key, value, "\n"}, "")
		}
	}

	return answer
}

// decodes IDN names to Unicode and adds it to value
func decodeIDN(field mapper.Field) mapper.Field {
	for _, item := range field.Value {
		idnItem, err := idna.ToUnicode(item)
		if err == nil && idnItem != item {
			field.Value = append(
				field.Value,
				strings.Replace(field.Format, "{idn}", idnItem, 1),
			)
		}
	}
	field.Format = ""
	return field
}

// handle all tags defined in format string
func handleTags(format string, value []string) string {
	// template of date to parse
	const (
		shortDateFormat = "2006.01.02"
		longDateFormat  = "2006-01-02 15:04:05"
	)
	for _, item := range value {
		if strings.Contains(format, "{date}") || strings.Contains(format, "{shortdate}") {
			buildTime, err := time.Parse(longDateFormat, item)
			if err != nil && len(strings.TrimSpace(item)) == 0 {
				buildTime = time.Now()
			}
			if strings.Contains(format, "{date}") {
				format = strings.Replace(format, "{date}", buildTime.Format(time.RFC3339), 1)
			} else {
				format = strings.Replace(format, "{shortdate}", buildTime.Format(shortDateFormat), 1)
			}
		}
		format = strings.Replace(format, "{string}", item, 1)
	}
	format = strings.NewReplacer("{string}", "", "{date}", "", "{shortdate}", "").Replace(format)

	return strings.Trim(format, ". ")
}
<|endoftext|>


<commit_before>package search

import (
	"github.com/couchbaselabs/bleve/document"
)

type Fragment struct {
	orig  []byte
	start int
	end   int
	score float64
	index int // used by heap
}

func (f *Fragment) Overlaps(other *Fragment) bool {
	if other.start >= f.start && other.start < f.end {
		return true
	}
	return false
}

type Fragmenter interface {
	Fragment([]byte, termLocations) []*Fragment
}

type FragmentFormatter interface {
	Format(f *Fragment, tlm TermLocationMap) string
}

type FragmentScorer interface {
	Score(f *Fragment) float64
}

type Highlighter interface {
	Fragmenter() Fragmenter
	SetFragmenter(Fragmenter)

	FragmentFormatter() FragmentFormatter
	SetFragmentFormatter(FragmentFormatter)

	Separator() string
	SetSeparator(string)

	BestFragmentInField(*DocumentMatch, *document.Document, string) string
	BestFragmentsInField(*DocumentMatch, *document.Document, string, int) []string
}
<commit_msg>fix bug in identifying overlapping fragments<commit_after>package search

import (
	"log"

	"github.com/couchbaselabs/bleve/document"
)

type Fragment struct {
	orig  []byte
	start int
	end   int
	score float64
	index int // used by heap
}

func (f *Fragment) Overlaps(other *Fragment) bool {
	if other.start >= f.start && other.start < f.end {
		return true
	} else if f.start >= other.start && f.start < other.end {
		return true
	}
	return false
}

type Fragmenter interface {
	Fragment([]byte, termLocations) []*Fragment
}

type FragmentFormatter interface {
	Format(f *Fragment, tlm TermLocationMap) string
}

type FragmentScorer interface {
	Score(f *Fragment) float64
}

type Highlighter interface {
	Fragmenter() Fragmenter
	SetFragmenter(Fragmenter)

	FragmentFormatter() FragmentFormatter
	SetFragmentFormatter(FragmentFormatter)

	Separator() string
	SetSeparator(string)

	BestFragmentInField(*DocumentMatch, *document.Document, string) string
	BestFragmentsInField(*DocumentMatch, *document.Document, string, int) []string
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

var (
	translatedassertImportIdent = &ast.Ident{Name: "translatedassert"}
	assertImportIdent           = &ast.Ident{Name: "assert"}
	errAssertImportNotFound     = errors.New("github.com/ToQoz/gopwt/assert is not found in imports")
)

func rewritePackage(dirPath, importPath string, tempGoSrcDir string) error {
	err := filepath.Walk(dirPath, func(path string, fInfo os.FileInfo, err error) error {
		if fInfo.Mode()&os.ModeSymlink == os.ModeSymlink {
			return nil
		}

		pathFromImportDir, err := filepath.Rel(dirPath, path)
		if err != nil {
			return err
		}

		if fInfo.IsDir() {
			rel, err := filepath.Rel(dirPath, path)
			if err != nil {
				return err
			}

			if rel == "." {
				return nil
			}

			// copy all files in <dirPath>/testdata/**/*
			if strings.Split(rel, "/")[0] == "testdata" {
				err = os.MkdirAll(filepath.Join(tempGoSrcDir, importPath, pathFromImportDir), os.ModePerm)
				if err != nil {
					return err
				}

				return nil
			}

			return filepath.SkipDir
		}

		out, err := os.Create(filepath.Join(tempGoSrcDir, importPath, pathFromImportDir))
		if err != nil {
			return err
		}
		defer func() {
			out.Close()
		}()

		err = rewriteFile(path, importPath, out)
		if err != nil {
			return err
		}

		return nil
	})

	return err
}

func rewriteFile(path, importPath string, out io.Writer) error {
	translatedassertImportIdent = &ast.Ident{Name: "translatedassert"}
	assertImportIdent = &ast.Ident{Name: "assert"}

	copyFile := func() error {
		filedata, err := ioutil.ReadFile(path)
		if err != nil {
			return err
		}

		_, err = out.Write(filedata)
		if err != nil {
			return err
		}

		return nil
	}

	if !isTestGoFile(path) {
		return copyFile()
	}

	fset := token.NewFileSet()
	a, err := parser.ParseFile(fset, path, nil, 0)
	if err != nil {
		return err
	}

	err = translateAssertImport(a)
	if err != nil {
		if err == errAssertImportNotFound {
			return copyFile()
		}

		return err
	}

	err = translateAllAsserts(fset, a)
	if err != nil {
		return err
	}

	err = printer.Fprint(out, fset, a)
	if err != nil {
		return err
	}
	return nil
}

func isTestGoFile(name string) bool {
	return strings.HasSuffix(name, "_test.go") && !strings.HasPrefix(name, ".") && !strings.HasPrefix(name, "_")
}

func newPackageInfo(globalOrLocalImportPath string) (*packageInfo, error) {
	var err error
	var importPath string
	var dirPath string
	var recursive bool

	if strings.HasSuffix(globalOrLocalImportPath, "/...") {
		recursive = true
		globalOrLocalImportPath = strings.TrimSuffix(globalOrLocalImportPath, "/...")
	}

	if globalOrLocalImportPath == "" {
		globalOrLocalImportPath = "."
	}

	if strings.HasPrefix(globalOrLocalImportPath, ".") {
		wd, err := os.Getwd()
		if err != nil {
			return nil, err
		}

		dirPath = filepath.Join(wd, globalOrLocalImportPath)
		if _, err := os.Stat(dirPath); err != nil {
			return nil, err
		}

		importPath, err = findImportPathByPath(dirPath)
		if err != nil {
			return nil, err
		}
	} else {
		importPath = globalOrLocalImportPath

		dirPath, err = findPathByImportPath(importPath)
		if err != nil {
			return nil, err
		}
	}

	return &packageInfo{dirPath: dirPath, importPath: importPath, recursive: recursive}, nil
}

func translateAssertImport(a *ast.File) error {
	for _, decl := range a.Decls {
		decl, ok := decl.(*ast.GenDecl)
		if !ok {
			continue
		}
		if len(decl.Specs) == 0 {
			continue
		}

		if _, ok := decl.Specs[0].(*ast.ImportSpec); !ok {
			continue
		}

		for _, imp := range decl.Specs {
			imp := imp.(*ast.ImportSpec)

			if imp.Path.Value != `"github.com/ToQoz/gopwt/assert"` {
				continue
			}

			imp.Path.Value = `"github.com/ToQoz/gopwt/translatedassert"`
			if imp.Name != nil {
				assertImportIdent = imp.Name
				imp.Name = translatedassertImportIdent
			}

			goto Done
		}
	}

	return errAssertImportNotFound

Done:
	return nil
}

func translateAllAsserts(fset *token.FileSet, a *ast.File) error {
	ast.Inspect(a, func(n ast.Node) bool {
		if n, ok := n.(*ast.CallExpr); ok {
			// skip inspecting children in n
			if !isAssert(assertImportIdent, n) {
				return false
			}

			file := fset.File(n.Pos())
			header := fmt.Sprintf("[FAIL] %s:%d", file.Name(), file.Line(n.Pos()))

			replaceAllRawStringLitByStringLit(n)

			b := []byte{}
			buf := bytes.NewBuffer(b)
			// This printing **must** success.(valid expr -> code)
			// So call panic on failing.
			err := printer.Fprint(buf, token.NewFileSet(), n)
			if err != nil {
				panic(err)
			}

			// This parsing **must** success.(valid code -> expr)
			// So call panic on failing.
			formatted, err := parser.ParseExpr(buf.String())
			if err != nil {
				panic(err)
			}
			*n = *formatted.(*ast.CallExpr)

			n.Args = append(n.Args, createRawStringLit(header+"\n"+buf.String()))
			n.Args = append(n.Args, &ast.BasicLit{Kind: token.INT, Value: strconv.Itoa(termw)})
			n.Args = append(n.Args, createPosValuePairExpr(extractPrintExprs(nil, n.Args[1]))...)
			n.Fun.(*ast.SelectorExpr).X = &ast.Ident{Name: "translatedassert"}
		}

		return true
	})

	return nil
}

type printExpr struct {
	Pos  int
	Expr ast.Expr
}

func newPrintExpr(pos token.Pos, e ast.Expr) printExpr {
	return printExpr{Pos: int(pos), Expr: e}
}

func extractPrintExprs(parent ast.Expr, n ast.Expr) []printExpr {
	ps := []printExpr{}

	switch n.(type) {
	case *ast.BasicLit:
		n := n.(*ast.BasicLit)
		if n.Kind == token.STRING {
			if len(strings.Split(n.Value, "\\n")) > 1 {
				ps = append(ps, newPrintExpr(n.Pos(), n))
			}
		}
	case *ast.CompositeLit:
		n := n.(*ast.CompositeLit)

		for _, elt := range n.Elts {
			ps = append(ps, extractPrintExprs(n, elt)...)
		}
	case *ast.KeyValueExpr:
		n := n.(*ast.KeyValueExpr)

		if isMapType(parent) {
			ps = append(ps, extractPrintExprs(n, n.Key)...)
		}

		ps = append(ps, extractPrintExprs(n, n.Value)...)
	case *ast.Ident:
		ps = append(ps, newPrintExpr(n.Pos(), n))
	case *ast.ParenExpr:
		n := n.(*ast.ParenExpr)
		ps = append(ps, extractPrintExprs(n, n.X)...)
	case *ast.StarExpr:
		n := n.(*ast.StarExpr)
		ps = append(ps, newPrintExpr(n.Pos(), n))
		ps = append(ps, extractPrintExprs(n, n.X)...)
	case *ast.UnaryExpr:
		n := n.(*ast.UnaryExpr)
		ps = append(ps, newPrintExpr(n.Pos(), n))
		ps = append(ps, extractPrintExprs(n, n.X)...)
	case *ast.BinaryExpr:
		n := n.(*ast.BinaryExpr)
		ps = append(ps, extractPrintExprs(n, n.X)...)
		ps = append(ps, newPrintExpr(n.OpPos, n))
		ps = append(ps, extractPrintExprs(n, n.Y)...)
	case *ast.IndexExpr:
		n := n.(*ast.IndexExpr)
		ps = append(ps, extractPrintExprs(n, n.X)...)
		ps = append(ps, extractPrintExprs(n, n.Index)...)
	case *ast.SelectorExpr:
		n := n.(*ast.SelectorExpr)
		ps = append(ps, extractPrintExprs(n, n.X)...)
		ps = append(ps, newPrintExpr(n.Sel.Pos(), n))
	case *ast.CallExpr:
		n := n.(*ast.CallExpr)
		ps = append(ps, newPrintExpr(n.Pos(), n))
		for _, arg := range n.Args {
			ps = append(ps, extractPrintExprs(n, arg)...)
		}
	case *ast.SliceExpr:
		n := n.(*ast.SliceExpr)
		ps = append(ps, extractPrintExprs(n, n.Low)...)
		ps = append(ps, extractPrintExprs(n, n.High)...)
		if n.Slice3 {
			ps = append(ps, extractPrintExprs(n, n.Max)...)
		}
	}

	return ps
}

func isAssert(x *ast.Ident, c *ast.CallExpr) bool {
	if s, ok := c.Fun.(*ast.SelectorExpr); ok {
		return s.X.(*ast.Ident).Name == x.Name && s.Sel.Name == "OK"
	}

	return false
}

func createRawStringLit(s string) *ast.BasicLit {
	return &ast.BasicLit{Kind: token.STRING, Value: "`" + s + "`"}
}

func isRawStringLit(n *ast.BasicLit) bool {
	return strings.HasPrefix(n.Value, "`") && strings.HasSuffix(n.Value, "`")
}

func isMapType(n ast.Node) bool {
	if n, ok := n.(*ast.CompositeLit); ok {
		_, ismt := n.Type.(*ast.MapType)
		return ismt
	}

	return false
}

func replaceAllRawStringLitByStringLit(root ast.Node) {
	ast.Inspect(root, func(n ast.Node) bool {
		if n, ok := n.(*ast.BasicLit); ok {
			if isRawStringLit(n) {
				n.Value = strconv.Quote(strings.Trim(n.Value, "`"))
			}
		}

		return true
	})
}

func createPosValuePairExpr(ps []printExpr) []ast.Expr {
	args := []ast.Expr{}

	for _, n := range ps {
		a := &ast.CallExpr{
			Fun: &ast.SelectorExpr{
				X:   translatedassertImportIdent,
				Sel: &ast.Ident{Name: "NewPosValuePair"},
			},
			Args: []ast.Expr{
				&ast.BasicLit{Kind: token.INT, Value: strconv.Itoa(int(n.Pos))},
				n.Expr,
			},
		}

		args = append(args, a)
	}

	return args
}
<commit_msg>Inspect inner funclit callexpr<commit_after>package main

import (
	"bytes"
	"errors"
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

var (
	translatedassertImportIdent = &ast.Ident{Name: "translatedassert"}
	assertImportIdent           = &ast.Ident{Name: "assert"}
	errAssertImportNotFound     = errors.New("github.com/ToQoz/gopwt/assert is not found in imports")
)

func rewritePackage(dirPath, importPath string, tempGoSrcDir string) error {
	err := filepath.Walk(dirPath, func(path string, fInfo os.FileInfo, err error) error {
		if fInfo.Mode()&os.ModeSymlink == os.ModeSymlink {
			return nil
		}

		pathFromImportDir, err := filepath.Rel(dirPath, path)
		if err != nil {
			return err
		}

		if fInfo.IsDir() {
			rel, err := filepath.Rel(dirPath, path)
			if err != nil {
				return err
			}

			if rel == "." {
				return nil
			}

			// copy all files in <dirPath>/testdata/**/*
			if strings.Split(rel, "/")[0] == "testdata" {
				err = os.MkdirAll(filepath.Join(tempGoSrcDir, importPath, pathFromImportDir), os.ModePerm)
				if err != nil {
					return err
				}

				return nil
			}

			return filepath.SkipDir
		}

		out, err := os.Create(filepath.Join(tempGoSrcDir, importPath, pathFromImportDir))
		if err != nil {
			return err
		}
		defer func() {
			out.Close()
		}()

		err = rewriteFile(path, importPath, out)
		if err != nil {
			return err
		}

		return nil
	})

	return err
}

func rewriteFile(path, importPath string, out io.Writer) error {
	translatedassertImportIdent = &ast.Ident{Name: "translatedassert"}
	assertImportIdent = &ast.Ident{Name: "assert"}

	copyFile := func() error {
		filedata, err := ioutil.ReadFile(path)
		if err != nil {
			return err
		}

		_, err = out.Write(filedata)
		if err != nil {
			return err
		}

		return nil
	}

	if !isTestGoFile(path) {
		return copyFile()
	}

	fset := token.NewFileSet()
	a, err := parser.ParseFile(fset, path, nil, 0)
	if err != nil {
		return err
	}

	err = translateAssertImport(a)
	if err != nil {
		if err == errAssertImportNotFound {
			return copyFile()
		}

		return err
	}

	err = translateAllAsserts(fset, a)
	if err != nil {
		return err
	}

	err = printer.Fprint(out, fset, a)
	if err != nil {
		return err
	}
	return nil
}

func isTestGoFile(name string) bool {
	return strings.HasSuffix(name, "_test.go") && !strings.HasPrefix(name, ".") && !strings.HasPrefix(name, "_")
}

func newPackageInfo(globalOrLocalImportPath string) (*packageInfo, error) {
	var err error
	var importPath string
	var dirPath string
	var recursive bool

	if strings.HasSuffix(globalOrLocalImportPath, "/...") {
		recursive = true
		globalOrLocalImportPath = strings.TrimSuffix(globalOrLocalImportPath, "/...")
	}

	if globalOrLocalImportPath == "" {
		globalOrLocalImportPath = "."
	}

	if strings.HasPrefix(globalOrLocalImportPath, ".") {
		wd, err := os.Getwd()
		if err != nil {
			return nil, err
		}

		dirPath = filepath.Join(wd, globalOrLocalImportPath)
		if _, err := os.Stat(dirPath); err != nil {
			return nil, err
		}

		importPath, err = findImportPathByPath(dirPath)
		if err != nil {
			return nil, err
		}
	} else {
		importPath = globalOrLocalImportPath

		dirPath, err = findPathByImportPath(importPath)
		if err != nil {
			return nil, err
		}
	}

	return &packageInfo{dirPath: dirPath, importPath: importPath, recursive: recursive}, nil
}

func translateAssertImport(a *ast.File) error {
	for _, decl := range a.Decls {
		decl, ok := decl.(*ast.GenDecl)
		if !ok {
			continue
		}
		if len(decl.Specs) == 0 {
			continue
		}

		if _, ok := decl.Specs[0].(*ast.ImportSpec); !ok {
			continue
		}

		for _, imp := range decl.Specs {
			imp := imp.(*ast.ImportSpec)

			if imp.Path.Value != `"github.com/ToQoz/gopwt/assert"` {
				continue
			}

			imp.Path.Value = `"github.com/ToQoz/gopwt/translatedassert"`
			if imp.Name != nil {
				assertImportIdent = imp.Name
				imp.Name = translatedassertImportIdent
			}

			goto Done
		}
	}

	return errAssertImportNotFound

Done:
	return nil
}

func translateAllAsserts(fset *token.FileSet, a *ast.File) error {
	ast.Inspect(a, func(n ast.Node) bool {
		if n, ok := n.(*ast.CallExpr); ok {
			if _, ok := n.Fun.(*ast.FuncLit); ok {
				return true
			}

			// skip inspecting children in n
			if !isAssert(assertImportIdent, n) {
				return false
			}

			file := fset.File(n.Pos())
			header := fmt.Sprintf("[FAIL] %s:%d", file.Name(), file.Line(n.Pos()))

			replaceAllRawStringLitByStringLit(n)

			b := []byte{}
			buf := bytes.NewBuffer(b)
			// This printing **must** success.(valid expr -> code)
			// So call panic on failing.
			err := printer.Fprint(buf, token.NewFileSet(), n)
			if err != nil {
				panic(err)
			}

			// This parsing **must** success.(valid code -> expr)
			// So call panic on failing.
			formatted, err := parser.ParseExpr(buf.String())
			if err != nil {
				panic(err)
			}
			*n = *formatted.(*ast.CallExpr)

			n.Args = append(n.Args, createRawStringLit(header+"\n"+buf.String()))
			n.Args = append(n.Args, &ast.BasicLit{Kind: token.INT, Value: strconv.Itoa(termw)})
			n.Args = append(n.Args, createPosValuePairExpr(extractPrintExprs(nil, n.Args[1]))...)
			n.Fun.(*ast.SelectorExpr).X = &ast.Ident{Name: "translatedassert"}
		}

		return true
	})

	return nil
}

type printExpr struct {
	Pos  int
	Expr ast.Expr
}

func newPrintExpr(pos token.Pos, e ast.Expr) printExpr {
	return printExpr{Pos: int(pos), Expr: e}
}

func extractPrintExprs(parent ast.Expr, n ast.Expr) []printExpr {
	ps := []printExpr{}

	switch n.(type) {
	case *ast.BasicLit:
		n := n.(*ast.BasicLit)
		if n.Kind == token.STRING {
			if len(strings.Split(n.Value, "\\n")) > 1 {
				ps = append(ps, newPrintExpr(n.Pos(), n))
			}
		}
	case *ast.CompositeLit:
		n := n.(*ast.CompositeLit)

		for _, elt := range n.Elts {
			ps = append(ps, extractPrintExprs(n, elt)...)
		}
	case *ast.KeyValueExpr:
		n := n.(*ast.KeyValueExpr)

		if isMapType(parent) {
			ps = append(ps, extractPrintExprs(n, n.Key)...)
		}

		ps = append(ps, extractPrintExprs(n, n.Value)...)
	case *ast.Ident:
		ps = append(ps, newPrintExpr(n.Pos(), n))
	case *ast.ParenExpr:
		n := n.(*ast.ParenExpr)
		ps = append(ps, extractPrintExprs(n, n.X)...)
	case *ast.StarExpr:
		n := n.(*ast.StarExpr)
		ps = append(ps, newPrintExpr(n.Pos(), n))
		ps = append(ps, extractPrintExprs(n, n.X)...)
	case *ast.UnaryExpr:
		n := n.(*ast.UnaryExpr)
		ps = append(ps, newPrintExpr(n.Pos(), n))
		ps = append(ps, extractPrintExprs(n, n.X)...)
	case *ast.BinaryExpr:
		n := n.(*ast.BinaryExpr)
		ps = append(ps, extractPrintExprs(n, n.X)...)
		ps = append(ps, newPrintExpr(n.OpPos, n))
		ps = append(ps, extractPrintExprs(n, n.Y)...)
	case *ast.IndexExpr:
		n := n.(*ast.IndexExpr)
		ps = append(ps, extractPrintExprs(n, n.X)...)
		ps = append(ps, extractPrintExprs(n, n.Index)...)
	case *ast.SelectorExpr:
		n := n.(*ast.SelectorExpr)
		ps = append(ps, extractPrintExprs(n, n.X)...)
		ps = append(ps, newPrintExpr(n.Sel.Pos(), n))
	case *ast.CallExpr:
		n := n.(*ast.CallExpr)
		ps = append(ps, newPrintExpr(n.Pos(), n))
		for _, arg := range n.Args {
			ps = append(ps, extractPrintExprs(n, arg)...)
		}
	case *ast.SliceExpr:
		n := n.(*ast.SliceExpr)
		ps = append(ps, extractPrintExprs(n, n.Low)...)
		ps = append(ps, extractPrintExprs(n, n.High)...)
		if n.Slice3 {
			ps = append(ps, extractPrintExprs(n, n.Max)...)
		}
	}

	return ps
}

func isAssert(x *ast.Ident, c *ast.CallExpr) bool {
	if s, ok := c.Fun.(*ast.SelectorExpr); ok {
		return s.X.(*ast.Ident).Name == x.Name && s.Sel.Name == "OK"
	}

	return false
}

func createRawStringLit(s string) *ast.BasicLit {
	return &ast.BasicLit{Kind: token.STRING, Value: "`" + s + "`"}
}

func isRawStringLit(n *ast.BasicLit) bool {
	return strings.HasPrefix(n.Value, "`") && strings.HasSuffix(n.Value, "`")
}

func isMapType(n ast.Node) bool {
	if n, ok := n.(*ast.CompositeLit); ok {
		_, ismt := n.Type.(*ast.MapType)
		return ismt
	}

	return false
}

func replaceAllRawStringLitByStringLit(root ast.Node) {
	ast.Inspect(root, func(n ast.Node) bool {
		if n, ok := n.(*ast.BasicLit); ok {
			if isRawStringLit(n) {
				n.Value = strconv.Quote(strings.Trim(n.Value, "`"))
			}
		}

		return true
	})
}

func createPosValuePairExpr(ps []printExpr) []ast.Expr {
	args := []ast.Expr{}

	for _, n := range ps {
		a := &ast.CallExpr{
			Fun: &ast.SelectorExpr{
				X:   translatedassertImportIdent,
				Sel: &ast.Ident{Name: "NewPosValuePair"},
			},
			Args: []ast.Expr{
				&ast.BasicLit{Kind: token.INT, Value: strconv.Itoa(int(n.Pos))},
				n.Expr,
			},
		}

		args = append(args, a)
	}

	return args
}
<|endoftext|>


<commit_before>package skiplist

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

const (
	p            = 0.3
	defaultDepth = 2
)

type Cmp uint8

const (
	LT Cmp = iota
	EQ
	GT
)

type Comparable interface {
	Compare(Comparable) Cmp
}

type SkipList struct {
	length             uint
	terminus           *Node
	levelProbabilities []float32
	curCapacity        uint
	curDepth           uint
	nodes              []Node
	ptrs               []*Node
	localRand          *rand.Rand
}

type Node struct {
	Key        Comparable
	Value      interface{}
	heightRand float32
	prev       *Node
	nexts      []*Node
	skiplist   *SkipList
}

func New(rng *rand.Rand) *SkipList {
	depth := defaultDepth

	s := &SkipList{
		length:             0,
		curDepth:           uint(depth),
		localRand:          rng,
		levelProbabilities: []float32{p},
	}
	s.determineCapacity()

	terminus := s.getNode()
	terminus.heightRand = 0
	terminus.nexts = make([]*Node, depth)
	for idx := 0; idx < len(terminus.nexts); idx++ {
		terminus.nexts[idx] = terminus
	}
	terminus.prev = terminus
	terminus.skiplist = s

	s.terminus = terminus

	// s.validate()

	return s
}

func (s *SkipList) determineCapacity() {
	base := float64(1.0) / p
	capacity := math.Pow(base, float64(s.curDepth))
	s.curCapacity = uint(math.Floor(capacity))
}

func (s *SkipList) chooseNumLevels() (float32, int, bool) {
	r := s.localRand.Float32()
	max := len(s.levelProbabilities)
	for idx := 0; idx < max; idx++ {
		if r > s.levelProbabilities[idx] {
			return r, idx + 1, true
		}
	}
	return r, max + 1, false
}

func (s *SkipList) ensureCapacity() {
	// defer s.validate()
	if s.length < s.curCapacity {
		return
	}

	threshold := p * s.levelProbabilities[s.curDepth-2]
	s.curDepth++
	s.levelProbabilities = append(s.levelProbabilities, threshold)

	s.determineCapacity()

	// cur and next are just used to walk through the list at lvl. prev
	// records the last node that made it up to the new level.
	cur := s.terminus
	lvl := len(cur.nexts) - 1
	prev := cur
	for {
		next := cur.nexts[lvl]
		if cur.heightRand <= threshold {
			cur.nexts = append(cur.nexts, s.terminus)
			prev.nexts[lvl+1] = cur
			prev = cur
		}
		if next == s.terminus {
			break
		} else {
			cur = next
		}
	}
}

func (s *SkipList) getNode() *Node {
	l := len(s.nodes)
	if l == 0 {
		l = int(s.curCapacity)
		s.nodes = make([]Node, l)
	}
	l--
	n := &s.nodes[l]
	s.nodes = s.nodes[:l]
	return n
}

func (s *SkipList) nextPtrs(l int) []*Node {
	if len(s.ptrs) < l {
		s.ptrs = make([]*Node, s.curDepth*s.curCapacity)
	}
	var ptrs []*Node
	ptrs, s.ptrs = s.ptrs[:l], s.ptrs[l:]
	return ptrs
}

func (s *SkipList) getEqOrLessThan(cur *Node, k Comparable, descentHeight int) (*Node, bool, []*Node) {
	// defer s.validate()

	var descent []*Node
	if descentHeight > 0 {
		descent = s.nextPtrs(descentHeight)
	}

	if s.length == 0 {
		return s.terminus, false, descent
	}
	if cur != s.terminus {
		switch k.Compare(cur.Key) {
		case EQ:
			return cur, true, descent
		case LT:
			return s.getEqOrLessThan(s.terminus, k, descentHeight)
		}
	}

	// 1. Travel, not-descending, as far as possible
	lvl := len(cur.nexts) - 1
Outer1:
	for {
		n := cur.nexts[lvl]
		if n == s.terminus {
			break
		}
		switch k.Compare(n.Key) {
		case GT:
			cur = n
			lvl = len(cur.nexts) - 1
		case EQ:
			return n, true, descent
		default:
			break Outer1
		}
	}

	// 2. Now descend as needed
	if l := lvl + 1; descentHeight > l {
		descent = descent[:l]
		descentHeight = l
	}
	if lvl < descentHeight {
		descent[lvl] = cur
	}
	for lvl--; lvl >= 0; lvl-- {
	Outer2:
		for {
			n := cur.nexts[lvl]
			if n == s.terminus {
				break
			}
			switch k.Compare(n.Key) {
			case GT:
				cur = n
			case EQ:
				return n, true, descent
			default:
				break Outer2
			}
		}
		if lvl < descentHeight {
			descent[lvl] = cur
		}
	}
	return cur, false, descent
}

func (s *SkipList) insert(cur *Node, k Comparable, v interface{}, n *Node) *Node {
	// defer s.validate()

	// do this first even though we may not need to - if we do it after
	// the getEqOrLessThan call, we may break descent.
	s.ensureCapacity()

	heightRand, height, fixed := s.chooseNumLevels()

	cur, found, descent := s.getEqOrLessThan(cur, k, height)
	if found {
		cur.Value = v
		return cur
	}
	// We didn't find k, so cur will be the node immediately prior to
	// where k should go.
	if n == nil {
		n = s.getNode()
	}
	n.Key = k
	n.Value = v
	n.heightRand = heightRand
	n.prev = cur
	n.skiplist = s

	if len(cur.nexts) >= height {
		if fixed {
			n.nexts = descent[:height]
		} else {
			n.nexts = make([]*Node, height)
			s.ptrs = descent[:cap(descent)]
		}
		for idx := 0; idx < height; idx++ {
			n.nexts[idx], cur.nexts[idx] = cur.nexts[idx], n
		}

	} else {
		// Descent may capture only part of the path: it may be shorter
		// than levels (in the case where the original cur is !=
		// s.terminus) and we reached the correct location without
		// travelling up very far. However, because we didn't find k, we
		// know that all the "lower" levels of descent will be populated
		// (where "lower" is "closer to [0]"), so we just need to fill in
		// the "top".
		if l := len(descent); height > l {
			_, _, extra := s.getEqOrLessThan(s.terminus, descent[l-1].Key, height)
			// Aside: because we know we'll find that Key, all the lower
			// indices of extra will be nil.
			copy(extra, descent)
			descent = extra
		}

		if fixed {
			n.nexts = descent
		} else {
			n.nexts = make([]*Node, height)
			s.ptrs = descent[:cap(descent)]
		}
		for idx := 0; idx < height; idx++ {
			n.nexts[idx], descent[idx].nexts[idx] = descent[idx].nexts[idx], n
		}
	}
	n._next().prev = n
	s.length++
	return n
}

func (s *SkipList) remove(cur *Node, k Comparable) interface{} {
	// defer s.validate()

	n, found, _ := s.getEqOrLessThan(cur, k, 0)
	if !found {
		return nil
	}
	s.removeNode(n)
	n.nullify()
	return n.Value
}

func (s *SkipList) removeNode(n *Node) {
	// defer s.validate()

	p := n.prev
	n._next().prev = p
	s.length--
	for idx := 0; idx < len(p.nexts) && idx < len(n.nexts); idx++ {
		p.nexts[idx] = n.nexts[idx]
	}
	if nNextLen, pNextLen := len(n.nexts), len(p.nexts); pNextLen < nNextLen {
		_, _, descent := s.getEqOrLessThan(s.terminus, p.Key, nNextLen)
		// because we know we're going to find Key, the lower indices
		// of descent will be nil. But we know p == n.prev, so all of
		// those pointers will be to n anyway, which we've already
		// dealt with in the previous loop.
		for idx := pNextLen; idx < nNextLen; idx++ {
			descent[idx].nexts[idx] = n.nexts[idx]
		}
	}
}

func (s *SkipList) reposition(cur *Node, k Comparable) {
	// defer s.validate()

	needsMove := false
	if cur != s.terminus {
		p := cur.prev
		needsMove = p != s.terminus && p.Key.Compare(k) != LT
		if !needsMove {
			n := cur._next()
			needsMove = n != s.terminus && k.Compare(n.Key) != LT
		}
	}
	if needsMove {
		s.removeNode(cur)
		cur.Key = k
		s.insert(cur.prev, cur.Key, cur.Value, cur)
	}
}

func (s *SkipList) First() *Node {
	return s.terminus.Next()
}

func (s *SkipList) Last() *Node {
	return s.terminus.Prev()
}

func (s *SkipList) Insert(k Comparable, v interface{}) *Node {
	return s.insert(s.terminus, k, v, nil)
}

func (s *SkipList) Get(k Comparable) *Node {
	return s.terminus.Get(k)
}

func (s *SkipList) Remove(k Comparable) interface{} {
	return s.remove(s.terminus, k)
}

func (s *SkipList) Len() uint {
	return s.length
}

// NB: this destroys t. Do not use t after this.
func (s *SkipList) Merge(t *SkipList) {
	// defer s.validate()

	cur := s.terminus
	for n := t.First(); n != nil; {
		m := n.Next() // need to save this out before we destroy it in the insert
		cur = s.insert(cur, n.Key, n.Value, n)
		n = m
	}
}

func (s *SkipList) validate() {
	visited := make(map[*Node]bool, int(s.length))
	cur := s.terminus
	visited[cur] = true
	l := uint(0)
	for {
		if cur != s.terminus {
			l++
		}
		if cur._next().prev != cur {
			panic(fmt.Sprintf("Node (%v) has next pointer to %v, which has prev pointer to %v", cur, cur._next(), cur._next().prev))
		}
		if cur.prev._next() != cur {
			panic(fmt.Sprintf("Node (%v) has prev pointer to %v, which has next pointer to %v", cur, cur.prev, cur.prev._next()))
		}
		for h, n := range cur.nexts {
			if h >= len(n.nexts) {
				panic(fmt.Sprintf("Node (%v) has next pointer at level %v pointing down to node (%v) which has %v height", cur, h, n, len(n.nexts)))
			}
		}
		n := cur._next()
		if n == s.terminus {
			break
		}
		if visited[n] {
			panic(fmt.Sprintf("Node (%v) has next as %v which is already visited!", cur, n))
		}
		if cur != s.terminus && cur.Key.Compare(n.Key) != LT {
			panic(fmt.Sprintf("Node keys in wrong order: expecting %v < %v", cur.Key, n.Key))
		}
		if n.prev != cur {
			panic(fmt.Sprintf("Node (%v) has next (%v) which does not point back correctly", cur, n))
		}
		cur = n
	}
	if l != s.length {
		panic(fmt.Sprintf("length is wrong: counted %v but length is %v", l, s.length))
	}
}

func (n *Node) Get(k Comparable) *Node {
	m, found, _ := n.skiplist.getEqOrLessThan(n, k, 0)
	if found {
		return m
	} else {
		return nil
	}
}

func (n *Node) Insert(k Comparable, v interface{}) *Node {
	return n.skiplist.insert(n, k, v, nil)
}

func (n *Node) Remove() interface{} {
	return n.skiplist.remove(n, n.Key)
}

func (n *Node) _next() *Node {
	return n.nexts[0]
}

func (n *Node) Next() *Node {
	if m := n.nexts[0]; m != n.skiplist.terminus {
		return m
	} else {
		return nil
	}
}

func (n *Node) Prev() *Node {
	if m := n.prev; m != n.skiplist.terminus {
		return m
	} else {
		return nil
	}
}

func (n *Node) Reposition(k Comparable) {
	n.skiplist.reposition(n, k)
}

func (n *Node) nullify() {
	// this is called when n is removed from the skiplist. It's really
	// just to ensure that if someone has a reference to n lying
	// around, they can't use it.
	n.prev = nil
	n.nexts = nil
	n.skiplist = nil
}

func (s *SkipList) String() string {
	strs := make([]string, 1, s.length+1)
	strs[0] = fmt.Sprint(s.terminus)
	for cur := s.terminus._next(); cur != s.terminus; cur = cur._next() {
		strs = append(strs, fmt.Sprint(cur))
	}
	return fmt.Sprintf("Skiplist of length %v (counted: %v), levelProbabilities %v, and nodes:\n\t[%v]",
		s.length, len(strs)-1, s.levelProbabilities, strings.Join(strs, ",\n\t "))
}

func (n *Node) String() string {
	strs := make([]string, len(n.nexts))
	for idx := 0; idx < len(strs); idx++ {
		strs[idx] = fmt.Sprint(n.nexts[idx].Key)
	}
	return fmt.Sprintf("%v -> %v (nexts: [%v])", n.Key, n.Value, strings.Join(strs, ", "))
}
<commit_msg>Well that was terrifying...<commit_after>package skiplist

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

const (
	p            = 0.3
	defaultDepth = 2
)

type Cmp int8

const (
	LT Cmp = iota - 1
	EQ
	GT
)

type Comparable interface {
	Compare(Comparable) Cmp
}

type SkipList struct {
	length             uint
	terminus           *Node
	levelProbabilities []float32
	curCapacity        uint
	curDepth           uint
	nodes              []Node
	ptrs               []*Node
	localRand          *rand.Rand
}

type Node struct {
	Key        Comparable
	Value      interface{}
	heightRand float32
	prev       *Node
	nexts      []*Node
	skiplist   *SkipList
}

func New(rng *rand.Rand) *SkipList {
	depth := defaultDepth

	s := &SkipList{
		length:             0,
		curDepth:           uint(depth),
		localRand:          rng,
		levelProbabilities: []float32{p},
	}
	s.determineCapacity()

	terminus := s.getNode()
	terminus.heightRand = 0
	terminus.nexts = make([]*Node, depth)
	for idx := 0; idx < len(terminus.nexts); idx++ {
		terminus.nexts[idx] = terminus
	}
	terminus.prev = terminus
	terminus.skiplist = s

	s.terminus = terminus

	// s.validate()

	return s
}

func (s *SkipList) determineCapacity() {
	base := float64(1.0) / p
	capacity := math.Pow(base, float64(s.curDepth))
	s.curCapacity = uint(math.Floor(capacity))
}

func (s *SkipList) chooseNumLevels() (float32, int, bool) {
	r := s.localRand.Float32()
	max := len(s.levelProbabilities)
	for idx := 0; idx < max; idx++ {
		if r > s.levelProbabilities[idx] {
			return r, idx + 1, true
		}
	}
	return r, max + 1, false
}

func (s *SkipList) ensureCapacity() {
	// defer s.validate()
	if s.length < s.curCapacity {
		return
	}

	threshold := p * s.levelProbabilities[s.curDepth-2]
	s.curDepth++
	s.levelProbabilities = append(s.levelProbabilities, threshold)

	s.determineCapacity()

	// cur and next are just used to walk through the list at lvl. prev
	// records the last node that made it up to the new level.
	cur := s.terminus
	lvl := len(cur.nexts) - 1
	prev := cur
	for {
		next := cur.nexts[lvl]
		if cur.heightRand <= threshold {
			cur.nexts = append(cur.nexts, s.terminus)
			prev.nexts[lvl+1] = cur
			prev = cur
		}
		if next == s.terminus {
			break
		} else {
			cur = next
		}
	}
}

func (s *SkipList) getNode() *Node {
	l := len(s.nodes)
	if l == 0 {
		l = int(s.curCapacity)
		s.nodes = make([]Node, l)
	}
	l--
	n := &s.nodes[l]
	s.nodes = s.nodes[:l]
	return n
}

func (s *SkipList) nextPtrs(l int) []*Node {
	if len(s.ptrs) < l {
		s.ptrs = make([]*Node, s.curDepth*s.curCapacity)
	}
	var ptrs []*Node
	ptrs, s.ptrs = s.ptrs[:l], s.ptrs[l:]
	return ptrs
}

func (s *SkipList) getEqOrLessThan(cur *Node, k Comparable, descentHeight int) (*Node, bool, []*Node) {
	// defer s.validate()

	var descent []*Node
	if descentHeight > 0 {
		descent = s.nextPtrs(descentHeight)
	}

	if s.length == 0 {
		return s.terminus, false, descent
	}
	if cur != s.terminus {
		switch k.Compare(cur.Key) {
		case EQ:
			return cur, true, descent
		case LT:
			return s.getEqOrLessThan(s.terminus, k, descentHeight)
		}
	}

	// 1. Travel, not-descending, as far as possible
	lvl := len(cur.nexts) - 1
Outer1:
	for {
		n := cur.nexts[lvl]
		if n == s.terminus {
			break
		}
		switch k.Compare(n.Key) {
		case GT:
			cur = n
			lvl = len(cur.nexts) - 1
		case EQ:
			return n, true, descent
		default:
			break Outer1
		}
	}

	// 2. Now descend as needed
	if l := lvl + 1; descentHeight > l {
		descent = descent[:l]
		descentHeight = l
	}
	if lvl < descentHeight {
		descent[lvl] = cur
	}
	for lvl--; lvl >= 0; lvl-- {
	Outer2:
		for {
			n := cur.nexts[lvl]
			if n == s.terminus {
				break
			}
			switch k.Compare(n.Key) {
			case GT:
				cur = n
			case EQ:
				return n, true, descent
			default:
				break Outer2
			}
		}
		if lvl < descentHeight {
			descent[lvl] = cur
		}
	}
	return cur, false, descent
}

func (s *SkipList) insert(cur *Node, k Comparable, v interface{}, n *Node) *Node {
	// defer s.validate()

	// do this first even though we may not need to - if we do it after
	// the getEqOrLessThan call, we may break descent.
	s.ensureCapacity()

	heightRand, height, fixed := s.chooseNumLevels()

	cur, found, descent := s.getEqOrLessThan(cur, k, height)
	if found {
		cur.Value = v
		return cur
	}
	// We didn't find k, so cur will be the node immediately prior to
	// where k should go.
	if n == nil {
		n = s.getNode()
	}
	n.Key = k
	n.Value = v
	n.heightRand = heightRand
	n.prev = cur
	n.skiplist = s

	if len(cur.nexts) >= height {
		if fixed {
			n.nexts = descent[:height]
		} else {
			n.nexts = make([]*Node, height)
			s.ptrs = descent[:cap(descent)]
		}
		for idx := 0; idx < height; idx++ {
			n.nexts[idx], cur.nexts[idx] = cur.nexts[idx], n
		}

	} else {
		// Descent may capture only part of the path: it may be shorter
		// than levels (in the case where the original cur is !=
		// s.terminus) and we reached the correct location without
		// travelling up very far. However, because we didn't find k, we
		// know that all the "lower" levels of descent will be populated
		// (where "lower" is "closer to [0]"), so we just need to fill in
		// the "top".
		if l := len(descent); height > l {
			_, _, extra := s.getEqOrLessThan(s.terminus, descent[l-1].Key, height)
			// Aside: because we know we'll find that Key, all the lower
			// indices of extra will be nil.
			copy(extra, descent)
			descent = extra
		}

		if fixed {
			n.nexts = descent
		} else {
			n.nexts = make([]*Node, height)
			s.ptrs = descent[:cap(descent)]
		}
		for idx := 0; idx < height; idx++ {
			n.nexts[idx], descent[idx].nexts[idx] = descent[idx].nexts[idx], n
		}
	}
	n._next().prev = n
	s.length++
	return n
}

func (s *SkipList) remove(cur *Node, k Comparable) interface{} {
	// defer s.validate()

	n, found, _ := s.getEqOrLessThan(cur, k, 0)
	if !found {
		return nil
	}
	s.removeNode(n)
	n.nullify()
	return n.Value
}

func (s *SkipList) removeNode(n *Node) {
	// defer s.validate()

	p := n.prev
	n._next().prev = p
	s.length--
	for idx := 0; idx < len(p.nexts) && idx < len(n.nexts); idx++ {
		p.nexts[idx] = n.nexts[idx]
	}
	if nNextLen, pNextLen := len(n.nexts), len(p.nexts); pNextLen < nNextLen {
		_, _, descent := s.getEqOrLessThan(s.terminus, p.Key, nNextLen)
		// because we know we're going to find Key, the lower indices
		// of descent will be nil. But we know p == n.prev, so all of
		// those pointers will be to n anyway, which we've already
		// dealt with in the previous loop.
		for idx := pNextLen; idx < nNextLen; idx++ {
			descent[idx].nexts[idx] = n.nexts[idx]
		}
	}
}

func (s *SkipList) reposition(cur *Node, k Comparable) {
	// defer s.validate()

	needsMove := false
	if cur != s.terminus {
		p := cur.prev
		needsMove = p != s.terminus && p.Key.Compare(k) != LT
		if !needsMove {
			n := cur._next()
			needsMove = n != s.terminus && k.Compare(n.Key) != LT
		}
	}
	if needsMove {
		s.removeNode(cur)
		cur.Key = k
		s.insert(cur.prev, cur.Key, cur.Value, cur)
	}
}

func (s *SkipList) First() *Node {
	return s.terminus.Next()
}

func (s *SkipList) Last() *Node {
	return s.terminus.Prev()
}

func (s *SkipList) Insert(k Comparable, v interface{}) *Node {
	return s.insert(s.terminus, k, v, nil)
}

func (s *SkipList) Get(k Comparable) *Node {
	return s.terminus.Get(k)
}

func (s *SkipList) Remove(k Comparable) interface{} {
	return s.remove(s.terminus, k)
}

func (s *SkipList) Len() uint {
	return s.length
}

// NB: this destroys t. Do not use t after this.
func (s *SkipList) Merge(t *SkipList) {
	// defer s.validate()

	cur := s.terminus
	for n := t.First(); n != nil; {
		m := n.Next() // need to save this out before we destroy it in the insert
		cur = s.insert(cur, n.Key, n.Value, n)
		n = m
	}
}

func (s *SkipList) validate() {
	visited := make(map[*Node]bool, int(s.length))
	cur := s.terminus
	visited[cur] = true
	l := uint(0)
	for {
		if cur != s.terminus {
			l++
		}
		if cur._next().prev != cur {
			panic(fmt.Sprintf("Node (%v) has next pointer to %v, which has prev pointer to %v", cur, cur._next(), cur._next().prev))
		}
		if cur.prev._next() != cur {
			panic(fmt.Sprintf("Node (%v) has prev pointer to %v, which has next pointer to %v", cur, cur.prev, cur.prev._next()))
		}
		for h, n := range cur.nexts {
			if h >= len(n.nexts) {
				panic(fmt.Sprintf("Node (%v) has next pointer at level %v pointing down to node (%v) which has %v height", cur, h, n, len(n.nexts)))
			}
		}
		n := cur._next()
		if n == s.terminus {
			break
		}
		if visited[n] {
			panic(fmt.Sprintf("Node (%v) has next as %v which is already visited!", cur, n))
		}
		if cur != s.terminus && cur.Key.Compare(n.Key) != LT {
			panic(fmt.Sprintf("Node keys in wrong order: expecting %v < %v", cur.Key, n.Key))
		}
		if n.prev != cur {
			panic(fmt.Sprintf("Node (%v) has next (%v) which does not point back correctly", cur, n))
		}
		cur = n
	}
	if l != s.length {
		panic(fmt.Sprintf("length is wrong: counted %v but length is %v", l, s.length))
	}
}

func (n *Node) Get(k Comparable) *Node {
	m, found, _ := n.skiplist.getEqOrLessThan(n, k, 0)
	if found {
		return m
	} else {
		return nil
	}
}

func (n *Node) Insert(k Comparable, v interface{}) *Node {
	return n.skiplist.insert(n, k, v, nil)
}

func (n *Node) Remove() interface{} {
	return n.skiplist.remove(n, n.Key)
}

func (n *Node) _next() *Node {
	return n.nexts[0]
}

func (n *Node) Next() *Node {
	if m := n.nexts[0]; m != n.skiplist.terminus {
		return m
	} else {
		return nil
	}
}

func (n *Node) Prev() *Node {
	if m := n.prev; m != n.skiplist.terminus {
		return m
	} else {
		return nil
	}
}

func (n *Node) Reposition(k Comparable) {
	n.skiplist.reposition(n, k)
}

func (n *Node) nullify() {
	// this is called when n is removed from the skiplist. It's really
	// just to ensure that if someone has a reference to n lying
	// around, they can't use it.
	n.prev = nil
	n.nexts = nil
	n.skiplist = nil
}

func (s *SkipList) String() string {
	strs := make([]string, 1, s.length+1)
	strs[0] = fmt.Sprint(s.terminus)
	for cur := s.terminus._next(); cur != s.terminus; cur = cur._next() {
		strs = append(strs, fmt.Sprint(cur))
	}
	return fmt.Sprintf("Skiplist of length %v (counted: %v), levelProbabilities %v, and nodes:\n\t[%v]",
		s.length, len(strs)-1, s.levelProbabilities, strings.Join(strs, ",\n\t "))
}

func (n *Node) String() string {
	strs := make([]string, len(n.nexts))
	for idx := 0; idx < len(strs); idx++ {
		strs[idx] = fmt.Sprint(n.nexts[idx].Key)
	}
	return fmt.Sprintf("%v -> %v (nexts: [%v])", n.Key, n.Value, strings.Join(strs, ", "))
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"os"
	"strings"
)

type SlackAPI struct {
	Token string
}

func (s *SlackAPI) AutoConfigure() {
	s.Token = os.Getenv("SLACK_TOKEN")
}

func (s *SlackAPI) ReportError(err error) {
	fmt.Printf("Error: %s\n", err)
	os.Exit(1)
}

func (s *SlackAPI) PrintJson(data interface{}) {
	response, err := json.MarshalIndent(data, "", "\x20\x20")

	if err != nil {
		s.ReportError(err)
	}

	fmt.Printf("%s\n", response)
	os.Exit(0)
}

func (s *SlackAPI) GetRequest(data interface{}, action string, params ...string) interface{} {
	var url string = fmt.Sprintf("https://slack.com/api/%s", action)

	if len(params) > 0 {
		var anchor string

		for key, keyvalue := range params {
			if key == 0 {
				anchor = "?"
			} else {
				anchor = "&"
			}

			if keyvalue == "token" {
				keyvalue += "=" + s.Token
			}

			url += anchor + keyvalue
		}
	}

	req, err := http.NewRequest("GET", url, nil)
	client := &http.Client{}

	req.Header.Add("DNT", "1")
	req.Header.Add("Accept", "*/*")
	req.Header.Add("Connection", "keep-alive")
	req.Header.Add("Accept-Language", "en-US,en")
	req.Header.Add("Origin", "https://sucuri.slack.com")
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("User-Agent", "Mozilla/5.0 (KHTML, like Gecko) Safari/537.36")

	if err != nil {
		s.ReportError(err)
	}

	resp, err := client.Do(req)

	if err != nil {
		s.ReportError(err)
	}

	defer resp.Body.Close()

	dec := json.NewDecoder(resp.Body)
	err = dec.Decode(data)

	if err != nil {
		s.ReportError(err)
	}

	return data
}

func (s *SlackAPI) Test() {
	var response interface{}
	s.GetRequest(&response, "api.test")
	s.PrintJson(response)
}

func (s *SlackAPI) AuthTest() {
	var response interface{}
	s.GetRequest(&response, "auth.test", "token")
	s.PrintJson(response)
}

func (s *SlackAPI) UsersGetPresence(query string) {
	var response interface{}
	s.GetRequest(&response, "users.getPresence", "token", "user="+query)
	s.PrintJson(response)
}

func (s *SlackAPI) UsersInfo(query string) {
	var response interface{}
	s.GetRequest(&response, "users.info", "token", "user="+query)
	s.PrintJson(response)
}

func (s *SlackAPI) UsersList() {
	var response interface{}
	s.GetRequest(&response, "users.list", "token", "presence=1")
	s.PrintJson(response)
}

func (s *SlackAPI) UsersSearch(query string) {
	if len(query) == 0 {
		s.ReportError(errors.New("empty query is invalid"))
	}

	var response Users
	var matches []User
	s.GetRequest(&response, "users.list", "token", "presence=1")

	for _, user := range response.Members {
		if strings.Contains(user.Name, query) ||
			strings.Contains(user.RealName, query) ||
			strings.Contains(user.Profile.Email, query) {
			matches = append(matches, user)
		}
	}

	s.PrintJson(matches)
}

func (s *SlackAPI) UsersSetActive() {
	var response interface{}
	s.GetRequest(&response, "users.setActive", "token")
	s.PrintJson(response)
}

func (s *SlackAPI) UsersSetPresence(query string) {
	var response interface{}
	s.GetRequest(&response, "users.setPresence", "token", "presence="+query)
	s.PrintJson(response)
}
<commit_msg>Modified function to build API URL endpoint<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"os"
	"strings"
)

type SlackAPI struct {
	Token string
}

func (s *SlackAPI) AutoConfigure() {
	s.Token = os.Getenv("SLACK_TOKEN")
}

func (s *SlackAPI) ReportError(err error) {
	fmt.Printf("Error: %s\n", err)
	os.Exit(1)
}

func (s *SlackAPI) PrintJson(data interface{}) {
	response, err := json.MarshalIndent(data, "", "\x20\x20")

	if err != nil {
		s.ReportError(err)
	}

	fmt.Printf("%s\n", response)
	os.Exit(0)
}

func (s *SlackAPI) Url(action string, params []string) string {
	var url string = fmt.Sprintf("https://slack.com/api/%s", action)

	if len(params) > 0 {
		var anchor string

		for key, keyvalue := range params {
			if key == 0 {
				anchor = "?"
			} else {
				anchor = "&"
			}

			if keyvalue == "token" {
				keyvalue += "=" + s.Token
			}

			url += anchor + keyvalue
		}
	}

	return url
}

func (s *SlackAPI) GetRequest(data interface{}, action string, params ...string) interface{} {
	var url string = s.Url(action, params)
	req, err := http.NewRequest("GET", url, nil)
	client := &http.Client{}

	req.Header.Add("DNT", "1")
	req.Header.Add("Accept", "*/*")
	req.Header.Add("Connection", "keep-alive")
	req.Header.Add("Accept-Language", "en-US,en")
	req.Header.Add("Origin", "https://sucuri.slack.com")
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("User-Agent", "Mozilla/5.0 (KHTML, like Gecko) Safari/537.36")

	if err != nil {
		s.ReportError(err)
	}

	resp, err := client.Do(req)

	if err != nil {
		s.ReportError(err)
	}

	defer resp.Body.Close()

	dec := json.NewDecoder(resp.Body)
	err = dec.Decode(data)

	if err != nil {
		s.ReportError(err)
	}

	return data
}

func (s *SlackAPI) Test() {
	var response interface{}
	s.GetRequest(&response, "api.test")
	s.PrintJson(response)
}

func (s *SlackAPI) AuthTest() {
	var response interface{}
	s.GetRequest(&response, "auth.test", "token")
	s.PrintJson(response)
}

func (s *SlackAPI) UsersGetPresence(query string) {
	var response interface{}
	s.GetRequest(&response, "users.getPresence", "token", "user="+query)
	s.PrintJson(response)
}

func (s *SlackAPI) UsersInfo(query string) {
	var response interface{}
	s.GetRequest(&response, "users.info", "token", "user="+query)
	s.PrintJson(response)
}

func (s *SlackAPI) UsersList() {
	var response interface{}
	s.GetRequest(&response, "users.list", "token", "presence=1")
	s.PrintJson(response)
}

func (s *SlackAPI) UsersSearch(query string) {
	if len(query) == 0 {
		s.ReportError(errors.New("empty query is invalid"))
	}

	var response Users
	var matches []User
	s.GetRequest(&response, "users.list", "token", "presence=1")

	for _, user := range response.Members {
		if strings.Contains(user.Name, query) ||
			strings.Contains(user.RealName, query) ||
			strings.Contains(user.Profile.Email, query) {
			matches = append(matches, user)
		}
	}

	s.PrintJson(matches)
}

func (s *SlackAPI) UsersSetActive() {
	var response interface{}
	s.GetRequest(&response, "users.setActive", "token")
	s.PrintJson(response)
}

func (s *SlackAPI) UsersSetPresence(query string) {
	var response interface{}
	s.GetRequest(&response, "users.setPresence", "token", "presence="+query)
	s.PrintJson(response)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
)
// 使用panic和recover编写一个不包含return语句但能返回一个非零值的函数。

func foo() {
	panic("testing")
}

func main() {
	defer func() {
		if p:=recover(); p != nil {
			fmt.Println(p)
		}
	}()
	foo()

}
<commit_msg>ex5.19<commit_after>package main

import (
	"fmt"
)
// 使用panic和recover编写一个不包含return语句但能返回一个非零值的函数。

func foo(num int) (ret int) {
	defer func() {
		recover()
		ret = 618 + num
	}()
	panic("test")
}

func main() {
	fmt.Println(foo(306))
}
<|endoftext|>


<commit_before>package kata

import "testing"

var game Game

func setUp() {
	game = Game{}
}

func rollMany(n, pins int) {
	for i := 0; i < n; i++ {
		game.roll(pins)
	}
}

func TestGutterGame(t *testing.T) {
	setUp()
	rollMany(20, 0)
	if game.score() != 0 {
		t.Errorf("Game.score() for a 0 pins game expect 0, got %d", game.score())
	}
}

func TestAllOnes(t *testing.T) {
	setUp()
	rollMany(20, 1)
	if game.score() != 20 {
		t.Errorf("Game.score() for all 1 pins rolls expect 20, got %d", game.score())
	}
}

func TestOneSpare(t *testing.T) {
	setUp()
	game.roll(5)
	game.roll(5)
	game.roll(3)
	rollMany(17, 0)
	if game.score() != 16 {
		t.Errorf("Game.score() for spare expect 16, got %d", game.score())
	}
}
<commit_msg>Extract spare roll in game test<commit_after>package kata

import "testing"

var game Game

func setUp() {
	game = Game{}
}

func rollMany(n, pins int) {
	for i := 0; i < n; i++ {
		game.roll(pins)
	}
}

func rollSpare() {
	game.roll(5)
	game.roll(5)
}

func TestGutterGame(t *testing.T) {
	setUp()
	rollMany(20, 0)
	if game.score() != 0 {
		t.Errorf("Game.score() for a 0 pins game expect 0, got %d", game.score())
	}
}

func TestAllOnes(t *testing.T) {
	setUp()
	rollMany(20, 1)
	if game.score() != 20 {
		t.Errorf("Game.score() for all 1 pins rolls expect 20, got %d", game.score())
	}
}

func TestOneSpare(t *testing.T) {
	setUp()
	rollSpare()
	game.roll(3)
	rollMany(17, 0)
	if game.score() != 16 {
		t.Errorf("Game.score() for spare expect 16, got %d", game.score())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/geobe/gostip/go/controller"
	"github.com/geobe/gostip/go/model"
	"net/http"
	"log"
	//"net"
	"net/url"
	"strings"
)

const httpport = ":8070"
const tlsport = ":8090"
const schema  = "http"

func main() {
	// prepare database
	model.Setup("")
	db := model.Db()
	defer db.Close()
	model.ClearTestDb(db)
	model.InitTestDb(db)

	mux := controller.SetRouting()

	// konfiguriere server
	server := &http.Server{
		Addr:    "0.0.0.0" + tlsport,
		Handler: mux,
	}

	// konfiguriere redirect server
	redirectserver := &http.Server{
		Addr:    "0.0.0.0" + httpport,
		Handler: http.HandlerFunc(RedirectHTTP),
	}
	// starte den redirect server
	go redirectserver.ListenAndServe()

	// und starte den primären server
	log.Printf("server starting\n")
	server.ListenAndServe()
}

// RedirectHTTP is an HTTP handler (suitable for use with http.HandleFunc)
// that responds to all requests by redirecting to the same URL served over HTTPS.
// It should only be invoked for requests received over HTTP.
func RedirectHTTP(w http.ResponseWriter, r *http.Request) {
	if r.TLS != nil || r.Host == "" {
		http.Error(w, "not found", 404)
	}

	var u *url.URL
	u = r.URL
	host := r.Host
	u.Host = strings.Split(host, ":")[0] + tlsport
	u.Scheme = schema
	log.Printf("redirect to u.host  %s -> %s\n", r.Host, u.String())
	http.Redirect(w, r, u.String(), 302)
}
<commit_msg>destinguish between local and internet access<commit_after>package main

import (
	"github.com/geobe/gostip/go/controller"
	"github.com/geobe/gostip/go/model"
	"net/http"
	"log"
	//"net"
	"net/url"
	"strings"
	"regexp"
)

const httpport = ":8070"
const tlsport = ":8090"
const schema = "http"

func main() {
	// prepare database
	model.Setup("")
	db := model.Db()
	defer db.Close()
	model.ClearTestDb(db)
	model.InitTestDb(db)

	mux := controller.SetRouting()

	// konfiguriere server
	server := &http.Server{
		Addr:    "0.0.0.0" + tlsport,
		Handler: mux,
	}

	// switching redirect handler
	handlerSwitch := &HandlerSwitch{
		Mux:    mux,
		Redirect: http.HandlerFunc(RedirectHTTP),
	}

	// konfiguriere redirect server
	redirectserver := &http.Server{
		Addr:    "0.0.0.0" + httpport,
		Handler: handlerSwitch, //http.HandlerFunc(RedirectHTTP),
	}
	// starte den redirect server
	go redirectserver.ListenAndServe()

	// und starte den primären server
	log.Printf("server starting\n")
	server.ListenAndServe()
}

// RedirectHTTP is an HTTP handler (suitable for use with http.HandleFunc)
// that responds to all requests by redirecting to the same URL served over HTTPS.
// It should only be invoked for requests received over HTTP.
func RedirectHTTP(w http.ResponseWriter, r *http.Request) {
	if r.TLS != nil || r.Host == "" {
		http.Error(w, "not found", 404)
	}

	var u *url.URL
	u = r.URL
	host := r.Host
	u.Host = strings.Split(host, ":")[0] + tlsport
	u.Scheme = schema
	log.Printf("redirect to u.host  %s -> %s\n", r.Host, u.String())
	http.Redirect(w, r, u.String(), 302)
}

type HandlerSwitch struct {
	Mux      http.Handler
	Redirect http.Handler
}

// nicht richtig für 172.16.0.0/12
var matcher = regexp.MustCompile("(192\\.168.*)|(localhost)|(10\\..*)|(172\\..*)")

func (h *HandlerSwitch) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	host := r.Host
	local := matcher.MatchString(host)
	if local {
		h.Mux.ServeHTTP(w, r)
	} else {
		h.Redirect.ServeHTTP(w, r)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package service

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/engine"
	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol"
	rpc "github.com/keybase/go-framed-msgpack-rpc"
	jsonw "github.com/keybase/go-jsonw"
)

type ConfigHandler struct {
	libkb.Contextified
	xp     rpc.Transporter
	svc    *Service
	connID libkb.ConnectionID
}

var _ keybase1.ConfigInterface = (*ConfigHandler)(nil)

func NewConfigHandler(xp rpc.Transporter, i libkb.ConnectionID, g *libkb.GlobalContext, svc *Service) *ConfigHandler {
	return &ConfigHandler{
		Contextified: libkb.NewContextified(g),
		xp:           xp,
		svc:          svc,
		connID:       i,
	}
}

func (h ConfigHandler) GetCurrentStatus(_ context.Context, sessionID int) (res keybase1.GetCurrentStatusRes, err error) {
	var cs libkb.CurrentStatus
	if cs, err = libkb.GetCurrentStatus(h.G()); err == nil {
		res = cs.Export()
	}
	return
}

func getPlatformInfo() keybase1.PlatformInfo {
	return keybase1.PlatformInfo{
		Os:        runtime.GOOS,
		Arch:      runtime.GOARCH,
		GoVersion: runtime.Version(),
	}
}

func (h ConfigHandler) GetValue(_ context.Context, path string) (ret keybase1.ConfigValue, err error) {
	var i interface{}
	i, err = h.G().Env.GetConfig().GetInterfaceAtPath(path)
	if err != nil {
		return ret, err
	}
	if i == nil {
		ret.IsNull = true
	} else {
		switch v := i.(type) {
		case int:
			ret.I = &v
		case string:
			ret.S = &v
		case bool:
			ret.B = &v
		case float64:
			tmp := int(v)
			ret.I = &tmp
		default:
			var b []byte
			b, err = json.Marshal(v)
			if err == nil {
				tmp := string(b)
				ret.O = &tmp
			}
		}
	}
	return ret, err
}

func (h ConfigHandler) SetValue(_ context.Context, arg keybase1.SetValueArg) (err error) {
	w := h.G().Env.GetConfigWriter()
	if arg.Path == "users" {
		err = fmt.Errorf("The field 'users' cannot be edited for fear of config corruption")
		return err
	}
	switch {
	case arg.Value.IsNull:
		w.SetNullAtPath(arg.Path)
	case arg.Value.S != nil:
		w.SetStringAtPath(arg.Path, *arg.Value.S)
	case arg.Value.I != nil:
		w.SetIntAtPath(arg.Path, *arg.Value.I)
	case arg.Value.B != nil:
		w.SetBoolAtPath(arg.Path, *arg.Value.B)
	case arg.Value.O != nil:
		var jw *jsonw.Wrapper
		jw, err = jsonw.Unmarshal([]byte(*arg.Value.O))
		if err == nil {
			err = w.SetWrapperAtPath(arg.Path, jw)
		}
	default:
		err = fmt.Errorf("Bad type for setting a value")
	}
	if err == nil {
		h.G().ConfigReload()
	}
	return err
}

func (h ConfigHandler) ClearValue(_ context.Context, path string) error {
	h.G().Env.GetConfigWriter().DeleteAtPath(path)
	h.G().ConfigReload()
	return nil
}

func (h ConfigHandler) GetExtendedStatus(_ context.Context, sessionID int) (res keybase1.ExtendedStatus, err error) {
	defer h.G().Trace("ConfigHandler::GetExtendedStatus", func() error { return err })()

	res.Standalone = h.G().Env.GetStandalone()
	res.LogDir = h.G().Env.GetLogDir()

	// Should work in standalone mode too
	if h.G().ConnectionManager != nil {
		res.Clients = h.G().ConnectionManager.ListAllLabeledConnections()
	}

	me, err := libkb.LoadMe(libkb.NewLoadUserArg(h.G()))
	if err != nil {
		h.G().Log.Debug("| could not load me user")
	} else {
		device, err := me.GetComputedKeyFamily().GetCurrentDevice(h.G())
		if err != nil {
			h.G().Log.Debug("| GetCurrentDevice failed: %s", err)
		} else {
			res.Device = device.ProtExport()
		}
	}

	h.G().LoginState().Account(func(a *libkb.Account) {
		res.PassphraseStreamCached = a.PassphraseStreamCache().ValidPassphraseStream()
		res.TsecCached = a.PassphraseStreamCache().ValidTsec()

		// cached keys status
		sk, err := a.CachedSecretKey(libkb.SecretKeyArg{KeyType: libkb.DeviceSigningKeyType})
		if err == nil && sk != nil {
			res.DeviceSigKeyCached = true
		}
		ek, err := a.CachedSecretKey(libkb.SecretKeyArg{KeyType: libkb.DeviceEncryptionKeyType})
		if err == nil && ek != nil {
			res.DeviceEncKeyCached = true
		}
		if a.GetUnlockedPaperSigKey() != nil {
			res.PaperSigKeyCached = true
		}
		if a.GetUnlockedPaperEncKey() != nil {
			res.PaperEncKeyCached = true
		}

		res.SecretPromptSkip = a.SkipSecretPrompt()

		if a.LoginSession() != nil {
			res.Session = a.LoginSession().Status()
		}
	}, "ConfigHandler::GetExtendedStatus")

	current, all, err := h.G().GetAllUserNames()
	if err != nil {
		h.G().Log.Debug("| died in GetAllUseranmes()")
		return res, err
	}
	res.DefaultUsername = current.String()
	p := make([]string, len(all))
	for i, u := range all {
		p[i] = u.String()
	}
	res.ProvisionedUsernames = p
	res.PlatformInfo = getPlatformInfo()

	if me != nil && h.G().SecretStoreAll != nil {
		s, err := h.G().SecretStoreAll.RetrieveSecret(me.GetNormalizedName())
		if err == nil && s != nil {
			res.StoredSecret = true
		}
	}

	return res, nil
}

func (h ConfigHandler) GetConfig(_ context.Context, sessionID int) (keybase1.Config, error) {
	var c keybase1.Config

	c.ServerURI = h.G().Env.GetServerURI()
	c.RunMode = string(h.G().Env.GetRunMode())
	var err error
	c.SocketFile, err = h.G().Env.GetSocketFile()
	if err != nil {
		return c, err
	}

	gpg := h.G().GetGpgClient()
	canExec, err := gpg.CanExec()
	if err == nil {
		c.GpgExists = canExec
		c.GpgPath = gpg.Path()
	}

	c.Version = libkb.VersionString()
	c.VersionShort = libkb.Version

	var v []string
	libkb.VersionMessage(func(s string) {
		v = append(v, s)
	})
	c.VersionFull = strings.Join(v, "\n")

	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err == nil {
		c.Path = dir
	}

	c.ConfigPath = h.G().Env.GetConfigFilename()
	c.Label = h.G().Env.GetLabel()
	if h.svc != nil {
		if h.svc.ForkType == keybase1.ForkType_AUTO {
			c.IsAutoForked = true
		}
		c.ForkType = h.svc.ForkType
	}

	return c, nil
}

func (h ConfigHandler) SetUserConfig(_ context.Context, arg keybase1.SetUserConfigArg) (err error) {
	eng := engine.NewUserConfigEngine(&engine.UserConfigEngineArg{
		Key:   arg.Key,
		Value: arg.Value,
	}, h.G())

	ctx := &engine.Context{}
	err = engine.RunEngine(eng, ctx)
	if err != nil {
		return err
	}
	return nil
}

func (h ConfigHandler) SetPath(_ context.Context, arg keybase1.SetPathArg) error {
	h.G().Log.Debug("SetPath calling mergeIntoPath(%s)", arg.Path)
	return mergeIntoPath(h.G(), arg.Path)
}

func mergeIntoPath(g *libkb.GlobalContext, p2 string) error {

	svcPath := os.Getenv("PATH")
	g.Log.Debug("mergeIntoPath: service path = %s", svcPath)
	g.Log.Debug("mergeIntoPath: merge path   = %s", p2)

	pathenv := filepath.SplitList(svcPath)
	pathset := make(map[string]bool)
	for _, p := range pathenv {
		pathset[p] = true
	}

	var clientAdditions []string
	for _, dir := range filepath.SplitList(p2) {
		if _, ok := pathset[dir]; ok {
			continue
		}
		clientAdditions = append(clientAdditions, dir)
	}

	pathenv = append(pathenv, clientAdditions...)
	combined := strings.Join(pathenv, string(os.PathListSeparator))

	if combined == svcPath {
		g.Log.Debug("No path changes needed")
		return nil
	}

	g.Log.Debug("mergeIntoPath: merged path = %s", combined)
	os.Setenv("PATH", combined)
	return nil
}

func (h ConfigHandler) HelloIAm(_ context.Context, arg keybase1.ClientDetails) error {
	return h.G().ConnectionManager.Label(h.connID, arg)
}

func (h ConfigHandler) CheckAPIServerOutOfDateWarning(_ context.Context) (keybase1.OutOfDateInfo, error) {
	return h.G().OutOfDateInfo, nil
}
<commit_msg>Log LoadMe error<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package service

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/engine"
	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol"
	rpc "github.com/keybase/go-framed-msgpack-rpc"
	jsonw "github.com/keybase/go-jsonw"
)

type ConfigHandler struct {
	libkb.Contextified
	xp     rpc.Transporter
	svc    *Service
	connID libkb.ConnectionID
}

var _ keybase1.ConfigInterface = (*ConfigHandler)(nil)

func NewConfigHandler(xp rpc.Transporter, i libkb.ConnectionID, g *libkb.GlobalContext, svc *Service) *ConfigHandler {
	return &ConfigHandler{
		Contextified: libkb.NewContextified(g),
		xp:           xp,
		svc:          svc,
		connID:       i,
	}
}

func (h ConfigHandler) GetCurrentStatus(_ context.Context, sessionID int) (res keybase1.GetCurrentStatusRes, err error) {
	var cs libkb.CurrentStatus
	if cs, err = libkb.GetCurrentStatus(h.G()); err == nil {
		res = cs.Export()
	}
	return
}

func getPlatformInfo() keybase1.PlatformInfo {
	return keybase1.PlatformInfo{
		Os:        runtime.GOOS,
		Arch:      runtime.GOARCH,
		GoVersion: runtime.Version(),
	}
}

func (h ConfigHandler) GetValue(_ context.Context, path string) (ret keybase1.ConfigValue, err error) {
	var i interface{}
	i, err = h.G().Env.GetConfig().GetInterfaceAtPath(path)
	if err != nil {
		return ret, err
	}
	if i == nil {
		ret.IsNull = true
	} else {
		switch v := i.(type) {
		case int:
			ret.I = &v
		case string:
			ret.S = &v
		case bool:
			ret.B = &v
		case float64:
			tmp := int(v)
			ret.I = &tmp
		default:
			var b []byte
			b, err = json.Marshal(v)
			if err == nil {
				tmp := string(b)
				ret.O = &tmp
			}
		}
	}
	return ret, err
}

func (h ConfigHandler) SetValue(_ context.Context, arg keybase1.SetValueArg) (err error) {
	w := h.G().Env.GetConfigWriter()
	if arg.Path == "users" {
		err = fmt.Errorf("The field 'users' cannot be edited for fear of config corruption")
		return err
	}
	switch {
	case arg.Value.IsNull:
		w.SetNullAtPath(arg.Path)
	case arg.Value.S != nil:
		w.SetStringAtPath(arg.Path, *arg.Value.S)
	case arg.Value.I != nil:
		w.SetIntAtPath(arg.Path, *arg.Value.I)
	case arg.Value.B != nil:
		w.SetBoolAtPath(arg.Path, *arg.Value.B)
	case arg.Value.O != nil:
		var jw *jsonw.Wrapper
		jw, err = jsonw.Unmarshal([]byte(*arg.Value.O))
		if err == nil {
			err = w.SetWrapperAtPath(arg.Path, jw)
		}
	default:
		err = fmt.Errorf("Bad type for setting a value")
	}
	if err == nil {
		h.G().ConfigReload()
	}
	return err
}

func (h ConfigHandler) ClearValue(_ context.Context, path string) error {
	h.G().Env.GetConfigWriter().DeleteAtPath(path)
	h.G().ConfigReload()
	return nil
}

func (h ConfigHandler) GetExtendedStatus(_ context.Context, sessionID int) (res keybase1.ExtendedStatus, err error) {
	defer h.G().Trace("ConfigHandler::GetExtendedStatus", func() error { return err })()

	res.Standalone = h.G().Env.GetStandalone()
	res.LogDir = h.G().Env.GetLogDir()

	// Should work in standalone mode too
	if h.G().ConnectionManager != nil {
		res.Clients = h.G().ConnectionManager.ListAllLabeledConnections()
	}

	me, err := libkb.LoadMe(libkb.NewLoadUserArg(h.G()))
	if err != nil {
		h.G().Log.Debug("| could not load me user: %s", err)
	} else {
		device, err := me.GetComputedKeyFamily().GetCurrentDevice(h.G())
		if err != nil {
			h.G().Log.Debug("| GetCurrentDevice failed: %s", err)
		} else {
			res.Device = device.ProtExport()
		}
	}

	h.G().LoginState().Account(func(a *libkb.Account) {
		res.PassphraseStreamCached = a.PassphraseStreamCache().ValidPassphraseStream()
		res.TsecCached = a.PassphraseStreamCache().ValidTsec()

		// cached keys status
		sk, err := a.CachedSecretKey(libkb.SecretKeyArg{KeyType: libkb.DeviceSigningKeyType})
		if err == nil && sk != nil {
			res.DeviceSigKeyCached = true
		}
		ek, err := a.CachedSecretKey(libkb.SecretKeyArg{KeyType: libkb.DeviceEncryptionKeyType})
		if err == nil && ek != nil {
			res.DeviceEncKeyCached = true
		}
		if a.GetUnlockedPaperSigKey() != nil {
			res.PaperSigKeyCached = true
		}
		if a.GetUnlockedPaperEncKey() != nil {
			res.PaperEncKeyCached = true
		}

		res.SecretPromptSkip = a.SkipSecretPrompt()

		if a.LoginSession() != nil {
			res.Session = a.LoginSession().Status()
		}
	}, "ConfigHandler::GetExtendedStatus")

	current, all, err := h.G().GetAllUserNames()
	if err != nil {
		h.G().Log.Debug("| died in GetAllUseranmes()")
		return res, err
	}
	res.DefaultUsername = current.String()
	p := make([]string, len(all))
	for i, u := range all {
		p[i] = u.String()
	}
	res.ProvisionedUsernames = p
	res.PlatformInfo = getPlatformInfo()

	if me != nil && h.G().SecretStoreAll != nil {
		s, err := h.G().SecretStoreAll.RetrieveSecret(me.GetNormalizedName())
		if err == nil && s != nil {
			res.StoredSecret = true
		}
	}

	return res, nil
}

func (h ConfigHandler) GetConfig(_ context.Context, sessionID int) (keybase1.Config, error) {
	var c keybase1.Config

	c.ServerURI = h.G().Env.GetServerURI()
	c.RunMode = string(h.G().Env.GetRunMode())
	var err error
	c.SocketFile, err = h.G().Env.GetSocketFile()
	if err != nil {
		return c, err
	}

	gpg := h.G().GetGpgClient()
	canExec, err := gpg.CanExec()
	if err == nil {
		c.GpgExists = canExec
		c.GpgPath = gpg.Path()
	}

	c.Version = libkb.VersionString()
	c.VersionShort = libkb.Version

	var v []string
	libkb.VersionMessage(func(s string) {
		v = append(v, s)
	})
	c.VersionFull = strings.Join(v, "\n")

	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err == nil {
		c.Path = dir
	}

	c.ConfigPath = h.G().Env.GetConfigFilename()
	c.Label = h.G().Env.GetLabel()
	if h.svc != nil {
		if h.svc.ForkType == keybase1.ForkType_AUTO {
			c.IsAutoForked = true
		}
		c.ForkType = h.svc.ForkType
	}

	return c, nil
}

func (h ConfigHandler) SetUserConfig(_ context.Context, arg keybase1.SetUserConfigArg) (err error) {
	eng := engine.NewUserConfigEngine(&engine.UserConfigEngineArg{
		Key:   arg.Key,
		Value: arg.Value,
	}, h.G())

	ctx := &engine.Context{}
	err = engine.RunEngine(eng, ctx)
	if err != nil {
		return err
	}
	return nil
}

func (h ConfigHandler) SetPath(_ context.Context, arg keybase1.SetPathArg) error {
	h.G().Log.Debug("SetPath calling mergeIntoPath(%s)", arg.Path)
	return mergeIntoPath(h.G(), arg.Path)
}

func mergeIntoPath(g *libkb.GlobalContext, p2 string) error {

	svcPath := os.Getenv("PATH")
	g.Log.Debug("mergeIntoPath: service path = %s", svcPath)
	g.Log.Debug("mergeIntoPath: merge path   = %s", p2)

	pathenv := filepath.SplitList(svcPath)
	pathset := make(map[string]bool)
	for _, p := range pathenv {
		pathset[p] = true
	}

	var clientAdditions []string
	for _, dir := range filepath.SplitList(p2) {
		if _, ok := pathset[dir]; ok {
			continue
		}
		clientAdditions = append(clientAdditions, dir)
	}

	pathenv = append(pathenv, clientAdditions...)
	combined := strings.Join(pathenv, string(os.PathListSeparator))

	if combined == svcPath {
		g.Log.Debug("No path changes needed")
		return nil
	}

	g.Log.Debug("mergeIntoPath: merged path = %s", combined)
	os.Setenv("PATH", combined)
	return nil
}

func (h ConfigHandler) HelloIAm(_ context.Context, arg keybase1.ClientDetails) error {
	return h.G().ConnectionManager.Label(h.connID, arg)
}

func (h ConfigHandler) CheckAPIServerOutOfDateWarning(_ context.Context) (keybase1.OutOfDateInfo, error) {
	return h.G().OutOfDateInfo, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"flag"
	"os"
	"oval"
)

const (
	OPMODE_LIST = 1
	OPMODE_RUN = 2
)

var cfg config

func run_mode() {
	od, ret := oval.Parse(cfg.flag_run)
	if ret != nil {
		fmt.Fprintf(os.Stderr, "%v\n", ret)
	}
	oval.Execute(od)
}

func list_mode() {
	od, ret := oval.Parse(cfg.flag_list)
	if ret != nil {
		fmt.Fprintf(os.Stderr, "%v\n", ret)
	}

	for _, v := range od.Definitions.Definitions {
		fmt.Printf("%s %s\n", v.ID, v.Metadata.Title)
	}
}

func main() {
	var opmode int = 0

	cfg = default_config()
	flag.BoolVar(&cfg.flag_debug, "d", false, "enable debugging")
	flag.StringVar(&cfg.flag_list, "l", "path", "list checks")
	flag.StringVar(&cfg.flag_run, "r", "path", "run checks")
	if len(os.Args) < 2 {
		flag.Usage()
		os.Exit(2)
	}
	flag.Parse()

	var validmode bool = false
	if (cfg.flag_list != "path") {
		opmode = OPMODE_LIST
		validmode = true
	} else if (cfg.flag_run != "path") {
		opmode = OPMODE_RUN
		validmode = true
	}
	if !validmode {
		flag.Usage()
		os.Exit(2)
	}

	oval.Init()

	if (cfg.flag_debug) {
		set_debug(true)
		// If we enable debugging on the command line, also turn it on
		// in the OVAL library
		oval.Set_debug(true)
		debug_prt("Debugging enabled\n")
	}

	switch opmode {
	case OPMODE_LIST:
		debug_prt("Entering list mode\n")
		list_mode()
	case OPMODE_RUN:
		debug_prt("Entering run mode\n")
		run_mode()
	default:
		flag.Usage()
	}
}
<commit_msg>use iota in enum const<commit_after>package main

import (
	"fmt"
	"flag"
	"os"
	"oval"
)

const (
	_ = iota
	OPMODE_LIST
	OPMODE_RUN
)

var cfg config

func run_mode() {
	od, ret := oval.Parse(cfg.flag_run)
	if ret != nil {
		fmt.Fprintf(os.Stderr, "%v\n", ret)
	}
	oval.Execute(od)
}

func list_mode() {
	od, ret := oval.Parse(cfg.flag_list)
	if ret != nil {
		fmt.Fprintf(os.Stderr, "%v\n", ret)
	}

	for _, v := range od.Definitions.Definitions {
		fmt.Printf("%s %s\n", v.ID, v.Metadata.Title)
	}
}

func main() {
	var opmode int = 0

	cfg = default_config()
	flag.BoolVar(&cfg.flag_debug, "d", false, "enable debugging")
	flag.StringVar(&cfg.flag_list, "l", "path", "list checks")
	flag.StringVar(&cfg.flag_run, "r", "path", "run checks")
	if len(os.Args) < 2 {
		flag.Usage()
		os.Exit(2)
	}
	flag.Parse()

	var validmode bool = false
	if (cfg.flag_list != "path") {
		opmode = OPMODE_LIST
		validmode = true
	} else if (cfg.flag_run != "path") {
		opmode = OPMODE_RUN
		validmode = true
	}
	if !validmode {
		flag.Usage()
		os.Exit(2)
	}

	oval.Init()

	if (cfg.flag_debug) {
		set_debug(true)
		// If we enable debugging on the command line, also turn it on
		// in the OVAL library
		oval.Set_debug(true)
		debug_prt("Debugging enabled\n")
	}

	switch opmode {
	case OPMODE_LIST:
		debug_prt("Entering list mode\n")
		list_mode()
	case OPMODE_RUN:
		debug_prt("Entering run mode\n")
		run_mode()
	default:
		flag.Usage()
	}
}
<|endoftext|>


<commit_before>// go_cover_reporter.go
package main

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"regexp"
	"strconv"
	"strings"
	"text/template"
	"time"
)

type message struct {
	Name string
	Body string
}

const (
	filename = "persist.txt"
)

func main() {
	http.HandleFunc("/", handler) // each request calls handler function
	http.HandleFunc("/receiver", receiver)
	http.HandleFunc("/demo_badge", func(w http.ResponseWriter, r *http.Request) {
		date := time.Now().Format(http.TimeFormat)
		log.Printf("%v", date)
		w.Header().Set("Content-Type", "image/gif")
		w.Header().Set("Cache-Control", "no-cache")
		w.Header().Set("Cache-Control", "no-store")
		w.Header().Set("Cache-Control", "private")
		w.Header().Set("Date", date)
		w.Header().Set("Expires", date)
		coverBadge(w, readPercentageFromFile())
	})
	log.Fatal(http.ListenAndServe(":"+os.Getenv("PORT"), nil))
}

func handler(w http.ResponseWriter, r *http.Request) {
	coverage := struct{ Percent float64 }{readPercentageFromFile()}
	err := pageTemplate.Execute(w, coverage)
	if err != nil {
		log.Print(err)
	}

}

func readPercentageFromFile() (i float64) {

	buffer, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatalln(err)
	}

	percentString := string(buffer)
	percent, _ := strconv.ParseFloat(strings.TrimSpace(percentString), 64)
	log.Println("percent>>>>>" + strconv.FormatFloat(percent, 'f', 2, 64))

	return percent
}

var pageTemplate = template.Must(template.New("pageTemplate").Parse(`
<!DOCTYPE html>

Most recent reported code coverage is {{.Percent}}%

`))

func receiver(rw http.ResponseWriter, req *http.Request) {

	file, err := os.Create(filename)
	if err != nil {
		log.Fatalln(err)
	}

	body, err := ioutil.ReadAll(req.Body)
	if err != nil {
		log.Fatalln(err)
	}
	log.Println(string(body))

	var t message
	err = json.Unmarshal(body, &t)
	if err != nil {
		log.Fatalln(err)
	}

	re := regexp.MustCompile(`\d+.*\d*%`)

	numericalValue := re.FindString(string(t.Body))

	_, err = io.WriteString(file, numericalValue[:len(numericalValue)-1])
	if err != nil {
		log.Fatalln(err)
	}
	file.Close()

	log.Println(t.Body)
}

func dummyFunction(i int, j int) int {
	return i + j
}
<commit_msg>added some logging println-s<commit_after>// go_cover_reporter.go
package main

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"regexp"
	"strconv"
	"strings"
	"text/template"
	"time"
)

type message struct {
	Name string
	Body string
}

const (
	filename = "persist.txt"
)

func main() {
	http.HandleFunc("/", handler) // each request calls handler function
	http.HandleFunc("/receiver", receiver)
	http.HandleFunc("/demo_badge", func(w http.ResponseWriter, r *http.Request) {
		date := time.Now().Format(http.TimeFormat)
		log.Printf("%v", date)
		w.Header().Set("Content-Type", "image/gif")
		w.Header().Set("Cache-Control", "no-cache")
		w.Header().Set("Cache-Control", "no-store")
		w.Header().Set("Cache-Control", "private")
		w.Header().Set("Date", date)
		w.Header().Set("Expires", date)
		coverBadge(w, readPercentageFromFile())
	})
	log.Fatal(http.ListenAndServe(":"+os.Getenv("PORT"), nil))
}

func handler(w http.ResponseWriter, r *http.Request) {
	coverage := struct{ Percent float64 }{readPercentageFromFile()}
	err := pageTemplate.Execute(w, coverage)
	if err != nil {
		log.Print(err)
	}

}

func readPercentageFromFile() (i float64) {

	buffer, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatalln(err)
	}

	percentString := string(buffer)
	percent, _ := strconv.ParseFloat(strings.TrimSpace(percentString), 64)
	log.Println("percent>>>>>" + strconv.FormatFloat(percent, 'f', 2, 64))

	return percent
}

var pageTemplate = template.Must(template.New("pageTemplate").Parse(`
<!DOCTYPE html>

Most recent reported code coverage is {{.Percent}}%

`))

func receiver(rw http.ResponseWriter, req *http.Request) {

	file, err := os.Create(filename)
	if err != nil {
		log.Fatalln(err)
	}

	body, err := ioutil.ReadAll(req.Body)
	if err != nil {
		log.Fatalln(err)
	}
	log.Println(string(body))

	var t message
	err = json.Unmarshal(body, &t)
	if err != nil {
		log.Fatalln(err)
	}

	re := regexp.MustCompile(`\d+.*\d*%`)

	numericalValue := re.FindString(string(t.Body))

	log.Println(numericalValue)

	_, err = io.WriteString(file, numericalValue[:len(numericalValue)-1])
	if err != nil {
		log.Fatalln(err)
	}
	file.Close()

	log.Println(t.Body)
}

func dummyFunction(i int, j int) int {
	return i + j
}
<|endoftext|>