<commit_before>package main

import (
	"bytes"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"text/tabwriter"

	"github.com/coreos/updatectl/client/update/v1"
)

type MetadataFile struct {
	MetadataSize         string `json:"metadata_size"`
	MetadataSignatureRsa string `json:"metadata_signature_rsa"`
}

var (
	packageFlags struct {
		appId   StringFlag
		version StringFlag
		url     string
		file    string
		meta    string
	}

	cmdPackage = &Command{
		Name:    "package",
		Summary: "List or create packages for an application.",
		Subcommands: []*Command{
			cmdPackageList,
			cmdPackageCreate,
		},
	}

	cmdPackageList = &Command{
		Name:        "package list",
		Usage:       "[OPTION]...",
		Description: `List all of the packages that exist including their metadata.`,
		Run:         packageList,
	}
	cmdPackageCreate = &Command{
		Name:        "package create",
		Usage:       "[OPTION]...",
		Description: `Create a new package for an application.`,
		Run:         packageCreate,
	}
)

func init() {
	cmdPackageList.Flags.Var(&packageFlags.appId, "app-id", "Application to list the package of.")

	cmdPackageCreate.Flags.Var(&packageFlags.appId, "app-id", "Application to add the package to.")
	cmdPackageCreate.Flags.Var(&packageFlags.version, "version", "Application version associated with the package.")
	cmdPackageCreate.Flags.StringVar(&packageFlags.url, "url", "", "Package URL.")
	cmdPackageCreate.Flags.StringVar(&packageFlags.file, "file", "update.gz", "Package file.")
	cmdPackageCreate.Flags.StringVar(&packageFlags.meta, "meta", "", "JSON file containing metadata.")
}

func packageCreate(args []string, service *update.Service, out *tabwriter.Writer) int {
	if packageFlags.appId.Get() == nil ||
		packageFlags.version.Get() == nil {
		return ERROR_USAGE
	}

	file := packageFlags.file
	info, err := os.Stat(file)
	if err != nil {
		log.Fatalf("stat of %s failed: %v", file, err)
	}
	content, err := ioutil.ReadFile(file)
	if err != nil {
		log.Fatalf("reading %s failed: %v", file, err)
	}

	file = packageFlags.meta
	var meta MetadataFile
	if file != "" {
		content, err = ioutil.ReadFile(file)
		if err != nil {
			log.Fatalf("reading %s failed: %v", file, err)
		}
		err = json.Unmarshal(content, &meta)
		if err != nil {
			log.Fatalf("reading %s failed: %v", file, err)
		}
	}

	var sha1base64 bytes.Buffer
	encoder := base64.NewEncoder(base64.StdEncoding, &sha1base64)
	sha1h := sha1.New()
	io.Copy(sha1h, bytes.NewReader(content))
	encoder.Write(sha1h.Sum(nil))
	encoder.Close()

	var sha256base64 bytes.Buffer
	encoder = base64.NewEncoder(base64.StdEncoding, &sha256base64)
	sha256h := sha256.New()
	io.Copy(sha256h, bytes.NewReader(content))
	encoder.Write(sha256h.Sum(nil))
	encoder.Close()

	pkg := &update.Package{
		Url:                  packageFlags.url,
		Size:                 strconv.FormatInt(info.Size(), 10),
		Sha1Sum:              sha1base64.String(),
		Sha256Sum:            sha256base64.String(),
		MetadataSignatureRsa: meta.MetadataSignatureRsa,
		MetadataSize:         meta.MetadataSize,
	}

	jbytes, _ := json.MarshalIndent(pkg, "", " ")
	fmt.Printf("%s\n", string(jbytes))

	call := service.App.Package.Insert(packageFlags.appId.String(), packageFlags.version.String(), pkg)
	pkg, err = call.Do()

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

	fmt.Fprintln(out, packageFlags.appId, packageFlags.version)

	out.Flush()
	return OK
}

func packageList(args []string, service *update.Service, out *tabwriter.Writer) int {
	if packageFlags.appId.Get() == nil {
		return ERROR_USAGE
	}

	call := service.App.Package.List(packageFlags.appId.String())
	list, err := call.Do()

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

	fmt.Fprintln(out, "Version\tURL\tSize")
	for _, pkg := range list.Items {
		fmt.Fprintf(out, "%s\t%s\t%s\n", pkg.Version, pkg.Url, pkg.Size)
	}

	out.Flush()
	return OK
}
<commit_msg>feat(package): add delete command<commit_after>package main

import (
	"bytes"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"text/tabwriter"

	update "github.com/coreos/updatectl/client/update/v1"
)

type MetadataFile struct {
	MetadataSize         string `json:"metadata_size"`
	MetadataSignatureRsa string `json:"metadata_signature_rsa"`
}

var (
	packageFlags struct {
		appId   StringFlag
		version StringFlag
		url     string
		file    string
		meta    string
	}

	cmdPackage = &Command{
		Name:    "package",
		Summary: "List or create packages for an application.",
		Subcommands: []*Command{
			cmdPackageList,
			cmdPackageCreate,
			cmdPackageDelete,
		},
	}

	cmdPackageList = &Command{
		Name:        "package list",
		Usage:       "[OPTION]...",
		Description: `List all of the packages that exist including their metadata.`,
		Run:         packageList,
	}
	cmdPackageCreate = &Command{
		Name:        "package create",
		Usage:       "[OPTION]...",
		Description: `Create a new package for an application.`,
		Run:         packageCreate,
	}
	cmdPackageDelete = &Command{
		Name:        "package delete",
		Usage:       "[OPTION]...",
		Description: `Delete a package for an application.`,
		Run:         packageDelete,
	}
)

func init() {
	cmdPackageList.Flags.Var(&packageFlags.appId, "app-id", "Application to list the package of.")

	cmdPackageCreate.Flags.Var(&packageFlags.appId, "app-id", "Application to add the package to.")
	cmdPackageCreate.Flags.Var(&packageFlags.version, "version", "Application version associated with the package.")
	cmdPackageCreate.Flags.StringVar(&packageFlags.url, "url", "", "Package URL.")
	cmdPackageCreate.Flags.StringVar(&packageFlags.file, "file", "update.gz", "Package file.")
	cmdPackageCreate.Flags.StringVar(&packageFlags.meta, "meta", "", "JSON file containing metadata.")

	cmdPackageDelete.Flags.Var(&packageFlags.appId, "app-id",
		"Application with package to delete.")
	cmdPackageDelete.Flags.Var(&packageFlags.version, "version",
		"Version of package to delete.")
}

func formatPackage(pkg *update.Package) string {
	return fmt.Sprintf("%s\t%s\t%s\n", pkg.Version, pkg.Url, pkg.Size)
}

func packageCreate(args []string, service *update.Service, out *tabwriter.Writer) int {
	if packageFlags.appId.Get() == nil ||
		packageFlags.version.Get() == nil {
		return ERROR_USAGE
	}

	file := packageFlags.file
	info, err := os.Stat(file)
	if err != nil {
		log.Fatalf("stat of %s failed: %v", file, err)
	}
	content, err := ioutil.ReadFile(file)
	if err != nil {
		log.Fatalf("reading %s failed: %v", file, err)
	}

	file = packageFlags.meta
	var meta MetadataFile
	if file != "" {
		content, err = ioutil.ReadFile(file)
		if err != nil {
			log.Fatalf("reading %s failed: %v", file, err)
		}
		err = json.Unmarshal(content, &meta)
		if err != nil {
			log.Fatalf("reading %s failed: %v", file, err)
		}
	}

	var sha1base64 bytes.Buffer
	encoder := base64.NewEncoder(base64.StdEncoding, &sha1base64)
	sha1h := sha1.New()
	io.Copy(sha1h, bytes.NewReader(content))
	encoder.Write(sha1h.Sum(nil))
	encoder.Close()

	var sha256base64 bytes.Buffer
	encoder = base64.NewEncoder(base64.StdEncoding, &sha256base64)
	sha256h := sha256.New()
	io.Copy(sha256h, bytes.NewReader(content))
	encoder.Write(sha256h.Sum(nil))
	encoder.Close()

	pkg := &update.Package{
		Url:                  packageFlags.url,
		Size:                 strconv.FormatInt(info.Size(), 10),
		Sha1Sum:              sha1base64.String(),
		Sha256Sum:            sha256base64.String(),
		MetadataSignatureRsa: meta.MetadataSignatureRsa,
		MetadataSize:         meta.MetadataSize,
	}

	jbytes, _ := json.MarshalIndent(pkg, "", " ")
	fmt.Printf("%s\n", string(jbytes))

	call := service.App.Package.Insert(packageFlags.appId.String(), packageFlags.version.String(), pkg)
	pkg, err = call.Do()

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

	fmt.Fprintln(out, packageFlags.appId, packageFlags.version)

	out.Flush()
	return OK
}

func packageList(args []string, service *update.Service, out *tabwriter.Writer) int {
	if packageFlags.appId.Get() == nil {
		return ERROR_USAGE
	}

	call := service.App.Package.List(packageFlags.appId.String())
	list, err := call.Do()

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

	fmt.Fprintln(out, "Version\tURL\tSize")
	for _, pkg := range list.Items {
		fmt.Fprintf(out, "%s\t%s\t%s\n", pkg.Version, pkg.Url, pkg.Size)
	}

	out.Flush()
	return OK
}

func packageDelete(args []string, service *update.Service, out *tabwriter.Writer) int {
	if packageFlags.appId.Get() == nil ||
		packageFlags.version.Get() == nil {
		return ERROR_USAGE
	}

	call := service.App.Package.Delete(packageFlags.appId.String(), packageFlags.version.String())
	pkg, err := call.Do()

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

	fmt.Fprintf(out, "%s", formatPackage(pkg))

	out.Flush()
	return OK

}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"os"

	"github.com/rcrowley/go-tigertonic"

	"github.com/room101-ci/agent/api"
	"github.com/room101-ci/agent/api/builds/builder"
	"github.com/room101-ci/agent/api/builds/scheduler"
)

var listenAddr = flag.String(
	"listen",
	"0.0.0.0:4637",
	"listening address",
)

func main() {
	logger := log.New(os.Stdout, "", 0)
	logger.Println("Booting...")

	handler := api.New(logger, scheduler.NewScheduler(builder.NewBuilder()))
	server := tigertonic.NewServer(*listenAddr, handler)

	err := server.ListenAndServe()
	logger.Fatalln("listen error:", err)
}
<commit_msg>inject everything in main<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/cloudfoundry-incubator/gordon"
	"github.com/fsouza/go-dockerclient"
	"github.com/pivotal-golang/archiver/extractor"
	"github.com/rcrowley/go-tigertonic"

	"github.com/room101-ci/agent/api"
	"github.com/room101-ci/agent/api/builds/builder"
	"github.com/room101-ci/agent/api/builds/imagefetcher"
	"github.com/room101-ci/agent/api/builds/scheduler"
	"github.com/room101-ci/agent/api/builds/sourcefetcher"
)

var listenAddr = flag.String(
	"listen",
	"0.0.0.0:4637",
	"listening address",
)

var tmpdir = flag.String(
	"tmpdir",
	os.Getenv("TMPDIR"),
	"directory in which to store ephemeral data",
)

var dockerEndpoint = flag.String(
	"dockerEndpoint",
	os.Getenv("DOCKER_HOST"),
	"docker remote API endpoint",
)

var wardenNetwork = flag.String(
	"wardenNetwork",
	"unix",
	"warden API connection network (unix or tcp)",
)

var wardenAddr = flag.String(
	"wardenAddr",
	"/tmp/warden.sock",
	"warden API connection address",
)

func main() {
	logger := log.New(os.Stdout, "", 0)
	logger.Println("Booting...")

	fmt.Println(*dockerEndpoint)

	dockerClient, err := docker.NewClient(*dockerEndpoint)
	if err != nil {
		logger.Fatalln("could not initialize docker client:", err)
	}

	wardenClient := gordon.NewClient(&gordon.ConnectionInfo{
		Network: *wardenNetwork,
		Addr:    *wardenAddr,
	})

	extractor := extractor.NewDetectable()
	sourceFetcher := sourcefetcher.NewSourceFetcher(*tmpdir, extractor)
	imageFetcher := imagefetcher.NewImageFetcher(dockerClient)

	builder := builder.NewBuilder(sourceFetcher, imageFetcher, wardenClient)

	handler := api.New(logger, scheduler.NewScheduler(builder))

	server := tigertonic.NewServer(*listenAddr, handler)

	err = server.ListenAndServe()
	logger.Fatalln("listen error:", err)
}
<|endoftext|>


<commit_before>/*
agorn is a wrapper around gorename for use with Acme.
It renames the entity under the cursor.

Usage:
	agorn <name>

Example:
	agorn Foo
renames the entity under the cursor with 'Foo'.

gorename must be installed:
	% go get golang.org/x/tools/cmd/gorename
*/
package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"9fans.net/go/acme"
)

type bodyReader struct{ *acme.Win }

func (r bodyReader) Read(data []byte) (int, error) {
	return r.Win.Read("body", data)
}

func openWin() (*acme.Win, error) {
	id, err := strconv.Atoi(os.Getenv("winid"))
	if err != nil {
		return nil, err
	}
	return acme.Open(id, nil)
}

func readAddr(win *acme.Win) (q0, q1 int, err error) {
	if _, _, err := win.ReadAddr(); err != nil {
		return 0, 0, err
	}
	if err := win.Ctl("addr=dot"); err != nil {
		return 0, 0, err
	}
	return win.ReadAddr()
}

