<commit_before>package main

import (
	"fmt"
	"time"

	"github.com/gbl08ma/disturbancesmlx/dataobjects"
	"github.com/heetch/sqalx"
)

// ComputeTypicalSeconds calculates and updates the TypicalSeconds
// for all the Connections and Transfers where that can be done using the registered Trips
// Current TypicalSeconds are ignored and discarded.
func ComputeTypicalSeconds(node sqalx.Node) error {
	tx, err := node.Beginx()
	if err != nil {
		return err
	}
	defer tx.Rollback()

	tripIDs, err := dataobjects.GetTripIDs(tx)
	if err != nil {
		return err
	}

	fmt.Printf("%d trip IDs\n", len(tripIDs))

	type TransferKey struct {
		Station string
		From    string
		To      string
	}

	transferCache := make(map[TransferKey]*dataobjects.Transfer)
	getTransfer := func(station, from, to string) (*dataobjects.Transfer, error) {
		transfer, cached := transferCache[TransferKey{station, from, to}]
		if !cached {
			var err error
			transfer, err = dataobjects.GetTransfer(tx, station, from, to)
			if err != nil {
				return nil, err
			}
			transferCache[TransferKey{station, from, to}] = transfer
		}
		return transfer, nil
	}
	// we can use pointers as keys in the following maps because getTransfer and transferCache
	// make sure only one instance of each transfer is created throughout the execution of this function
	transferAvgNumerator := make(map[*dataobjects.Transfer]float64)
	transferAvgDenominator := make(map[*dataobjects.Transfer]float64)

	type ConnectionKey struct {
		From string
		To   string
	}

	connectionCache := make(map[ConnectionKey]*dataobjects.Connection)
	getConnection := func(from, to string) (*dataobjects.Connection, error) {
		connection, cached := connectionCache[ConnectionKey{from, to}]
		if !cached {
			var err error
			connection, err = dataobjects.GetConnection(tx, from, to)
			if err != nil {
				return nil, err
			}
			connectionCache[ConnectionKey{from, to}] = connection
		}
		return connection, nil
	}
	// we can use pointers as keys in the following maps because getConnection and connectionCache
	// make sure only one instance of each connection is created throughout the execution of this function
	connectionAvgNumerator := make(map[*dataobjects.Connection]float64)
	connectionAvgDenominator := make(map[*dataobjects.Connection]float64)
	connectionStopAvgNumerator := make(map[*dataobjects.Connection]float64)
	connectionStopAvgDenominator := make(map[*dataobjects.Connection]float64)
	connectionWaitAvgNumerator := make(map[*dataobjects.Connection]float64)
	connectionWaitAvgDenominator := make(map[*dataobjects.Connection]float64)

	processTransfer := func(transfer *dataobjects.Transfer, use *dataobjects.StationUse) error {
		seconds := use.LeaveTime.Sub(use.EntryTime).Seconds()
		transferAvgNumerator[transfer] += seconds
		transferAvgDenominator[transfer]++
		return nil
	}

	processConnection := func(connection *dataobjects.Connection, sourceUse *dataobjects.StationUse, targetUse *dataobjects.StationUse) error {
		seconds := targetUse.EntryTime.Sub(sourceUse.LeaveTime).Seconds()
		connectionAvgNumerator[connection] += seconds
		connectionAvgDenominator[connection]++

		waitSeconds := sourceUse.LeaveTime.Sub(sourceUse.EntryTime).Seconds()
		if sourceUse.Type == dataobjects.NetworkEntry {
			connectionWaitAvgNumerator[connection] += waitSeconds
			connectionWaitAvgDenominator[connection]++
		} else if sourceUse.Type == dataobjects.GoneThrough {
			connectionStopAvgNumerator[connection] += waitSeconds
			connectionStopAvgDenominator[connection]++
		}
		return nil
	}

	processTrip := func(trip *dataobjects.Trip) error {
		if len(trip.StationUses) <= 1 {
			// station visit or invalid trip
			// can't extract any data about connections
			return nil
		}

		for useIdx := 0; useIdx < len(trip.StationUses)-1; useIdx++ {
			sourceUse := trip.StationUses[useIdx]

			if sourceUse.Manual {
				// manual path extensions don't contain valid time data
				// skip
				continue
			}

			// if this is a transfer, process it
			if sourceUse.Type == dataobjects.Interchange {
				transfer, err := getTransfer(sourceUse.Station.ID, sourceUse.SourceLine.ID, sourceUse.TargetLine.ID)
				if err != nil {
					// transfer might no longer exist (closed stations, etc.)
					// move on
					fmt.Printf("Transfer on %s from %s to %s skipped\n", sourceUse.Station.ID, sourceUse.SourceLine.ID, sourceUse.TargetLine.ID)
					return nil
				}

				if err = processTransfer(transfer, sourceUse); err != nil {
					return err
				}
			}

			targetUse := trip.StationUses[useIdx+1]

			if targetUse.Manual {
				// manual path extensions don't contain valid time data
				// skip
				continue
			}

			connection, err := getConnection(sourceUse.Station.ID, targetUse.Station.ID)
			if err != nil {
				// connection might no longer exist (closed stations, etc.)
				// move on
				fmt.Printf("Connection from %s to %s skipped\n", sourceUse.Station.ID, targetUse.Station.ID)
				return nil
			}
			if useIdx+2 < len(trip.StationUses) && trip.StationUses[useIdx+2].EntryTime.Sub(targetUse.EntryTime) < 1*time.Second {
				// this station use is certainly a forced extension to make up for a station the client did not capture correct times for
				// skip
				return nil
			}

			if err = processConnection(connection, sourceUse, targetUse); err != nil {
				return err
			}
		}
		return nil
	}

	// instantiate each trip from DB individually
	// (instead of using dataobjects.GetTrips)
	// to reduce memory usage
	for _, tripID := range tripIDs {
		trip, err := dataobjects.GetTrip(tx, tripID)
		if err != nil {
			return err
		}

		if err = processTrip(trip); err != nil {
			return err
		}
	}

	for transfer, denominator := range transferAvgDenominator {
		if denominator < 2 {
			// data is not significant enough
			continue
		}
		average := transferAvgNumerator[transfer] / denominator
		// TODO: add math.Round to int cast once Go 1.10 is released
		transfer.TypicalSeconds = int(average)
		fmt.Printf("Updating transfer from %s to %s with %d (%f)\n", transfer.From.ID, transfer.To.ID, transfer.TypicalSeconds, denominator)
		err := transfer.Update(tx)
		if err != nil {
			return err
		}
	}

	for connection, denominator := range connectionAvgDenominator {
		if denominator < 2 {
			// data is not significant enough
			continue
		}
		average := connectionAvgNumerator[connection] / denominator
		// TODO: add math.Round to int cast once Go 1.10 is released
		connection.TypicalSeconds = int(average)
		fmt.Printf("Updating connection from %s to %s with %d (%f)\n", connection.From.ID, connection.To.ID, connection.TypicalSeconds, denominator)
		err := connection.Update(tx)
		if err != nil {
			return err
		}
	}

	for connection, denominator := range connectionStopAvgDenominator {
		if denominator < 2 {
			// data is not significant enough
			continue
		}
		average := connectionStopAvgNumerator[connection] / denominator
		// TODO: add math.Round to int cast once Go 1.10 is released
		connection.TypicalStopSeconds = int(average)
		fmt.Printf("Updating connection from %s to %s with stop %d (%f)\n", connection.From.ID, connection.To.ID, connection.TypicalStopSeconds, denominator)
		err := connection.Update(tx)
		if err != nil {
			return err
		}
	}

	for connection, denominator := range connectionWaitAvgDenominator {
		if denominator < 2 {
			// data is not significant enough
			continue
		}
		average := connectionWaitAvgNumerator[connection] / denominator
		// TODO: add math.Round to int cast once Go 1.10 is released
		connection.TypicalWaitingSeconds = int(average)
		fmt.Printf("Updating connection from %s to %s with wait %d (%f)\n", connection.From.ID, connection.To.ID, connection.TypicalWaitingSeconds, denominator)
		err := connection.Update(tx)
		if err != nil {
			return err
		}
	}

	return tx.Commit()
}

// ComputeAverageSpeed returns the average service speed in km/h
// based on the trips in the specified time range
func ComputeAverageSpeed(node sqalx.Node, fromTime time.Time, toTime time.Time) (float64, error) {
	tx, err := node.Beginx()
	if err != nil {
		return 0, err
	}
	defer tx.Commit() // read-only tx

	tripIDs, err := dataobjects.GetTripIDsBetween(tx, fromTime, toTime)
	if err != nil {
		return 0, err
	}

	fmt.Printf("%d trip IDs\n", len(tripIDs))

	type TransferKey struct {
		Station string
		From    string
		To      string
	}

	type ConnectionKey struct {
		From string
		To   string
	}

	connectionCache := make(map[ConnectionKey]*dataobjects.Connection)
	getConnection := func(from, to string) (*dataobjects.Connection, error) {
		connection, cached := connectionCache[ConnectionKey{from, to}]
		if !cached {
			var err error
			connection, err = dataobjects.GetConnection(tx, from, to)
			if err != nil {
				return nil, err
			}
			connectionCache[ConnectionKey{from, to}] = connection
		}
		return connection, nil
	}

	var totalTime time.Duration
	var totalDistance int64

	processTrip := func(trip *dataobjects.Trip) error {
		if len(trip.StationUses) <= 1 {
			// station visit or invalid trip
			// can't extract any data about connections
			return nil
		}

		var startTime, endTime time.Time
		for useIdx := 0; useIdx < len(trip.StationUses)-1; useIdx++ {
			sourceUse := trip.StationUses[useIdx]

			if sourceUse.Manual {
				// manual path extensions don't contain valid time data
				// skip
				continue
			}

			if sourceUse.Type == dataobjects.Interchange ||
				sourceUse.Type == dataobjects.Visit {
				continue
			}

			targetUse := trip.StationUses[useIdx+1]

			if targetUse.Manual {
				// manual path extensions don't contain valid time data
				// skip
				continue
			}

			connection, err := getConnection(sourceUse.Station.ID, targetUse.Station.ID)
			if err != nil {
				// connection might no longer exist (closed stations, etc.)
				// move on
				fmt.Printf("Connection from %s to %s skipped\n", sourceUse.Station.ID, targetUse.Station.ID)
				return nil
			}

			totalDistance += int64(connection.WorldLength)
			if startTime.IsZero() {
				startTime = sourceUse.LeaveTime
			}
			endTime = targetUse.EntryTime
		}
		totalTime += endTime.Sub(startTime)
		return nil
	}

	// instantiate each trip from DB individually
	// (instead of using dataobjects.GetTrips)
	// to reduce memory usage
	for _, tripID := range tripIDs {
		trip, err := dataobjects.GetTrip(tx, tripID)
		if err != nil {
			return 0, err
		}

		if err = processTrip(trip); err != nil {
			return 0, err
		}
	}

	km := float64(totalDistance) / 1000
	hours := totalTime.Hours()

	return km / hours, nil
}
<commit_msg>Adjustments to typical time computation<commit_after>package main

import (
	"fmt"
	"time"

	"github.com/gbl08ma/disturbancesmlx/dataobjects"
	"github.com/heetch/sqalx"
)