func readFilename(win *acme.Win) (string, error) {
	b, err := win.ReadAll("tag")
	if err != nil {
		return "", err
	}
	tag := string(b)
	i := strings.Index(tag, " ")
	if i == -1 {
		return "", fmt.Errorf("cannot get filename from tag")
	}
	return tag[0:i], nil
}

func selection(win *acme.Win) (filename string, off int, err error) {
	filename, err = readFilename(win)
	if err != nil {
		return "", 0, err
	}
	q0, _, err := readAddr(win)
	if err != nil {
		return "", 0, err
	}
	off, err = byteOffset(bufio.NewReader(&bodyReader{win}), q0)
	if err != nil {
		return "", 0, err
	}
	return
}

func byteOffset(r io.RuneReader, off int) (bo int, err error) {
	for i := 0; i != off; i++ {
		_, s, err := r.ReadRune()
		if err != nil {
			return 0, err
		}
		bo += s
	}
	return
}

func reloadShowAddr(win *acme.Win, off int) error {
	if err := win.Ctl("get"); err != nil {
		return err
	}
	if err := win.Addr("#%d", off); err != nil {
		return err
	}
	return win.Ctl("dot=addr\nshow")
}

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "Usage: agorn <name>\n")
		os.Exit(1)
	}

	win, err := openWin()
	if err != nil {
		fmt.Fprintf(os.Stderr, "cannot open window: %v\n", err)
		os.Exit(1)
	}

	filename, off, err := selection(win)
	if err != nil {
		fmt.Fprintf(os.Stderr, "cannot get selection: %v\n", err)
		os.Exit(1)
	}

	c := exec.Command("gorename", "-offset", fmt.Sprintf("%s:#%d", filename, off), "-to", os.Args[1])
	c.Stderr = os.Stderr
	if err = c.Run(); err != nil {
		fmt.Fprintf(os.Stderr, "rename failed: %v\n", err)
		os.Exit(1)
	}
	if err := reloadShowAddr(win, off); err != nil {
		fmt.Fprintf(os.Stderr, "cannot restore selection: %s\n", err)
		os.Exit(1)
	}
}
<commit_msg>Rearrange code.<commit_after>/*
agorn is a wrapper around gorename for use with Acme.
It renames the entity under the cursor.

Usage:
	agorn <name>

Example:
	agorn Foo
renames the entity under the cursor with 'Foo'.

gorename must be installed:
	% go get golang.org/x/tools/cmd/gorename
*/
package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"9fans.net/go/acme"
)

type bodyReader struct{ *acme.Win }

func (r bodyReader) Read(data []byte) (int, error) {
	return r.Win.Read("body", data)
}

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "Usage: agorn <name>\n")
		os.Exit(1)
	}

	win, err := openWin()
	if err != nil {
		fmt.Fprintf(os.Stderr, "cannot open window: %v\n", err)
		os.Exit(1)
	}

	filename, off, err := selection(win)
	if err != nil {
		fmt.Fprintf(os.Stderr, "cannot get selection: %v\n", err)
		os.Exit(1)
	}

	c := exec.Command("gorename", "-offset", fmt.Sprintf("%s:#%d", filename, off), "-to", os.Args[1])
	c.Stderr = os.Stderr
	if err = c.Run(); err != nil {
		fmt.Fprintf(os.Stderr, "rename failed: %v\n", err)
		os.Exit(1)
	}
	if err := reloadShowAddr(win, off); err != nil {
		fmt.Fprintf(os.Stderr, "cannot restore selection: %s\n", err)
		os.Exit(1)
	}
}

func openWin() (*acme.Win, error) {
	id, err := strconv.Atoi(os.Getenv("winid"))
	if err != nil {
		return nil, err
	}
	return acme.Open(id, nil)
}

func selection(win *acme.Win) (filename string, off int, err error) {
	filename, err = readFilename(win)
	if err != nil {
		return "", 0, err
	}
	q0, _, err := readAddr(win)
	if err != nil {
		return "", 0, err
	}
	off, err = byteOffset(bufio.NewReader(&bodyReader{win}), q0)
	if err != nil {
		return "", 0, err
	}
	return
}

func readFilename(win *acme.Win) (string, error) {
	b, err := win.ReadAll("tag")
	if err != nil {
		return "", err
	}
	tag := string(b)
	i := strings.Index(tag, " ")
	if i == -1 {
		return "", fmt.Errorf("cannot get filename from tag")
	}
	return tag[0:i], nil
}

func readAddr(win *acme.Win) (q0, q1 int, err error) {
	if _, _, err := win.ReadAddr(); err != nil {
		return 0, 0, err
	}
	if err := win.Ctl("addr=dot"); err != nil {
		return 0, 0, err
	}
	return win.ReadAddr()
}

func byteOffset(r io.RuneReader, off int) (bo int, err error) {
	for i := 0; i != off; i++ {
		_, s, err := r.ReadRune()
		if err != nil {
			return 0, err
		}
		bo += s
	}
	return
}

func reloadShowAddr(win *acme.Win, off int) error {
	if err := win.Ctl("get"); err != nil {
		return err
	}
	if err := win.Addr("#%d", off); err != nil {
		return err
	}
	return win.Ctl("dot=addr\nshow")
}
<|endoftext|>


<commit_before>package sql

////////////////////////////////////////////////////////////////////////////////////////////////
/// Imports
////////////////////////////////////////////////////////////////////////////////////////////////

import (
	"fmt"
	"log"
	"strings"
	"strconv"
    "encoding/hex"
	"github.com/helyx-io/commute-importer/database"
	"github.com/helyx-io/commute-importer/models"
	"github.com/helyx-io/commute-importer/tasks"
	"github.com/helyx-io/commute-importer/utils"
)

////////////////////////////////////////////////////////////////////////////////////////////////
/// SQLStopRepository
////////////////////////////////////////////////////////////////////////////////////////////////

func (r SQLGTFSRepository) Routes() database.GTFSCreatedModelRepository {
	return SQLRouteRepository{
		SQLGTFSModelRepository{r.driver},
	}
}

type SQLRouteRepository struct {
	SQLGTFSModelRepository
}

func (s SQLRouteRepository) RemoveAllByAgencyKey(agencyKey string) (error) {
    schema := fmt.Sprintf("gtfs_%s", agencyKey)
    return s.driver.DropTable(schema, "routes")
}

func (r SQLRouteRepository) CreateImportTask(taskName string, jobIndex int, fileName, agencyKey string, headers []string, lines []byte, done chan error) tasks.Task {
	importTask := tasks.ImportTask{taskName, jobIndex, fileName, agencyKey, headers, lines, done}
	mysqlImportTask := SQLImportTask{importTask, r.driver}
	return SQLRoutesImportTask{mysqlImportTask}
}

func (s SQLRouteRepository) CreateTableByAgencyKey(agencyKey string, params map[string]interface{}) error {

    schema := fmt.Sprintf("gtfs_%s", agencyKey)
    return s.driver.CreateTable(schema, "routes", params, true)
}

func (s SQLRouteRepository) AddIndexesByAgencyKey(agencyKey string) error {

    schema := fmt.Sprintf("gtfs_%s", agencyKey)

    err := s.driver.CreateIndex(schema, "routes", "agency_id")

    return err
}

////////////////////////////////////////////////////////////////////////////////////////////////
/// SQLStopRepository
////////////////////////////////////////////////////////////////////////////////////////////////

type SQLRoutesImportTask struct {
	SQLImportTask
}

func (m SQLRoutesImportTask) DoWork(_ int) {
	m.ImportCsv(m, m);
}

func(m SQLRoutesImportTask) ConvertModels(headers []string, rs *models.Records) []interface{} {
	var st = make([]interface{}, len(*rs))

	for i, record := range *rs {
        routeId, _ := strconv.Atoi(record[0])
        agencyId, _ := strconv.Atoi(record[1])
		routeType, _ := strconv.Atoi(record[5])

		routeColor := strings.ToUpper(record[7])
		routeTextColor := strings.ToUpper(record[8])

		if routeColor == routeTextColor {
			if routeTextColor = "FFFFFF" {
				routeTextColor = "000000"
			} else {
				routeTextColor = "FFFFFF"
			}
		}

		st[i] = models.RouteImportRow{
            routeId,
            agencyId,
			strings.ToUpper(record[2]),
            strings.ToUpper(record[3]),
			record[4],
			routeType,
			record[6],
            routeColor,
			routeTextColor,
		}
	}

	return st
}

func colorToInt32(color string, defaultColor string) int32 {

    if color == "" || len(color) != 6 {
        color = defaultColor
    }

    b, _ := hex.DecodeString(color)
    return int32(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16)
}

func (m SQLRoutesImportTask) ImportModels(headers []string, as []interface{}) error {

	dbSql, err := m.OpenSqlConnection()

	if err != nil {
		panic(err.Error())
	}

	defer dbSql.Close()

	valueStrings := make([]string, 0, len(as))
	valueArgs := make([]interface{}, 0, len(as) * 9)

	table := fmt.Sprintf("gtfs_%s.routes", m.AgencyKey)

	log.Println(fmt.Sprintf("[%s][%d] Inserting into table: '%s'", m.AgencyKey, m.JobIndex, table))

	query := "INSERT INTO " + table + " (" +
		" route_id," +
		" agency_id," +
		" route_short_name," +
		" route_long_name," +
		" route_desc," +
		" route_type," +
		" route_url," +
		" route_color," +
		" route_text_color" +
		" ) VALUES %s"

	count := 0

	for _, entry := range as {
        i := count * 9
		r := entry.(models.RouteImportRow)

        var args string
        if m.driver.ConnectInfos.Dialect == "postgres" {
            args = fmt.Sprintf("($%d, $%d, $%d, $%d, $%d, $%d, $%d, $%d, $%d)", i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9)
        } else {
            args = "(?, ?, ?, ?, ?, ?, ?, ?, ?)"
        }

        valueStrings = append(valueStrings, args)
		valueArgs = append(
			valueArgs,
			r.RouteId,
			r.AgencyId,
			r.RouteShortName,
			r.RouteLongName,
			r.RouteDesc,
			r.RouteType,
			r.RouteUrl,
            colorToInt32(r.RouteColor, "FFFFFF"),
            colorToInt32(r.RouteTextColor, "000000"),
		)

		count += 1

		if count >= 1024 {
			stmt := fmt.Sprintf(query, strings.Join(valueStrings, ","))

			_, err = dbSql.Exec(stmt, valueArgs...)
			utils.FailOnError(err, fmt.Sprintf("Could not insert into table with name: '%s'", table))

			valueStrings = make([]string, 0, len(as))
			valueArgs = make([]interface{}, 0, len(as) * 9)
			count = 0
		}
	}

	if count > 0 {
		stmt := fmt.Sprintf(query, strings.Join(valueStrings, ","))

		_, err = dbSql.Exec(stmt, valueArgs...)
		utils.FailOnError(err, fmt.Sprintf("Could not insert into table with name: '%s'", table))
	}

	return err

}
<commit_msg>Renamed gtfs-* projects to commute-* projects. Added commute-*. Changed some env variables namings. Fixed same routeColor and routeTextColor issue.<commit_after>package sql

////////////////////////////////////////////////////////////////////////////////////////////////
/// Imports
////////////////////////////////////////////////////////////////////////////////////////////////

import (
	"fmt"
	"log"
	"strings"
	"strconv"
    "encoding/hex"
	"github.com/helyx-io/commute-importer/database"
	"github.com/helyx-io/commute-importer/models"
	"github.com/helyx-io/commute-importer/tasks"
	"github.com/helyx-io/commute-importer/utils"
)

////////////////////////////////////////////////////////////////////////////////////////////////
/// SQLStopRepository
////////////////////////////////////////////////////////////////////////////////////////////////

func (r SQLGTFSRepository) Routes() database.GTFSCreatedModelRepository {
	return SQLRouteRepository{
		SQLGTFSModelRepository{r.driver},
	}
}

type SQLRouteRepository struct {
	SQLGTFSModelRepository
}

func (s SQLRouteRepository) RemoveAllByAgencyKey(agencyKey string) (error) {
    schema := fmt.Sprintf("gtfs_%s", agencyKey)
    return s.driver.DropTable(schema, "routes")
}

func (r SQLRouteRepository) CreateImportTask(taskName string, jobIndex int, fileName, agencyKey string, headers []string, lines []byte, done chan error) tasks.Task {
	importTask := tasks.ImportTask{taskName, jobIndex, fileName, agencyKey, headers, lines, done}
	mysqlImportTask := SQLImportTask{importTask, r.driver}
	return SQLRoutesImportTask{mysqlImportTask}
}

func (s SQLRouteRepository) CreateTableByAgencyKey(agencyKey string, params map[string]interface{}) error {

    schema := fmt.Sprintf("gtfs_%s", agencyKey)
    return s.driver.CreateTable(schema, "routes", params, true)
}

func (s SQLRouteRepository) AddIndexesByAgencyKey(agencyKey string) error {

    schema := fmt.Sprintf("gtfs_%s", agencyKey)

    err := s.driver.CreateIndex(schema, "routes", "agency_id")

    return err
}

////////////////////////////////////////////////////////////////////////////////////////////////
/// SQLStopRepository
////////////////////////////////////////////////////////////////////////////////////////////////

type SQLRoutesImportTask struct {
	SQLImportTask
}

func (m SQLRoutesImportTask) DoWork(_ int) {
	m.ImportCsv(m, m);
}