// ComputeTypicalSeconds calculates and updates the TypicalSeconds
// for all the Connections and Transfers where that can be done using the registered Trips
// Current TypicalSeconds are ignored and discarded.
func ComputeTypicalSeconds(node sqalx.Node) error {
	tx, err := node.Beginx()
	if err != nil {
		return err
	}
	defer tx.Rollback()

	tripIDs, err := dataobjects.GetTripIDs(tx)
	if err != nil {
		return err
	}

	fmt.Printf("%d trip IDs\n", len(tripIDs))

	type TransferKey struct {
		Station string
		From    string
		To      string
	}

	transferCache := make(map[TransferKey]*dataobjects.Transfer)
	getTransfer := func(station, from, to string) (*dataobjects.Transfer, error) {
		transfer, cached := transferCache[TransferKey{station, from, to}]
		if !cached {
			var err error
			transfer, err = dataobjects.GetTransfer(tx, station, from, to)
			if err != nil {
				return nil, err
			}
			transferCache[TransferKey{station, from, to}] = transfer
		}
		return transfer, nil
	}
	// we can use pointers as keys in the following maps because getTransfer and transferCache
	// make sure only one instance of each transfer is created throughout the execution of this function
	transferAvgNumerator := make(map[*dataobjects.Transfer]float64)
	transferAvgDenominator := make(map[*dataobjects.Transfer]float64)

	type ConnectionKey struct {
		From string
		To   string
	}

	connectionCache := make(map[ConnectionKey]*dataobjects.Connection)
	getConnection := func(from, to string) (*dataobjects.Connection, error) {
		connection, cached := connectionCache[ConnectionKey{from, to}]
		if !cached {
			var err error
			connection, err = dataobjects.GetConnection(tx, from, to)
			if err != nil {
				return nil, err
			}
			connectionCache[ConnectionKey{from, to}] = connection
		}
		return connection, nil
	}
	// we can use pointers as keys in the following maps because getConnection and connectionCache
	// make sure only one instance of each connection is created throughout the execution of this function
	connectionAvgNumerator := make(map[*dataobjects.Connection]float64)
	connectionAvgDenominator := make(map[*dataobjects.Connection]float64)
	connectionStopAvgNumerator := make(map[*dataobjects.Connection]float64)
	connectionStopAvgDenominator := make(map[*dataobjects.Connection]float64)
	connectionWaitAvgNumerator := make(map[*dataobjects.Connection]float64)
	connectionWaitAvgDenominator := make(map[*dataobjects.Connection]float64)

	processTransfer := func(transfer *dataobjects.Transfer, use *dataobjects.StationUse) error {
		seconds := use.LeaveTime.Sub(use.EntryTime).Seconds()
		transferAvgNumerator[transfer] += seconds - 20
		transferAvgDenominator[transfer]++
		return nil
	}

	processConnection := func(connection *dataobjects.Connection, sourceUse *dataobjects.StationUse, targetUse *dataobjects.StationUse) error {
		seconds := targetUse.EntryTime.Sub(sourceUse.LeaveTime).Seconds()
		connectionAvgNumerator[connection] += seconds + 20
		connectionAvgDenominator[connection]++

		waitSeconds := sourceUse.LeaveTime.Sub(sourceUse.EntryTime).Seconds()
		if sourceUse.Type == dataobjects.NetworkEntry {
			connectionWaitAvgNumerator[connection] += waitSeconds - 20
			connectionWaitAvgDenominator[connection]++
		} else if sourceUse.Type == dataobjects.GoneThrough && waitSeconds < 60*3 {
			connectionStopAvgNumerator[connection] += waitSeconds - 20
			connectionStopAvgDenominator[connection]++
		}
		return nil
	}

	processTrip := func(trip *dataobjects.Trip) error {
		if len(trip.StationUses) <= 1 {
			// station visit or invalid trip
			// can't extract any data about connections
			return nil
		}

		for useIdx := 0; useIdx < len(trip.StationUses)-1; useIdx++ {
			sourceUse := trip.StationUses[useIdx]

			if sourceUse.Manual {
				// manual path extensions don't contain valid time data
				// skip
				continue
			}

			// if this is a transfer, process it
			if sourceUse.Type == dataobjects.Interchange {
				transfer, err := getTransfer(sourceUse.Station.ID, sourceUse.SourceLine.ID, sourceUse.TargetLine.ID)
				if err != nil {
					// transfer might no longer exist (closed stations, etc.)
					// move on
					fmt.Printf("Transfer on %s from %s to %s skipped\n", sourceUse.Station.ID, sourceUse.SourceLine.ID, sourceUse.TargetLine.ID)
					return nil
				}

				if err = processTransfer(transfer, sourceUse); err != nil {
					return err
				}
			}

			targetUse := trip.StationUses[useIdx+1]

			if targetUse.Manual {
				// manual path extensions don't contain valid time data
				// skip
				continue
			}

			connection, err := getConnection(sourceUse.Station.ID, targetUse.Station.ID)
			if err != nil {
				// connection might no longer exist (closed stations, etc.)
				// move on
				fmt.Printf("Connection from %s to %s skipped\n", sourceUse.Station.ID, targetUse.Station.ID)
				continue
			}
			if useIdx+2 < len(trip.StationUses) && trip.StationUses[useIdx+2].EntryTime.Sub(targetUse.EntryTime) < 1*time.Second {
				// this station use is certainly a forced extension to make up for a station the client did not capture correct times for
				// skip
				continue
			}

			if err = processConnection(connection, sourceUse, targetUse); err != nil {
				return err
			}
		}
		return nil
	}

	// instantiate each trip from DB individually
	// (instead of using dataobjects.GetTrips)
	// to reduce memory usage
	for _, tripID := range tripIDs {
		trip, err := dataobjects.GetTrip(tx, tripID)
		if err != nil {
			return err
		}

		if err = processTrip(trip); err != nil {
			return err
		}
	}

	for transfer, denominator := range transferAvgDenominator {
		if denominator < 2 {
			// data is not significant enough
			continue
		}
		average := transferAvgNumerator[transfer] / denominator
		// TODO: add math.Round to int cast once Go 1.10 is released
		transfer.TypicalSeconds = int(average)
		fmt.Printf("Updating transfer from %s to %s with %d (%f)\n", transfer.From.ID, transfer.To.ID, transfer.TypicalSeconds, denominator)
		err := transfer.Update(tx)
		if err != nil {
			return err
		}
	}

	for connection, denominator := range connectionAvgDenominator {
		if denominator < 2 {
			// data is not significant enough
			continue
		}
		average := connectionAvgNumerator[connection] / denominator
		// TODO: add math.Round to int cast once Go 1.10 is released
		connection.TypicalSeconds = int(average)
		fmt.Printf("Updating connection from %s to %s with %d (%f)\n", connection.From.ID, connection.To.ID, connection.TypicalSeconds, denominator)
		err := connection.Update(tx)
		if err != nil {
			return err
		}
	}

	for connection, denominator := range connectionStopAvgDenominator {
		if denominator < 2 {
			// data is not significant enough
			continue
		}
		average := connectionStopAvgNumerator[connection] / denominator
		// TODO: add math.Round to int cast once Go 1.10 is released
		connection.TypicalStopSeconds = int(average)
		fmt.Printf("Updating connection from %s to %s with stop %d (%f)\n", connection.From.ID, connection.To.ID, connection.TypicalStopSeconds, denominator)
		err := connection.Update(tx)
		if err != nil {
			return err
		}
	}

	for connection, denominator := range connectionWaitAvgDenominator {
		if denominator < 2 {
			// data is not significant enough
			continue
		}
		average := connectionWaitAvgNumerator[connection] / denominator
		// TODO: add math.Round to int cast once Go 1.10 is released
		connection.TypicalWaitingSeconds = int(average)
		fmt.Printf("Updating connection from %s to %s with wait %d (%f)\n", connection.From.ID, connection.To.ID, connection.TypicalWaitingSeconds, denominator)
		err := connection.Update(tx)
		if err != nil {
			return err
		}
	}

	return tx.Commit()
}

// ComputeAverageSpeed returns the average service speed in km/h
// based on the trips in the specified time range
func ComputeAverageSpeed(node sqalx.Node, fromTime time.Time, toTime time.Time) (float64, error) {
	tx, err := node.Beginx()
	if err != nil {
		return 0, err
	}
	defer tx.Commit() // read-only tx

	tripIDs, err := dataobjects.GetTripIDsBetween(tx, fromTime, toTime)
	if err != nil {
		return 0, err
	}

	fmt.Printf("%d trip IDs\n", len(tripIDs))

	type TransferKey struct {
		Station string
		From    string
		To      string
	}

	type ConnectionKey struct {
		From string
		To   string
	}

	connectionCache := make(map[ConnectionKey]*dataobjects.Connection)
	getConnection := func(from, to string) (*dataobjects.Connection, error) {
		connection, cached := connectionCache[ConnectionKey{from, to}]
		if !cached {
			var err error
			connection, err = dataobjects.GetConnection(tx, from, to)
			if err != nil {
				return nil, err
			}
			connectionCache[ConnectionKey{from, to}] = connection
		}
		return connection, nil
	}

	var totalTime time.Duration
	var totalDistance int64

	processTrip := func(trip *dataobjects.Trip) error {
		if len(trip.StationUses) <= 1 {
			// station visit or invalid trip
			// can't extract any data about connections
			return nil
		}

		var startTime, endTime time.Time
		for useIdx := 0; useIdx < len(trip.StationUses)-1; useIdx++ {
			sourceUse := trip.StationUses[useIdx]

			if sourceUse.Manual {
				// manual path extensions don't contain valid time data
				// skip
				continue
			}

			if sourceUse.Type == dataobjects.Interchange ||
				sourceUse.Type == dataobjects.Visit {
				continue
			}

			targetUse := trip.StationUses[useIdx+1]

			if targetUse.Manual {
				// manual path extensions don't contain valid time data
				// skip
				continue
			}

			connection, err := getConnection(sourceUse.Station.ID, targetUse.Station.ID)
			if err != nil {
				// connection might no longer exist (closed stations, etc.)
				// move on
				fmt.Printf("Connection from %s to %s skipped\n", sourceUse.Station.ID, targetUse.Station.ID)
				return nil
			}

			totalDistance += int64(connection.WorldLength)
			if startTime.IsZero() {
				startTime = sourceUse.LeaveTime
			}
			endTime = targetUse.EntryTime
		}
		totalTime += endTime.Sub(startTime)
		return nil
	}

	// instantiate each trip from DB individually
	// (instead of using dataobjects.GetTrips)
	// to reduce memory usage
	for _, tripID := range tripIDs {
		trip, err := dataobjects.GetTrip(tx, tripID)
		if err != nil {
			return 0, err
		}

		if err = processTrip(trip); err != nil {
			return 0, err
		}
	}

	km := float64(totalDistance) / 1000
	hours := totalTime.Hours()

	return km / hours, nil
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/hanwen/go-fuse/termite"
	"flag"
	"io/ioutil"
	"log"
)

var _ = log.Printf

func main() {
	cachedir := flag.String("cachedir", "/tmp/worker-cache", "content cache")
	secretFile := flag.String("secret", "/tmp/secret.txt", "file containing password.")
	port := flag.Int("port", 1235, "Where to listen for work requests.")
	httpPort := flag.Int("http-port", 1296, "Where to serve HTTP status.")
	chrootBinary := flag.String("chroot", "", "binary to use for chroot'ing.")
	jobs := flag.Int("jobs", 1, "Max number of jobs to run.")
	flag.Parse()
	secret, err := ioutil.ReadFile(*secretFile)
	if err != nil {
		log.Fatal("ReadFile", err)
	}

	daemon := termite.NewWorkerDaemon(secret, *cachedir, *jobs)
	daemon.ChrootBinary = *chrootBinary
	go daemon.RunWorkerServer(*port)

	daemon.ServeHTTPStatus(*httpPort)
}
<commit_msg>Put default worker cache under /var/cache.<commit_after>package main

import (
	"github.com/hanwen/go-fuse/termite"
	"flag"
	"io/ioutil"
	"log"
)

var _ = log.Printf

func main() {
	cachedir := flag.String("cachedir", "/var/cache/termite/worker-cache", "content cache")
	secretFile := flag.String("secret", "/tmp/secret.txt", "file containing password.")
	port := flag.Int("port", 1235, "Where to listen for work requests.")
	httpPort := flag.Int("http-port", 1296, "Where to serve HTTP status.")
	chrootBinary := flag.String("chroot", "", "binary to use for chroot'ing.")
	jobs := flag.Int("jobs", 1, "Max number of jobs to run.")
	flag.Parse()
	secret, err := ioutil.ReadFile(*secretFile)
	if err != nil {
		log.Fatal("ReadFile", err)
	}

	daemon := termite.NewWorkerDaemon(secret, *cachedir, *jobs)
	daemon.ChrootBinary = *chrootBinary
	go daemon.RunWorkerServer(*port)

	daemon.ServeHTTPStatus(*httpPort)
}
<|endoftext|>


<commit_before>// Package conekta contains Conekta REST API wrappers.
/*
	Use of this source code is governed by a MIT
	license that can be found in the LICENSE file.
*/
package conekta

import (
	"bytes"
	"encoding/json"
	"log"
	"net/http"
	"time"
)

const (
	// Host host URL.
	Host = "https://api.conekta.io"

	// OrderURI Order REST.
	OrderURI = "/orders"

	// CustomerURI Customer REST.
	CustomerURI = "/customers"
)

// Client implements all Conekta REST API endpoints.
type Client struct {
	client      *http.Client
	key, secret string
	sandbox     bool
	debug       bool
}

// NewClient returns a new Conekta client with http default settings. Use sandbox
// flag as false for production environments.
func NewClient(key, secret string, sandbox bool) (*Client, error) {
	c := &Client{
		key:     key,
		secret:  secret,
		sandbox: sandbox,
		client: &http.Client{
			Timeout: 60 * time.Second,
		},
	}
	return c, nil
}