func(m SQLRoutesImportTask) ConvertModels(headers []string, rs *models.Records) []interface{} {
	var st = make([]interface{}, len(*rs))

	for i, record := range *rs {
        routeId, _ := strconv.Atoi(record[0])
        agencyId, _ := strconv.Atoi(record[1])
		routeType, _ := strconv.Atoi(record[5])

		routeColor := strings.ToUpper(record[7])
		routeTextColor := strings.ToUpper(record[8])

		if routeColor == routeTextColor {
			if routeTextColor == "FFFFFF" {
				routeTextColor = "000000"
			} else {
				routeTextColor = "FFFFFF"
			}
		}

		st[i] = models.RouteImportRow{
            routeId,
            agencyId,
			strings.ToUpper(record[2]),
            strings.ToUpper(record[3]),
			record[4],
			routeType,
			record[6],
            routeColor,
			routeTextColor,
		}
	}

	return st
}

func colorToInt32(color string, defaultColor string) int32 {

    if color == "" || len(color) != 6 {
        color = defaultColor
    }

    b, _ := hex.DecodeString(color)
    return int32(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16)
}

func (m SQLRoutesImportTask) ImportModels(headers []string, as []interface{}) error {

	dbSql, err := m.OpenSqlConnection()

	if err != nil {
		panic(err.Error())
	}

	defer dbSql.Close()

	valueStrings := make([]string, 0, len(as))
	valueArgs := make([]interface{}, 0, len(as) * 9)

	table := fmt.Sprintf("gtfs_%s.routes", m.AgencyKey)

	log.Println(fmt.Sprintf("[%s][%d] Inserting into table: '%s'", m.AgencyKey, m.JobIndex, table))

	query := "INSERT INTO " + table + " (" +
		" route_id," +
		" agency_id," +
		" route_short_name," +
		" route_long_name," +
		" route_desc," +
		" route_type," +
		" route_url," +
		" route_color," +
		" route_text_color" +
		" ) VALUES %s"

	count := 0

	for _, entry := range as {
        i := count * 9
		r := entry.(models.RouteImportRow)

        var args string
        if m.driver.ConnectInfos.Dialect == "postgres" {
            args = fmt.Sprintf("($%d, $%d, $%d, $%d, $%d, $%d, $%d, $%d, $%d)", i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9)
        } else {
            args = "(?, ?, ?, ?, ?, ?, ?, ?, ?)"
        }

        valueStrings = append(valueStrings, args)
		valueArgs = append(
			valueArgs,
			r.RouteId,
			r.AgencyId,
			r.RouteShortName,
			r.RouteLongName,
			r.RouteDesc,
			r.RouteType,
			r.RouteUrl,
            colorToInt32(r.RouteColor, "FFFFFF"),
            colorToInt32(r.RouteTextColor, "000000"),
		)

		count += 1

		if count >= 1024 {
			stmt := fmt.Sprintf(query, strings.Join(valueStrings, ","))

			_, err = dbSql.Exec(stmt, valueArgs...)
			utils.FailOnError(err, fmt.Sprintf("Could not insert into table with name: '%s'", table))

			valueStrings = make([]string, 0, len(as))
			valueArgs = make([]interface{}, 0, len(as) * 9)
			count = 0
		}
	}

	if count > 0 {
		stmt := fmt.Sprintf(query, strings.Join(valueStrings, ","))

		_, err = dbSql.Exec(stmt, valueArgs...)
		utils.FailOnError(err, fmt.Sprintf("Could not insert into table with name: '%s'", table))
	}

	return err

}
<|endoftext|>


<commit_before>package alexa

import (
	"context"
	"errors"
	"fmt"
	"log"
	"math"
	"strconv"
	"time"
)

const sdkVersion = "1.0"
const launchRequestName = "LaunchRequest"
const intentRequestName = "IntentRequest"
const sessionEndedRequestName = "SessionEndedRequest"

var timestampTolerance = 150

// ErrRequestEnvelopeNil reports that the request envelope was nil
// there might be edge case which causes panic if for whatever reason this object is empty
var ErrRequestEnvelopeNil = errors.New("request envelope was nil")

// Alexa defines the primary interface to use to create an Alexa request handler.
type Alexa struct {
	ApplicationID       string
	RequestHandler      RequestHandler
	IgnoreApplicationID bool
	IgnoreTimestamp     bool
}

// RequestHandler defines the interface that must be implemented to handle
// Alexa Requests
type RequestHandler interface {
	OnSessionStarted(context.Context, *Request, *Session, *Context, *Response) error
	OnLaunch(context.Context, *Request, *Session, *Context, *Response) error
	OnIntent(context.Context, *Request, *Session, *Context, *Response) error
	OnSessionEnded(context.Context, *Request, *Session, *Context, *Response) error
}

// RequestEnvelope contains the data passed from Alexa to the request handler.
type RequestEnvelope struct {
	Version string   `json:"version"`
	Session *Session `json:"session"`
	Request *Request `json:"request"`
	Context *Context `json:"context"`
}

// Session contains the session data from the Alexa request.
type Session struct {
	New        bool   `json:"new"`
	SessionID  string `json:"sessionId"`
	Attributes struct {
		String map[string]interface{} `json:"string"`
	} `json:"attributes"`
	User struct {
		UserID      string `json:"userId"`
		AccessToken string `json:"accessToken"`
	} `json:"user"`
	Application struct {
		ApplicationID string `json:"applicationId"`
	} `json:"application"`
}

// Context contains the context data from the Alexa Request.
type Context struct {
	AudioPlayer struct {
		PlayerActivity string `json:"playerActivity"`
	} `json:"AudioPlayer"`
	Display struct {
		Token string `json:"token"`
	} `json:"Display"`
	System struct {
		Application struct {
			ApplicationID string `json:"applicationId"`
		} `json:"application"`
		User struct {
			UserID string `json:"userId"`
		} `json:"user"`
		Device struct {
			DeviceID            string `json:"deviceId"`
			SupportedInterfaces struct {
				AudioPlayer struct {
				} `json:"AudioPlayer"`
				Display struct {
					TemplateVersion string `json:"templateVersion"`
					MarkupVersion   string `json:"markupVersion"`
				} `json:"Display"`
			} `json:"supportedInterfaces"`
		} `json:"device"`
		APIEndpoint    string `json:"apiEndpoint"`
		APIAccessToken string `json:"apiAccessToken"`
	} `json:"System"`
}

// Request contines the data in the request within the main request.
type Request struct {
	Locale      string `json:"locale"`
	Timestamp   string `json:"timestamp"`
	Type        string `json:"type"`
	RequestID   string `json:"requestId"`
	DialogState string `json:"dialogState"`
	Intent      Intent `json:"intent"`
	Name        string `json:"name"`
}

// Intent contains the data about the Alexa Intent requested.
type Intent struct {
	Name               string                `json:"name"`
	ConfirmationStatus string                `json:"confirmationStatus,omitempty"`
	Slots              map[string]IntentSlot `json:"slots"`
}

// IntentSlot contains the data for one Slot
type IntentSlot struct {
	Name               string `json:"name"`
	ConfirmationStatus string `json:"confirmationStatus,omitempty"`
	Value              string `json:"value"`
	ID                 string `json:"id,omitempty"`
}

// ResponseEnvelope contains the Response and additional attributes.
type ResponseEnvelope struct {
	Version           string                 `json:"version"`
	SessionAttributes map[string]interface{} `json:"sessionAttributes,omitempty"`
	Response          *Response              `json:"response"`
}

// Response contains the body of the response.
type Response struct {
	OutputSpeech     *OutputSpeech `json:"outputSpeech,omitempty"`
	Card             *Card         `json:"card,omitempty"`
	Reprompt         *Reprompt     `json:"reprompt,omitempty"`
	Directives       []interface{} `json:"directives,omitempty"`
	ShouldSessionEnd bool          `json:"shouldEndSession"`
}

// OutputSpeech contains the data the defines what Alexa should say to the user.
type OutputSpeech struct {
	Type string `json:"type"`
	Text string `json:"text,omitempty"`
	SSML string `json:"ssml,omitempty"`
}

// Card contains the data displayed to the user by the Alexa app.
type Card struct {
	Type    string `json:"type"`
	Title   string `json:"title,omitempty"`
	Content string `json:"content,omitempty"`
	Text    string `json:"text,omitempty"`
	Image   *Image `json:"image,omitempty"`
}

// Image provides URL(s) to the image to display in resposne to the request.
type Image struct {
	SmallImageURL string `json:"smallImageUrl,omitempty"`
	LargeImageURL string `json:"largeImageUrl,omitempty"`
}

// Reprompt contains data about whether Alexa should prompt the user for more data.
type Reprompt struct {
	OutputSpeech *OutputSpeech `json:"outputSpeech,omitempty"`
}

// AudioPlayerDirective contains device level instructions on how to handle the response.
type AudioPlayerDirective struct {
	Type         string     `json:"type"`
	PlayBehavior string     `json:"playBehavior,omitempty"`
	AudioItem    *AudioItem `json:"audioItem,omitempty"`
}

// AudioItem contains an audio Stream definition for playback.
type AudioItem struct {
	Stream Stream `json:"stream,omitempty"`
}

// Stream contains instructions on playing an audio stream.
type Stream struct {
	Token                string `json:"token"`
	URL                  string `json:"url"`
	OffsetInMilliseconds int    `json:"offsetInMilliseconds"`
}

// DialogDirective contains directives for use in Dialog prompts.
type DialogDirective struct {
	Type          string  `json:"type"`
	SlotToElicit  string  `json:"slotToElicit,omitempty"`
	SlotToConfirm string  `json:"slotToConfirm,omitempty"`
	UpdatedIntent *Intent `json:"updatedIntent,omitempty"`
}

// ProcessRequest handles a request passed from Alexa
func (alexa *Alexa) ProcessRequest(ctx context.Context, requestEnv *RequestEnvelope) (*ResponseEnvelope, error) {
	if requestEnv == nil {
		return nil, ErrRequestEnvelopeNil
	}

	if !alexa.IgnoreApplicationID {
		err := alexa.verifyApplicationID(requestEnv)
		if err != nil {
			return nil, err
		}
	}
	if !alexa.IgnoreTimestamp {
		err := alexa.verifyTimestamp(requestEnv)
		if err != nil {
			return nil, err
		}
	} else {
		log.Println("Ignoring timestamp verification.")
	}

	request := requestEnv.Request
	session := requestEnv.Session
	if session.Attributes.String == nil {
		session.Attributes.String = make(map[string]interface{})
	}
	context := requestEnv.Context

	responseEnv := &ResponseEnvelope{}
	responseEnv.Version = sdkVersion
	responseEnv.Response = &Response{}
	responseEnv.Response.ShouldSessionEnd = true // Set default value.

	response := responseEnv.Response

	// If it is a new session, invoke onSessionStarted
	if session.New {
		err := alexa.RequestHandler.OnSessionStarted(ctx, request, session, context, response)
		if err != nil {
			log.Println("Error handling OnSessionStarted.", err.Error())
			return nil, err
		}
	}

	switch requestEnv.Request.Type {
	case launchRequestName:
		err := alexa.RequestHandler.OnLaunch(ctx, request, session, context, response)
		if err != nil {
			log.Println("Error handling OnLaunch.", err.Error())
			return nil, err
		}
	case intentRequestName:
		err := alexa.RequestHandler.OnIntent(ctx, request, session, context, response)
		if err != nil {
			log.Println("Error handling OnIntent.", err.Error())
			return nil, err
		}
	case sessionEndedRequestName:
		err := alexa.RequestHandler.OnSessionEnded(ctx, request, session, context, response)
		if err != nil {
			log.Println("Error handling OnSessionEnded.", err.Error())
			return nil, err
		}
	}

	// Copy Session Attributes into ResponseEnvelope
	responseEnv.SessionAttributes = make(map[string]interface{})
	for n, v := range session.Attributes.String {
		fmt.Println("Setting ", n, "to", v)
		responseEnv.SessionAttributes[n] = v
	}

	return responseEnv, nil
}

// SetTimestampTolerance sets the maximum number of seconds to allow between
// the current time and the request Timestamp.  Default value is 150 seconds.
func (alexa *Alexa) SetTimestampTolerance(seconds int) {
	timestampTolerance = seconds
}

// SetSimpleCard creates a new simple card with the specified content.
func (r *Response) SetSimpleCard(title string, content string) {
	r.Card = &Card{Type: "Simple", Title: title, Content: content}
}

// SetStandardCard creates a new standard card with the specified content.
func (r *Response) SetStandardCard(title string, text string, smallImageURL string, largeImageURL string) {
	r.Card = &Card{Type: "Standard", Title: title, Text: text}
	r.Card.Image = &Image{SmallImageURL: smallImageURL, LargeImageURL: largeImageURL}
}

// SetLinkAccountCard creates a new LinkAccount card.
func (r *Response) SetLinkAccountCard() {
	r.Card = &Card{Type: "LinkAccount"}
}

// SetOutputText sets the OutputSpeech type to text and sets the value specified.
func (r *Response) SetOutputText(text string) {
	r.OutputSpeech = &OutputSpeech{Type: "PlainText", Text: text}
}

// SetOutputSSML sets the OutputSpeech type to ssml and sets the value specified.
func (r *Response) SetOutputSSML(ssml string) {
	r.OutputSpeech = &OutputSpeech{Type: "SSML", SSML: ssml}
}

// SetRepromptText created a Reprompt if needed and sets the OutputSpeech type to text and sets the value specified.
func (r *Response) SetRepromptText(text string) {
	if r.Reprompt == nil {
		r.Reprompt = &Reprompt{}
	}
	r.Reprompt.OutputSpeech = &OutputSpeech{Type: "PlainText", Text: text}
}