func (c *Client) bind(dst, src interface{}, method, uri string) error {
	b, err := json.MarshalIndent(src, "", "	")
	if err != nil {
		return err
	}
	if c.debug {
		log.Printf("bind : method [%s] uri [%s] request body [%s]", method, uri, string(b))
	}
	req, err := http.NewRequest(method, uri, bytes.NewBuffer(b))
	if err != nil {
		return err
	}
	req.Header.Set("Accept", "application/vnd.conekta-v2.0.0+json")
	req.Header.Set("Content-Type", "application/json")
	req.SetBasicAuth(c.secret, "")
	resp, err := c.client.Do(req)
	if err != nil {
		return err
	}
	defer func() {
		if err := resp.Body.Close(); err != nil {
			log.Printf("bind : close body : err [%s]", err)
		}
	}()
	if resp.StatusCode != http.StatusOK {
		buf := new(bytes.Buffer)
		if _, err := buf.ReadFrom(resp.Body); err != nil {
			log.Printf("bind : read error response : err [%s]", err)
		}
		if c.debug {
			log.Printf("bind : read error response [%s]", buf.String())
		}

		var f Fail
		if err := json.NewDecoder(buf).Decode(&f); err != nil {
			return err
		}
		return f
	}
	if err := json.NewDecoder(resp.Body).Decode(dst); err != nil {
		return err
	}
	return nil
}

// CreateOrder _
func (c *Client) CreateOrder(or *OrderRequest) (*Order, error) {
	var order *Order
	err := c.bind(&order, or, "POST", Host+OrderURI)
	return order, err
}

// CreateCustomer _
func (c *Client) CreateCustomer(cr *CustomerRequest) (*Customer, error) {
	var cus *Customer
	err := c.bind(&cus, cr, "POST", Host+CustomerURI)
	return cus, err
}

// Fail  _
type Fail struct {
	Details []Detail `json:"details"`
	Object  string   `json:"object"`
	Type    string   `json:"type"`
	LogID   string   `json:"log_id"`
}

// Error implements error.
func (f Fail) Error() string {
	return f.Type
}

// Detail _
type Detail struct {
	DebugMessage string `json:"debug_message"`
	Message      string `json:"message"`
	Code         string `json:"code"`
	Param        string `json:"param"`
}

const (
	// MXN mexican pesos code ISO 4217.
	MXN = "MXN"
)

// OrderRequest type.
// see: https://developers.conekta.com/api?language=bash#order
type OrderRequest struct {
	Currency        string           `json:"currency,omitempty"`
	LineItems       []Product        `json:"line_items,omitempty"`
	ShippingLines   []Shipping       `json:"shipping_lines,omitempty"`
	TaxLines        []Tax            `json:"tax_lines,omitempty"`
	DiscountLines   []Discount       `json:"discount_lines,omitempty"`
	PreAuthorize    bool             `json:"pre_authorize,omitempty"`
	CustomerInfo    *Customer        `json:"customer_info,omitempty"`
	ShippingContact *ShippingContact `json:"shipping_contact,omitempty"`
	Charges         []Charge         `json:"charges,omitempty"`
}

// Product type.
type Product struct {
	ID          string   `json:"id,omitempty"`
	Name        string   `json:"name,omitempty"`
	Description string   `json:"description,omitempty"`
	UnitPrice   int64    `json:"unit_price,omitempty"`
	Quantity    int      `json:"quantity,omitempty"`
	SKU         string   `json:"sku,omitempty"`
	Tags        []string `json:"tags,omitempty"`
	Brand       string   `json:"brand,omitempty"`
}

// Shipping type.
type Shipping struct{}

// Tax type.
type Tax struct {
	ID          string `json:"id,omitempty"`
	Description string `json:"description,omitempty"`
	Amount      int64  `json:"amount,omitempty"`
}

// Discount type.
type Discount struct {
	ID     string `json:"id,omitempty"`
	Code   string `json:"code,omitempty"`
	Type   string `json:"type,omitempty"`
	Amount int64  `json:"amount,omitempty"`
}

// CustomerRequest _
type CustomerRequest struct {
	Name             string            `json:"name,omitempty"`
	Phone            string            `json:"phone,omitempty"`
	Email            string            `json:"email,omitempty"`
	PlanID           string            `json:"plan_id,omitempty"`
	PaymentSources   []PaymentSource   `json:"payment_sources,omitempty"`
	Corporate        bool              `json:"corporate,omitempty"`
	ShippingContacts []ShippingContact `json:"shipping_contacts,omitempty"`
}

// PaymentSource _
type PaymentSource struct {
	TokenID string `json:"token_id,omitempty"`
	Type    string `json:"type,omitempty"`
}

// Customer type.
type Customer struct {
	CustomerID string `json:"customer_id,omitempty"`
	Name       string `json:"name,omitempty"`
	Phone      string `json:"phone,omitempty"`
	Email      string `json:"email,omitempty"`
	Corporate  bool   `json:"corporate,omitempty"`
}

// ShippingContact type.
type ShippingContact struct {
	Phone          string  `json:"phone,omitempty"`
	Receiver       string  `json:"receiver,omitempty"`
	BetweenStreets string  `json:"between_streets,omitempty"`
	Address        Address `json:"address,omitempty"`
}

// Address _
type Address struct {
	Street1     string `json:"street1,omitempty"`
	Street2     string `json:"street2,omitempty"`
	City        string `json:"city,omitempty"`
	State       string `json:"state,omitempty"`
	Country     string `json:"country,omitempty"`
	PostalCode  string `json:"postal_code,omitempty"`
	Residential bool   `json:"residential,omitempty"`
}

// Charge type.
type Charge struct {
	ID            string        `json:"id,omitempty"`
	CreatedAt     int64         `json:"created_at,omitempty"`
	Currency      string        `json:"currency,omitempty"`
	Amount        int64         `json:"amount,omitempty"`
	Livemode      bool          `json:"livemode,omitempty"`
	PaymentMethod PaymentMethod `json:"payment_method,omitempty"`
	Fee           int64         `json:"fee,omitempty"`
}

// PaymentMethod _
type PaymentMethod struct {
	TokenID string `json:"token_id,omitempty"`
	Type    string `json:"type,omitempty"`
}

// Order type.
type Order struct{}
<commit_msg>Added fields to order<commit_after>// Package conekta contains Conekta REST API wrappers.
/*
	Use of this source code is governed by a MIT
	license that can be found in the LICENSE file.
*/
package conekta

import (
	"bytes"
	"encoding/json"
	"log"
	"net/http"
	"time"
)

const (
	// Host host URL.
	Host = "https://api.conekta.io"

	// OrderURI Order REST.
	OrderURI = "/orders"

	// CustomerURI Customer REST.
	CustomerURI = "/customers"
)

// Client implements all Conekta REST API endpoints.
type Client struct {
	client      *http.Client
	key, secret string
	sandbox     bool
	debug       bool
}

// NewClient returns a new Conekta client with http default settings. Use sandbox
// flag as false for production environments.
func NewClient(key, secret string, sandbox bool) (*Client, error) {
	c := &Client{
		key:     key,
		secret:  secret,
		sandbox: sandbox,
		client: &http.Client{
			Timeout: 60 * time.Second,
		},
	}
	return c, nil
}

func (c *Client) bind(dst, src interface{}, method, uri string) error {
	b, err := json.MarshalIndent(src, "", "	")
	if err != nil {
		return err
	}
	if c.debug {
		log.Printf("bind : method [%s] uri [%s] request body [%s]", method, uri, string(b))
	}
	req, err := http.NewRequest(method, uri, bytes.NewBuffer(b))
	if err != nil {
		return err
	}
	req.Header.Set("Accept", "application/vnd.conekta-v2.0.0+json")
	req.Header.Set("Content-Type", "application/json")
	req.SetBasicAuth(c.secret, "")
	resp, err := c.client.Do(req)
	if err != nil {
		return err
	}
	defer func() {
		if err := resp.Body.Close(); err != nil {
			log.Printf("bind : close body : err [%s]", err)
		}
	}()
	if resp.StatusCode != http.StatusOK {
		buf := new(bytes.Buffer)
		if _, err := buf.ReadFrom(resp.Body); err != nil {
			log.Printf("bind : read error response : err [%s]", err)
		}
		if c.debug {
			log.Printf("bind : read error response [%s]", buf.String())
		}

		var f Fail
		if err := json.NewDecoder(buf).Decode(&f); err != nil {
			return err
		}
		return f
	}
	if err := json.NewDecoder(resp.Body).Decode(dst); err != nil {
		return err
	}
	return nil
}

// CreateOrder _
func (c *Client) CreateOrder(or *OrderRequest) (*Order, error) {
	var order *Order
	err := c.bind(&order, or, "POST", Host+OrderURI)
	return order, err
}

// CreateCustomer _
func (c *Client) CreateCustomer(cr *CustomerRequest) (*Customer, error) {
	var cus *Customer
	err := c.bind(&cus, cr, "POST", Host+CustomerURI)
	return cus, err
}

// Fail  _
type Fail struct {
	Details []Detail `json:"details"`
	Object  string   `json:"object"`
	Type    string   `json:"type"`
	LogID   string   `json:"log_id"`
}

// Error implements error.
func (f Fail) Error() string {
	return f.Type
}

// Detail _
type Detail struct {
	DebugMessage string `json:"debug_message"`
	Message      string `json:"message"`
	Code         string `json:"code"`
	Param        string `json:"param"`
}

const (
	// MXN mexican pesos code ISO 4217.
	MXN = "MXN"
)

// OrderRequest type.
// see: https://developers.conekta.com/api?language=bash#order
type OrderRequest struct {
	Currency        string           `json:"currency,omitempty"`
	LineItems       []Product        `json:"line_items,omitempty"`
	ShippingLines   []Shipping       `json:"shipping_lines,omitempty"`
	TaxLines        []Tax            `json:"tax_lines,omitempty"`
	DiscountLines   []Discount       `json:"discount_lines,omitempty"`
	PreAuthorize    bool             `json:"pre_authorize,omitempty"`
	CustomerInfo    *Customer        `json:"customer_info,omitempty"`
	ShippingContact *ShippingContact `json:"shipping_contact,omitempty"`
	Charges         []Charge         `json:"charges,omitempty"`
}

// Product type.
type Product struct {
	ID          string   `json:"id,omitempty"`
	Name        string   `json:"name,omitempty"`
	Description string   `json:"description,omitempty"`
	UnitPrice   int64    `json:"unit_price,omitempty"`
	Quantity    int      `json:"quantity,omitempty"`
	SKU         string   `json:"sku,omitempty"`
	Tags        []string `json:"tags,omitempty"`
	Brand       string   `json:"brand,omitempty"`
}

// Shipping type.
type Shipping struct{}

// Tax type.
type Tax struct {
	ID          string `json:"id,omitempty"`
	Description string `json:"description,omitempty"`
	Amount      int64  `json:"amount,omitempty"`
}

// Discount type.
type Discount struct {
	ID     string `json:"id,omitempty"`
	Code   string `json:"code,omitempty"`
	Type   string `json:"type,omitempty"`
	Amount int64  `json:"amount,omitempty"`
}

// CustomerRequest _
type CustomerRequest struct {
	Name             string            `json:"name,omitempty"`
	Phone            string            `json:"phone,omitempty"`
	Email            string            `json:"email,omitempty"`
	PlanID           string            `json:"plan_id,omitempty"`
	PaymentSources   []PaymentSource   `json:"payment_sources,omitempty"`
	Corporate        bool              `json:"corporate,omitempty"`
	ShippingContacts []ShippingContact `json:"shipping_contacts,omitempty"`
}

// PaymentSource _
type PaymentSource struct {
	TokenID string `json:"token_id,omitempty"`
	Type    string `json:"type,omitempty"`
}

// Customer type.
type Customer struct {
	CustomerID string `json:"customer_id,omitempty"`
	Name       string `json:"name,omitempty"`
	Phone      string `json:"phone,omitempty"`
	Email      string `json:"email,omitempty"`
	Corporate  bool   `json:"corporate,omitempty"`
}

// ShippingContact type.
type ShippingContact struct {
	Phone          string  `json:"phone,omitempty"`
	Receiver       string  `json:"receiver,omitempty"`
	BetweenStreets string  `json:"between_streets,omitempty"`
	Address        Address `json:"address,omitempty"`
}

// Address _
type Address struct {
	Street1     string `json:"street1,omitempty"`
	Street2     string `json:"street2,omitempty"`
	City        string `json:"city,omitempty"`
	State       string `json:"state,omitempty"`
	Country     string `json:"country,omitempty"`
	PostalCode  string `json:"postal_code,omitempty"`
	Residential bool   `json:"residential,omitempty"`
}

// Charge type.
type Charge struct {
	ID            string        `json:"id,omitempty"`
	CreatedAt     int64         `json:"created_at,omitempty"`
	Currency      string        `json:"currency,omitempty"`
	Amount        int64         `json:"amount,omitempty"`
	Livemode      bool          `json:"livemode,omitempty"`
	PaymentMethod PaymentMethod `json:"payment_method,omitempty"`
	Fee           int64         `json:"fee,omitempty"`
}

// PaymentMethod _
type PaymentMethod struct {
	TokenID string `json:"token_id,omitempty"`
	Type    string `json:"type,omitempty"`
}