// SetRepromptSSML created a Reprompt if needed and sets the OutputSpeech type to ssml and sets the value specified.
func (r *Response) SetRepromptSSML(ssml string) {
	if r.Reprompt == nil {
		r.Reprompt = &Reprompt{}
	}
	r.Reprompt.OutputSpeech = &OutputSpeech{Type: "SSML", SSML: ssml}
}

// AddAudioPlayer adds an AudioPlayer directive to the Response.
func (r *Response) AddAudioPlayer(playerType, playBehavior, streamToken, url string, offsetInMilliseconds int) {
	d := AudioPlayerDirective{
		Type:         playerType,
		PlayBehavior: playBehavior,
		AudioItem: &AudioItem{
			Stream: Stream{
				Token:                streamToken,
				URL:                  url,
				OffsetInMilliseconds: offsetInMilliseconds,
			},
		},
	}
	r.Directives = append(r.Directives, d)
}

// AddDialogDirective adds a Dialog directive to the Response.
func (r *Response) AddDialogDirective(dialogType, slotToElicit, slotToConfirm string, intent *Intent) {
	d := DialogDirective{
		Type:          dialogType,
		SlotToElicit:  slotToElicit,
		SlotToConfirm: slotToConfirm,
		UpdatedIntent: intent,
	}
	r.Directives = append(r.Directives, d)
}

// verifyApplicationId verifies that the ApplicationID sent in the request
// matches the one configured for this skill.
func (alexa *Alexa) verifyApplicationID(request *RequestEnvelope) error {
	if request == nil {
		return ErrRequestEnvelopeNil
	}

	appID := alexa.ApplicationID
	requestAppID := request.Session.Application.ApplicationID
	if appID == "" {
		return errors.New("application ID was set to an empty string")
	}
	if requestAppID == "" {
		return errors.New("request Application ID was set to an empty string")
	}
	if appID != requestAppID {
		return errors.New("request Application ID does not match expected ApplicationId")
	}

	return nil
}

// verifyTimestamp compares the request timestamp to the current timestamp
// and returns an error if they are too far apart.
func (alexa *Alexa) verifyTimestamp(request *RequestEnvelope) error {
	if request == nil {
		return ErrRequestEnvelopeNil
	}

	timestamp, err := time.Parse(time.RFC3339, request.Request.Timestamp)
	if err != nil {
		return errors.New("Unable to parse request timestamp.  Err: " + err.Error())
	}
	now := time.Now()
	delta := now.Sub(timestamp)
	deltaSecsAbs := math.Abs(delta.Seconds())
	if deltaSecsAbs > float64(timestampTolerance) {
		return errors.New("Invalid Timestamp. The request timestap " + timestamp.String() + " was off the current time " + now.String() + " by more than " + strconv.FormatInt(int64(timestampTolerance), 10) + " seconds.")
	}

	return nil
}
<commit_msg>Fixed spelling errors.<commit_after>package alexa

import (
	"context"
	"errors"
	"fmt"
	"log"
	"math"
	"strconv"
	"time"
)

const sdkVersion = "1.0"
const launchRequestName = "LaunchRequest"
const intentRequestName = "IntentRequest"
const sessionEndedRequestName = "SessionEndedRequest"

var timestampTolerance = 150

// ErrRequestEnvelopeNil reports that the request envelope was nil
// there might be edge case which causes panic if for whatever reason this object is empty
var ErrRequestEnvelopeNil = errors.New("request envelope was nil")

// Alexa defines the primary interface to use to create an Alexa request handler.
type Alexa struct {
	ApplicationID       string
	RequestHandler      RequestHandler
	IgnoreApplicationID bool
	IgnoreTimestamp     bool
}

// RequestHandler defines the interface that must be implemented to handle
// Alexa Requests
type RequestHandler interface {
	OnSessionStarted(context.Context, *Request, *Session, *Context, *Response) error
	OnLaunch(context.Context, *Request, *Session, *Context, *Response) error
	OnIntent(context.Context, *Request, *Session, *Context, *Response) error
	OnSessionEnded(context.Context, *Request, *Session, *Context, *Response) error
}

// RequestEnvelope contains the data passed from Alexa to the request handler.
type RequestEnvelope struct {
	Version string   `json:"version"`
	Session *Session `json:"session"`
	Request *Request `json:"request"`
	Context *Context `json:"context"`
}

// Session contains the session data from the Alexa request.
type Session struct {
	New        bool   `json:"new"`
	SessionID  string `json:"sessionId"`
	Attributes struct {
		String map[string]interface{} `json:"string"`
	} `json:"attributes"`
	User struct {
		UserID      string `json:"userId"`
		AccessToken string `json:"accessToken"`
	} `json:"user"`
	Application struct {
		ApplicationID string `json:"applicationId"`
	} `json:"application"`
}

// Context contains the context data from the Alexa Request.
type Context struct {
	AudioPlayer struct {
		PlayerActivity string `json:"playerActivity"`
	} `json:"AudioPlayer"`
	Display struct {
		Token string `json:"token"`
	} `json:"Display"`
	System struct {
		Application struct {
			ApplicationID string `json:"applicationId"`
		} `json:"application"`
		User struct {
			UserID string `json:"userId"`
		} `json:"user"`
		Device struct {
			DeviceID            string `json:"deviceId"`
			SupportedInterfaces struct {
				AudioPlayer struct {
				} `json:"AudioPlayer"`
				Display struct {
					TemplateVersion string `json:"templateVersion"`
					MarkupVersion   string `json:"markupVersion"`
				} `json:"Display"`
			} `json:"supportedInterfaces"`
		} `json:"device"`
		APIEndpoint    string `json:"apiEndpoint"`
		APIAccessToken string `json:"apiAccessToken"`
	} `json:"System"`
}

// Request contains the data in the request within the main request.
type Request struct {
	Locale      string `json:"locale"`
	Timestamp   string `json:"timestamp"`
	Type        string `json:"type"`
	RequestID   string `json:"requestId"`
	DialogState string `json:"dialogState"`
	Intent      Intent `json:"intent"`
	Name        string `json:"name"`
}

// Intent contains the data about the Alexa Intent requested.
type Intent struct {
	Name               string                `json:"name"`
	ConfirmationStatus string                `json:"confirmationStatus,omitempty"`
	Slots              map[string]IntentSlot `json:"slots"`
}

// IntentSlot contains the data for one Slot
type IntentSlot struct {
	Name               string `json:"name"`
	ConfirmationStatus string `json:"confirmationStatus,omitempty"`
	Value              string `json:"value"`
	ID                 string `json:"id,omitempty"`
}

// ResponseEnvelope contains the Response and additional attributes.
type ResponseEnvelope struct {
	Version           string                 `json:"version"`
	SessionAttributes map[string]interface{} `json:"sessionAttributes,omitempty"`
	Response          *Response              `json:"response"`
}

// Response contains the body of the response.
type Response struct {
	OutputSpeech     *OutputSpeech `json:"outputSpeech,omitempty"`
	Card             *Card         `json:"card,omitempty"`
	Reprompt         *Reprompt     `json:"reprompt,omitempty"`
	Directives       []interface{} `json:"directives,omitempty"`
	ShouldSessionEnd bool          `json:"shouldEndSession"`
}

// OutputSpeech contains the data the defines what Alexa should say to the user.
type OutputSpeech struct {
	Type string `json:"type"`
	Text string `json:"text,omitempty"`
	SSML string `json:"ssml,omitempty"`
}

// Card contains the data displayed to the user by the Alexa app.
type Card struct {
	Type    string `json:"type"`
	Title   string `json:"title,omitempty"`
	Content string `json:"content,omitempty"`
	Text    string `json:"text,omitempty"`
	Image   *Image `json:"image,omitempty"`
}

// Image provides URL(s) to the image to display in resposne to the request.
type Image struct {
	SmallImageURL string `json:"smallImageUrl,omitempty"`
	LargeImageURL string `json:"largeImageUrl,omitempty"`
}

// Reprompt contains data about whether Alexa should prompt the user for more data.
type Reprompt struct {
	OutputSpeech *OutputSpeech `json:"outputSpeech,omitempty"`
}

// AudioPlayerDirective contains device level instructions on how to handle the response.
type AudioPlayerDirective struct {
	Type         string     `json:"type"`
	PlayBehavior string     `json:"playBehavior,omitempty"`
	AudioItem    *AudioItem `json:"audioItem,omitempty"`
}

// AudioItem contains an audio Stream definition for playback.
type AudioItem struct {
	Stream Stream `json:"stream,omitempty"`
}

// Stream contains instructions on playing an audio stream.
type Stream struct {
	Token                string `json:"token"`
	URL                  string `json:"url"`
	OffsetInMilliseconds int    `json:"offsetInMilliseconds"`
}

// DialogDirective contains directives for use in Dialog prompts.
type DialogDirective struct {
	Type          string  `json:"type"`
	SlotToElicit  string  `json:"slotToElicit,omitempty"`
	SlotToConfirm string  `json:"slotToConfirm,omitempty"`
	UpdatedIntent *Intent `json:"updatedIntent,omitempty"`
}

// ProcessRequest handles a request passed from Alexa
func (alexa *Alexa) ProcessRequest(ctx context.Context, requestEnv *RequestEnvelope) (*ResponseEnvelope, error) {
	if requestEnv == nil {
		return nil, ErrRequestEnvelopeNil
	}

	if !alexa.IgnoreApplicationID {
		err := alexa.verifyApplicationID(requestEnv)
		if err != nil {
			return nil, err
		}
	}
	if !alexa.IgnoreTimestamp {
		err := alexa.verifyTimestamp(requestEnv)
		if err != nil {
			return nil, err
		}
	} else {
		log.Println("Ignoring timestamp verification.")
	}

	request := requestEnv.Request
	session := requestEnv.Session
	if session.Attributes.String == nil {
		session.Attributes.String = make(map[string]interface{})
	}
	context := requestEnv.Context

	responseEnv := &ResponseEnvelope{}
	responseEnv.Version = sdkVersion
	responseEnv.Response = &Response{}
	responseEnv.Response.ShouldSessionEnd = true // Set default value.

	response := responseEnv.Response

	// If it is a new session, invoke onSessionStarted
	if session.New {
		err := alexa.RequestHandler.OnSessionStarted(ctx, request, session, context, response)
		if err != nil {
			log.Println("Error handling OnSessionStarted.", err.Error())
			return nil, err
		}
	}

	switch requestEnv.Request.Type {
	case launchRequestName:
		err := alexa.RequestHandler.OnLaunch(ctx, request, session, context, response)
		if err != nil {
			log.Println("Error handling OnLaunch.", err.Error())
			return nil, err
		}
	case intentRequestName:
		err := alexa.RequestHandler.OnIntent(ctx, request, session, context, response)
		if err != nil {
			log.Println("Error handling OnIntent.", err.Error())
			return nil, err
		}
	case sessionEndedRequestName:
		err := alexa.RequestHandler.OnSessionEnded(ctx, request, session, context, response)
		if err != nil {
			log.Println("Error handling OnSessionEnded.", err.Error())
			return nil, err
		}
	}

	// Copy Session Attributes into ResponseEnvelope
	responseEnv.SessionAttributes = make(map[string]interface{})
	for n, v := range session.Attributes.String {
		fmt.Println("Setting ", n, "to", v)
		responseEnv.SessionAttributes[n] = v
	}

	return responseEnv, nil
}

// SetTimestampTolerance sets the maximum number of seconds to allow between
// the current time and the request Timestamp.  Default value is 150 seconds.
func (alexa *Alexa) SetTimestampTolerance(seconds int) {
	timestampTolerance = seconds
}

// SetSimpleCard creates a new simple card with the specified content.
func (r *Response) SetSimpleCard(title string, content string) {
	r.Card = &Card{Type: "Simple", Title: title, Content: content}
}

// SetStandardCard creates a new standard card with the specified content.
func (r *Response) SetStandardCard(title string, text string, smallImageURL string, largeImageURL string) {
	r.Card = &Card{Type: "Standard", Title: title, Text: text}
	r.Card.Image = &Image{SmallImageURL: smallImageURL, LargeImageURL: largeImageURL}
}

// SetLinkAccountCard creates a new LinkAccount card.
func (r *Response) SetLinkAccountCard() {
	r.Card = &Card{Type: "LinkAccount"}
}

// SetOutputText sets the OutputSpeech type to text and sets the value specified.
func (r *Response) SetOutputText(text string) {
	r.OutputSpeech = &OutputSpeech{Type: "PlainText", Text: text}
}

// SetOutputSSML sets the OutputSpeech type to ssml and sets the value specified.
func (r *Response) SetOutputSSML(ssml string) {
	r.OutputSpeech = &OutputSpeech{Type: "SSML", SSML: ssml}
}

// SetRepromptText created a Reprompt if needed and sets the OutputSpeech type to text and sets the value specified.
func (r *Response) SetRepromptText(text string) {
	if r.Reprompt == nil {
		r.Reprompt = &Reprompt{}
	}
	r.Reprompt.OutputSpeech = &OutputSpeech{Type: "PlainText", Text: text}
}

// SetRepromptSSML created a Reprompt if needed and sets the OutputSpeech type to ssml and sets the value specified.
func (r *Response) SetRepromptSSML(ssml string) {
	if r.Reprompt == nil {
		r.Reprompt = &Reprompt{}
	}
	r.Reprompt.OutputSpeech = &OutputSpeech{Type: "SSML", SSML: ssml}
}

// AddAudioPlayer adds an AudioPlayer directive to the Response.
func (r *Response) AddAudioPlayer(playerType, playBehavior, streamToken, url string, offsetInMilliseconds int) {
	d := AudioPlayerDirective{
		Type:         playerType,
		PlayBehavior: playBehavior,
		AudioItem: &AudioItem{
			Stream: Stream{
				Token:                streamToken,
				URL:                  url,
				OffsetInMilliseconds: offsetInMilliseconds,
			},
		},
	}
	r.Directives = append(r.Directives, d)
}

// AddDialogDirective adds a Dialog directive to the Response.
func (r *Response) AddDialogDirective(dialogType, slotToElicit, slotToConfirm string, intent *Intent) {
	d := DialogDirective{
		Type:          dialogType,
		SlotToElicit:  slotToElicit,
		SlotToConfirm: slotToConfirm,
		UpdatedIntent: intent,
	}
	r.Directives = append(r.Directives, d)
}

// verifyApplicationId verifies that the ApplicationID sent in the request
// matches the one configured for this skill.
func (alexa *Alexa) verifyApplicationID(request *RequestEnvelope) error {
	if request == nil {
		return ErrRequestEnvelopeNil
	}

	appID := alexa.ApplicationID
	requestAppID := request.Session.Application.ApplicationID
	if appID == "" {
		return errors.New("application ID was set to an empty string")
	}
	if requestAppID == "" {
		return errors.New("request Application ID was set to an empty string")
	}
	if appID != requestAppID {
		return errors.New("request Application ID does not match expected ApplicationId")
	}

	return nil
}