// Order type.
type Order struct {
	ID       string `json:"id"`
	Amount   int64  `json:"amount"`
	Currency string `json:"currency,omitempty"`
	// TODO; add fields.
	// see: https://pastebin.com/nj8JnYYv
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"path"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"runtime/pprof"
)

/* This function takes a string and returns
   a (potentially nil) error object */
func TTWS(filename string, verbose bool) error {
	data, err := ioutil.ReadFile(filename);
	/* Did we manage to read the contents successfully? */

	fileType := http.DetectContentType(data);
	if (!strings.Contains(fileType, "text/plain")) {
		if (verbose) { fmt.Printf("Skipping file of type '%v': %v\n", fileType, filename); }
		return nil;
	}

	/* Open the output file in system temp dir*/
	outf, err := ioutil.TempFile("","");
	/* In case this function generates a "panic", be sure to close this file */
	defer outf.Close();
	/* Did we open it succesfully?  If not, close all and return. */
	if (err!=nil) { return err; }

	lines := strings.Split(string(data), "\n")
	nlines := len(lines)
	for i, line := range(lines) {
		//fmt.Println("Original line: '"+line+"'");

		/* Trim whitespace */
		line = strings.TrimRight(line, " \t")
		/* Don't add a \n to the last line if it is empty */
		if (i<nlines-1 || len(line)>0) { line = line+"\n" }
		outf.Write([]byte(line));

		//fmt.Println(" Trimmed line: '"+line+"'");
	}

	outf.Close();

	/* Replace the source file by the trimmed file */
	err = os.Rename(outf.Name(), filename);
	if (err!=nil) { return err; }

	if (verbose) { fmt.Printf("Trimmed %s\n", filename); }
	/* No errors, so we return nil */
	return nil;
}

var blacklist = []string{".bzr", ".cvs", ".git", ".hg", ".svn"}

func processNode(node string, verbose bool) error {
	fi, err := os.Lstat(node)
	if (err!=nil) { return err; }

	if (fi.IsDir()) {
		if contains(fi.Name(), blacklist) { return nil; }
		contents, err := ioutil.ReadDir(node);
		if (err!=nil) { return err; }
		for _, n := range(contents) {
			serr := processNode(path.Join(node, n.Name()), verbose);
			if (serr!=nil) { return serr; }
		}
		return nil;
	} else {
		return TTWS(node, verbose);
	}
}

func contains(x string, a []string) bool {
	for _, e := range(a) {
		if (x==e) { return true; }
	}
	return false;
}

func run(root string, verbose bool) {
	err := processNode(root, verbose);
	fmt.Printf("processNode("+root+") returned %v\n", err);
}

func main() {
	var verbose = flag.Bool("verbose", false, "request verbose output")
	var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")

	flag.Parse()

	root := flag.Arg(0)

	if (*cpuprofile!="") {
		f, err := os.Create(*cpuprofile)
        if err != nil {
            log.Fatal(err)
        }

		fmt.Println("Starting profiling");
		pprof.StartCPUProfile(f)
        defer pprof.StopCPUProfile()

		run(root, *verbose);

		pprof.StopCPUProfile();
		fmt.Println("...done profiling");
		f.Close();
	} else {
		run(root, *verbose);
	}
}
<commit_msg>Turns out opening the file twice is better performing.<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"path"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"runtime/pprof"
)

/* This function takes a string and returns
   a (potentially nil) error object */
func TTWS(filename string, verbose bool) error {
	/* Read only the first 512 bytes for type detection */
	inf, err := os.Open(filename)
	defer inf.Close();
	if (err!=nil) { return err; }
	read512 := io.LimitReader(inf, 512);
	data512, err := ioutil.ReadAll(read512);
	/* Finished with reading so close again */
	inf.Close();
	/* Determine file type */
	fileType := http.DetectContentType(data512);
	if (!strings.Contains(fileType, "text/plain")) {
		if (verbose) { fmt.Printf("Skipping file of type '%v': %v\n", fileType, filename); }
		return nil;
	}

	/* Open the output file in system temp dir*/
	outf, err := ioutil.TempFile("", "");
	/* In case this function generates a "panic", be sure to close this file */
	defer outf.Close();
	/* Did we open it succesfully?  If not, close all and return. */
	if (err!=nil) { return err; }

	/* Open the input file for processing */
	data, err := ioutil.ReadFile(filename);
	/* Did we manage to read the contents successfully? */
	lines := strings.Split(string(data), "\n")
	nlines := len(lines)
	for i, line := range(lines) {
		//fmt.Println("Original line: '"+line+"'");

		/* Trim whitespace */
		line = strings.TrimRight(line, " \t")
		/* Don't add a \n to the last line if it is empty */
		if (i<nlines-1 || len(line)>0) { line = line+"\n" }
		outf.Write([]byte(line));

		//fmt.Println(" Trimmed line: '"+line+"'");
	}

	outf.Close();

	/* Replace the source file by the trimmed file */
	err = os.Rename(outf.Name(), filename);
	if (err!=nil) { return err; }

	if (verbose) { fmt.Printf("Trimmed %s\n", filename); }
	/* No errors, so we return nil */
	return nil;
}

var blacklist = []string{".bzr", ".cvs", ".git", ".hg", ".svn"}

func processNode(node string, verbose bool) error {
	fi, err := os.Lstat(node)
	if (err!=nil) { return err; }

	if (fi.IsDir()) {
		if contains(fi.Name(), blacklist) { return nil; }
		contents, err := ioutil.ReadDir(node);
		if (err!=nil) { return err; }
		for _, n := range(contents) {
			serr := processNode(path.Join(node, n.Name()), verbose);
			if (serr!=nil) { return serr; }
		}
		return nil;
	} else {
		return TTWS(node, verbose);
	}
}

func contains(x string, a []string) bool {
	for _, e := range(a) {
		if (x==e) { return true; }
	}
	return false;
}

func run(root string, verbose bool) {
	err := processNode(root, verbose);
	fmt.Printf("processNode("+root+") returned %v\n", err);
}

func main() {
	var verbose = flag.Bool("verbose", false, "request verbose output")
	var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")

	flag.Parse()

	root := flag.Arg(0)

	if (*cpuprofile!="") {
		f, err := os.Create(*cpuprofile)
        if err != nil {
            log.Fatal(err)
        }

		fmt.Println("Starting profiling");
		pprof.StartCPUProfile(f)
        defer pprof.StopCPUProfile()

		run(root, *verbose);

		pprof.StopCPUProfile();
		fmt.Println("...done profiling");
		f.Close();
	} else {
		run(root, *verbose);
	}
}
<|endoftext|>


<commit_before>/*
* Copyright (C) 2013 - 2015 - FTW Forschungszentrum Telekommunikation Wien GmbH (www.ftw.at)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Author(s): Arian Baer (baer _at_ ftw.at)
*
*/
package dbs_import

import (
	"fmt"
	"log"
	"strconv"
	"strings"
)

/*
* InputConverter
*
* The InputConverter interface can be used to implement new input converters for different formats.
*/
type InputConverter interface {
	//convert one line of input data into an array of strings
	Line2Array(line string) []string
	//check if the line has all fields needed for the given format
	CheckLine(sline []string) (isValid bool)
	//extract time from one input line
	GetSerialTime(sline []string, lastSerialTime int64) (serialTime int64)
	//convert line into Postgres representation
	ConvertLine(sline []string, delimiter string)  string
}

//method generating new InputConverter according to the input format given by the probe
func GetInputConverter(inputFormat string) InputConverter {
	if inputFormat == "log_tcp_complete_v15" {
		return TstatLogTCPV15{28,29," "}
	}
	panic(fmt.Sprintf("Input type '%s' not implemented", inputFormat))
}

// TstatLogTCPV15 implementation
type TstatLogTCPV15 struct {
	first int
	last int
	inputDelimiter string
}

func (t TstatLogTCPV15) Line2Array(line string) []string {
	return strings.Split(line, " ")
}

func (t TstatLogTCPV15) CheckLine(sline []string) (isValid bool) {
	return len(sline) == 130
}

func (t TstatLogTCPV15) GetSerialTime(sline []string, lastSerialTime int64) (serialTime int64) {

	last, err := strconv.ParseFloat(sline[t.last], 64)
	if err != nil {
		log.Panic("ERROR: %s", err)
	}

	newTS := int64(last/1000)
	if newTS > lastSerialTime {
		return newTS
	} else {
		return lastSerialTime
	}
}

func (t TstatLogTCPV15) ConvertLine(sline []string, delimiter string)  string {
	return strings.Join(sline, delimiter)
}
// /TstatLogTCPV15 implementation
<commit_msg>added TstatLogVideo input_converter<commit_after>/*
* Copyright (C) 2013 - 2015 - FTW Forschungszentrum Telekommunikation Wien GmbH (www.ftw.at)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Author(s): Arian Baer (baer _at_ ftw.at)
*
*/
package dbs_import

import (
	"fmt"
	"log"
	"strconv"
	"strings"
)

/*
* InputConverter
*
* The InputConverter interface can be used to implement new input converters for different formats.
*/
type InputConverter interface {
	//convert one line of input data into an array of strings
	Line2Array(line string) []string
	//check if the line has all fields needed for the given format
	CheckLine(sline []string) (isValid bool)
	//extract time from one input line
	GetSerialTime(sline []string, lastSerialTime int64) (serialTime int64)
	//convert line into Postgres representation
	ConvertLine(sline []string, delimiter string)  string
}

//method generating new InputConverter according to the input format given by the probe
func GetInputConverter(inputFormat string) InputConverter {
	if inputFormat == "log_tcp_complete_v15" {
		return TstatLogTCPV15{28,29," "}
	} else if inputFormat == "log_video_complete" {
		return TstatLogVideo{
			first_abs:67,
			last:60,
			inputDelimiter: " ",
		}
	}
	panic(fmt.Sprintf("Input type '%s' not implemented", inputFormat))
}

// TstatLogTCPV15 implementation
type TstatLogTCPV15 struct {
	first int
	last int
	inputDelimiter string
}

func (t TstatLogTCPV15) Line2Array(line string) []string {
	return strings.Split(line, " ")
}

func (t TstatLogTCPV15) CheckLine(sline []string) (isValid bool) {
	return len(sline) == 130
}

func (t TstatLogTCPV15) GetSerialTime(sline []string, lastSerialTime int64) (serialTime int64) {

	last, err := strconv.ParseFloat(sline[t.last], 64)
	if err != nil {
		log.Panic("ERROR: %s", err)
	}

	newTS := int64(last/1000)
	if newTS > lastSerialTime {
		return newTS
	} else {
		return lastSerialTime
	}
}

func (t TstatLogTCPV15) ConvertLine(sline []string, delimiter string)  string {
	return strings.Join(sline, delimiter)
}
// /TstatLogTCPV15 implementation

// TstatLogVideo implementation
type TstatLogVideo struct {
	first_abs int
	last int
	inputDelimiter string
}

func (t TstatLogVideo) Line2Array(line string) []string {
	return strings.Split(line, t.inputDelimiter)
}

func (t TstatLogVideo) CheckLine(sline []string) (isValid bool) {
	if len(sline) != 125 {
		log.Panic("LINE LEN: ", len(sline))
	}
	return true
}

func (t TstatLogVideo) GetSerialTime(sline []string, lastSerialTime int64) (serialTime int64) {

	first_abs, err := strconv.ParseFloat(sline[t.first_abs], 64)
	if err != nil {
		log.Panic("ERROR: %s", err)
	}

	last, err := strconv.ParseFloat(sline[t.last], 64)
	if err != nil {
		log.Panic("ERROR: %s", err)
	}

	newTS := int64( (first_abs + last)/1000 )
	if newTS > lastSerialTime {
		return newTS
	} else {
		return lastSerialTime
	}
}

func (t TstatLogVideo) ConvertLine(sline []string, delimiter string)  string {
	return strings.Join(sline, delimiter)
}
// /TstatLogVideo implementation
<|endoftext|>


<commit_before>/*
Copyright 2015 Steven Labrum

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package CheckIt

import (
	"crypto/md5"
	"encoding/binary"
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"time"
)

var tempDirectory = ""

func writefile(filename string, body []byte, ext string) {

	err := ioutil.WriteFile(filename+ext, body, 0777)
	if err != nil {
		return
	}
}

func randFolder() string {
	b := make([]byte, 2)
	binary.LittleEndian.PutUint16(b, uint16(rand.Intn(1000)))
	hash := md5.Sum(b)

	return fmt.Sprintf("%x", hash)
}

func textAreas() []string {
	var texts []string

	for key := range boxes {
		texts = append(texts, boxes[key].Body)
	}
	return texts
}

/*
	Runs commands specified in args using input as Stdin
*/
func InterfaceRun(box Box, body []byte, args ...string) (out []byte, err error) {

	tempDirectory = randFolder()

	os.Mkdir("./"+tempDirectory, 0777)

	writefile("./"+tempDirectory+"/"+args[0], body, "")
	args = args[1:]
	textareas := textAreas()

	timeout := make(chan bool, 1)
	inTime := make(chan bool, 1)
	go func() {
		time.Sleep(1 * time.Second)
		timeout <- true
	}()

	go func() {
		out, err = box.Run(textareas, tempDirectory, args...)
		inTime <- true
	}()

	select{
	case<-timeout:
		out = []byte("ERROR: Execution of code took too long.")
	case<-inTime:
	}

	if err != nil {
		fmt.Println(string(out))
		return
	}

	defer os.RemoveAll("./" + tempDirectory + "/")

	return out, err
}

func TimeOut() {
	fmt.Print("TIME OUT")
}
<commit_msg>configuration.Time out used for timeout<commit_after>/*
Copyright 2015 Steven Labrum

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package CheckIt

import (
	"crypto/md5"
	"encoding/binary"
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"time"
)

var tempDirectory = ""

func writefile(filename string, body []byte, ext string) {

	err := ioutil.WriteFile(filename+ext, body, 0777)
	if err != nil {
		return
	}
}

func randFolder() string {
	b := make([]byte, 2)
	binary.LittleEndian.PutUint16(b, uint16(rand.Intn(1000)))
	hash := md5.Sum(b)

	return fmt.Sprintf("%x", hash)
}

func textAreas() []string {
	var texts []string

	for key := range boxes {
		texts = append(texts, boxes[key].Body)
	}
	return texts
}

/*
	Runs commands specified in args using input as Stdin
*/
func InterfaceRun(box Box, body []byte, args ...string) (out []byte, err error) {

	tempDirectory = randFolder()

	os.Mkdir("./"+tempDirectory, 0777)

	writefile("./"+tempDirectory+"/"+args[0], body, "")
	args = args[1:]
	textareas := textAreas()

	timeout := make(chan bool, 1)
	inTime := make(chan bool, 1)

	go func() {
		time.Sleep(configuration.Timeout * time.Second)
		timeout <- true
	}()

	go func() {
		out, err = box.Run(textareas, tempDirectory, args...)
		inTime <- true
	}()

	select {
	case <-timeout:
		out = []byte("ERROR: Execution of code took too long.")
	case <-inTime:
	}

	if err != nil {
		fmt.Println(string(out))
		return
	}

	defer os.RemoveAll("./" + tempDirectory + "/")

	return out, err
}

func TimeOut() {
	fmt.Print("TIME OUT")
}
<|endoftext|>


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

package rest

import (
	"bytes"
	"encoding/json"
	"fmt"
	"mime/multipart"
	"net/http"
	"net/textproto"

	"github.com/couchbaselabs/sync_gateway/base"
	"github.com/couchbaselabs/sync_gateway/db"
)

// HTTP handler for a GET of a document
func (h *handler) handleGetDoc() error {
	docid := h.PathVars()["docid"]
	revid := h.getQuery("rev")
	includeRevs := h.getBoolQuery("revs")
	openRevs := h.getQuery("open_revs")

	// What attachment bodies should be included?
	var attachmentsSince []string = nil
	if h.getBoolQuery("attachments") {
		atts := h.getQuery("atts_since")
		if atts != "" {
			err := json.Unmarshal([]byte(atts), &attachmentsSince)
			if err != nil {
				return &base.HTTPError{http.StatusBadRequest, "bad atts_since"}
			}
		} else {
			attachmentsSince = []string{}
		}
	}

	if openRevs == "" {
		// Single-revision GET:
		value, err := h.db.GetRev(docid, revid, includeRevs, attachmentsSince)
		if err != nil {
			return err
		}
		if value == nil {
			return kNotFoundError
		}
		h.setHeader("Etag", value["_rev"].(string))

		if h.requestAccepts("application/json") {
			h.writeJSON(value)
		} else {
			return h.writeMultipart(func(writer *multipart.Writer) error {
				h.db.WriteMultipartDocument(value, writer)
				return nil
			})
		}

	} else if openRevs == "all" {
		return &base.HTTPError{http.StatusNotImplemented, "open_revs=all unimplemented"} // TODO

	} else {
		attachmentsSince = []string{}
		var revids []string
		err := json.Unmarshal([]byte(openRevs), &revids)
		if err != nil {
			return &base.HTTPError{http.StatusBadRequest, "bad open_revs"}
		}

		err = h.writeMultipart(func(writer *multipart.Writer) error {
			for _, revid := range revids {
				var content []byte
				var contentType string
				revBody, err := h.db.GetRev(docid, revid, includeRevs, attachmentsSince)
				if err == nil && len(db.BodyAttachments(revBody)) > 0 {
					// Write as multipart, including attachments:
					var buffer bytes.Buffer
					docWriter := multipart.NewWriter(&buffer)
					contentType = fmt.Sprintf("multipart/related; boundary=%q",
						docWriter.Boundary())
					h.db.WriteMultipartDocument(revBody, docWriter)
					docWriter.Close()
					content = bytes.TrimRight(buffer.Bytes(), "\r\n")
				} else {
					// Write as JSON:
					contentType = "application/json"
					if err != nil {
						revBody = db.Body{"missing": revid} //TODO: More specific error
						contentType += `; error="true"`
					}
					content, _ = json.Marshal(revBody)
				}
				partHeaders := textproto.MIMEHeader{}
				partHeaders.Set("Content-Type", contentType)
				part, _ := writer.CreatePart(partHeaders)
				part.Write(content)
			}
			return nil
		})
		return err
	}
	return nil
}

// HTTP handler for a GET of a specific doc attachment
func (h *handler) handleGetAttachment() error {
	docid := h.PathVars()["docid"]
	attachmentName := h.PathVars()["attach"]
	revid := h.getQuery("rev")
	body, err := h.db.GetRev(docid, revid, false, nil)
	if err != nil {
		return err
	}
	if body == nil {
		return kNotFoundError
	}
	meta, ok := db.BodyAttachments(body)[attachmentName].(map[string]interface{})
	if !ok {
		return &base.HTTPError{http.StatusNotFound, "missing " + attachmentName}
	}
	digest := meta["digest"].(string)
	data, err := h.db.GetAttachment(db.AttachmentKey(digest))
	if err != nil {
		return err
	}

	h.setHeader("Etag", digest)
	if contentType, ok := meta["content_type"].(string); ok {
		h.setHeader("Content-Type", contentType)
	}
	if encoding, ok := meta["encoding"].(string); ok {
		h.setHeader("Content-Encoding", encoding)
	}
	h.response.Write(data)
	return nil
}

// HTTP handler for a PUT of a document
func (h *handler) handlePutDoc() error {
	docid := h.PathVars()["docid"]
	body, err := h.readDocument()
	if err != nil {
		return err
	}
	var newRev string

	if h.getQuery("new_edits") != "false" {
		// Regular PUT:
		newRev, err = h.db.Put(docid, body)
		if err != nil {
			return err
		}
		h.setHeader("Etag", newRev)
	} else {
		// Replicator-style PUT with new_edits=false:
		revisions := db.ParseRevisions(body)
		if revisions == nil {
			return &base.HTTPError{http.StatusBadRequest, "Bad _revisions"}
		}
		err = h.db.PutExistingRev(docid, body, revisions)
		if err != nil {
			return err
		}
		newRev = body["_rev"].(string)
	}
	h.writeJSONStatus(http.StatusCreated, db.Body{"ok": true, "id": docid, "rev": newRev})
	return nil
}

// HTTP handler for a POST to a database (creating a document)
func (h *handler) handlePostDoc() error {
	body, err := h.readDocument()
	if err != nil {
		return err
	}
	docid, newRev, err := h.db.Post(body)
	if err != nil {
		return err
	}
	h.setHeader("Location", docid)
	h.setHeader("Etag", newRev)
	h.writeJSON(db.Body{"ok": true, "id": docid, "rev": newRev})
	return nil
}

// HTTP handler for a DELETE of a document
func (h *handler) handleDeleteDoc() error {
	docid := h.PathVars()["docid"]
	revid := h.getQuery("rev")
	newRev, err := h.db.DeleteDoc(docid, revid)
	if err == nil {
		h.writeJSON(db.Body{"ok": true, "id": docid, "rev": newRev})
	}
	return err
}

//////// LOCAL DOCS:

// HTTP handler for a GET of a _local document
func (h *handler) handleGetLocalDoc() error {
	docid := h.PathVars()["docid"]
	value, err := h.db.GetSpecial("local", docid)
	if err != nil {
		return err
	}
	if value == nil {
		return kNotFoundError
	}
	value["_id"] = "_local/" + docid
	value.FixJSONNumbers()
	h.writeJSON(value)
	return nil
}

// HTTP handler for a PUT of a _local document
func (h *handler) handlePutLocalDoc() error {
	docid := h.PathVars()["docid"]
	body, err := h.readJSON()
	if err == nil {
		body.FixJSONNumbers()
		var revid string
		revid, err = h.db.PutSpecial("local", docid, body)
		if err == nil {
			h.writeJSONStatus(http.StatusCreated, db.Body{"ok": true, "id": "_local/" + docid, "rev": revid})
		}
	}
	return err
}

// HTTP handler for a DELETE of a _local document
func (h *handler) handleDelLocalDoc() error {
	docid := h.PathVars()["docid"]
	return h.db.DeleteSpecial("local", docid, h.getQuery("rev"))
}
<commit_msg>GET /db/doc should use multipart if caller accepts both it and JSON<commit_after>//  Copyright (c) 2012 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
//  except in compliance with the License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing, software distributed under the
//  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
//  either express or implied. See the License for the specific language governing permissions
//  and limitations under the License.

package rest

import (
	"bytes"
	"encoding/json"
	"fmt"
	"mime/multipart"
	"net/http"
	"net/textproto"

	"github.com/couchbaselabs/sync_gateway/base"
	"github.com/couchbaselabs/sync_gateway/db"
)

// HTTP handler for a GET of a document
func (h *handler) handleGetDoc() error {
	docid := h.PathVars()["docid"]
	revid := h.getQuery("rev")
	includeRevs := h.getBoolQuery("revs")
	openRevs := h.getQuery("open_revs")

	// What attachment bodies should be included?
	var attachmentsSince []string = nil
	if h.getBoolQuery("attachments") {
		atts := h.getQuery("atts_since")
		if atts != "" {
			err := json.Unmarshal([]byte(atts), &attachmentsSince)
			if err != nil {
				return &base.HTTPError{http.StatusBadRequest, "bad atts_since"}
			}
		} else {
			attachmentsSince = []string{}
		}
	}

	if openRevs == "" {
		// Single-revision GET:
		value, err := h.db.GetRev(docid, revid, includeRevs, attachmentsSince)
		if err != nil {
			return err
		}
		if value == nil {
			return kNotFoundError
		}
		h.setHeader("Etag", value["_rev"].(string))

		hasBodies := (attachmentsSince != nil && value["_attachments"] != nil)
		if h.requestAccepts("multipart/") && (hasBodies || !h.requestAccepts("application/json")) {
			return h.writeMultipart(func(writer *multipart.Writer) error {
				h.db.WriteMultipartDocument(value, writer)
				return nil
			})
		} else {
			h.writeJSON(value)
		}

	} else if openRevs == "all" {
		return &base.HTTPError{http.StatusNotImplemented, "open_revs=all unimplemented"} // TODO

	} else {
		attachmentsSince = []string{}
		var revids []string
		err := json.Unmarshal([]byte(openRevs), &revids)
		if err != nil {
			return &base.HTTPError{http.StatusBadRequest, "bad open_revs"}
		}

		err = h.writeMultipart(func(writer *multipart.Writer) error {
			for _, revid := range revids {
				var content []byte
				var contentType string
				revBody, err := h.db.GetRev(docid, revid, includeRevs, attachmentsSince)
				if err == nil && len(db.BodyAttachments(revBody)) > 0 {
					// Write as multipart, including attachments:
					var buffer bytes.Buffer
					docWriter := multipart.NewWriter(&buffer)
					contentType = fmt.Sprintf("multipart/related; boundary=%q",
						docWriter.Boundary())
					h.db.WriteMultipartDocument(revBody, docWriter)
					docWriter.Close()
					content = bytes.TrimRight(buffer.Bytes(), "\r\n")
				} else {
					// Write as JSON:
					contentType = "application/json"
					if err != nil {
						revBody = db.Body{"missing": revid} //TODO: More specific error
						contentType += `; error="true"`
					}
					content, _ = json.Marshal(revBody)
				}
				partHeaders := textproto.MIMEHeader{}
				partHeaders.Set("Content-Type", contentType)
				part, _ := writer.CreatePart(partHeaders)
				part.Write(content)
			}
			return nil
		})
		return err
	}
	return nil
}