// verifyTimestamp compares the request timestamp to the current timestamp
// and returns an error if they are too far apart.
func (alexa *Alexa) verifyTimestamp(request *RequestEnvelope) error {
	if request == nil {
		return ErrRequestEnvelopeNil
	}

	timestamp, err := time.Parse(time.RFC3339, request.Request.Timestamp)
	if err != nil {
		return errors.New("Unable to parse request timestamp.  Err: " + err.Error())
	}
	now := time.Now()
	delta := now.Sub(timestamp)
	deltaSecsAbs := math.Abs(delta.Seconds())
	if deltaSecsAbs > float64(timestampTolerance) {
		return errors.New("Invalid Timestamp. The request timestamp " + timestamp.String() + " was off the current time " + now.String() + " by more than " + strconv.FormatInt(int64(timestampTolerance), 10) + " seconds.")
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2012-2015, Jack Christopher Kastorff
// All rights reserved.
// BSD Licensed, see LICENSE for details.

// The alias package picks items from a discrete distribution
// efficiently using the alias method.
package alias

import (
	"errors"
	"math/rand"
)

type Alias struct {
	t []ipiece
}

type fpiece struct {
	p float64
	a uint32
}

type ipiece struct {
	p uint32 // [0,2^31)
	a uint32
}

// Create a new alias object.
// For example,
//   var v = alias.New([]float64{8,10,2})
// creates an alias that returns 0 40% of the time, 1 50% of the time, and
// 2 10% of the time.
func New(prob []float64) (*Alias, error) {

	// This implementation is based on
	// http://www.keithschwarz.com/darts-dice-coins/

	n := len(prob)

	if n < 1 {
		return nil, errors.New("Too few probabilities")
	}

	total := float64(0)
	for _, v := range prob {
		if v <= 0 {
			return nil, errors.New("A probability is non-positive")
		}
		total += v
	}

	var al Alias
	al.t = make([]ipiece, n)

	// Michael Vose's algorithm

	// "small" stack grows from the bottom of this array
	// "large" stack from the top
	twins := make([]fpiece, n)

	smTop := -1
	lgBot := n

	// invariant: smTop < lgBot, that is, the twin stacks don't collide

	mult := float64(n) / total
	for i, p := range prob {
		p = p * mult

		// push large items (>=1 probability) into the large stack
		// others in the small stack
		if p >= 1 {
			lgBot--
			twins[lgBot] = fpiece{p, uint32(i)}
		} else {
			smTop++
			twins[smTop] = fpiece{p, uint32(i)}
		}
	}

	for smTop >= 0 && lgBot < n {
		// pair off a small and large block, taking the chunk from the large block that's wanted
		l := twins[smTop]
		smTop--

		g := twins[lgBot]
		lgBot++

		al.t[l.a].p = uint32(l.p * (1<<31 - 1))
		al.t[l.a].a = g.a

		g.p = (g.p + l.p) - 1

		// put the rest of the large block back in a list
		if g.p < 1 {
			smTop++
			twins[smTop] = g
		} else {
			lgBot--
			twins[lgBot] = g
		}
	}

	// clear out any remaining blocks
	for i := n - 1; i >= lgBot; i-- {
		al.t[twins[i].a].p = 1<<31 - 1
	}

	// there shouldn't be anything here, but sometimes floating point
	// errors send a probability just under 1.
	for i := 0; i <= smTop; i++ {
		al.t[twins[i].a].p = 1<<31 - 1
	}

	return &al, nil
}

// Generates a random number according to the distribution using the rng passed.
func (al *Alias) Gen(rng *rand.Rand) uint32 {
	ri := uint32(rng.Int31())
	w := ri % uint32(len(al.t))
	if ri > al.t[w].p {
		return al.t[w].a
	}
	return w
}
<commit_msg>better errors in New<commit_after>// Copyright (c) 2012-2015, Jack Christopher Kastorff
// All rights reserved.
// BSD Licensed, see LICENSE for details.

// The alias package picks items from a discrete distribution
// efficiently using the alias method.
package alias

import (
	"errors"
	"math/rand"
)

type Alias struct {
	t []ipiece
}

type fpiece struct {
	p float64
	a uint32
}

type ipiece struct {
	p uint32 // [0,2^31)
	a uint32
}

// Create a new alias object.
// For example,
//   var v = alias.New([]float64{8,10,2})
// creates an alias that returns 0 40% of the time, 1 50% of the time, and
// 2 10% of the time.
func New(prob []float64) (*Alias, error) {

	// This implementation is based on
	// http://www.keithschwarz.com/darts-dice-coins/

	n := len(prob)

	if n < 1 {
		return nil, errors.New("too few probabilities")
	}

	if int(uint32(n)) != n {
		return nil, errors.New("too many probabilities")
	}

	total := float64(0)
	for _, v := range prob {
		if v <= 0 {
			return nil, errors.New("a probability is non-positive")
		}
		total += v
	}

	var al Alias
	al.t = make([]ipiece, n)

	// Michael Vose's algorithm

	// "small" stack grows from the bottom of this array
	// "large" stack from the top
	twins := make([]fpiece, n)

	smTop := -1
	lgBot := n

	// invariant: smTop < lgBot, that is, the twin stacks don't collide

	mult := float64(n) / total
	for i, p := range prob {
		p = p * mult

		// push large items (>=1 probability) into the large stack
		// others in the small stack
		if p >= 1 {
			lgBot--
			twins[lgBot] = fpiece{p, uint32(i)}
		} else {
			smTop++
			twins[smTop] = fpiece{p, uint32(i)}
		}
	}

	for smTop >= 0 && lgBot < n {
		// pair off a small and large block, taking the chunk from the large block that's wanted
		l := twins[smTop]
		smTop--

		g := twins[lgBot]
		lgBot++

		al.t[l.a].p = uint32(l.p * (1<<31 - 1))
		al.t[l.a].a = g.a

		g.p = (g.p + l.p) - 1

		// put the rest of the large block back in a list
		if g.p < 1 {
			smTop++
			twins[smTop] = g
		} else {
			lgBot--
			twins[lgBot] = g
		}
	}

	// clear out any remaining blocks
	for i := n - 1; i >= lgBot; i-- {
		al.t[twins[i].a].p = 1<<31 - 1
	}

	// there shouldn't be anything here, but sometimes floating point
	// errors send a probability just under 1.
	for i := 0; i <= smTop; i++ {
		al.t[twins[i].a].p = 1<<31 - 1
	}

	return &al, nil
}

// Generates a random number according to the distribution using the rng passed.
func (al *Alias) Gen(rng *rand.Rand) uint32 {
	ri := uint32(rng.Int31())
	w := ri % uint32(len(al.t))
	if ri > al.t[w].p {
		return al.t[w].a
	}
	return w
}
<|endoftext|>


<commit_before>package twitter

import (
	"context"
	"encoding/json"
	"net/url"
	"strconv"
)

// MentionsTimelineParams represents the query parameters for a
// /statuses/mentions_timeline.json request.
type MentionsTimelineParams struct {
	Count              int    `json:"count"`
	SinceID            string `json:"since_id"`
	MaxID              string `json:"max_id"`
	TrimUser           bool   `json:"trim_user"`
	ContributorDetails bool   `json:"contributor_details"`
	ExcludeEntities    bool   `json:"exclude_entities"`
}

// MentionsTimeline calls the Twitter /statuses/mentions_timeline.json endpoint.
func (c *Client) MentionsTimeline(ctx context.Context, params MentionsTimelineParams) (*TweetsResponse, error) {
	values := mentionsTimelineToQuery(params)
	resp, err := c.do(ctx, "GET", "https://api.twitter.com/1.1/statuses/mentions_timeline.json", values)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var tweets []Tweet
	err = json.NewDecoder(resp.Body).Decode(resp.Body)
	if err != nil {
		return nil, err
	}
	return &TweetsResponse{
		Tweets:    tweets,
		RateLimit: getRateLimit(resp.Header),
	}, nil
}

func mentionsTimelineToQuery(params MentionsTimelineParams) url.Values {
	values := url.Values{}
	if params.Count > 0 {
		values.Set("count", strconv.Itoa(params.Count))
	}
	if params.SinceID != "" {
		values.Set("since_id", params.SinceID)
	}
	if params.MaxID != "" {
		values.Set("max_id", params.MaxID)
	}
	if params.TrimUser {
		values.Set("trim_user", "true")
	}
	if params.ContributorDetails {
		values.Set("contributor_details", "true")
	}
	if params.ExcludeEntities {
		values.Set("include_entities", "false")
	}
	return values
}

// UserTimelineParams represents the query parameters for a
// /statuses/user_timeline.json request.
type UserTimelineParams struct {
	UserID             string `json:"user_id"`
	ScreenName         string `json:"screen_name"`
	SinceID            string `json:"since_id"`
	Count              int    `json:"count"`
	MaxID              string `json:"max_id"`
	TrimUser           bool   `json:"trim_user"`
	ExcludeReplies     bool   `json:"exclude_replies"`
	ContributorDetails bool   `json:"contributor_details"`
	ExcludeRTS         bool   `json:"exclude_rts"`
}

// UserTimeline calls the Twitter /statuses/user_timeline.json endpoint.
func (c *Client) UserTimeline(ctx context.Context, params UserTimelineParams) (*TweetsResponse, error) {
	values := userTimelineToQuery(params)
	resp, err := c.do(ctx, "GET", "https://api.twitter.com/1.1/statuses/user_timeline.json", values)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var tweets []Tweet
	err = json.NewDecoder(resp.Body).Decode(resp.Body)
	if err != nil {
		return nil, err
	}
	return &TweetsResponse{
		Tweets:    tweets,
		RateLimit: getRateLimit(resp.Header),
	}, nil
}

func userTimelineToQuery(params UserTimelineParams) url.Values {
	values := url.Values{}
	if params.UserID != "" {
		values.Set("user_id", params.UserID)
	}
	if params.ScreenName != "" {
		values.Set("screen_name", params.ScreenName)
	}
	if params.SinceID != "" {
		values.Set("since_id", params.SinceID)
	}
	if params.Count > 0 {
		values.Set("count", strconv.Itoa(params.Count))
	}
	if params.MaxID != "" {
		values.Set("max_id", params.MaxID)
	}
	if params.TrimUser {
		values.Set("trim_user", "true")
	}
	if params.ExcludeReplies {
		values.Set("exclude_replies", "true")
	}
	if params.ContributorDetails {
		values.Set("contributor_details", "true")
	}
	if params.ExcludeRTS {
		values.Set("include_rts", "false")
	}
	return values
}

// HomeTimelineParams represents the query parameters for a
// /statuses/home_timeline.json request.
type HomeTimelineParams struct {
	Count              int    `json:"count"`
	SinceID            string `json:"since_id"`
	MaxID              string `json:"max_id"`
	TrimUser           bool   `json:"trim_user"`
	ExcludeReplies     bool   `json:"exclude_replies"`
	ContributorDetails bool   `json:"contributor_details"`
	ExcludeEntities    bool   `json:"exclude_entities"`
}

// HomeTimeline calls the Twitter /statuses/home_timeline.json endpoint.
func (c *Client) HomeTimeline(ctx context.Context, params HomeTimelineParams) (*TweetsResponse, error) {
	values := homeTimelineToQuery(params)
	resp, err := c.do(ctx, "GET", "https://api.twitter.com/1.1/statuses/home_timeline.json", values)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var tweets []Tweet
	err = json.NewDecoder(resp.Body).Decode(resp.Body)
	if err != nil {
		return nil, err
	}
	return &TweetsResponse{
		Tweets:    tweets,
		RateLimit: getRateLimit(resp.Header),
	}, nil
}

func homeTimelineToQuery(params HomeTimelineParams) url.Values {
	values := url.Values{}
	if params.Count > 0 {
		values.Set("count", strconv.Itoa(params.Count))
	}
	if params.SinceID != "" {
		values.Set("since_id", params.SinceID)
	}
	if params.MaxID != "" {
		values.Set("max_id", params.MaxID)
	}
	if params.TrimUser {
		values.Set("trim_user", "true")
	}
	if params.ExcludeReplies {
		values.Set("exclude_replies", "true")
	}
	if params.ContributorDetails {
		values.Set("contributor_details", "true")
	}
	if params.ExcludeEntities {
		values.Set("include_entities", "false")
	}
	return values
}
<commit_msg>Add retweets of me endpoint<commit_after>package twitter

import (
	"context"
	"encoding/json"
	"net/url"
	"strconv"
)

// MentionsTimelineParams represents the query parameters for a
// /statuses/mentions_timeline.json request.
type MentionsTimelineParams struct {
	Count              int    `json:"count"`
	SinceID            string `json:"since_id"`
	MaxID              string `json:"max_id"`
	TrimUser           bool   `json:"trim_user"`
	ContributorDetails bool   `json:"contributor_details"`
	ExcludeEntities    bool   `json:"exclude_entities"`
}

// MentionsTimeline calls the Twitter /statuses/mentions_timeline.json endpoint.
func (c *Client) MentionsTimeline(ctx context.Context, params MentionsTimelineParams) (*TweetsResponse, error) {
	values := mentionsTimelineToQuery(params)
	resp, err := c.do(ctx, "GET", "https://api.twitter.com/1.1/statuses/mentions_timeline.json", values)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var tweets []Tweet
	err = json.NewDecoder(resp.Body).Decode(resp.Body)
	if err != nil {
		return nil, err
	}
	return &TweetsResponse{
		Tweets:    tweets,
		RateLimit: getRateLimit(resp.Header),
	}, nil
}

func mentionsTimelineToQuery(params MentionsTimelineParams) url.Values {
	values := url.Values{}
	if params.Count > 0 {
		values.Set("count", strconv.Itoa(params.Count))
	}
	if params.SinceID != "" {
		values.Set("since_id", params.SinceID)
	}
	if params.MaxID != "" {
		values.Set("max_id", params.MaxID)
	}
	if params.TrimUser {
		values.Set("trim_user", "true")
	}
	if params.ContributorDetails {
		values.Set("contributor_details", "true")
	}
	if params.ExcludeEntities {
		values.Set("include_entities", "false")
	}
	return values
}

// UserTimelineParams represents the query parameters for a
// /statuses/user_timeline.json request.
type UserTimelineParams struct {
	UserID             string `json:"user_id"`
	ScreenName         string `json:"screen_name"`
	SinceID            string `json:"since_id"`
	Count              int    `json:"count"`
	MaxID              string `json:"max_id"`
	TrimUser           bool   `json:"trim_user"`
	ExcludeReplies     bool   `json:"exclude_replies"`
	ContributorDetails bool   `json:"contributor_details"`
	ExcludeRTS         bool   `json:"exclude_rts"`
}

// UserTimeline calls the Twitter /statuses/user_timeline.json endpoint.
func (c *Client) UserTimeline(ctx context.Context, params UserTimelineParams) (*TweetsResponse, error) {
	values := userTimelineToQuery(params)
	resp, err := c.do(ctx, "GET", "https://api.twitter.com/1.1/statuses/user_timeline.json", values)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var tweets []Tweet
	err = json.NewDecoder(resp.Body).Decode(resp.Body)
	if err != nil {
		return nil, err
	}
	return &TweetsResponse{
		Tweets:    tweets,
		RateLimit: getRateLimit(resp.Header),
	}, nil
}

func userTimelineToQuery(params UserTimelineParams) url.Values {
	values := url.Values{}
	if params.UserID != "" {
		values.Set("user_id", params.UserID)
	}
	if params.ScreenName != "" {
		values.Set("screen_name", params.ScreenName)
	}
	if params.SinceID != "" {
		values.Set("since_id", params.SinceID)
	}
	if params.Count > 0 {
		values.Set("count", strconv.Itoa(params.Count))
	}
	if params.MaxID != "" {
		values.Set("max_id", params.MaxID)
	}
	if params.TrimUser {
		values.Set("trim_user", "true")
	}
	if params.ExcludeReplies {
		values.Set("exclude_replies", "true")
	}
	if params.ContributorDetails {
		values.Set("contributor_details", "true")
	}
	if params.ExcludeRTS {
		values.Set("include_rts", "false")
	}
	return values
}

// HomeTimelineParams represents the query parameters for a
// /statuses/home_timeline.json request.
type HomeTimelineParams struct {
	Count              int    `json:"count"`
	SinceID            string `json:"since_id"`
	MaxID              string `json:"max_id"`
	TrimUser           bool   `json:"trim_user"`
	ExcludeReplies     bool   `json:"exclude_replies"`
	ContributorDetails bool   `json:"contributor_details"`
	ExcludeEntities    bool   `json:"exclude_entities"`
}

// HomeTimeline calls the Twitter /statuses/home_timeline.json endpoint.
func (c *Client) HomeTimeline(ctx context.Context, params HomeTimelineParams) (*TweetsResponse, error) {
	values := homeTimelineToQuery(params)
	resp, err := c.do(ctx, "GET", "https://api.twitter.com/1.1/statuses/home_timeline.json", values)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var tweets []Tweet
	err = json.NewDecoder(resp.Body).Decode(resp.Body)
	if err != nil {
		return nil, err
	}
	return &TweetsResponse{
		Tweets:    tweets,
		RateLimit: getRateLimit(resp.Header),
	}, nil
}

func homeTimelineToQuery(params HomeTimelineParams) url.Values {
	values := url.Values{}
	if params.Count > 0 {
		values.Set("count", strconv.Itoa(params.Count))
	}
	if params.SinceID != "" {
		values.Set("since_id", params.SinceID)
	}
	if params.MaxID != "" {
		values.Set("max_id", params.MaxID)
	}
	if params.TrimUser {
		values.Set("trim_user", "true")
	}
	if params.ExcludeReplies {
		values.Set("exclude_replies", "true")
	}
	if params.ContributorDetails {
		values.Set("contributor_details", "true")
	}
	if params.ExcludeEntities {
		values.Set("include_entities", "false")
	}
	return values
}

// RetweetsOfMeParams represents the query parameters for a
// /statuses/retweets_of_me.json request.
type RetweetsOfMeParams struct {
	Count               int    `json:"count"`
	SinceID             string `json:"since_id"`
	MaxID               string `json:"max_id"`
	TrimUser            bool   `json:"trim_user"`
	ExcludeEntities     bool   `json:"exclude_entities"`
	ExcludeUserEntities bool   `json:"exclude_user_entities"`
}

// RetweetsOfMe calls the Twitter /statuses/retweets_of_me.json endpoint.
func (c *Client) RetweetsOfMe(ctx context.Context, params RetweetsOfMeParams) (*TweetsResponse, error) {
	values := retweetsOfMeToQuery(params)
	resp, err := c.do(ctx, "GET", "https://api.twitter.com/1.1/statuses/retweets_of_me.json", values)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var tweets []Tweet
	err = json.NewDecoder(resp.Body).Decode(resp.Body)
	if err != nil {
		return nil, err
	}
	return &TweetsResponse{
		Tweets:    tweets,
		RateLimit: getRateLimit(resp.Header),
	}, nil
}

func retweetsOfMeToQuery(params RetweetsOfMeParams) url.Values {
	values := url.Values{}
	if params.Count > 0 {
		values.Set("count", strconv.Itoa(params.Count))
	}
	if params.SinceID != "" {
		values.Set("since_id", params.SinceID)
	}
	if params.MaxID != "" {
		values.Set("max_id", params.MaxID)
	}
	if params.TrimUser {
		values.Set("trim_user", "true")
	}
	if params.ExcludeEntities {
		values.Set("include_entities", "false")
	}
	if params.ExcludeUserEntities {
		values.Set("include_user_entities", "false")
	}
	return values
}
<|endoftext|>


<commit_before>// Package stop represents a pattern for types that need to do some work
// when stopping. The Stop method returns a stop.Chan on which
// stop.Done is passed when the operation has completed.
//
// Stopper types when implementing the Stop method should use MakeChan
// to create and return a stop channel, and pass stop.Done on the
// channel once stopping has completed:
//     func Stop() stop.Chan {
//       c := stop.MakeChan()
//       go func(){
//         // TODO: tear stuff down
//         c <- stop.Done
//       }()
//       return c
//     }
//
// Stopper types can be stopped in the following ways:
//     // stop and forget
//     t.Stop()
//
//     // stop and wait
//     <-t.Stop()
//
//     // stop, do more work, then wait
//     stopped := t.Stop();
//     // do more work
//     <-stopped
//
//     // stop and timeout after 1 second
//     select {
//     case <-t.Stop():
//     case <-time.After(1 * time.Second):
//     }
//
//     // stop.All is the same as calling Stop() so
//     // all above patterns also work on many Stopper types,
//     // for example; stop and wait for many things:
//     <-stop.All(t1, t2, t3)
package stop
<commit_msg>added stop.Now example<commit_after>// Package stop represents a pattern for types that need to do some work
// when stopping. The Stop method returns a stop.Chan on which
// stop.Done is passed when the operation has completed.
//
// Stopper types when implementing the Stop method should use MakeChan
// to create and return a stop channel, and pass stop.Done on the
// channel once stopping has completed:
//     func (t Type) Stop() stop.Chan {
//       c := stop.MakeChan()
//       go func(){
//         // TODO: tear stuff down
//         c <- stop.Done
//       }()
//       return c
//     }
//
// If Stopper types do not need to do any background work, stop.Now() can
// be returned, for example:
//     func (t Type) Stop() stop.Chan {
//       t.stopped = true
//       return stop.Now()
//     }
//
// Stopper types can be stopped in the following ways:
//     // stop and forget
//     t.Stop()
//
//     // stop and wait
//     <-t.Stop()
//
//     // stop, do more work, then wait
//     stopped := t.Stop();
//     // do more work
//     <-stopped
//
//     // stop and timeout after 1 second
//     select {
//     case <-t.Stop():
//     case <-time.After(1 * time.Second):
//     }
//
//     // stop.All is the same as calling Stop() so
//     // all above patterns also work on many Stopper types,
//     // for example; stop and wait for many things:
//     <-stop.All(t1, t2, t3)
package stop
<|endoftext|>


<commit_before>package service

/*
The service.go defines what to do for each API-call. This part of the service
runs on the node.
*/

import (
	"time"

	"errors"
	"sync"

	"github.com/dedis/cothority_template"
	"github.com/dedis/cothority_template/protocol"
	"gopkg.in/dedis/onet.v1"
	"gopkg.in/dedis/onet.v1/log"
	"gopkg.in/dedis/onet.v1/network"
)

// Used for tests
var templateID onet.ServiceID

func init() {
	var err error
	templateID, err = onet.RegisterNewService(template.ServiceName, newService)
	log.ErrFatal(err)
	network.RegisterMessage(&storage{})
}

// Service is our template-service
type Service struct {
	// We need to embed the ServiceProcessor, so that incoming messages
	// are correctly handled.
	*onet.ServiceProcessor
	path string

	storage *storage
}

// storageID reflects the data we're storing - we could store more
// than one structure.
const storageID = "main"

// storage is used to save our data.
type storage struct {
	Count int
	sync.Mutex
}

// ClockRequest starts a template-protocol and returns the run-time.
func (s *Service) ClockRequest(req *template.ClockRequest) (*template.ClockResponse, onet.ClientError) {
	s.storage.Lock()
	s.storage.Count++
	s.storage.Unlock()
	s.save()
	tree := req.Roster.GenerateNaryTreeWithRoot(2, s.ServerIdentity())
	pi, err := s.CreateProtocol(protocol.Name, tree)
	if err != nil {
		return nil, onet.NewClientError(err)
	}
	start := time.Now()
	pi.Start()
	resp := &template.ClockResponse{
		Children: <-pi.(*protocol.Template).ChildCount,
	}
	resp.Time = time.Now().Sub(start).Seconds()
	return resp, nil
}

// CountRequest returns the number of instantiations of the protocol.
func (s *Service) CountRequest(req *template.CountRequest) (*template.CountResponse, onet.ClientError) {
	s.storage.Lock()
	defer s.storage.Unlock()
	return &template.CountResponse{s.storage.Count}, nil
}

// NewProtocol is called on all nodes of a Tree (except the root, since it is
// the one starting the protocol) so it's the Service that will be called to
// generate the PI on all others node.
// If you use CreateProtocolOnet, this will not be called, as the Onet will
// instantiate the protocol on its own. If you need more control at the
// instantiation of the protocol, use CreateProtocolService, and you can
// give some extra-configuration to your protocol in here.
func (s *Service) NewProtocol(tn *onet.TreeNodeInstance, conf *onet.GenericConfig) (onet.ProtocolInstance, error) {
	log.Lvl3("Not templated yet")
	return nil, nil
}

// saves all skipblocks.
func (s *Service) save() {
	s.storage.Lock()
	defer s.storage.Unlock()
	err := s.Save(storageID, s.storage)
	if err != nil {
		log.Error("Couldn't save file:", err)
	}
}

// Tries to load the configuration and updates the data in the service
// if it finds a valid config-file.
func (s *Service) tryLoad() error {
	s.storage = &storage{}
	if !s.DataAvailable(storageID) {
		return nil
	}
	msg, err := s.Load(storageID)
	if err != nil {
		return err
	}
	var ok bool
	s.storage, ok = msg.(*storage)
	if !ok {
		return errors.New("Data of wrong type")
	}
	return nil
}

// newTemplate receives the context and a path where it can write its
// configuration, if desired. As we don't know when the service will exit,
// we need to save the configuration on our own from time to time.
func newService(c *onet.Context) onet.Service {
	s := &Service{
		ServiceProcessor: onet.NewServiceProcessor(c),
	}
	if err := s.RegisterHandlers(s.ClockRequest, s.CountRequest); err != nil {
		log.ErrFatal(err, "Couldn't register messages")
	}
	if err := s.tryLoad(); err != nil {
		log.Error(err)
	}
	return s
}
<commit_msg>Update service.go<commit_after>package service

/*
The service.go defines what to do for each API-call. This part of the service
runs on the node.
*/

import (
	"time"

	"errors"
	"sync"

	"github.com/dedis/cothority_template"
	"github.com/dedis/cothority_template/protocol"
	"gopkg.in/dedis/onet.v1"
	"gopkg.in/dedis/onet.v1/log"
	"gopkg.in/dedis/onet.v1/network"
)

// Used for tests
var templateID onet.ServiceID

func init() {
	var err error
	templateID, err = onet.RegisterNewService(template.ServiceName, newService)
	log.ErrFatal(err)
	network.RegisterMessage(&storage{})
}

// Service is our template-service
type Service struct {
	// We need to embed the ServiceProcessor, so that incoming messages
	// are correctly handled.
	*onet.ServiceProcessor
	path string

	storage *storage
}

// storageID reflects the data we're storing - we could store more
// than one structure.
const storageID = "main"

// storage is used to save our data.
type storage struct {
	Count int
	sync.Mutex
}

// ClockRequest starts a template-protocol and returns the run-time.
func (s *Service) ClockRequest(req *template.ClockRequest) (*template.ClockResponse, onet.ClientError) {
	s.storage.Lock()
	s.storage.Count++
	s.storage.Unlock()
	s.save()
	tree := req.Roster.GenerateNaryTreeWithRoot(2, s.ServerIdentity())
	pi, err := s.CreateProtocol(protocol.Name, tree)
	if err != nil {
		return nil, onet.NewClientError(err)
	}
	start := time.Now()
	pi.Start()
	resp := &template.ClockResponse{
		Children: <-pi.(*protocol.Template).ChildCount,
	}
	resp.Time = time.Now().Sub(start).Seconds()
	return resp, nil
}

// CountRequest returns the number of instantiations of the protocol.
func (s *Service) CountRequest(req *template.CountRequest) (*template.CountResponse, onet.ClientError) {
	s.storage.Lock()
	defer s.storage.Unlock()
	return &template.CountResponse{s.storage.Count}, nil
}

// NewProtocol is called on all nodes of a Tree (except the root, since it is
// the one starting the protocol) so it's the Service that will be called to
// generate the PI on all others node.
// If you use CreateProtocolOnet, this will not be called, as the Onet will
// instantiate the protocol on its own. If you need more control at the
// instantiation of the protocol, use CreateProtocolService, and you can
// give some extra-configuration to your protocol in here.
func (s *Service) NewProtocol(tn *onet.TreeNodeInstance, conf *onet.GenericConfig) (onet.ProtocolInstance, error) {
	log.Lvl3("Not templated yet")
	return nil, nil
}

// saves all skipblocks.
func (s *Service) save() {
	s.storage.Lock()
	defer s.storage.Unlock()
	err := s.Save(storageID, s.storage)
	if err != nil {
		log.Error("Couldn't save file:", err)
	}
}

// Tries to load the configuration and updates the data in the service
// if it finds a valid config-file.
func (s *Service) tryLoad() error {
	s.storage = &storage{}
	if !s.DataAvailable(storageID) {
		return nil
	}
	msg, err := s.Load(storageID)
	if err != nil {
		return err
	}
	var ok bool
	s.storage, ok = msg.(*storage)
	if !ok {
		return errors.New("Data of wrong type")
	}
	return nil
}

// newService receives the context and a path where it can write its
// configuration, if desired. As we don't know when the service will exit,
// we need to save the configuration on our own from time to time.
func newService(c *onet.Context) onet.Service {
	s := &Service{
		ServiceProcessor: onet.NewServiceProcessor(c),
	}
	if err := s.RegisterHandlers(s.ClockRequest, s.CountRequest); err != nil {
		log.ErrFatal(err, "Couldn't register messages")
	}
	if err := s.tryLoad(); err != nil {
		log.Error(err)
	}
	return s
}
<|endoftext|>


<commit_before>/*
Package structor contains interface and default implementation of EL
(expression language) evaluator which evaluates EL expressions within tags of
the struct, using optional additional struct as an extra context.

Basic idea is to use simple expression language within Go struct tags to
compute struct fields based on other fields or provided additional context.

Due usage of reflection and EL interpretation, this package is hardly suitable
for tasks, requiring high performance, but rather intended to be used during
application setup or in cases where high performance is not an ultimate goal.

See tests for examples of usage with xpath, regexp, goquery, encryption,
reading from files, shell invocation, etc.
*/
package structor

import (
	"fmt"
	"reflect"
	"unsafe"

	multierror "github.com/hashicorp/go-multierror"

	"github.com/nikolay-turpitko/structor/el"
	"github.com/nikolay-turpitko/structor/funcs/use"
	"github.com/nikolay-turpitko/structor/scanner"
)

// Evaluator is an interface of evaluator, which gets structure and extra
// context as input, iterates over `s`'s fields and evaluate expression tag on
// every field.
type Evaluator interface {
	Eval(s, extra interface{}) error
}

// Interpreters is a map of tag names to el.Interpreters.  Used to register
// different interpreters for different tag names.
//
// Only first tag name on the struct field is currently recognized and
// processed. So, only one EL expression per structure field, but different
// fields of the same structure can be processed by different interpreters.
type Interpreters map[string]el.Interpreter

// WholeTag constant can be used as tag name in the Interpreters to indicate
// that whole tag value should be passed to the interpreter.
//
// Registering interpreter to the whole tag value conflicts with any other
// usage of the struct's tag, but can be convenient to simplify complex EL
// expressions with quotes (regexp, for example).
//
// WholeTag interpreter is probed after all other registered interpreters.
const WholeTag = ""

// NewEvaluatorWithOptions returns Evaluator with desired settings.
//
// Only first tag with EL will be recognized and used (only one
// expression per struct field). Different fields of the same struct can be
// processed using different EL interpreters.
//
//  scanner - is a scanner implementation to be used to scan tags.
//  interpreters - is a map of registered tag names to EL interpreters.
//  options - is an Options structure.
func NewEvaluatorWithOptions(
	scanner scanner.Scanner,
	interpreters Interpreters,
	options Options) Evaluator {
	if len(interpreters) == 0 {
		panic("no interpreters registered")
	}
	return &evaluator{scanner, interpreters, options}
}

// NewEvaluator returns Evaluator with desired settings.
// It invokes NewEvaluatorWithOptions with default options.
func NewEvaluator(
	scanner scanner.Scanner,
	interpreters Interpreters) Evaluator {
	return NewEvaluatorWithOptions(scanner, interpreters, Options{})
}

// NewDefaultEvaluator returns default Evaluator implementation. Default
// implementation uses tag "eval" for expressions and EL interpreter, based on
// `"text/template"`.
//
//  funcs - custom functions, available for interpreter;
func NewDefaultEvaluator(funcs use.FuncMap) Evaluator {
	return NewEvaluator(
		scanner.Default,
		Interpreters{
			"eval": &el.DefaultInterpreter{Funcs: funcs},
		})
}

// NewNonmutatingEvaluator creates Evaluator implementation which does not
// change original structure (does not save evaluated results) itself.  Though,
// interpreters can change structures' fields as a side effect.  In this case
// Evaluator can be used as a visitor of fields with tags for which it have
// registered interpreters.  It will invoke registered interpreter for field
// with corresponded tag.  Interpreter can then manipulate it's own state or
// el.Context.  For example, it can store processing results into context's
// Extra field.
//
// See NewEvaluator() for additional information.
func NewNonmutatingEvaluator(
	scanner scanner.Scanner,
	interpreters Interpreters) Evaluator {
	return NewEvaluatorWithOptions(scanner, interpreters, Options{NonMutating: true})
}

type evaluator struct {
	scanner      scanner.Scanner
	interpreters Interpreters
	options      Options
}

// Options is an options to create Evaluator.
type Options struct {

	// NonMutating creates non-mutating Evaluator, see NewNonmutatingEvaluator.
	NonMutating bool

	// EvalEmptyTags causes Evaluator to invoke Interpreter for fields with
	// empty tags.
	EvalEmptyTags bool
}

func (ev evaluator) Eval(s, extra interface{}) error {
	v := reflect.ValueOf(s)
	t := v.Type()
	k := t.Kind()
	prev := v
	for v.IsValid() && (k == reflect.Interface || k == reflect.Ptr) {
		prev = v
		v = v.Elem()
		if v.IsValid() {
			t = v.Type()
			k = t.Kind()
		}
		if prev == v {
			break
		}
	}
	if k != reflect.Struct || !v.CanSet() {
		return fmt.Errorf("structor: %T: not a settable struct", s)
	}
	return multierror.Prefix(
		ev.eval(
			"",
			nil,
			reflect.ValueOf(s),
			&el.Context{
				Struct:   s,
				Extra:    extra,
				EvalExpr: ev.evalExpr,
				LongName: fmt.Sprintf("%T", s),
			}), "structor:")
}

func (ev evaluator) evalExpr(
	intrprName, expr string,
	ctx *el.Context) (interface{}, error) {
	intrpr, ok := ev.interpreters[intrprName]
	if !ok {
		return nil, fmt.Errorf("unknown interpreter: %s", intrprName)
	}
	return intrpr.Execute(expr, ctx)
}

func (ev evaluator) eval(
	expr string,
	interpreter el.Interpreter,
	v reflect.Value,
	ctx *el.Context) (err error) {
	// Note: only errors returned by recursive call should not be prefixed.
	defer func() {
		if r := recover(); r != nil {
			var ok bool
			if err, ok = r.(error); !ok {
				err = multierror.Prefix(
					fmt.Errorf("%v", r),
					fmt.Sprintf("<<%s>>", ctx.LongName))
			}
		}
	}()
	if !v.IsValid() {
		return nil
	}
	t := v.Type()
	k := t.Kind()
	if v.CanAddr() && !v.CanSet() {
		// https://stackoverflow.com/a/43918797/2063744
		v = reflect.NewAt(t, unsafe.Pointer(v.UnsafeAddr())).Elem()
	}
	elV, elT, elK := v, t, k
	for elV.IsValid() && (elK == reflect.Interface || elK == reflect.Ptr) {
		v, t, k = elV, elT, elK
		elV = v.Elem()
		if elV.IsValid() {
			elT = elV.Type()
			elK = elT.Kind()
		}
		if v == elV {
			break
		}
	}
	if elV.IsValid() {
		if elV.CanAddr() && !elV.CanSet() {
			// https://stackoverflow.com/a/43918797/2063744
			elV = reflect.NewAt(elT, unsafe.Pointer(elV.UnsafeAddr())).Elem()
		}
		elT = elV.Type()
		elK = elT.Kind()
	}
	var merr *multierror.Error
	var ctxSub interface{}
	if (expr != "" || ev.options.EvalEmptyTags) && interpreter != nil {
		ctx.Val = nil
		if elV.IsValid() {
			ctx.Val = elV.Interface()
		}
		if result, err := interpreter.Execute(expr, ctx); err != nil {
			merr = multierror.Append(
				merr,
				multierror.Prefix(err, fmt.Sprintf("<<%s>>", ctx.LongName)))
		} else {
			ctxSub = result
			if !ev.options.NonMutating {
				if result == nil {
					if v.IsValid() {
						v.Set(reflect.Zero(t))
					}
				} else {
					vnv := reflect.ValueOf(result)
					if vnv.Type().ConvertibleTo(t) || elK != reflect.Struct {
						// Try to convert, it may give a panic with suitable
						// message.
						v.Set(vnv.Convert(t))
					}
				}
			}
		}
	}
	switch elK {
	case reflect.Slice, reflect.Array:
		prevLongName := ctx.LongName
		for i, l := 0, elV.Len(); i < l; i++ {
			v := elV.Index(i)
			ctx.Name = v.Type().Name()
			ctx.LongName = fmt.Sprintf("%s[%d]", ctx.LongName, i)
			ctx.Tags = nil
			err := ev.eval("", nil, v, ctx)
			ctx.LongName = prevLongName
			merr = multierror.Append(merr, err)
		}
	case reflect.Struct:
		ctx.Sub = ctxSub
		prevLongName := ctx.LongName
		for i, l := 0, elV.NumField(); i < l; i++ {
			tf := elT.Field(i)
			tags, err := ev.scanner.Tags(tf.Tag)
			if err != nil {
				merr = multierror.Append(
					merr,
					multierror.Prefix(err, fmt.Sprintf("<<%s>>", ctx.LongName)))
				break
			}
			expr := ""
			var interpreter el.Interpreter
			for k, t := range tags {
				if i, ok := ev.interpreters[k]; ok {
					delete(tags, k)
					expr, interpreter = t, i
				}
			}
			if i, ok := ev.interpreters[WholeTag]; ok && interpreter == nil {
				delete(tags, WholeTag)
				expr, interpreter = string(tf.Tag), i
			}
			ctx.Name = tf.Name
			ctx.LongName = fmt.Sprintf("%s.%s", ctx.LongName, tf.Name)
			ctx.Tags = tags
			v := elV.Field(i)
			err = ev.eval(expr, interpreter, v, ctx)
			ctx.LongName = prevLongName
			merr = multierror.Append(merr, err)
		}
	case reflect.Map:
		prevLongName := ctx.LongName
		for _, key := range elV.MapKeys() {
			v := elV.MapIndex(key)
			ctx.Name = v.Type().Name()
			ctx.LongName = fmt.Sprintf("%s[%v]", ctx.LongName, key)
			ctx.Tags = nil
			err := ev.eval("", nil, v, ctx)
			ctx.LongName = prevLongName
			merr = multierror.Append(merr, err)
		}
	}
	return merr.ErrorOrNil()
}

// AddressableCopy returns a pointer to the addressable copy of the struct.
func AddressableCopy(s interface{}) interface{} {
	v := reflect.Indirect(reflect.ValueOf(s))
	s2 := reflect.New(v.Type())
	s2.Elem().Set(v)
	return s2.Interface()
}

// DeepCopy returns a pointer to the deep copy of the struct.
// FIXME: not fully implemented, just a first lame draft.
func DeepCopy(s interface{}) interface{} {
	c := AddressableCopy(s)
	ev := NewEvaluatorWithOptions(
		scanner.Default,
		Interpreters{
			WholeTag: el.InterpreterFunc(func(s string, ctx *el.Context) (interface{}, error) {
				v := reflect.ValueOf(ctx.Val)
				t, k := v.Type(), v.Kind()
				switch k {
				case reflect.Slice:
					cp := reflect.MakeSlice(t, v.Len(), v.Cap())
					reflect.Copy(cp, v)
					return cp.Interface(), nil
				case reflect.Map:
					cp := reflect.MakeMapWithSize(t, v.Len())
					for _, key := range v.MapKeys() {
						v := reflect.Indirect(v.MapIndex(key))
						v2 := reflect.New(v.Type())
						v2.Elem().Set(v)
						cp.SetMapIndex(key, v2)
					}
					return cp.Interface(), nil
				}
				return ctx.Val, nil
			}),
		},
		Options{EvalEmptyTags: true})
	err := ev.Eval(c, nil)
	if err != nil {
		panic(err)
	}
	return c
}
<commit_msg>Fix for Go < 1.9<commit_after>/*
Package structor contains interface and default implementation of EL
(expression language) evaluator which evaluates EL expressions within tags of
the struct, using optional additional struct as an extra context.

Basic idea is to use simple expression language within Go struct tags to
compute struct fields based on other fields or provided additional context.

Due usage of reflection and EL interpretation, this package is hardly suitable
for tasks, requiring high performance, but rather intended to be used during
application setup or in cases where high performance is not an ultimate goal.

See tests for examples of usage with xpath, regexp, goquery, encryption,
reading from files, shell invocation, etc.
*/
package structor

import (
	"fmt"
	"reflect"
	"unsafe"

	multierror "github.com/hashicorp/go-multierror"

	"github.com/nikolay-turpitko/structor/el"
	"github.com/nikolay-turpitko/structor/funcs/use"
	"github.com/nikolay-turpitko/structor/scanner"
)

// Evaluator is an interface of evaluator, which gets structure and extra
// context as input, iterates over `s`'s fields and evaluate expression tag on
// every field.
type Evaluator interface {
	Eval(s, extra interface{}) error
}

// Interpreters is a map of tag names to el.Interpreters.  Used to register
// different interpreters for different tag names.
//
// Only first tag name on the struct field is currently recognized and
// processed. So, only one EL expression per structure field, but different
// fields of the same structure can be processed by different interpreters.
type Interpreters map[string]el.Interpreter

// WholeTag constant can be used as tag name in the Interpreters to indicate
// that whole tag value should be passed to the interpreter.
//
// Registering interpreter to the whole tag value conflicts with any other
// usage of the struct's tag, but can be convenient to simplify complex EL
// expressions with quotes (regexp, for example).
//
// WholeTag interpreter is probed after all other registered interpreters.
const WholeTag = ""

// NewEvaluatorWithOptions returns Evaluator with desired settings.
//
// Only first tag with EL will be recognized and used (only one
// expression per struct field). Different fields of the same struct can be
// processed using different EL interpreters.
//
//  scanner - is a scanner implementation to be used to scan tags.
//  interpreters - is a map of registered tag names to EL interpreters.
//  options - is an Options structure.
func NewEvaluatorWithOptions(
	scanner scanner.Scanner,
	interpreters Interpreters,
	options Options) Evaluator {
	if len(interpreters) == 0 {
		panic("no interpreters registered")
	}
	return &evaluator{scanner, interpreters, options}
}

// NewEvaluator returns Evaluator with desired settings.
// It invokes NewEvaluatorWithOptions with default options.
func NewEvaluator(
	scanner scanner.Scanner,
	interpreters Interpreters) Evaluator {
	return NewEvaluatorWithOptions(scanner, interpreters, Options{})
}

// NewDefaultEvaluator returns default Evaluator implementation. Default
// implementation uses tag "eval" for expressions and EL interpreter, based on
// `"text/template"`.
//
//  funcs - custom functions, available for interpreter;
func NewDefaultEvaluator(funcs use.FuncMap) Evaluator {
	return NewEvaluator(
		scanner.Default,
		Interpreters{
			"eval": &el.DefaultInterpreter{Funcs: funcs},
		})
}

// NewNonmutatingEvaluator creates Evaluator implementation which does not
// change original structure (does not save evaluated results) itself.  Though,
// interpreters can change structures' fields as a side effect.  In this case
// Evaluator can be used as a visitor of fields with tags for which it have
// registered interpreters.  It will invoke registered interpreter for field
// with corresponded tag.  Interpreter can then manipulate it's own state or
// el.Context.  For example, it can store processing results into context's
// Extra field.
//
// See NewEvaluator() for additional information.
func NewNonmutatingEvaluator(
	scanner scanner.Scanner,
	interpreters Interpreters) Evaluator {
	return NewEvaluatorWithOptions(scanner, interpreters, Options{NonMutating: true})
}

type evaluator struct {
	scanner      scanner.Scanner
	interpreters Interpreters
	options      Options
}

// Options is an options to create Evaluator.
type Options struct {

	// NonMutating creates non-mutating Evaluator, see NewNonmutatingEvaluator.
	NonMutating bool

	// EvalEmptyTags causes Evaluator to invoke Interpreter for fields with
	// empty tags.
	EvalEmptyTags bool
}

func (ev evaluator) Eval(s, extra interface{}) error {
	v := reflect.ValueOf(s)
	t := v.Type()
	k := t.Kind()
	prev := v
	for v.IsValid() && (k == reflect.Interface || k == reflect.Ptr) {
		prev = v
		v = v.Elem()
		if v.IsValid() {
			t = v.Type()
			k = t.Kind()
		}
		if prev == v {
			break
		}
	}
	if k != reflect.Struct || !v.CanSet() {
		return fmt.Errorf("structor: %T: not a settable struct", s)
	}
	return multierror.Prefix(
		ev.eval(
			"",
			nil,
			reflect.ValueOf(s),
			&el.Context{
				Struct:   s,
				Extra:    extra,
				EvalExpr: ev.evalExpr,
				LongName: fmt.Sprintf("%T", s),
			}), "structor:")
}

func (ev evaluator) evalExpr(
	intrprName, expr string,
	ctx *el.Context) (interface{}, error) {
	intrpr, ok := ev.interpreters[intrprName]
	if !ok {
		return nil, fmt.Errorf("unknown interpreter: %s", intrprName)
	}
	return intrpr.Execute(expr, ctx)
}

func (ev evaluator) eval(
	expr string,
	interpreter el.Interpreter,
	v reflect.Value,
	ctx *el.Context) (err error) {
	// Note: only errors returned by recursive call should not be prefixed.
	defer func() {
		if r := recover(); r != nil {
			var ok bool
			if err, ok = r.(error); !ok {
				err = multierror.Prefix(
					fmt.Errorf("%v", r),
					fmt.Sprintf("<<%s>>", ctx.LongName))
			}
		}
	}()
	if !v.IsValid() {
		return nil
	}
	t := v.Type()
	k := t.Kind()
	if v.CanAddr() && !v.CanSet() {
		// https://stackoverflow.com/a/43918797/2063744
		v = reflect.NewAt(t, unsafe.Pointer(v.UnsafeAddr())).Elem()
	}
	elV, elT, elK := v, t, k
	for elV.IsValid() && (elK == reflect.Interface || elK == reflect.Ptr) {
		v, t, k = elV, elT, elK
		elV = v.Elem()
		if elV.IsValid() {
			elT = elV.Type()
			elK = elT.Kind()
		}
		if v == elV {
			break
		}
	}
	if elV.IsValid() {
		if elV.CanAddr() && !elV.CanSet() {
			// https://stackoverflow.com/a/43918797/2063744
			elV = reflect.NewAt(elT, unsafe.Pointer(elV.UnsafeAddr())).Elem()
		}
		elT = elV.Type()
		elK = elT.Kind()
	}
	var merr *multierror.Error
	var ctxSub interface{}
	if (expr != "" || ev.options.EvalEmptyTags) && interpreter != nil {
		ctx.Val = nil
		if elV.IsValid() {
			ctx.Val = elV.Interface()
		}
		if result, err := interpreter.Execute(expr, ctx); err != nil {
			merr = multierror.Append(
				merr,
				multierror.Prefix(err, fmt.Sprintf("<<%s>>", ctx.LongName)))
		} else {
			ctxSub = result
			if !ev.options.NonMutating {
				if result == nil {
					if v.IsValid() {
						v.Set(reflect.Zero(t))
					}
				} else {
					vnv := reflect.ValueOf(result)
					if vnv.Type().ConvertibleTo(t) || elK != reflect.Struct {
						// Try to convert, it may give a panic with suitable
						// message.
						v.Set(vnv.Convert(t))
					}
				}
			}
		}
	}
	switch elK {
	case reflect.Slice, reflect.Array:
		prevLongName := ctx.LongName
		for i, l := 0, elV.Len(); i < l; i++ {
			v := elV.Index(i)
			ctx.Name = v.Type().Name()
			ctx.LongName = fmt.Sprintf("%s[%d]", ctx.LongName, i)
			ctx.Tags = nil
			err := ev.eval("", nil, v, ctx)
			ctx.LongName = prevLongName
			merr = multierror.Append(merr, err)
		}
	case reflect.Struct:
		ctx.Sub = ctxSub
		prevLongName := ctx.LongName
		for i, l := 0, elV.NumField(); i < l; i++ {
			tf := elT.Field(i)
			tags, err := ev.scanner.Tags(tf.Tag)
			if err != nil {
				merr = multierror.Append(
					merr,
					multierror.Prefix(err, fmt.Sprintf("<<%s>>", ctx.LongName)))
				break
			}
			expr := ""
			var interpreter el.Interpreter
			for k, t := range tags {
				if i, ok := ev.interpreters[k]; ok {
					delete(tags, k)
					expr, interpreter = t, i
				}
			}
			if i, ok := ev.interpreters[WholeTag]; ok && interpreter == nil {
				delete(tags, WholeTag)
				expr, interpreter = string(tf.Tag), i
			}
			ctx.Name = tf.Name
			ctx.LongName = fmt.Sprintf("%s.%s", ctx.LongName, tf.Name)
			ctx.Tags = tags
			v := elV.Field(i)
			err = ev.eval(expr, interpreter, v, ctx)
			ctx.LongName = prevLongName
			merr = multierror.Append(merr, err)
		}
	case reflect.Map:
		prevLongName := ctx.LongName
		for _, key := range elV.MapKeys() {
			v := elV.MapIndex(key)
			ctx.Name = v.Type().Name()
			ctx.LongName = fmt.Sprintf("%s[%v]", ctx.LongName, key)
			ctx.Tags = nil
			err := ev.eval("", nil, v, ctx)
			ctx.LongName = prevLongName
			merr = multierror.Append(merr, err)
		}
	}
	return merr.ErrorOrNil()
}

// AddressableCopy returns a pointer to the addressable copy of the struct.
func AddressableCopy(s interface{}) interface{} {
	v := reflect.Indirect(reflect.ValueOf(s))
	s2 := reflect.New(v.Type())
	s2.Elem().Set(v)
	return s2.Interface()
}

// DeepCopy returns a pointer to the deep copy of the struct.
// FIXME: not fully implemented, just a first lame draft.
func DeepCopy(s interface{}) interface{} {
	c := AddressableCopy(s)
	ev := NewEvaluatorWithOptions(
		scanner.Default,
		Interpreters{
			WholeTag: el.InterpreterFunc(func(s string, ctx *el.Context) (interface{}, error) {
				v := reflect.ValueOf(ctx.Val)
				t, k := v.Type(), v.Kind()
				switch k {
				case reflect.Slice:
					cp := reflect.MakeSlice(t, v.Len(), v.Cap())
					reflect.Copy(cp, v)
					return cp.Interface(), nil
				case reflect.Map:
					cp := reflect.MakeMap(t)
					for _, key := range v.MapKeys() {
						v := reflect.Indirect(v.MapIndex(key))
						v2 := reflect.New(v.Type())
						v2.Elem().Set(v)
						cp.SetMapIndex(key, v2)
					}
					return cp.Interface(), nil
				}
				return ctx.Val, nil
			}),
		},
		Options{EvalEmptyTags: true})
	err := ev.Eval(c, nil)
	if err != nil {
		panic(err)
	}
	return c
}
<|endoftext|>