// HTTP handler for a GET of a specific doc attachment
func (h *handler) handleGetAttachment() error {
	docid := h.PathVars()["docid"]
	attachmentName := h.PathVars()["attach"]
	revid := h.getQuery("rev")
	body, err := h.db.GetRev(docid, revid, false, nil)
	if err != nil {
		return err
	}
	if body == nil {
		return kNotFoundError
	}
	meta, ok := db.BodyAttachments(body)[attachmentName].(map[string]interface{})
	if !ok {
		return &base.HTTPError{http.StatusNotFound, "missing " + attachmentName}
	}
	digest := meta["digest"].(string)
	data, err := h.db.GetAttachment(db.AttachmentKey(digest))
	if err != nil {
		return err
	}

	h.setHeader("Etag", digest)
	if contentType, ok := meta["content_type"].(string); ok {
		h.setHeader("Content-Type", contentType)
	}
	if encoding, ok := meta["encoding"].(string); ok {
		h.setHeader("Content-Encoding", encoding)
	}
	h.response.Write(data)
	return nil
}

// HTTP handler for a PUT of a document
func (h *handler) handlePutDoc() error {
	docid := h.PathVars()["docid"]
	body, err := h.readDocument()
	if err != nil {
		return err
	}
	var newRev string

	if h.getQuery("new_edits") != "false" {
		// Regular PUT:
		newRev, err = h.db.Put(docid, body)
		if err != nil {
			return err
		}
		h.setHeader("Etag", newRev)
	} else {
		// Replicator-style PUT with new_edits=false:
		revisions := db.ParseRevisions(body)
		if revisions == nil {
			return &base.HTTPError{http.StatusBadRequest, "Bad _revisions"}
		}
		err = h.db.PutExistingRev(docid, body, revisions)
		if err != nil {
			return err
		}
		newRev = body["_rev"].(string)
	}
	h.writeJSONStatus(http.StatusCreated, db.Body{"ok": true, "id": docid, "rev": newRev})
	return nil
}

// HTTP handler for a POST to a database (creating a document)
func (h *handler) handlePostDoc() error {
	body, err := h.readDocument()
	if err != nil {
		return err
	}
	docid, newRev, err := h.db.Post(body)
	if err != nil {
		return err
	}
	h.setHeader("Location", docid)
	h.setHeader("Etag", newRev)
	h.writeJSON(db.Body{"ok": true, "id": docid, "rev": newRev})
	return nil
}

// HTTP handler for a DELETE of a document
func (h *handler) handleDeleteDoc() error {
	docid := h.PathVars()["docid"]
	revid := h.getQuery("rev")
	newRev, err := h.db.DeleteDoc(docid, revid)
	if err == nil {
		h.writeJSON(db.Body{"ok": true, "id": docid, "rev": newRev})
	}
	return err
}

//////// LOCAL DOCS:

// HTTP handler for a GET of a _local document
func (h *handler) handleGetLocalDoc() error {
	docid := h.PathVars()["docid"]
	value, err := h.db.GetSpecial("local", docid)
	if err != nil {
		return err
	}
	if value == nil {
		return kNotFoundError
	}
	value["_id"] = "_local/" + docid
	value.FixJSONNumbers()
	h.writeJSON(value)
	return nil
}

// HTTP handler for a PUT of a _local document
func (h *handler) handlePutLocalDoc() error {
	docid := h.PathVars()["docid"]
	body, err := h.readJSON()
	if err == nil {
		body.FixJSONNumbers()
		var revid string
		revid, err = h.db.PutSpecial("local", docid, body)
		if err == nil {
			h.writeJSONStatus(http.StatusCreated, db.Body{"ok": true, "id": "_local/" + docid, "rev": revid})
		}
	}
	return err
}

// HTTP handler for a DELETE of a _local document
func (h *handler) handleDelLocalDoc() error {
	docid := h.PathVars()["docid"]
	return h.db.DeleteSpecial("local", docid, h.getQuery("rev"))
}
<|endoftext|>


<commit_before>package smartsearch

import (
	"strings"
)

type IndexedTerm struct {
	term        string
	postings    []int
	occurrences int
}

type IndexedTerms []IndexedTerm

// Implementation of sort.Interface
func (s IndexedTerms) Len() int {
	return len(s)
}

// Implementation of sort.Interface
func (s IndexedTerms) Less(i, j int) bool {
	return strings.Compare(s[i].term, s[j].term) < 0
}

// Implementation of sort.Interface
func (s IndexedTerms) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}
<commit_msg>Fixing a compatibility issue with strings.Compare<commit_after>package smartsearch

type IndexedTerm struct {
	term        string
	postings    []int
	occurrences int
}

type IndexedTerms []IndexedTerm

// Implementation of sort.Interface
func (s IndexedTerms) Len() int {
	return len(s)
}

// Implementation of sort.Interface
func (s IndexedTerms) Less(i, j int) bool {
	return s[i].term < s[j].term
}

// Implementation of sort.Interface
func (s IndexedTerms) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}
<|endoftext|>


<commit_before>package bdiscord

import (
	"github.com/42wim/matterbridge/bridge/config"
	log "github.com/Sirupsen/logrus"
	"github.com/bwmarrin/discordgo"
	"regexp"
	"strings"
	"sync"
)

type bdiscord struct {
	c             *discordgo.Session
	Config        *config.Protocol
	Remote        chan config.Message
	Account       string
	Channels      []*discordgo.Channel
	Nick          string
	UseChannelID  bool
	userMemberMap map[string]*discordgo.Member
	guildID       string
	sync.RWMutex
}

var flog *log.Entry
var protocol = "discord"

func init() {
	flog = log.WithFields(log.Fields{"module": protocol})
}

func New(cfg config.Protocol, account string, c chan config.Message) *bdiscord {
	b := &bdiscord{}
	b.Config = &cfg
	b.Remote = c
	b.Account = account
	b.userMemberMap = make(map[string]*discordgo.Member)
	return b
}

func (b *bdiscord) Connect() error {
	var err error
	flog.Info("Connecting")
	if !strings.HasPrefix(b.Config.Token, "Bot ") {
		b.Config.Token = "Bot " + b.Config.Token
	}
	b.c, err = discordgo.New(b.Config.Token)
	if err != nil {
		flog.Debugf("%#v", err)
		return err
	}
	flog.Info("Connection succeeded")
	b.c.AddHandler(b.messageCreate)
	b.c.AddHandler(b.memberUpdate)
	b.c.AddHandler(b.messageUpdate)
	err = b.c.Open()
	if err != nil {
		flog.Debugf("%#v", err)
		return err
	}
	guilds, err := b.c.UserGuilds()
	if err != nil {
		flog.Debugf("%#v", err)
		return err
	}
	userinfo, err := b.c.User("@me")
	if err != nil {
		flog.Debugf("%#v", err)
		return err
	}
	b.Nick = userinfo.Username
	for _, guild := range guilds {
		if guild.Name == b.Config.Server {
			b.Channels, err = b.c.GuildChannels(guild.ID)
			b.guildID = guild.ID
			if err != nil {
				flog.Debugf("%#v", err)
				return err
			}
		}
	}
	return nil
}

func (b *bdiscord) Disconnect() error {
	return nil
}

func (b *bdiscord) JoinChannel(channel string) error {
	idcheck := strings.Split(channel, "ID:")
	if len(idcheck) > 1 {
		b.UseChannelID = true
	}
	return nil
}

func (b *bdiscord) Send(msg config.Message) error {
	flog.Debugf("Receiving %#v", msg)
	channelID := b.getChannelID(msg.Channel)
	if channelID == "" {
		flog.Errorf("Could not find channelID for %v", msg.Channel)
		return nil
	}
	b.c.ChannelMessageSend(channelID, msg.Username+msg.Text)
	return nil
}

func (b *bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdate) {
	if b.Config.EditDisable {
		return
	}
	// only when message is actually edited
	if m.Message.EditedTimestamp != "" {
		flog.Debugf("Sending edit message")
		m.Content = m.Content + b.Config.EditSuffix
		b.messageCreate(s, (*discordgo.MessageCreate)(m))
	}
}

func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	// not relay our own messages
	if m.Author.Username == b.Nick {
		return
	}
	if len(m.Attachments) > 0 {
		for _, attach := range m.Attachments {
			m.Content = m.Content + "\n" + attach.URL
		}
	}
	if m.Content == "" {
		return
	}
	flog.Debugf("Sending message from %s on %s to gateway", m.Author.Username, b.Account)
	channelName := b.getChannelName(m.ChannelID)
	if b.UseChannelID {
		channelName = "ID:" + m.ChannelID
	}
	username := b.getNick(m.Author)
	if len(m.MentionRoles) > 0 {
		m.Message.Content = b.replaceRoleMentions(m.Message.Content)
	}
	m.Message.Content = b.stripCustomoji(m.Message.Content)
	b.Remote <- config.Message{Username: username, Text: m.ContentWithMentionsReplaced(), Channel: channelName,
		Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg"}
}

func (b *bdiscord) memberUpdate(s *discordgo.Session, m *discordgo.GuildMemberUpdate) {
	b.Lock()
	if _, ok := b.userMemberMap[m.Member.User.ID]; ok {
		flog.Debugf("%s: memberupdate: user %s (nick %s) changes nick to %s", b.Account, m.Member.User.Username, b.userMemberMap[m.Member.User.ID].Nick, m.Member.Nick)
	}
	b.userMemberMap[m.Member.User.ID] = m.Member
	b.Unlock()
}

func (b *bdiscord) getNick(user *discordgo.User) string {
	var err error
	b.Lock()
	defer b.Unlock()
	if _, ok := b.userMemberMap[user.ID]; ok {
		if b.userMemberMap[user.ID] != nil {
			if b.userMemberMap[user.ID].Nick != "" {
				// only return if nick is set
				return b.userMemberMap[user.ID].Nick
			}
			// otherwise return username
			return user.Username
		}
	}
	// if we didn't find nick, search for it
	b.userMemberMap[user.ID], err = b.c.GuildMember(b.guildID, user.ID)
	if err != nil {
		return user.Username
	}
	// only return if nick is set
	if b.userMemberMap[user.ID].Nick != "" {
		return b.userMemberMap[user.ID].Nick
	}
	return user.Username
}

func (b *bdiscord) getChannelID(name string) string {
	idcheck := strings.Split(name, "ID:")
	if len(idcheck) > 1 {
		return idcheck[1]
	}
	for _, channel := range b.Channels {
		if channel.Name == name {
			return channel.ID
		}
	}
	return ""
}

func (b *bdiscord) getChannelName(id string) string {
	for _, channel := range b.Channels {
		if channel.ID == id {
			return channel.Name
		}
	}
	return ""
}

func (b *bdiscord) replaceRoleMentions(text string) string {
	roles, err := b.c.GuildRoles(b.guildID)
	if err != nil {
		flog.Debugf("%#v", string(err.(*discordgo.RESTError).ResponseBody))
		return text
	}
	for _, role := range roles {
		text = strings.Replace(text, "<@&"+role.ID+">", "@"+role.Name, -1)
	}
	return text
}

func (b *bdiscord) stripCustomoji(text string) string {
	// <:doge:302803592035958784>
	re := regexp.MustCompile("<(:.*?:)[0-9]+>")
	return re.ReplaceAllString(text, `$1`)
}
<commit_msg>Replace long ids in channel metions (discord). Fixes #174<commit_after>package bdiscord

import (
	"github.com/42wim/matterbridge/bridge/config"
	log "github.com/Sirupsen/logrus"
	"github.com/bwmarrin/discordgo"
	"regexp"
	"strings"
	"sync"
)

type bdiscord struct {
	c             *discordgo.Session
	Config        *config.Protocol
	Remote        chan config.Message
	Account       string
	Channels      []*discordgo.Channel
	Nick          string
	UseChannelID  bool
	userMemberMap map[string]*discordgo.Member
	guildID       string
	sync.RWMutex
}

var flog *log.Entry
var protocol = "discord"

func init() {
	flog = log.WithFields(log.Fields{"module": protocol})
}

func New(cfg config.Protocol, account string, c chan config.Message) *bdiscord {
	b := &bdiscord{}
	b.Config = &cfg
	b.Remote = c
	b.Account = account
	b.userMemberMap = make(map[string]*discordgo.Member)
	return b
}

func (b *bdiscord) Connect() error {
	var err error
	flog.Info("Connecting")
	if !strings.HasPrefix(b.Config.Token, "Bot ") {
		b.Config.Token = "Bot " + b.Config.Token
	}
	b.c, err = discordgo.New(b.Config.Token)
	if err != nil {
		flog.Debugf("%#v", err)
		return err
	}
	flog.Info("Connection succeeded")
	b.c.AddHandler(b.messageCreate)
	b.c.AddHandler(b.memberUpdate)
	b.c.AddHandler(b.messageUpdate)
	err = b.c.Open()
	if err != nil {
		flog.Debugf("%#v", err)
		return err
	}
	guilds, err := b.c.UserGuilds()
	if err != nil {
		flog.Debugf("%#v", err)
		return err
	}
	userinfo, err := b.c.User("@me")
	if err != nil {
		flog.Debugf("%#v", err)
		return err
	}
	b.Nick = userinfo.Username
	for _, guild := range guilds {
		if guild.Name == b.Config.Server {
			b.Channels, err = b.c.GuildChannels(guild.ID)
			b.guildID = guild.ID
			if err != nil {
				flog.Debugf("%#v", err)
				return err
			}
		}
	}
	return nil
}

func (b *bdiscord) Disconnect() error {
	return nil
}

func (b *bdiscord) JoinChannel(channel string) error {
	idcheck := strings.Split(channel, "ID:")
	if len(idcheck) > 1 {
		b.UseChannelID = true
	}
	return nil
}

func (b *bdiscord) Send(msg config.Message) error {
	flog.Debugf("Receiving %#v", msg)
	channelID := b.getChannelID(msg.Channel)
	if channelID == "" {
		flog.Errorf("Could not find channelID for %v", msg.Channel)
		return nil
	}
	b.c.ChannelMessageSend(channelID, msg.Username+msg.Text)
	return nil
}

func (b *bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdate) {
	if b.Config.EditDisable {
		return
	}
	// only when message is actually edited
	if m.Message.EditedTimestamp != "" {
		flog.Debugf("Sending edit message")
		m.Content = m.Content + b.Config.EditSuffix
		b.messageCreate(s, (*discordgo.MessageCreate)(m))
	}
}

func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	// not relay our own messages
	if m.Author.Username == b.Nick {
		return
	}
	if len(m.Attachments) > 0 {
		for _, attach := range m.Attachments {
			m.Content = m.Content + "\n" + attach.URL
		}
	}
	if m.Content == "" {
		return
	}
	flog.Debugf("Sending message from %s on %s to gateway", m.Author.Username, b.Account)
	channelName := b.getChannelName(m.ChannelID)
	if b.UseChannelID {
		channelName = "ID:" + m.ChannelID
	}
	username := b.getNick(m.Author)
	if len(m.MentionRoles) > 0 {
		m.Message.Content = b.replaceRoleMentions(m.Message.Content)
	}
	m.Message.Content = b.stripCustomoji(m.Message.Content)
	m.Message.Content = b.replaceChannelMentions(m.Message.Content)
	b.Remote <- config.Message{Username: username, Text: m.ContentWithMentionsReplaced(), Channel: channelName,
		Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg"}
}

func (b *bdiscord) memberUpdate(s *discordgo.Session, m *discordgo.GuildMemberUpdate) {
	b.Lock()
	if _, ok := b.userMemberMap[m.Member.User.ID]; ok {
		flog.Debugf("%s: memberupdate: user %s (nick %s) changes nick to %s", b.Account, m.Member.User.Username, b.userMemberMap[m.Member.User.ID].Nick, m.Member.Nick)
	}
	b.userMemberMap[m.Member.User.ID] = m.Member
	b.Unlock()
}

func (b *bdiscord) getNick(user *discordgo.User) string {
	var err error
	b.Lock()
	defer b.Unlock()
	if _, ok := b.userMemberMap[user.ID]; ok {
		if b.userMemberMap[user.ID] != nil {
			if b.userMemberMap[user.ID].Nick != "" {
				// only return if nick is set
				return b.userMemberMap[user.ID].Nick
			}
			// otherwise return username
			return user.Username
		}
	}
	// if we didn't find nick, search for it
	b.userMemberMap[user.ID], err = b.c.GuildMember(b.guildID, user.ID)
	if err != nil {
		return user.Username
	}
	// only return if nick is set
	if b.userMemberMap[user.ID].Nick != "" {
		return b.userMemberMap[user.ID].Nick
	}
	return user.Username
}

func (b *bdiscord) getChannelID(name string) string {
	idcheck := strings.Split(name, "ID:")
	if len(idcheck) > 1 {
		return idcheck[1]
	}
	for _, channel := range b.Channels {
		if channel.Name == name {
			return channel.ID
		}
	}
	return ""
}

func (b *bdiscord) getChannelName(id string) string {
	for _, channel := range b.Channels {
		if channel.ID == id {
			return channel.Name
		}
	}
	return ""
}

func (b *bdiscord) replaceRoleMentions(text string) string {
	roles, err := b.c.GuildRoles(b.guildID)
	if err != nil {
		flog.Debugf("%#v", string(err.(*discordgo.RESTError).ResponseBody))
		return text
	}
	for _, role := range roles {
		text = strings.Replace(text, "<@&"+role.ID+">", "@"+role.Name, -1)
	}
	return text
}

func (b *bdiscord) replaceChannelMentions(text string) string {
	var err error
	re := regexp.MustCompile("<#[0-9]+>")
	text = re.ReplaceAllStringFunc(text, func(m string) string {
		channel := b.getChannelName(m[2 : len(m)-1])
		// if at first don't succeed, try again
		if channel == "" {
			b.Channels, err = b.c.GuildChannels(b.guildID)
			if err != nil {
				return "#unknownchannel"
			}
			channel = b.getChannelName(m[2 : len(m)-1])
			return channel
		}
		return channel
	})
	return text
}

func (b *bdiscord) stripCustomoji(text string) string {
	// <:doge:302803592035958784>
	re := regexp.MustCompile("<(:.*?:)[0-9]+>")
	return re.ReplaceAllString(text, `$1`)
}
<|endoftext|>


<commit_before>/*
The skilldrill model package is a multi-file package that can model a hierachical
set of skills and a set of people who hold some of those skills. The api.go file
exposes the Api type, which provides methods for CRUD operations, while the other
files deal with much of the internal workings. The model supports serialization
and de-serialization using a yaml form.
*/
package model

import (
	"errors"
	"gopkg.in/yaml.v2"
	"strings"
)

// The Api structure is the fundamental type exposed by the skilldrill model
// package, and provides CRUD interfaces to do things like adding skills or
// people into the model and registering a person as having a particular skill.
// All model editing operations should be done via Api calls rather than
// accessing the internal objects directly, so that the integrity of various
// supplemental look up tables is preserved.
// The design intent is that none of Api fields are exported, but the reason
// that some are, is solely to facilitate automated serialization by
// yaml.Marshal().
type Api struct {
	SerializeVers int
	Skills        []*skillNode
	People        []*person
	skillFromId   map[int]*skillNode
	persFromMail  map[string]*person
	SkillRoot     int            // root of taxonomy tree (skill.Uid)
	SkillHoldings *skillHoldings // who has what skill?
	NextSkill     int
}

// The function NewApi() is a (compulsory) constructor for an initialized, but
// empty Api struct.
func NewApi() *Api {
	return &Api{
		SerializeVers: 1,
		Skills:        make([]*skillNode, 0),
		People:        make([]*person, 0),
		skillFromId:   make(map[int]*skillNode),
		persFromMail:  make(map[string]*person),
		SkillRoot:     -1,
		SkillHoldings: newSkillHoldings(),
		NextSkill:     1,
	}
}

// The function NewFromSerialized() is a factory for an Api based on
// content previously serialized using the Api.Serialize() method.
func NewFromSerialized(in []byte) (api *Api, err error) {
	api = NewApi()
	err = yaml.Unmarshal(in, api)
	if err != nil {
		return
	}
	api.finishBuildFromDeSerialize()
	return
}

// The AddPerson() method adds a person to the model in terms of the user name
// part of their email address. It is an error to add a person that already
// exists in the model. The email address is coerced to lowercase.
func (api *Api) AddPerson(email string) (err error) {
	// disallow duplicate additions
    email = strings.ToLower(email)
	_, ok := api.persFromMail[email]
	if ok {
		return errors.New("Person already exists")
	}
	incomer := newPerson(email)
	api.People = append(api.People, incomer)
	api.persFromMail[email] = incomer
	return nil
}

/*
The AddSkill() method adds a skill into the model's hierachy of skills.  You
specify the skill in terms of description and title strings. These strings should
describe how they additionally qualify their context in the hierachy, and should
not duplicate context information.  You specify the tree location by providing
the Uid of the parent skill, and the new Uid for the added skill is returned.
The role parameter should be one of the constants SKILL or CATEGORY.  When the
skill tree is empty, this skill will be added as the root, and the parentUid
parameter is ignored.  Errors are generated if you attempt to add a skill to a
node that is not a CATEGORY, or if the parent skill you provide is not
recognized.
*/
func (api *Api) AddSkill(role string, title string, desc string,
	parent int) (uid int, err error) {

	// Special case when tree is empty
	if api.SkillRoot == -1 {
		uid = api.NextSkill
		api.NextSkill++
		skill := newSkillNode(uid, role, title, desc, -1)
		api.Skills = append(api.Skills, skill)
		api.skillFromId[uid] = skill
		api.SkillRoot = uid
		return
	}
	parentSkill, ok := api.skillFromId[parent]
	if !ok {
		err = errors.New("Unknown parent.")
		return
	}
	if parentSkill.Role != CATEGORY {
		err = errors.New("Parent must be a category node")
		return
	}
	uid = api.NextSkill
	api.NextSkill++
	newSkill := newSkillNode(uid, role, title, desc, parentSkill.Uid)
	api.Skills = append(api.Skills, newSkill)
	api.skillFromId[uid] = newSkill
	parentSkill.addChild(newSkill.Uid)
	return
}

/*
The GivePersonSkill() method adds the given skill into the set of skills the
model holds for that person.  You are only allowed to give people SKILLS, not
CATEGORIES.  An error is generated if either the person or skill given are not
recognized, or you give a person a CATEGORY rather than a SKILL. The email you
provide is lower-cased before it is used.
*/
func (api *Api) GivePersonSkill(email string, skillId int) error {
    email = strings.ToLower(email)
	foundPerson, ok := api.persFromMail[email]
	if !ok {
		return errors.New("Person does not exist.")
	}
	foundSkill, ok := api.skillFromId[skillId]
	if !ok {
		return errors.New("Skill does not exist.")
	}
	if foundSkill.Role == CATEGORY {
		return errors.New("Cannot give someone a CATEGORY skill.")
	}
	api.SkillHoldings.bind(foundSkill.Uid, foundPerson.Email)
	return nil
}

/*
The function Serialize() makes a machine-readable representation of the Api
object and packages it into a slice of bytes. See also NewFromSerialized().
*/
func (api *Api) Serialize() (out []byte, err error) {
	return yaml.Marshal(api)
}

/*
The function finishBuildFromDeSerialize() takes the state of an Api object that
has been partly initialized from de-serialization, and builds the supplemental
fields required. These are mainly look up tables for convenience and speed.
*/
func (api *Api) finishBuildFromDeSerialize() {
	for _, skill := range api.Skills {
		uid := skill.Uid
		api.skillFromId[uid] = skill
	}
	for _, person := range api.People {
		email := person.Email
		api.persFromMail[email] = person
	}
}
<commit_msg>Somehow missed this file?<commit_after>/*
The skilldrill model package is a multi-file package that can model a hierachical
set of skills and a set of people who hold some of those skills. The api.go file
exposes the Api type, which provides methods for CRUD operations, while the other
files deal with much of the internal workings. The model supports serialization
and de-serialization using a yaml form.
*/
package model

import (
	"errors"
	"gopkg.in/yaml.v2"
	"strings"
)

// The Api structure is the fundamental type exposed by the skilldrill model
// package, and provides CRUD interfaces to do things like adding skills or
// people into the model and registering a person as having a particular skill.
// All model editing operations should be done via Api calls rather than
// accessing the internal objects directly, so that the integrity of various
// supplemental look up tables is preserved.
// The design intent is that none of Api fields are exported, but the reason
// that some are, is solely to facilitate automated serialization by
// yaml.Marshal().
type Api struct {
	SerializeVers  int
	Skills         []*skillNode
	People         []*person
	SkillRoot      int            // root of taxonomy tree (skill.Uid)
	SkillHoldings  *skillHoldings // who has what skill?
	NextSkill      int
	UiStates       map[string]*uiState
	// Supplemental, (duplicate) data for quick lookups
	skillFromId  map[int]*skillNode
	persFromMail map[string]*person
}

// The function NewApi() is a (compulsory) constructor for an initialized, but
// empty Api struct.
func NewApi() *Api {
	return &Api{
		SerializeVers:  1,
		Skills:         make([]*skillNode, 0),
		People:         make([]*person, 0),
		SkillRoot:      -1,
		SkillHoldings:  newSkillHoldings(),
		NextSkill:      1,
		UiStates:       make(map[string]*uiState),
		// Supplemental fields
		skillFromId:  make(map[int]*skillNode),
		persFromMail: make(map[string]*person),
	}
}

// The function NewFromSerialized() is a factory for an Api based on
// content previously serialized using the Api.Serialize() method.
func NewFromSerialized(in []byte) (api *Api, err error) {
	api = NewApi()
	err = yaml.Unmarshal(in, api)
	if err != nil {
		return
	}
	api.finishBuildFromDeSerialize()
	return
}

// The AddPerson() method adds a person to the model in terms of the user name
// part of their email address. It is an error to add a person that already
// exists in the model. The email address is coerced to lowercase.
func (api *Api) AddPerson(email string) (err error) {
	// disallow duplicate additions
	email = strings.ToLower(email)
	_, ok := api.persFromMail[email]
	if ok {
		return errors.New(PersonExists)
	}
	incomer := newPerson(email)
	api.People = append(api.People, incomer)
	api.persFromMail[email] = incomer
    api.UiStates[email] = newUiState()
	return nil
}

/*
The AddSkill() method adds a skill into the model's hierachy of skills.  You
specify the skill in terms of description and title strings. These strings should
describe how they additionally qualify their context in the hierachy, and should
not duplicate context information.  You specify the tree location by providing
the Uid of the parent skill, and the new Uid for the added skill is returned.
The role parameter should be one of the constants Skill or Category.  When the
skill tree is empty, this skill will be added as the root, and the parentUid
parameter is ignored.  Errors are generated if you attempt to add a skill to a
node that is not a Category, or if the parent skill you provide is not
recognized.
*/
func (api *Api) AddSkill(role string, title string, desc string,
	parent int) (uid int, err error) {

	// Special case when tree is empty
	if api.SkillRoot == -1 {
		uid = api.NextSkill
		api.NextSkill++
		skill := newSkillNode(uid, role, title, desc, -1)
		api.Skills = append(api.Skills, skill)
		api.skillFromId[uid] = skill
		api.SkillRoot = uid
		return
	}
	parentSkill, ok := api.skillFromId[parent]
	if !ok {
		err = errors.New(UnknownParent)
		return
	}
	if parentSkill.Role != Category {
		err = errors.New(ParentNotCategory)
		return
	}
	uid = api.NextSkill
	api.NextSkill++
	newSkill := newSkillNode(uid, role, title, desc, parentSkill.Uid)
	api.Skills = append(api.Skills, newSkill)
	api.skillFromId[uid] = newSkill
	parentSkill.addChild(newSkill.Uid)
	return
}

/*
The GivePersonSkill() method adds the given skill into the set of skills the
model holds for that person.  You are only allowed to give people Skill, not
CATEGORIES.  An error is generated if either the person or skill given are not
recognized, or you give a person a Category rather than a Skill. The email you
provide is lower-cased before it is used.
*/
func (api *Api) GivePersonSkill(email string, skillId int) error {
	email = strings.ToLower(email)
	foundPerson, ok := api.persFromMail[email]
	if !ok {
		return errors.New(UnknownPerson)
	}
	foundSkill, ok := api.skillFromId[skillId]
	if !ok {
		return errors.New(UnknownSkill)
	}
	if foundSkill.Role == Category {
		return errors.New(CategoryDisallowed)
	}
	api.SkillHoldings.bind(foundSkill.Uid, foundPerson.Email)
	return nil
}

/*
The CollapseSkill() method operates on the part of the model that represents the
abstracted user experience. In this case to collapse a node in the tree display
of skills hierachy. Errors are generated when either the person or the skill is
not recognized.
*/
func (api *Api) CollapseSkill(email string, skillId int) error {
	email = strings.ToLower(email)
	_, ok := api.persFromMail[email]
	if !ok {
		return errors.New(UnknownPerson)
	}
	foundSkill, ok := api.skillFromId[skillId]
	if !ok {
		return errors.New(UnknownSkill)
	}
	api.UiStates[email].collapseNode(foundSkill)
	return nil
}

/*
The function Serialize() makes a machine-readable representation of the Api
object and packages it into a slice of bytes. See also NewFromSerialized().
*/
func (api *Api) Serialize() (out []byte, err error) {
	return yaml.Marshal(api)
}

/*
The function finishBuildFromDeSerialize() takes the state of an Api object that
has been partly initialized from de-serialization, and builds the supplemental
fields required. These are mainly look up tables for convenience and speed.
*/
func (api *Api) finishBuildFromDeSerialize() {
	for _, skill := range api.Skills {
		uid := skill.Uid
		api.skillFromId[uid] = skill
	}
	for _, person := range api.People {
		email := person.Email
		api.persFromMail[email] = person
	}
}
<|endoftext|>


<commit_before>package bot

const helpConfig = `
AllChannels: true
CommandMatchers:
- Command: help
  Regex: '(?i:help ?([\d\w]+)?)'
`

const adminConfig = `
AllChannels: true
RequireAdmin: true
Help:
- Keywords: [ "reload" ]
  Helptext: [ "(bot), reload - have the robot reload configuration files" ]
- Keywords: [ "quit" ]
  Helptext: [ "(bot), quit - request a graceful shutdown" ]
CommandMatchers:
- Command: reload
  Regex: '(?i:reload)'
- Command: quit
  Regex: '(?i:quit|exit)'
- Command: info
  Regex: '(?i:info|tell me about yourself)'
`

const launchCodesConfig = `
AllChannels: true
Help:
- Keywords: [ "send", "launch", "codes" ]
  Helptext: [ "(bot), send launch codes - one-time send of Google Authenticator string token, for use with TOTP elevation" ]
- Keywords: [ "check", "launch", "codes", "code" ]
  Helptext: [ "(bot), check launch code <code> - verify launch codes operation without launching any missiles" ]
CommandMatchers:
- Command: "send"
  Regex: '(?i:send (?:launch )?codes?)'
- Command: "check"
  Regex: '(?i:check (?:launch )?codes? ([\d]{6}))'
`

const dumpConfig = `
DirectOnly: true
RequireAdmin: true
Help:
- Keywords: [ "dump", "plugin" ]
  Helptext: [ "(bot), dump plugin (default) <plugname> - dump the current or default configuration for the plugin" ]
- Keywords: [ "list", "plugin", "plugins" ]
  Helptext: [ "(bot), list plugins" ]
- Keywords: [ "dump", "robot" ]
  Helptext: [ "(bot), dump (default) robot - dump the current configuration for the robot" ]
CommandMatchers:
- Command: "list"
  Regex: '(?i:list plugins?)'
- Command: "plugdefault"
  Regex: '(?i:dump plugin default ([\d\w]+))'
- Command: "robotdefault"
  Regex: "dump default robot"
- Command: "plugin"
  Regex: '(?i:dump plugin ([\d\w]+))'
- Command: "robot"
  Regex: "dump robot"
`

const logConfig = `
DirectOnly: true
RequireAdmin: true
Help:
- Keywords: [ "log", "logs", "level" ]
  Helptext: [ "(bot), set log level to <trace|debug|info|warning|error> - adjust the logging verbosity" ]
- Keywords: [ "show", "log", "logs" ]
  Helptext: [ "(bot), show log (page X) - display the last or Xth previous page of log output" ]
- Keywords: [ "show", "log", "logs", "level" ]
  Helptext: [ "(bot), show log level - show the current logging level" ]
- Keywords: [ "log", "page", "lines" ]
  Helptext: [ "(bot), set log lines to <number> - set the number of lines returned by show log"]
CommandMatchers:
- Command: "level"
  Regex: '(?i:set log ?level(?: to)? (trace|debug|info|warning|error))'
- Command: "show"
  Regex: '(?i:show logs?(?: page (\d+))?)'
- Command: "showlevel"
  Regex: '(?i:show (?:log ?)?level)'
- Command: "setlines"
  Regex: '(?i:set log ?lines(?: to)? (\d+))'
`
<commit_msg>Add help for info command<commit_after>package bot

const helpConfig = `
AllChannels: true
CommandMatchers:
- Command: help
  Regex: '(?i:help ?([\d\w]+)?)'
`

const adminConfig = `
AllChannels: true
RequireAdmin: true
Help:
- Keywords: [ "reload" ]
  Helptext: [ "(bot), reload - have the robot reload configuration files" ]
- Keywords: [ "quit" ]
  Helptext: [ "(bot), quit - request a graceful shutdown" ]
- Keywords: [ "info", "information", "robot", "admin", "administrators" ]
  Helptext: [ "(bot), info | tell me about yourself - provide useful information for admins, or a list of admins" ]
CommandMatchers:
- Command: reload
  Regex: '(?i:reload)'
- Command: quit
  Regex: '(?i:quit|exit)'
- Command: info
  Regex: '(?i:info|tell me about yourself)'
`

const launchCodesConfig = `
AllChannels: true
Help:
- Keywords: [ "send", "launch", "codes" ]
  Helptext: [ "(bot), send launch codes - one-time send of Google Authenticator string token, for use with TOTP elevation" ]
- Keywords: [ "check", "launch", "codes", "code" ]
  Helptext: [ "(bot), check launch code <code> - verify launch codes operation without launching any missiles" ]
CommandMatchers:
- Command: "send"
  Regex: '(?i:send (?:launch )?codes?)'
- Command: "check"
  Regex: '(?i:check (?:launch )?codes? ([\d]{6}))'
`

const dumpConfig = `
DirectOnly: true
RequireAdmin: true
Help:
- Keywords: [ "dump", "plugin" ]
  Helptext: [ "(bot), dump plugin (default) <plugname> - dump the current or default configuration for the plugin" ]
- Keywords: [ "list", "plugin", "plugins" ]
  Helptext: [ "(bot), list plugins" ]
- Keywords: [ "dump", "robot" ]
  Helptext: [ "(bot), dump (default) robot - dump the current configuration for the robot" ]
CommandMatchers:
- Command: "list"
  Regex: '(?i:list plugins?)'
- Command: "plugdefault"
  Regex: '(?i:dump plugin default ([\d\w]+))'
- Command: "robotdefault"
  Regex: "dump default robot"
- Command: "plugin"
  Regex: '(?i:dump plugin ([\d\w]+))'
- Command: "robot"
  Regex: "dump robot"
`

const logConfig = `
DirectOnly: true
RequireAdmin: true
Help:
- Keywords: [ "log", "logs", "level" ]
  Helptext: [ "(bot), set log level to <trace|debug|info|warning|error> - adjust the logging verbosity" ]
- Keywords: [ "show", "log", "logs" ]
  Helptext: [ "(bot), show log (page X) - display the last or Xth previous page of log output" ]
- Keywords: [ "show", "log", "logs", "level" ]
  Helptext: [ "(bot), show log level - show the current logging level" ]
- Keywords: [ "log", "page", "lines" ]
  Helptext: [ "(bot), set log lines to <number> - set the number of lines returned by show log"]
CommandMatchers:
- Command: "level"
  Regex: '(?i:set log ?level(?: to)? (trace|debug|info|warning|error))'
- Command: "show"
  Regex: '(?i:show logs?(?: page (\d+))?)'
- Command: "showlevel"
  Regex: '(?i:show (?:log ?)?level)'
- Command: "setlines"
  Regex: '(?i:set log ?lines(?: to)? (\d+))'
`
<|endoftext|>


<commit_before>//
//Console is a lightweight logging tool inspired by the NodeJS console object
// and http://github.com/bluejamesbond/scribe.js project.
//
//	console.Info("Some info")
//	console.Tag("Hello").Time().File().Log("Hello World")
//
//Console provided Info, Log, Warning and Error method and Tag, Time, File optional information
//
//With use of ansi colors, it output something like below in terminal :
//	[Tag1][Tag2] [main.go:48] 2015-02-15T09:22:06+01:00 Hello World
//
//Author: http://github.com/guillaumewuip
package console

//Create a new console
//	myConsole = console.NewConsole(console.ColorsOptions{})
//Pass a ColorsOptions map (could be empty to use default values).
//
//Colors from https://github.com/mgutz/ansi.
//See examples below :
func NewConsole(colors ColorsOptions) *Logger {

	logger := Logger{}
	logger.options.Colors = colors

	for key, color := range defaultColors {
		if colors[key] == "" {
			colors[key] = color
		}
	}

	return &logger
}
<commit_msg>update doc<commit_after>//
//Console is a lightweight logging tool inspired by the NodeJS console object
// and http://github.com/bluejamesbond/scribe.js project.
//
//	console.Info("Some info")
//	console.Tag("Hello").Time().File().Log("Hello %s", "World")
//
//Console provided Info, Log, Warning and Error method and Tag, Time, File optional information
//
//With use of ansi colors, it output something like below in terminal :
//	[Tag1][Tag2] [main.go:48] 2015-02-15T09:22:06+01:00 Hello World
//
//Author: http://github.com/guillaumewuip
package console

//Create a new console
//	myConsole = console.NewConsole(console.ColorsOptions{})
//Pass a ColorsOptions map (could be empty to use default values).
//
//Colors from https://github.com/mgutz/ansi.
//See examples below :
func NewConsole(colors ColorsOptions) *Logger {

	logger := Logger{}
	logger.options.Colors = colors

	for key, color := range defaultColors {
		if colors[key] == "" {
			colors[key] = color
		}
	}

	return &logger
}
<|endoftext|>