<commit_before>/*
Copyright (c) 2016, UPMC Enterprises
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name UPMC Enterprises nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL UPMC ENTERPRISES BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
*/

package main

import (
	"fmt"
	"os"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ecr"
	"github.com/golang/glog"
	flag "github.com/spf13/pflag"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/unversioned"
	kubectl_util "k8s.io/kubernetes/pkg/kubectl/cmd/util"
)

var (
	flags                = flag.NewFlagSet("", flag.ContinueOnError)
	cluster              = flags.Bool("use-kubernetes-cluster-service", true, `If true, use the built in kubernetes cluster for creating the client`)
	argAWSAccountID      = flags.String("aws-account", "", `AWS Account ID`)
	argKubecfgFile       = flags.String("kubecfg-file", "", `Location of kubecfg file for access to kubernetes master service; --kube_master_url overrides the URL part of this; if neither this nor --kube_master_url are provided, defaults to service account tokens`)
	argKubeMasterURL     = flags.String("kube-master-url", "", `URL to reach kubernetes master. Env variables in this flag will be expanded.`)
	argDefaultSecretName = flags.String("default-secret-name", "awsecr-creds", `Default secret name`)
	argDefaultNamespace  = flags.String("default-namespace", "default", `Default namespace`)
	argAWSRegion         = flags.String("aws-region", "us-east-1", `Default namespace`)
	argRefreshMinutes    = flags.Int("refresh-mins", 715, `Default time to wait before refreshing (11 hours 55 mins)`)
)

var kubeClient *unversioned.Client

func getECRAuthorizationKey() (token *ecr.AuthorizationData, err error) {
	svc := ecr.New(session.New(), aws.NewConfig().WithRegion(*argAWSRegion))

	params := &ecr.GetAuthorizationTokenInput{
		RegistryIds: []*string{
			aws.String(*argAWSAccountID),
		},
	}

	resp, err := svc.GetAuthorizationToken(params)

	if err != nil {
		// Print the error, cast err to awserr.Error to get the Code and
		// Message from an error.
		fmt.Println(err.Error())
		return
	}

	token = resp.AuthorizationData[0]

	return
}

// Gets the default secret from the api
func getSecret() (*api.Secret, error) {
	secret, err := kubeClient.Secrets(*argDefaultNamespace).Get(*argDefaultSecretName)
	return secret, err
}

func getSecretObj(dockerConfigJSONContent []byte) *api.Secret {
	secret := &api.Secret{
		ObjectMeta: api.ObjectMeta{
			Name: *argDefaultSecretName,
		},
		Data: map[string][]byte{
			".dockerconfigjson": dockerConfigJSONContent,
		},
		Type: "kubernetes.io/dockerconfigjson",
	}

	return secret
}

func process() {
	// Get new token to seed the secret
	dockerJSONTemplate := `{"auths":{"%v":{"auth":"%v","email":"none"}}}`

	newToken, _ := getECRAuthorizationKey()
	authToken := fmt.Sprintf(dockerJSONTemplate, *newToken.ProxyEndpoint, *newToken.AuthorizationToken)
	newSecret := getSecretObj([]byte(authToken))

	// Check if the default secret exists
	_, err := getSecret()

	if err != nil {
		// Secret not found, create
		kubeClient.Secrets(*argDefaultNamespace).Create(newSecret)
	} else {
		// Existing secret needs updated
		kubeClient.Secrets(*argDefaultNamespace).Update(newSecret)
	}

	// Get all namespaces
	namespaces, err := kubeClient.Namespaces().List(api.ListOptions{})

	for _, namespace := range namespaces.Items {

		if namespace.GetName() == "kube-system" {
			continue
		}

		// Check if ServiceAccount has the imagePullSecrets
		serviceAccount, err := kubeClient.ServiceAccounts(namespace.GetName()).Get("default")

		if err != nil {
			glog.Fatalf("Could get find default service account!")
		}

		serviceAccount.ImagePullSecrets = []api.LocalObjectReference{{Name: *argDefaultSecretName}}
		_, err = kubeClient.ServiceAccounts(namespace.GetName()).Update(serviceAccount)

		if err != nil {
			fmt.Println("err: ", err)
		}

	}
}

func main() {
	glog.Info("Starting up...")

	clientConfig := kubectl_util.DefaultClientConfig(flags)
	flags.Parse(os.Args)

	glog.Info("Using AWS Account: ", *argAWSAccountID)
	glog.Info("Refresh Interval (minutes): ", *argRefreshMinutes)

	var err error

	if *cluster {
		if kubeClient, err = unversioned.NewInCluster(); err != nil {
			glog.Fatalf("Failed to create client: %v", err)
		}
	} else {
		config, err := clientConfig.ClientConfig()
		if err != nil {
			glog.Fatalf("error connecting to the client: %v", err)
		}
		kubeClient, err = unversioned.New(config)
	}

	tick := time.Tick(time.Duration(*argRefreshMinutes) * time.Minute)

	// Process once now, then wait for tick
	process()

	for {
		select {
		case <-tick:
			glog.Info("Refreshing credentials...")
			process()
		}
	}

}
<commit_msg>Create secret for each namespace instead of just default<commit_after>/*
Copyright (c) 2016, UPMC Enterprises
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name UPMC Enterprises nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL UPMC ENTERPRISES BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
*/

package main

import (
	"fmt"
	"os"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ecr"
	"github.com/golang/glog"
	flag "github.com/spf13/pflag"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/unversioned"
	kubectl_util "k8s.io/kubernetes/pkg/kubectl/cmd/util"
)

var (
	flags                = flag.NewFlagSet("", flag.ContinueOnError)
	cluster              = flags.Bool("use-kubernetes-cluster-service", true, `If true, use the built in kubernetes cluster for creating the client`)
	argAWSAccountID      = flags.String("aws-account", "", `AWS Account ID`)
	argKubecfgFile       = flags.String("kubecfg-file", "", `Location of kubecfg file for access to kubernetes master service; --kube_master_url overrides the URL part of this; if neither this nor --kube_master_url are provided, defaults to service account tokens`)
	argKubeMasterURL     = flags.String("kube-master-url", "", `URL to reach kubernetes master. Env variables in this flag will be expanded.`)
	argDefaultSecretName = flags.String("default-secret-name", "awsecr-creds", `Default secret name`)
	argDefaultNamespace  = flags.String("default-namespace", "default", `Default namespace`)
	argAWSRegion         = flags.String("aws-region", "us-east-1", `Default namespace`)
	argRefreshMinutes    = flags.Int("refresh-mins", 715, `Default time to wait before refreshing (11 hours 55 mins)`)
)

var kubeClient *unversioned.Client

func getECRAuthorizationKey() (token *ecr.AuthorizationData, err error) {
	svc := ecr.New(session.New(), aws.NewConfig().WithRegion(*argAWSRegion))

	params := &ecr.GetAuthorizationTokenInput{
		RegistryIds: []*string{
			aws.String(*argAWSAccountID),
		},
	}

	resp, err := svc.GetAuthorizationToken(params)

	if err != nil {
		// Print the error, cast err to awserr.Error to get the Code and
		// Message from an error.
		fmt.Println(err.Error())
		return
	}

	token = resp.AuthorizationData[0]

	return
}

// Gets the default secret from the api
func getSecret(namespace string) (*api.Secret, error) {
	secret, err := kubeClient.Secrets(namespace).Get(*argDefaultSecretName)
	return secret, err
}

func getSecretObj(dockerConfigJSONContent []byte) *api.Secret {
	secret := &api.Secret{
		ObjectMeta: api.ObjectMeta{
			Name: *argDefaultSecretName,
		},
		Data: map[string][]byte{
			".dockerconfigjson": dockerConfigJSONContent,
		},
		Type: "kubernetes.io/dockerconfigjson",
	}

	return secret
}

func process() {
	// Get new token to seed the secret
	dockerJSONTemplate := `{"auths":{"%v":{"auth":"%v","email":"none"}}}`

	newToken, _ := getECRAuthorizationKey()
	authToken := fmt.Sprintf(dockerJSONTemplate, *newToken.ProxyEndpoint, *newToken.AuthorizationToken)
	newSecret := getSecretObj([]byte(authToken))

	// Get all namespaces
	namespaces, _ := kubeClient.Namespaces().List(api.ListOptions{})

	for _, namespace := range namespaces.Items {

		if namespace.GetName() == "kube-system" {
			continue
		}

		// Check if the secret exists for the namespace
		_, err := getSecret(namespace.GetName())

		if err != nil {
			// Secret not found, create
			kubeClient.Secrets(namespace.GetName()).Create(newSecret)
		} else {
			// Existing secret needs updated
			kubeClient.Secrets(namespace.GetName()).Update(newSecret)
		}

		// Check if ServiceAccount has the imagePullSecrets
		serviceAccount, err := kubeClient.ServiceAccounts(namespace.GetName()).Get("default")

		if err != nil {
			glog.Fatalf("Could get find default service account!")
		}

		serviceAccount.ImagePullSecrets = []api.LocalObjectReference{{Name: *argDefaultSecretName}}
		_, err = kubeClient.ServiceAccounts(namespace.GetName()).Update(serviceAccount)

		if err != nil {
			fmt.Println("err: ", err)
		}

	}
}

func main() {
	glog.Info("Starting up...")

	clientConfig := kubectl_util.DefaultClientConfig(flags)
	flags.Parse(os.Args)

	glog.Info("Using AWS Account: ", *argAWSAccountID)
	glog.Info("Refresh Interval (minutes): ", *argRefreshMinutes)

	var err error

	if *cluster {
		if kubeClient, err = unversioned.NewInCluster(); err != nil {
			glog.Fatalf("Failed to create client: %v", err)
		}
	} else {
		config, err := clientConfig.ClientConfig()
		if err != nil {
			glog.Fatalf("error connecting to the client: %v", err)
		}
		kubeClient, err = unversioned.New(config)
	}

	tick := time.Tick(time.Duration(*argRefreshMinutes) * time.Minute)

	// Process once now, then wait for tick
	process()

	for {
		select {
		case <-tick:
			glog.Info("Refreshing credentials...")
			process()
		}
	}

}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"log"
	"net/http"
	"strings"
)

type pageResult struct {
	Error error
}

func redirectToFile(w http.ResponseWriter, r *http.Request, release Release) {
	url := ""
	if release.DownloadUrl() != "" {
		url = release.DownloadUrl()
	}
	url = "/file/" + release.Path()
	log.Println("Redirecting to: " + url)
	http.Redirect(w, r, url, http.StatusFound)
}

func downloadPage(url, file string) pageResult {
	log.Println("File doesn't exist yet. Downloading: " + url)
	res, err := http.Get(url)
	if err != nil {
		return pageResult{Error: err}
	}

	if file != "" {
		body, err := ioutil.ReadAll(res.Body)
		if err != nil {
			return pageResult{Error: err}
		}
		err = ioutil.WriteFile(file, body, 0644)
		if err != nil {
			return pageResult{Error: err}
		}
	}
	return pageResult{Error: nil}
}

// If a file exists, just serve it directly. Otherwise, download, then serve.
func cachedFileHandler(w http.ResponseWriter, r *http.Request) {
	paths := strings.Split(r.URL.Path, "/")
	name := paths[len(paths)-1]
	log.Println("Request for cached file: " + name)
	release := Release{
		Name:     r.FormValue("package"),
		Version:  r.FormValue("release"),
		DataDir:  Config.DataDir,
		Filename: name,
	}

	if release.Exists() {
		log.Println(release.Filename + " already exists. Redirecting to download.")
		redirectToFile(w, r, release)
		return
	}

	original := r.FormValue("original")
	res := downloadPage(original, release.ReleaseFilePath())

	if res.Error != nil {
		http.Error(w, "Unable to download page", http.StatusInternalServerError)
		return
	}

	redirectToFile(w, r, release)
}
<commit_msg>Don't override the download url<commit_after>package main

import (
	"io/ioutil"
	"log"
	"net/http"
	"strings"
)

type pageResult struct {
	Error error
}

func redirectToFile(w http.ResponseWriter, r *http.Request, release Release) {
	url := ""
	if release.DownloadUrl() != "" {
		println("DownloadUrl exists")
		url = release.DownloadUrl()
	} else {
		url = "/file/" + release.Path()
	}
	log.Println("Redirecting to: " + url)
	http.Redirect(w, r, url, http.StatusFound)
}

func downloadPage(url, file string) pageResult {
	log.Println("File doesn't exist yet. Downloading: " + url)
	res, err := http.Get(url)
	if err != nil {
		return pageResult{Error: err}
	}

	if file != "" {
		body, err := ioutil.ReadAll(res.Body)
		if err != nil {
			return pageResult{Error: err}
		}
		err = ioutil.WriteFile(file, body, 0644)
		if err != nil {
			return pageResult{Error: err}
		}
	}
	return pageResult{Error: nil}
}

// If a file exists, just serve it directly. Otherwise, download, then serve.
func cachedFileHandler(w http.ResponseWriter, r *http.Request) {
	paths := strings.Split(r.URL.Path, "/")
	name := paths[len(paths)-1]
	log.Println("Request for cached file: " + name)
	release := Release{
		Name:     r.FormValue("package"),
		Version:  r.FormValue("release"),
		DataDir:  Config.DataDir,
		Filename: name,
	}

	if release.Exists() {
		log.Println(release.Filename + " already exists. Redirecting to download.")
		redirectToFile(w, r, release)
		return
	}

	original := r.FormValue("original")
	res := downloadPage(original, release.ReleaseFilePath())

	if res.Error != nil {
		http.Error(w, "Unable to download page", http.StatusInternalServerError)
		return
	}

	redirectToFile(w, r, release)
}
<|endoftext|>


<commit_before>package gopush

import (
	"fmt"
	"io"
	"io/ioutil"
	"strconv"
	"strings"
)

// Options holds the configuration options for a Push Interpreter
type Options struct {
	// When TRUE (which is the default), code passed to the top level of the
	// interpreter will be pushed onto the CODE stack prior to execution.
	TopLevelPushCode bool

	// When TRUE, the CODE stack will be popped at the end of top level
	// calls to the interpreter. The default is FALSE.
	TopLevelPopCode bool

	// The maximum number of points that will be executed in a single
	// top-level call to the interpreter.
	EvalPushLimit int

	// The probability that the selection of the ephemeral random NAME
	// constant for inclusion in randomly generated code will produce a new
	// name (rather than a name that was previously generated).
	NewERCNameProbabilty float64

	// The maximum number of points that can occur in any program on the
	// CODE stack. Instructions that would violate this limit act as NOOPs.
	MaxPointsInProgram int

	// The maximum number of points in an expression produced by the
	// CODE.RAND instruction.
	MaxPointsInRandomExpression int64

	// The maximum FLOAT that will be produced as an ephemeral random FLOAT
	// constant or from a call to FLOAT.RAND.
	MaxRandomFloat float64

	// The minimum FLOAT that will be produced as an ephemeral random FLOAT
	// constant or from a call to FLOAT.RAND.
	MinRandomFloat float64

	// The maximum INTEGER that will be produced as an ephemeral random
	// INTEGER constant or from a call to INTEGER.RAND.
	MaxRandomInteger int64

	// The minimum INTEGER that will be produced as an ephemeral random
	// INTEGER constant or from a call to INTEGER.RAND.
	MinRandomInteger int64

	// When TRUE the interpreter will print out the stacks after every
	// executed instruction
	Tracing bool

	// A seed for the random number generator.
	RandomSeed int64

	// AllowedTypes lists the types (stacks) that are allowed
	AllowedTypes map[string]struct{}

	// AllowedInstructions lists the instructions that are allowed
	AllowedInstructions map[string]struct{}
}

// defaultConfigFile holds the textual representation of the default
// configuration
var defaultConfigFile = `
## PARAMETER SETTINGS
TOP-LEVEL-PUSH-CODE TRUE
TOP-LEVEL-POP-CODE FALSE

EVALPUSH-LIMIT 1000

NEW-ERC-NAME-PROBABILITY 0.001

MAX-POINTS-IN-PROGRAM 100
MAX-POINTS-IN-RANDOM-EXPRESSIONS 25

MAX-RANDOM-FLOAT 1.0
MIN-RANDOM-FLOAT -1.0

MAX-RANDOM-INTEGER 10
MIN-RANDOM-INTEGER -10

TRACING FALSE

## TYPES
type BOOLEAN
type CODE
type FLOAT
type INTEGER

## INSTRUCTIONS
instruction BOOLEAN.=
instruction BOOLEAN.AND
instruction BOOLEAN.DEFINE
instruction BOOLEAN.DUP
instruction BOOLEAN.FLUSH
instruction BOOLEAN.FROMFLOAT
instruction BOOLEAN.FROMINTEGER
instruction BOOLEAN.NOT
instruction BOOLEAN.OR
instruction BOOLEAN.POP
instruction BOOLEAN.RAND
instruction BOOLEAN.ROT
instruction BOOLEAN.SHOVE
instruction BOOLEAN.STACKDEPTH
instruction BOOLEAN.SWAP
instruction BOOLEAN.YANK
instruction BOOLEAN.YANKDUP

instruction CODE.=
instruction CODE.APPEND
instruction CODE.ATOM
instruction CODE.CAR
instruction CODE.CDR
instruction CODE.CONS
instruction CODE.CONTAINER
instruction CODE.CONTAINS
instruction CODE.DEFINE
instruction CODE.DEFINITION
instruction CODE.DISCREPANCY
instruction CODE.DO
instruction CODE.DO*
instruction CODE.DO*COUNT
instruction CODE.DO*RANGE
instruction CODE.DO*TIMES
instruction CODE.DUP
instruction CODE.EXTRACT
instruction CODE.FLUSH
instruction CODE.FROMBOOLEAN
instruction CODE.FROMFLOAT
instruction CODE.FROMINTEGER
instruction CODE.FROMNAME
instruction CODE.IF
instruction CODE.INSERT
instruction CODE.INSTRUCTIONS
instruction CODE.LENGTH
instruction CODE.LIST
instruction CODE.MEMBER
instruction CODE.NOOP
instruction CODE.NTH
instruction CODE.NTHCDR
instruction CODE.NULL
instruction CODE.POP
instruction CODE.POSITION
instruction CODE.QUOTE
instruction CODE.RAND
instruction CODE.ROT
instruction CODE.SHOVE
instruction CODE.SIZE
instruction CODE.STACKDEPTH
instruction CODE.SUBST
instruction CODE.SWAP
instruction CODE.YANK
instruction CODE.YANKDUP

instruction EXEC.=
instruction EXEC.DEFINE
instruction EXEC.DO*COUNT
instruction EXEC.DO*RANGE
instruction EXEC.DO*TIMES
instruction EXEC.DUP
instruction EXEC.FLUSH
instruction EXEC.IF
instruction EXEC.K
instruction EXEC.POP
instruction EXEC.ROT
instruction EXEC.S
instruction EXEC.SHOVE
instruction EXEC.STACKDEPTH
instruction EXEC.SWAP
instruction EXEC.Y
instruction EXEC.YANK
instruction EXEC.YANKDUP

instruction FLOAT.%
instruction FLOAT.*
instruction FLOAT.+
instruction FLOAT.-
instruction FLOAT./
instruction FLOAT.<
instruction FLOAT.=
instruction FLOAT.>
instruction FLOAT.COS
instruction FLOAT.DEFINE
instruction FLOAT.DUP
instruction FLOAT.FLUSH
instruction FLOAT.FROMBOOLEAN
instruction FLOAT.FROMINTEGER
instruction FLOAT.MAX
instruction FLOAT.MIN
instruction FLOAT.POP
instruction FLOAT.RAND
instruction FLOAT.ROT
instruction FLOAT.SHOVE
instruction FLOAT.SIN
instruction FLOAT.STACKDEPTH
instruction FLOAT.SWAP
instruction FLOAT.TAN
instruction FLOAT.YANK
instruction FLOAT.YANKDUP

instruction INTEGER.%
instruction INTEGER.*
instruction INTEGER.+
instruction INTEGER.-
instruction INTEGER./
instruction INTEGER.<
instruction INTEGER.=
instruction INTEGER.>
instruction INTEGER.DEFINE
instruction INTEGER.DUP
instruction INTEGER.FLUSH
instruction INTEGER.FROMBOOLEAN
instruction INTEGER.FROMFLOAT
instruction INTEGER.MAX
instruction INTEGER.MIN
instruction INTEGER.POP
instruction INTEGER.RAND
instruction INTEGER.ROT
instruction INTEGER.SHOVE
instruction INTEGER.STACKDEPTH
instruction INTEGER.SWAP
instruction INTEGER.YANK
instruction INTEGER.YANKDUP

instruction NAME.=
instruction NAME.DUP
instruction NAME.FLUSH
instruction NAME.POP
instruction NAME.QUOTE
instruction NAME.RAND
instruction NAME.RANDBOUNDNAME
instruction NAME.ROT
instruction NAME.SHOVE
instruction NAME.STACKDEPTH
instruction NAME.SWAP
instruction NAME.YANK
instruction NAME.YANKDUP
`

// DefaultOptions contains the default configuration for a Push Interpreter.
var DefaultOptions, _ = parseOptions(defaultConfigFile)

func parseOptions(s string) (Options, error) {
	o := Options{
		AllowedInstructions:         make(map[string]struct{}),
		AllowedTypes:                make(map[string]struct{}),
		EvalPushLimit:               1000,
		MaxPointsInProgram:          100,
		MaxPointsInRandomExpression: 25,
		MaxRandomFloat:              1.0,
		MaxRandomInteger:            10,
		MinRandomFloat:              -1.0,
		MinRandomInteger:            -10,
		NewERCNameProbabilty:        0.001,
		RandomSeed:                  0,
		TopLevelPopCode:             false,
		TopLevelPushCode:            true,
		Tracing:                     false,
	}

	var parameter, setting string

	for len(s) > 0 {

		parameter, setting, s = getParameterSettingPair(s)

		if parameter == "" {
			break
		}

		if setting == "" {
			return Options{}, fmt.Errorf("expected setting to follow %q", parameter)
		}

		switch strings.ToLower(parameter) {
		case "type":
			t := strings.ToLower(setting)
			switch t {
			case "boolean":
				fallthrough
			case "code":
				fallthrough
			case "float":
				fallthrough
			case "integer":
				o.AllowedTypes[t] = struct{}{}

			// NAME and EXEC stacks always exist, so they are a
			// no-op with the type parameter
			case "name":
			case "exec":

			default:
				return Options{}, fmt.Errorf("unknown type: %q", setting)
			}

		case "instruction":
			instr := strings.ToLower(setting)
			o.AllowedInstructions[instr] = struct{}{}

		case "min-random-integer":
			i, err := strconv.ParseInt(setting, 10, 64)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as integer", setting)
			}
			o.MinRandomInteger = i

		case "max-random-integer":
			i, err := strconv.ParseInt(setting, 10, 64)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as integer", setting)
			}
			o.MinRandomInteger = i

		case "min-random-float":
			f, err := strconv.ParseFloat(setting, 64)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as float", setting)
			}
			o.MinRandomFloat = f

		case "max-random-float":
			f, err := strconv.ParseFloat(setting, 64)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as float", setting)
			}
			o.MaxRandomFloat = f

		case "max-points-in-random-expressions":
			i, err := strconv.ParseInt(setting, 10, 64)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as integer", setting)
			}

			if i < 1 {
				return Options{}, fmt.Errorf("MAX-POINTS-IN-RANDOM-EXPRESSIONS must be at least 1, got %v", i)
			}

			o.MaxPointsInRandomExpression = i

		case "max-points-in-program":
			i, err := strconv.ParseInt(setting, 10, 64)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as integer", setting)
			}

			if i < 1 {
				return Options{}, fmt.Errorf("MAX-POINTS-IN-PROGRAM must be at least 1, got %v", i)
			}

			o.MaxPointsInProgram = int(i)

		case "evalpush-limit":
			i, err := strconv.ParseInt(setting, 10, 64)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as integer", setting)
			}

			if i < 1 {
				return Options{}, fmt.Errorf("EVALPUSH-LIMIT must be at least 1, got %v", i)
			}

			o.EvalPushLimit = int(i)

		case "new-erc-name-probability":
			f, err := strconv.ParseFloat(setting, 64)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as float", setting)
			}

			if f < 0 || f > 1 {
				return Options{}, fmt.Errorf("NEW-ERC-NAME-PROBABILITY must be between 0 and 1 inclusive, got %v", f)
			}

			o.NewERCNameProbabilty = f

		case "random-seed":
			i, err := strconv.ParseInt(setting, 10, 64)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as integer", setting)
			}

			o.RandomSeed = i

		case "top-level-push-code":
			b, err := strconv.ParseBool(setting)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as boolean", setting)
			}

			o.TopLevelPushCode = b

		case "top-level-pop-code":
			b, err := strconv.ParseBool(setting)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as boolean", setting)
			}

			o.TopLevelPopCode = b

		case "tracing":
			b, err := strconv.ParseBool(setting)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as boolean", setting)
			}

			o.Tracing = b
		default:
			return Options{}, fmt.Errorf("unknown parameter %q", parameter)
		}
	}

	return o, nil
}

// ReadOptions reads the options from the given reader
func ReadOptions(r io.Reader) (Options, error) {
	b, err := ioutil.ReadAll(r)
	if err != nil {
		return Options{}, err
	}

	s := string(b)

	o, err := parseOptions(s)
	if err != nil {
		return Options{}, err
	}

	return o, nil
}
<commit_msg>Make ParseOptions public and add ReadOptionsFromFile<commit_after>package gopush

import (
	"fmt"
	"io"
	"io/ioutil"
	"strconv"
	"strings"
)

// Options holds the configuration options for a Push Interpreter
type Options struct {
	// When TRUE (which is the default), code passed to the top level of the
	// interpreter will be pushed onto the CODE stack prior to execution.
	TopLevelPushCode bool

	// When TRUE, the CODE stack will be popped at the end of top level
	// calls to the interpreter. The default is FALSE.
	TopLevelPopCode bool

	// The maximum number of points that will be executed in a single
	// top-level call to the interpreter.
	EvalPushLimit int

	// The probability that the selection of the ephemeral random NAME
	// constant for inclusion in randomly generated code will produce a new
	// name (rather than a name that was previously generated).
	NewERCNameProbabilty float64

	// The maximum number of points that can occur in any program on the
	// CODE stack. Instructions that would violate this limit act as NOOPs.
	MaxPointsInProgram int

	// The maximum number of points in an expression produced by the
	// CODE.RAND instruction.
	MaxPointsInRandomExpression int64

	// The maximum FLOAT that will be produced as an ephemeral random FLOAT
	// constant or from a call to FLOAT.RAND.
	MaxRandomFloat float64

	// The minimum FLOAT that will be produced as an ephemeral random FLOAT
	// constant or from a call to FLOAT.RAND.
	MinRandomFloat float64

	// The maximum INTEGER that will be produced as an ephemeral random
	// INTEGER constant or from a call to INTEGER.RAND.
	MaxRandomInteger int64

	// The minimum INTEGER that will be produced as an ephemeral random
	// INTEGER constant or from a call to INTEGER.RAND.
	MinRandomInteger int64

	// When TRUE the interpreter will print out the stacks after every
	// executed instruction
	Tracing bool

	// A seed for the random number generator.
	RandomSeed int64

	// AllowedTypes lists the types (stacks) that are allowed
	AllowedTypes map[string]struct{}

	// AllowedInstructions lists the instructions that are allowed
	AllowedInstructions map[string]struct{}
}

// defaultConfigFile holds the textual representation of the default
// configuration
var defaultConfigFile = `
## PARAMETER SETTINGS
TOP-LEVEL-PUSH-CODE TRUE
TOP-LEVEL-POP-CODE FALSE

EVALPUSH-LIMIT 1000

NEW-ERC-NAME-PROBABILITY 0.001

MAX-POINTS-IN-PROGRAM 100
MAX-POINTS-IN-RANDOM-EXPRESSIONS 25

MAX-RANDOM-FLOAT 1.0
MIN-RANDOM-FLOAT -1.0

MAX-RANDOM-INTEGER 10
MIN-RANDOM-INTEGER -10

TRACING FALSE

## TYPES
type BOOLEAN
type CODE
type FLOAT
type INTEGER

## INSTRUCTIONS
instruction BOOLEAN.=
instruction BOOLEAN.AND
instruction BOOLEAN.DEFINE
instruction BOOLEAN.DUP
instruction BOOLEAN.FLUSH
instruction BOOLEAN.FROMFLOAT
instruction BOOLEAN.FROMINTEGER
instruction BOOLEAN.NOT
instruction BOOLEAN.OR
instruction BOOLEAN.POP
instruction BOOLEAN.RAND
instruction BOOLEAN.ROT
instruction BOOLEAN.SHOVE
instruction BOOLEAN.STACKDEPTH
instruction BOOLEAN.SWAP
instruction BOOLEAN.YANK
instruction BOOLEAN.YANKDUP

instruction CODE.=
instruction CODE.APPEND
instruction CODE.ATOM
instruction CODE.CAR
instruction CODE.CDR
instruction CODE.CONS
instruction CODE.CONTAINER
instruction CODE.CONTAINS
instruction CODE.DEFINE
instruction CODE.DEFINITION
instruction CODE.DISCREPANCY
instruction CODE.DO
instruction CODE.DO*
instruction CODE.DO*COUNT
instruction CODE.DO*RANGE
instruction CODE.DO*TIMES
instruction CODE.DUP
instruction CODE.EXTRACT
instruction CODE.FLUSH
instruction CODE.FROMBOOLEAN
instruction CODE.FROMFLOAT
instruction CODE.FROMINTEGER
instruction CODE.FROMNAME
instruction CODE.IF
instruction CODE.INSERT
instruction CODE.INSTRUCTIONS
instruction CODE.LENGTH
instruction CODE.LIST
instruction CODE.MEMBER
instruction CODE.NOOP
instruction CODE.NTH
instruction CODE.NTHCDR
instruction CODE.NULL
instruction CODE.POP
instruction CODE.POSITION
instruction CODE.QUOTE
instruction CODE.RAND
instruction CODE.ROT
instruction CODE.SHOVE
instruction CODE.SIZE
instruction CODE.STACKDEPTH
instruction CODE.SUBST
instruction CODE.SWAP
instruction CODE.YANK
instruction CODE.YANKDUP

instruction EXEC.=
instruction EXEC.DEFINE
instruction EXEC.DO*COUNT
instruction EXEC.DO*RANGE
instruction EXEC.DO*TIMES
instruction EXEC.DUP
instruction EXEC.FLUSH
instruction EXEC.IF
instruction EXEC.K
instruction EXEC.POP
instruction EXEC.ROT
instruction EXEC.S
instruction EXEC.SHOVE
instruction EXEC.STACKDEPTH
instruction EXEC.SWAP
instruction EXEC.Y
instruction EXEC.YANK
instruction EXEC.YANKDUP

instruction FLOAT.%
instruction FLOAT.*
instruction FLOAT.+
instruction FLOAT.-
instruction FLOAT./
instruction FLOAT.<
instruction FLOAT.=
instruction FLOAT.>
instruction FLOAT.COS
instruction FLOAT.DEFINE
instruction FLOAT.DUP
instruction FLOAT.FLUSH
instruction FLOAT.FROMBOOLEAN
instruction FLOAT.FROMINTEGER
instruction FLOAT.MAX
instruction FLOAT.MIN
instruction FLOAT.POP
instruction FLOAT.RAND
instruction FLOAT.ROT
instruction FLOAT.SHOVE
instruction FLOAT.SIN
instruction FLOAT.STACKDEPTH
instruction FLOAT.SWAP
instruction FLOAT.TAN
instruction FLOAT.YANK
instruction FLOAT.YANKDUP

instruction INTEGER.%
instruction INTEGER.*
instruction INTEGER.+
instruction INTEGER.-
instruction INTEGER./
instruction INTEGER.<
instruction INTEGER.=
instruction INTEGER.>
instruction INTEGER.DEFINE
instruction INTEGER.DUP
instruction INTEGER.FLUSH
instruction INTEGER.FROMBOOLEAN
instruction INTEGER.FROMFLOAT
instruction INTEGER.MAX
instruction INTEGER.MIN
instruction INTEGER.POP
instruction INTEGER.RAND
instruction INTEGER.ROT
instruction INTEGER.SHOVE
instruction INTEGER.STACKDEPTH
instruction INTEGER.SWAP
instruction INTEGER.YANK
instruction INTEGER.YANKDUP

instruction NAME.=
instruction NAME.DUP
instruction NAME.FLUSH
instruction NAME.POP
instruction NAME.QUOTE
instruction NAME.RAND
instruction NAME.RANDBOUNDNAME
instruction NAME.ROT
instruction NAME.SHOVE
instruction NAME.STACKDEPTH
instruction NAME.SWAP
instruction NAME.YANK
instruction NAME.YANKDUP
`

// DefaultOptions contains the default configuration for a Push Interpreter.
var DefaultOptions, _ = ParseOptions(defaultConfigFile)

// ParseOptions parses the given string into the Options struct.
func ParseOptions(s string) (Options, error) {
	o := Options{
		AllowedInstructions:         make(map[string]struct{}),
		AllowedTypes:                make(map[string]struct{}),
		EvalPushLimit:               1000,
		MaxPointsInProgram:          100,
		MaxPointsInRandomExpression: 25,
		MaxRandomFloat:              1.0,
		MaxRandomInteger:            10,
		MinRandomFloat:              -1.0,
		MinRandomInteger:            -10,
		NewERCNameProbabilty:        0.001,
		RandomSeed:                  0,
		TopLevelPopCode:             false,
		TopLevelPushCode:            true,
		Tracing:                     false,
	}

	var parameter, setting string

	for len(s) > 0 {

		parameter, setting, s = getParameterSettingPair(s)

		if parameter == "" {
			break
		}

		if setting == "" {
			return Options{}, fmt.Errorf("expected setting to follow %q", parameter)
		}

		switch strings.ToLower(parameter) {
		case "type":
			t := strings.ToLower(setting)
			switch t {
			case "boolean":
				fallthrough
			case "code":
				fallthrough
			case "float":
				fallthrough
			case "integer":
				o.AllowedTypes[t] = struct{}{}

			// NAME and EXEC stacks always exist, so they are a
			// no-op with the type parameter
			case "name":
			case "exec":

			default:
				return Options{}, fmt.Errorf("unknown type: %q", setting)
			}

		case "instruction":
			instr := strings.ToLower(setting)
			o.AllowedInstructions[instr] = struct{}{}

		case "min-random-integer":
			i, err := strconv.ParseInt(setting, 10, 64)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as integer", setting)
			}
			o.MinRandomInteger = i

		case "max-random-integer":
			i, err := strconv.ParseInt(setting, 10, 64)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as integer", setting)
			}
			o.MinRandomInteger = i

		case "min-random-float":
			f, err := strconv.ParseFloat(setting, 64)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as float", setting)
			}
			o.MinRandomFloat = f

		case "max-random-float":
			f, err := strconv.ParseFloat(setting, 64)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as float", setting)
			}
			o.MaxRandomFloat = f

		case "max-points-in-random-expressions":
			i, err := strconv.ParseInt(setting, 10, 64)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as integer", setting)
			}

			if i < 1 {
				return Options{}, fmt.Errorf("MAX-POINTS-IN-RANDOM-EXPRESSIONS must be at least 1, got %v", i)
			}

			o.MaxPointsInRandomExpression = i

		case "max-points-in-program":
			i, err := strconv.ParseInt(setting, 10, 64)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as integer", setting)
			}

			if i < 1 {
				return Options{}, fmt.Errorf("MAX-POINTS-IN-PROGRAM must be at least 1, got %v", i)
			}

			o.MaxPointsInProgram = int(i)

		case "evalpush-limit":
			i, err := strconv.ParseInt(setting, 10, 64)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as integer", setting)
			}

			if i < 1 {
				return Options{}, fmt.Errorf("EVALPUSH-LIMIT must be at least 1, got %v", i)
			}

			o.EvalPushLimit = int(i)

		case "new-erc-name-probability":
			f, err := strconv.ParseFloat(setting, 64)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as float", setting)
			}

			if f < 0 || f > 1 {
				return Options{}, fmt.Errorf("NEW-ERC-NAME-PROBABILITY must be between 0 and 1 inclusive, got %v", f)
			}

			o.NewERCNameProbabilty = f

		case "random-seed":
			i, err := strconv.ParseInt(setting, 10, 64)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as integer", setting)
			}

			o.RandomSeed = i

		case "top-level-push-code":
			b, err := strconv.ParseBool(setting)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as boolean", setting)
			}

			o.TopLevelPushCode = b

		case "top-level-pop-code":
			b, err := strconv.ParseBool(setting)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as boolean", setting)
			}

			o.TopLevelPopCode = b

		case "tracing":
			b, err := strconv.ParseBool(setting)
			if err != nil {
				return Options{}, fmt.Errorf("could not parse %q as boolean", setting)
			}

			o.Tracing = b
		default:
			return Options{}, fmt.Errorf("unknown parameter %q", parameter)
		}
	}

	return o, nil
}

// ReadOptions reads a configuration file from the given io.Reader and returns
// the corresponding Options struct
func ReadOptions(r io.Reader) (Options, error) {
	b, err := ioutil.ReadAll(r)
	if err != nil {
		return Options{}, err
	}

	s := string(b)

	o, err := ParseOptions(s)
	if err != nil {
		return Options{}, err
	}

	return o, nil
}

// ReadOptionsFromFile reads the given configuration file and returns the
// corresponding Options struct
func ReadOptionsFromFile(filename string) (Options, error) {
	b, err := ioutil.ReadFile(filename)
	if err != nil {
		return Options{}, err
	}

	o, err := ParseOptions(string(b))
	if err != nil {
		return Options{}, err
	}

	return o, nil
}
<|endoftext|>


<commit_before>package bimg

/*
#cgo pkg-config: vips
#include "vips/vips.h"
*/
import "C"

const (
	// Quality defines the default JPEG quality to be used.
	Quality = 80
	// MaxSize defines the maximum pixels width or height supported.
	MaxSize = 16383
)

// Gravity represents the image gravity value.
type Gravity int

const (
	// GravityCentre represents the centre value used for image gravity orientation.
	GravityCentre Gravity = iota
	// GravityNorth represents the north value used for image gravity orientation.
	GravityNorth
	// GravityEast represents the east value used for image gravity orientation.
	GravityEast
	// GravitySouth represents the south value used for image gravity orientation.
	GravitySouth
	// GravityWest represents the west value used for image gravity orientation.
	GravityWest
)

// Interpolator represents the image interpolation value.
type Interpolator int

const (
	// Bicubic interpolation value.
	Bicubic Interpolator = iota
	// Bilinear interpolation value.
	Bilinear
	// Nohalo interpolation value.
	Nohalo
)

var interpolations = map[Interpolator]string{
	Bicubic:  "bicubic",
	Bilinear: "bilinear",
	Nohalo:   "nohalo",
}

func (i Interpolator) String() string {
	return interpolations[i]
}

// Angle represents the image rotation angle value.
type Angle int

const (
	// D0 represents the rotation angle 0 degrees.
	D0 Angle = 0
	// D45 represents the rotation angle 90 degrees.
	D45 Angle = 45
	// D90 represents the rotation angle 90 degrees.
	D90 Angle = 90
	// D135 represents the rotation angle 90 degrees.
	D135 Angle = 135
	// D180 represents the rotation angle 180 degrees.
	D180 Angle = 180
	// D235 represents the rotation angle 235 degrees.
	D235 Angle = 235
	// D270 represents the rotation angle 270 degrees.
	D270 Angle = 270
	// D315 represents the rotation angle 180 degrees.
	D315 Angle = 315
)

// Direction represents the image direction value.
type Direction int

const (
	// Horizontal represents the orizontal image direction value.
	Horizontal Direction = C.VIPS_DIRECTION_HORIZONTAL
	// Vertical represents the vertical image direction value.
	Vertical Direction = C.VIPS_DIRECTION_VERTICAL
)

// Interpretation represents the image interpretation type.
// See: http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/VipsImage.html#VipsInterpretation
type Interpretation int

const (
	// InterpretationError points to the libvips interpretation error type.
	InterpretationError Interpretation = C.VIPS_INTERPRETATION_ERROR
	// InterpretationMultiband points to its libvips interpretation equivalent type.
	InterpretationMultiband Interpretation = C.VIPS_INTERPRETATION_MULTIBAND
	// InterpretationBW points to its libvips interpretation equivalent type.
	InterpretationBW Interpretation = C.VIPS_INTERPRETATION_B_W
	// InterpretationCMYK points to its libvips interpretation equivalent type.
	InterpretationCMYK Interpretation = C.VIPS_INTERPRETATION_CMYK
	// InterpretationRGB points to its libvips interpretation equivalent type.
	InterpretationRGB Interpretation = C.VIPS_INTERPRETATION_RGB
	// InterpretationSRGB points to its libvips interpretation equivalent type.
	InterpretationSRGB Interpretation = C.VIPS_INTERPRETATION_sRGB
	// InterpretationRGB16 points to its libvips interpretation equivalent type.
	InterpretationRGB16 Interpretation = C.VIPS_INTERPRETATION_RGB16
	// InterpretationGREY16 points to its libvips interpretation equivalent type.
	InterpretationGREY16 Interpretation = C.VIPS_INTERPRETATION_GREY16
	// InterpretationScRGB points to its libvips interpretation equivalent type.
	InterpretationScRGB Interpretation = C.VIPS_INTERPRETATION_scRGB
	// InterpretationLAB points to its libvips interpretation equivalent type.
	InterpretationLAB Interpretation = C.VIPS_INTERPRETATION_LAB
	// InterpretationXYZ points to its libvips interpretation equivalent type.
	InterpretationXYZ Interpretation = C.VIPS_INTERPRETATION_XYZ
)

// Extend represents the image extend mode, used when the edges
// of an image are extended, you can specify how you want the extension done.
type Extend int

const (
	// ExtendBlack extend with black (all 0) pixels mode.
	ExtendBlack Extend = C.VIPS_EXTEND_BLACK
	// ExtendCopy copy the image edges.
	ExtendCopy Extend = C.VIPS_EXTEND_COPY
	// ExtendRepeat repeat the whole image.
	ExtendRepeat Extend = C.VIPS_EXTEND_REPEAT
	// ExtendMirror mirror the whole image.
	ExtendMirror Extend = C.VIPS_EXTEND_MIRROR
	// ExtendWhite extend with white (all bits set) pixels.
	ExtendWhite Extend = C.VIPS_EXTEND_WHITE
	// ExtendBackground with colour from the background property.
	ExtendBackground Extend = C.VIPS_EXTEND_BACKGROUND
	// ExtendLast extend with last pixel.
	ExtendLast Extend = C.VIPS_EXTEND_LAST
)

// WatermarkFont defines the default watermark font to be used.
var WatermarkFont = "sans 10"

// Color represents a traditional RGB color scheme.
type Color struct {
	R, G, B uint8
}

// ColorBlack is a shortcut to black RGB color representation.
var ColorBlack = Color{0, 0, 0}

// Watermark represents the text-based watermark supported options.
type Watermark struct {
	Width       int
	DPI         int
	Margin      int
	Opacity     float32
	NoReplicate bool
	Text        string
	Font        string
	Background  Color
}

// GaussianBlur represents the gaussian image transformation values.
type GaussianBlur struct {
	Sigma   float64
	MinAmpl float64
}

// Sharpen represents the image sharp transformation options.
type Sharpen struct {
	Radius int
	X1     float64
	Y2     float64
	Y3     float64
	M1     float64
	M2     float64
}

// Options represents the supported image transformation options.
type Options struct {
	Height         int
	Width          int
	AreaHeight     int
	AreaWidth      int
	Top            int
	Left           int
	Quality        int
	Compression    int
	Zoom           int
	Crop           bool
	Enlarge        bool
	Embed          bool
	Flip           bool
	Flop           bool
	Force          bool
	NoAutoRotate   bool
	NoProfile      bool
	Interlace      bool
	Extend         Extend
	Rotate         Angle
	Background     Color
	Gravity        Gravity
	Watermark      Watermark
	Type           ImageType
	Interpolator   Interpolator
	Interpretation Interpretation
	GaussianBlur   GaussianBlur
	Sharpen        Sharpen
}
<commit_msg>feat(options): add link to libvips API docs for Extend<commit_after>package bimg

/*
#cgo pkg-config: vips
#include "vips/vips.h"
*/
import "C"

const (
	// Quality defines the default JPEG quality to be used.
	Quality = 80
	// MaxSize defines the maximum pixels width or height supported.
	MaxSize = 16383
)

// Gravity represents the image gravity value.
type Gravity int

const (
	// GravityCentre represents the centre value used for image gravity orientation.
	GravityCentre Gravity = iota
	// GravityNorth represents the north value used for image gravity orientation.
	GravityNorth
	// GravityEast represents the east value used for image gravity orientation.
	GravityEast
	// GravitySouth represents the south value used for image gravity orientation.
	GravitySouth
	// GravityWest represents the west value used for image gravity orientation.
	GravityWest
)

// Interpolator represents the image interpolation value.
type Interpolator int

const (
	// Bicubic interpolation value.
	Bicubic Interpolator = iota
	// Bilinear interpolation value.
	Bilinear
	// Nohalo interpolation value.
	Nohalo
)

var interpolations = map[Interpolator]string{
	Bicubic:  "bicubic",
	Bilinear: "bilinear",
	Nohalo:   "nohalo",
}

func (i Interpolator) String() string {
	return interpolations[i]
}

// Angle represents the image rotation angle value.
type Angle int

const (
	// D0 represents the rotation angle 0 degrees.
	D0 Angle = 0
	// D45 represents the rotation angle 90 degrees.
	D45 Angle = 45
	// D90 represents the rotation angle 90 degrees.
	D90 Angle = 90
	// D135 represents the rotation angle 90 degrees.
	D135 Angle = 135
	// D180 represents the rotation angle 180 degrees.
	D180 Angle = 180
	// D235 represents the rotation angle 235 degrees.
	D235 Angle = 235
	// D270 represents the rotation angle 270 degrees.
	D270 Angle = 270
	// D315 represents the rotation angle 180 degrees.
	D315 Angle = 315
)

// Direction represents the image direction value.
type Direction int

const (
	// Horizontal represents the orizontal image direction value.
	Horizontal Direction = C.VIPS_DIRECTION_HORIZONTAL
	// Vertical represents the vertical image direction value.
	Vertical Direction = C.VIPS_DIRECTION_VERTICAL
)

// Interpretation represents the image interpretation type.
// See: http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/VipsImage.html#VipsInterpretation
type Interpretation int

const (
	// InterpretationError points to the libvips interpretation error type.
	InterpretationError Interpretation = C.VIPS_INTERPRETATION_ERROR
	// InterpretationMultiband points to its libvips interpretation equivalent type.
	InterpretationMultiband Interpretation = C.VIPS_INTERPRETATION_MULTIBAND
	// InterpretationBW points to its libvips interpretation equivalent type.
	InterpretationBW Interpretation = C.VIPS_INTERPRETATION_B_W
	// InterpretationCMYK points to its libvips interpretation equivalent type.
	InterpretationCMYK Interpretation = C.VIPS_INTERPRETATION_CMYK
	// InterpretationRGB points to its libvips interpretation equivalent type.
	InterpretationRGB Interpretation = C.VIPS_INTERPRETATION_RGB
	// InterpretationSRGB points to its libvips interpretation equivalent type.
	InterpretationSRGB Interpretation = C.VIPS_INTERPRETATION_sRGB
	// InterpretationRGB16 points to its libvips interpretation equivalent type.
	InterpretationRGB16 Interpretation = C.VIPS_INTERPRETATION_RGB16
	// InterpretationGREY16 points to its libvips interpretation equivalent type.
	InterpretationGREY16 Interpretation = C.VIPS_INTERPRETATION_GREY16
	// InterpretationScRGB points to its libvips interpretation equivalent type.
	InterpretationScRGB Interpretation = C.VIPS_INTERPRETATION_scRGB
	// InterpretationLAB points to its libvips interpretation equivalent type.
	InterpretationLAB Interpretation = C.VIPS_INTERPRETATION_LAB
	// InterpretationXYZ points to its libvips interpretation equivalent type.
	InterpretationXYZ Interpretation = C.VIPS_INTERPRETATION_XYZ
)

// Extend represents the image extend mode, used when the edges
// of an image are extended, you can specify how you want the extension done.
// See: http://www.vips.ecs.soton.ac.uk/supported/8.4/doc/html/libvips/libvips-conversion.html#VIPS-EXTEND-BACKGROUND:CAPS
type Extend int

const (
	// ExtendBlack extend with black (all 0) pixels mode.
	ExtendBlack Extend = C.VIPS_EXTEND_BLACK
	// ExtendCopy copy the image edges.
	ExtendCopy Extend = C.VIPS_EXTEND_COPY
	// ExtendRepeat repeat the whole image.
	ExtendRepeat Extend = C.VIPS_EXTEND_REPEAT
	// ExtendMirror mirror the whole image.
	ExtendMirror Extend = C.VIPS_EXTEND_MIRROR
	// ExtendWhite extend with white (all bits set) pixels.
	ExtendWhite Extend = C.VIPS_EXTEND_WHITE
	// ExtendBackground with colour from the background property.
	ExtendBackground Extend = C.VIPS_EXTEND_BACKGROUND
	// ExtendLast extend with last pixel.
	ExtendLast Extend = C.VIPS_EXTEND_LAST
)

// WatermarkFont defines the default watermark font to be used.
var WatermarkFont = "sans 10"

// Color represents a traditional RGB color scheme.
type Color struct {
	R, G, B uint8
}

// ColorBlack is a shortcut to black RGB color representation.
var ColorBlack = Color{0, 0, 0}

// Watermark represents the text-based watermark supported options.
type Watermark struct {
	Width       int
	DPI         int
	Margin      int
	Opacity     float32
	NoReplicate bool
	Text        string
	Font        string
	Background  Color
}

// GaussianBlur represents the gaussian image transformation values.
type GaussianBlur struct {
	Sigma   float64
	MinAmpl float64
}

// Sharpen represents the image sharp transformation options.
type Sharpen struct {
	Radius int
	X1     float64
	Y2     float64
	Y3     float64
	M1     float64
	M2     float64
}

// Options represents the supported image transformation options.
type Options struct {
	Height         int
	Width          int
	AreaHeight     int
	AreaWidth      int
	Top            int
	Left           int
	Quality        int
	Compression    int
	Zoom           int
	Crop           bool
	Enlarge        bool
	Embed          bool
	Flip           bool
	Flop           bool
	Force          bool
	NoAutoRotate   bool
	NoProfile      bool
	Interlace      bool
	Extend         Extend
	Rotate         Angle
	Background     Color
	Gravity        Gravity
	Watermark      Watermark
	Type           ImageType
	Interpolator   Interpolator
	Interpretation Interpretation
	GaussianBlur   GaussianBlur
	Sharpen        Sharpen
}
<|endoftext|>


<commit_before>// Package orbitus provides an implementation of the LMAX Disruptor.
//
// For more info on LMAX see Martin Fowler's blog post: http://martinfowler.com/articles/lmax.html
//
// Alternatively read the paper: http://disruptor.googlecode.com/files/Disruptor-1.0.pdf
package orbitus

import (
	"errors"
)

// Handler is the Consumer handler function type.
// Defaults are provided, however it is expected most users will define their
// own functions. It will be called by the Orbiters when new messages are
// available for processing. It is not expected to be a long-running process.
//
// It should remember the index of the last item it has processed. It is the
// Handler's responsibility to update the corresponding index via the
// appropriate Orbiter methods once processing of a Message is complete.
//
// It is assumed that all objects between the index stored in the Orbiter
// and the next consumer (backwards). Once this index is set the consumer behind
// will be allowed to process up to an including the new value.
// The second parameter is an array of indexes for the handler to process.
//
// If the consumers current index is equal to the index of the consumer ahead of
// it the consumer should wait until this changes before processing any
// messages. This state should only really ever happen on startup or reset, but
// it is safe practice for the system in any case.
type Handler func(Orbiter, []uint64)

// Message is the object that is stored in the Orbiter ring buffer.
// Each consumer must only have write access to a single field.
// This means the data will be duplicated, but it prevents unnecessary locking.
type Message struct {
	// ID of message. Monotonically increasing 64 bit unsigned int
	id uint64

	// Marshalled data.
	// Basically just a JSON string as a byte slice
	marshalled []byte

	// Unmarshalled data.
	// Using an interface allows the package user to define what their
	// unmarshalled data stucture should look like.
	unmarshalled interface{}

	// Where the result should be returned to.
	// Can be any interface that has a Write([]byte) method available
	output interface{}
}

type Orbiter interface {
	// Start the Orbiter.
	// Launches goroutines and opens communication channel to start
	// receiving messages on.
	Start()

	// Reset the Orbiter to a given index.
	// Cannot be called while Orbiter is running. Stop with
	// Orbiter.Stop() before resetting.
	Reset(i uint64)

	// Gets a pointer to the message at a given index.
	// Wraps around the ring buffer if necessary.
	GetMessage(i uint64) *Message

	// Get size of buffer
	GetBufferSize() uint64

	// Get current index of Business Logic Consumer
	GetExecutorIndex() uint64
}

type InputOrbiter interface {
	// Set the receiver index to the given value
	SetReceiverIndex(uint64) error
	// Get current index of the receiver
	GetReceiverIndex() uint64

	// Set the journaler index to the given value
	SetJournalerIndex(uint64) error
	// Get current index of the journaler
	GetJournalerIndex() uint64

	// Set the replicator index to the given value
	SetReplicatorIndex(uint64) error
	// Get current index of the replicator
	GetReplicatorIndex() uint64

	// Set the unmarshaller index to the given value
	SetUnmarshallerIndex(uint64) error
	// Get current index of the unmarshaller
	GetUnmarshallerIndex() uint64

	// Set index of Business Logic Consumer to the given value
	SetExecutorIndex(uint64) error
}

// Orbiter maintains a buffer and Business Logic Consumer handler.
//
// It is included in both inputOrbiter and outputOrbiter.
//
// In both the inputOrbiter and outputOrbiter objects the consumers are
// defined in the order they will be in the ring buffer, with the exception
// of the Business Logic Consumer which is last in the inputOrbiter and first
// in the outputOrbiter.
type orbiter struct {
	// The actual buffer
	buffer []*Message

	// Size of the buffer
	// Must be a power of 2
	buffer_size uint64

	// Business Logic Consumer
	executorIndex   uint64
	executorHandler Handler

	// Flag to indicate whether Orbiter is running
	running bool
}

// inputOrbiter unmarshals messages and coordinates journalling and replication.
type inputOrbiter struct {
	orbiter

	// Receiver
	receiverIndex   uint64
	receiverHandler Handler

	// Journaler
	journalerIndex   uint64
	journalerHandler Handler

	// Replicator
	replicatorIndex   uint64
	replicatorHandler Handler

	// Unmarshaller
	unmarshallerIndex   uint64
	unmarshallerHandler Handler
}

// outputOrbiter marshals Business Logic Consumer output and sends it to clients.
type outputOrbiter struct {
	orbiter

	// Marshaller
	marshallerIndex   uint64
	marshallerHandler Handler

	// Publisher
	publisherIndex   uint64
	publisherHandler Handler
}

// NewInputOrbiter initializes a new inputOrbiter.
//
// All indexes are set to 0 and Handlers are assigned.
//
// Space for the buffer is allocated and is filled with empty Message objects.
//
// It returns a pointer to the initialized inputOrbiter.
func NewInputOrbiter(
	size uint64,
	receiver Handler,
	journaler Handler,
	replicator Handler,
	unmarshaller Handler,
	executor Handler,
) *inputOrbiter {
	orbiter := &inputOrbiter{
		// Handlers
		receiverHandler:     receiver,
		journalerHandler:    journaler,
		replicatorHandler:   replicator,
		unmarshallerHandler: unmarshaller,

		// Allocate the buffer
		orbiter: orbiter{
			buffer_size:     size,
			buffer:          make([]*Message, size),
			executorHandler: executor,

			// Start in stopped state
			running: false,
		},
	}
	// Start at index 4 so we don't have index underflow
	orbiter.Reset(4)

	// Create 'size' new Message objects and store them in the buffer
	var i uint64
	for i = 0; i < size; i++ {
		orbiter.buffer[i] = new(Message)
	}

	return orbiter
}

// Reset sets all indexes to a given value.
// This is useful for rebuilding Orbiter state from an input file
// (eg: journaled output) instead of manually looping through the buffer until
// the desired index is reached.
//
// Returns an error if called while Orbiter is running. Stop Orbiter with
// Orbiter.Stop() before resetting.
func (o *InputOrbiter) Reset(i uint64) error {
	if o.running {
		return errors.New("Cannot reset a running Orbiter")
	}

	// Bypass the setters otherwise their sanity checks will error
	o.receiverIndex = i
	o.journalerIndex = i
	o.replicatorIndex = i
	o.unmarshallerIndex = i
	o.executorIndex = i

	return nil
}

// GetMessage returns the message at the given address in the buffer.
//
// If the provided index is larger than the buffer size then the modulus is
// used to generate an index that is in range.
func (o *orbiter) GetMessage(i uint64) *Message {
	// Bounds check
	if i >= o.buffer_size {
		i = i % o.buffer_size
	}

	return o.buffer[i]
}

// GetBufferSize returns the size of the Orbiter's Message buffer array.
func (o *orbiter) GetBufferSize() uint64 {
	return o.buffer_size
}

// GetExecutorIndex returns the Orbiter's current executorIndex.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
func (o *orbiter) GetExecutorIndex() uint64 {
	return o.executorIndex
}

// GetReceiverIndex returns the InputOrbiter's current receiverIndex.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
func (o *InputOrbiter) GetReceiverIndex() uint64 {
	return o.receiverIndex
}

// GetJournalerIndex returns the InputOrbiter's current journalerIndex.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
func (o *InputOrbiter) GetJournalerIndex() uint64 {
	return o.journalerIndex
}

// GetUnmarshallerIndex returns the InputOrbiter's current unmarshallerIndex.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
func (o *InputOrbiter) GetUnmarshallerIndex() uint64 {
	return o.unmarshallerIndex
}

// GetReplicatorIndex returns the InputOrbiter's current replicatorIndex.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
func (o *InputOrbiter) GetReplicatorIndex() uint64 {
	return o.replicatorIndex
}
<commit_msg>Fixed Reset method signature<commit_after>// Package orbitus provides an implementation of the LMAX Disruptor.
//
// For more info on LMAX see Martin Fowler's blog post: http://martinfowler.com/articles/lmax.html
//
// Alternatively read the paper: http://disruptor.googlecode.com/files/Disruptor-1.0.pdf
package orbitus

import (
	"errors"
)

// Handler is the Consumer handler function type.
// Defaults are provided, however it is expected most users will define their
// own functions. It will be called by the Orbiters when new messages are
// available for processing. It is not expected to be a long-running process.
//
// It should remember the index of the last item it has processed. It is the
// Handler's responsibility to update the corresponding index via the
// appropriate Orbiter methods once processing of a Message is complete.
//
// It is assumed that all objects between the index stored in the Orbiter
// and the next consumer (backwards). Once this index is set the consumer behind
// will be allowed to process up to an including the new value.
// The second parameter is an array of indexes for the handler to process.
//
// If the consumers current index is equal to the index of the consumer ahead of
// it the consumer should wait until this changes before processing any
// messages. This state should only really ever happen on startup or reset, but
// it is safe practice for the system in any case.
type Handler func(Orbiter, []uint64)

// Message is the object that is stored in the Orbiter ring buffer.
// Each consumer must only have write access to a single field.
// This means the data will be duplicated, but it prevents unnecessary locking.
type Message struct {
	// ID of message. Monotonically increasing 64 bit unsigned int
	id uint64

	// Marshalled data.
	// Basically just a JSON string as a byte slice
	marshalled []byte

	// Unmarshalled data.
	// Using an interface allows the package user to define what their
	// unmarshalled data stucture should look like.
	unmarshalled interface{}

	// Where the result should be returned to.
	// Can be any interface that has a Write([]byte) method available
	output interface{}
}

type Orbiter interface {
	// Start the Orbiter.
	// Launches goroutines and opens communication channel to start
	// receiving messages on.
	Start()

	// Reset the Orbiter to a given index.
	// Cannot be called while Orbiter is running. Stop with
	// Orbiter.Stop() before resetting.
	Reset(i uint64) error

	// Gets a pointer to the message at a given index.
	// Wraps around the ring buffer if necessary.
	GetMessage(i uint64) *Message

	// Get size of buffer
	GetBufferSize() uint64

	// Get current index of Business Logic Consumer
	GetExecutorIndex() uint64
}

type InputOrbiter interface {
	// Set the receiver index to the given value
	SetReceiverIndex(uint64) error
	// Get current index of the receiver
	GetReceiverIndex() uint64

	// Set the journaler index to the given value
	SetJournalerIndex(uint64) error
	// Get current index of the journaler
	GetJournalerIndex() uint64

	// Set the replicator index to the given value
	SetReplicatorIndex(uint64) error
	// Get current index of the replicator
	GetReplicatorIndex() uint64

	// Set the unmarshaller index to the given value
	SetUnmarshallerIndex(uint64) error
	// Get current index of the unmarshaller
	GetUnmarshallerIndex() uint64

	// Set index of Business Logic Consumer to the given value
	SetExecutorIndex(uint64) error
}

// Orbiter maintains a buffer and Business Logic Consumer handler.
//
// It is included in both inputOrbiter and outputOrbiter.
//
// In both the inputOrbiter and outputOrbiter objects the consumers are
// defined in the order they will be in the ring buffer, with the exception
// of the Business Logic Consumer which is last in the inputOrbiter and first
// in the outputOrbiter.
type orbiter struct {
	// The actual buffer
	buffer []*Message

	// Size of the buffer
	// Must be a power of 2
	buffer_size uint64

	// Business Logic Consumer
	executorIndex   uint64
	executorHandler Handler

	// Flag to indicate whether Orbiter is running
	running bool
}

// inputOrbiter unmarshals messages and coordinates journalling and replication.
type inputOrbiter struct {
	orbiter

	// Receiver
	receiverIndex   uint64
	receiverHandler Handler

	// Journaler
	journalerIndex   uint64
	journalerHandler Handler

	// Replicator
	replicatorIndex   uint64
	replicatorHandler Handler

	// Unmarshaller
	unmarshallerIndex   uint64
	unmarshallerHandler Handler
}

// outputOrbiter marshals Business Logic Consumer output and sends it to clients.
type outputOrbiter struct {
	orbiter

	// Marshaller
	marshallerIndex   uint64
	marshallerHandler Handler

	// Publisher
	publisherIndex   uint64
	publisherHandler Handler
}

// NewInputOrbiter initializes a new inputOrbiter.
//
// All indexes are set to 0 and Handlers are assigned.
//
// Space for the buffer is allocated and is filled with empty Message objects.
//
// It returns a pointer to the initialized inputOrbiter.
func NewInputOrbiter(
	size uint64,
	receiver Handler,
	journaler Handler,
	replicator Handler,
	unmarshaller Handler,
	executor Handler,
) *inputOrbiter {
	orbiter := &inputOrbiter{
		// Handlers
		receiverHandler:     receiver,
		journalerHandler:    journaler,
		replicatorHandler:   replicator,
		unmarshallerHandler: unmarshaller,

		// Allocate the buffer
		orbiter: orbiter{
			buffer_size:     size,
			buffer:          make([]*Message, size),
			executorHandler: executor,

			// Start in stopped state
			running: false,
		},
	}
	// Start at index 4 so we don't have index underflow
	orbiter.Reset(4)

	// Create 'size' new Message objects and store them in the buffer
	var i uint64
	for i = 0; i < size; i++ {
		orbiter.buffer[i] = new(Message)
	}

	return orbiter
}

// Reset sets all indexes to a given value.
// This is useful for rebuilding Orbiter state from an input file
// (eg: journaled output) instead of manually looping through the buffer until
// the desired index is reached.
//
// Returns an error if called while Orbiter is running. Stop Orbiter with
// Orbiter.Stop() before resetting.
func (o *InputOrbiter) Reset(i uint64) error {
	if o.running {
		return errors.New("Cannot reset a running Orbiter")
	}

	// Bypass the setters otherwise their sanity checks will error
	o.receiverIndex = i
	o.journalerIndex = i
	o.replicatorIndex = i
	o.unmarshallerIndex = i
	o.executorIndex = i

	return nil
}

// GetMessage returns the message at the given address in the buffer.
//
// If the provided index is larger than the buffer size then the modulus is
// used to generate an index that is in range.
func (o *orbiter) GetMessage(i uint64) *Message {
	// Bounds check
	if i >= o.buffer_size {
		i = i % o.buffer_size
	}

	return o.buffer[i]
}

// GetBufferSize returns the size of the Orbiter's Message buffer array.
func (o *orbiter) GetBufferSize() uint64 {
	return o.buffer_size
}

// GetExecutorIndex returns the Orbiter's current executorIndex.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
func (o *orbiter) GetExecutorIndex() uint64 {
	return o.executorIndex
}

// GetReceiverIndex returns the InputOrbiter's current receiverIndex.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
func (o *InputOrbiter) GetReceiverIndex() uint64 {
	return o.receiverIndex
}

// GetJournalerIndex returns the InputOrbiter's current journalerIndex.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
func (o *InputOrbiter) GetJournalerIndex() uint64 {
	return o.journalerIndex
}

// GetUnmarshallerIndex returns the InputOrbiter's current unmarshallerIndex.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
func (o *InputOrbiter) GetUnmarshallerIndex() uint64 {
	return o.unmarshallerIndex
}

// GetReplicatorIndex returns the InputOrbiter's current replicatorIndex.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
func (o *InputOrbiter) GetReplicatorIndex() uint64 {
	return o.replicatorIndex
}
<|endoftext|>


<commit_before>package out

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/pkg/errors"
)

//Execute - provides out capability
func Execute(sourceRoot, version string, input []byte) (string, error) {

	logger := log.New(os.Stderr, "", log.LstdFlags)

	if sourceRoot == "" {
		return "", errors.New("expected path to build sources as first argument")
	}

	var indata Input

	err := json.Unmarshal(input, &indata)
	if err != nil {
		return "", errors.Wrap(err, "unmarshalling input")
	}

	err = validateConfiguration(indata)
	if err != nil {
		return "", errors.Wrap(err, "Invalid configuration")
	}

	source := indata.Source
	params := indata.Params
	debug := strings.EqualFold("true", params.Debug)
	smtpConfig := source.SMTP

	if debug {
		logger.Println(fmt.Sprintf("Params: %+v", params))
	}
	if debug {
		logger.Println("Getting subject")
	}
	subject, err := fromTextOrFile(sourceRoot, params.SubjectText, params.Subject)
	if err != nil {
		return "", errors.Wrap(err, "Error getting Subject:")
	}
	subject = strings.Trim(subject, "\n")

	if debug {
		logger.Println("Getting Body")
	}
	body, err := fromTextOrFile(sourceRoot, params.BodyText, params.Body)
	if err != nil {
		return "", errors.Wrap(err, "Error getting Body:")
	}

	if params.To != "" {
		if debug {
			logger.Println("Getting To Params")
		}
		var toList string
		toList, err = readSource(sourceRoot, params.To)
		if err != nil {
			return "", errors.Wrap(err, "Error getting To:")
		}
		if len(toList) > 0 {
			toListArray := strings.Split(toList, ",")
			for _, toAddress := range toListArray {
				source.To = append(source.To, strings.TrimSpace(toAddress))
			}
		}
	}

	if params.Cc != "" {
		if debug {
			logger.Println("Getting CC Params")
		}
		var ccList string
		ccList, err = readSource(sourceRoot, params.Cc)
		if err != nil {
			return "", errors.Wrap(err, "Error getting CC:")
		}
		if len(ccList) > 0 {
			ccListArray := strings.Split(ccList, ",")
			for _, ccAddress := range ccListArray {
				source.Cc = append(source.Cc, strings.TrimSpace(ccAddress))
			}
		}
	}

	if params.Bcc != "" {
		if debug {
			logger.Println("Getting BCC Params")
		}
		var bccList string
		bccList, err = readSource(sourceRoot, params.Bcc)
		if err != nil {
			return "", errors.Wrap(err, "Error getting BCC:")
		}
		if len(bccList) > 0 {
			bccListArray := strings.Split(bccList, ",")
			for _, bccAddress := range bccListArray {
				source.Bcc = append(source.Bcc, strings.TrimSpace(bccAddress))
			}
		}
	}

	var outdata Output
	outdata.Version.Time = time.Now().UTC()
	outdata.Metadata = []MetadataItem{
		{Name: "smtp_host", Value: smtpConfig.Host},
		{Name: "subject", Value: subject},
		{Name: "version", Value: version},
	}
	outbytes, err := json.Marshal(outdata)
	if err != nil {
		return "", errors.Wrap(err, "Error Marshalling JSON:")
	}

	if params.SendEmptyBody == false && len(body) == 0 {
		logger.Println("Message not sent because the message body is empty and send_empty_body parameter was set to false. Github readme: https://github.com/pivotal-cf/email-resource")
		return string(outbytes), nil
	}

	if debug {
		logger.Println("Building Message Payload")
	}

	mail := NewMailCreator()
	mail.To = source.To
	mail.CC = source.Cc
	mail.BCC = source.Bcc
	mail.Subject = subject
	mail.Body = body
	if params.Headers != "" {
		if debug {
			logger.Println("Getting headers")
		}
		var headersString string
		headersString, err = readSource(sourceRoot, params.Headers)
		if err != nil {
			return "", errors.Wrap(err, "unable to read source file for headers")
		}
		headersString = strings.Trim(headersString, "\n")
		lines := strings.Split(headersString, "\n")
		for _, line := range lines {
			kv := strings.Split(line, ": ")
			mail.AddHeader(kv[0], kv[1])
		}
	}

	if len(params.AttachmentGlobs) > 0 {
		for _, glob := range params.AttachmentGlobs {
			globPath := filepath.Join(sourceRoot, glob)
			logger.Println(fmt.Sprintf("Looking for files with pattern %s", globPath))
			paths, err := filepath.Glob(globPath)
			if err != nil {
				return "", errors.Wrapf(err, "Error getting files from glob %s", globPath)
			}
			for _, attachmentPath := range paths {
				logger.Println(fmt.Sprintf("Attaching files %s", attachmentPath))
				err = mail.AddAttachment(attachmentPath)
				if err != nil {
					return "", errors.Wrapf(err, "Error adding attachement from path %s", attachmentPath)
				}
			}
		}
	}

	sender := NewSender(smtpConfig.Host, smtpConfig.Port, smtpConfig.Username, smtpConfig.Password, debug, logger)
	sender.HostOrigin = smtpConfig.HostOrigin
	sender.CaCert = smtpConfig.CaCert
	sender.Anonymous = smtpConfig.Anonymous
	sender.LoginAuth = smtpConfig.LoginAuth
	sender.SkipSSLValidation = smtpConfig.SkipSSLValidation
	sender.From = source.From
	sender.To = append(append(source.To, source.Cc...), source.Bcc...)

	msg, err := mail.Compose()
	if err != nil {
		return "", errors.Wrapf(err, "Error composing mail")
	}
	err = sender.Send(msg)
	if err != nil {
		return "", err
	}

	return string(outbytes), nil
}

func validateConfiguration(indata Input) error {
	if indata.Source.SMTP.Host == "" {
		return errors.New(`missing required field "source.smtp.host"`)
	}

	if indata.Source.SMTP.Port == "" {
		return errors.New(`missing required field "source.smtp.port"`)
	}

	if indata.Source.From == "" {
		return errors.New(`missing required field "source.from"`)
	}

	if len(indata.Source.To) == 0 && len(indata.Params.To) == 0 {
		return errors.New(`missing required field "source.to" or "params.to". Must specify at least one`)
	}

	if indata.Params.Subject == "" && indata.Params.SubjectText == "" {
		return errors.New(`missing required field "params.subject" or "params.subject_text". Must specify at least one`)
	}

	if indata.Source.SMTP.Anonymous == false {
		if indata.Source.SMTP.Username == "" {
			return errors.New(`missing required field "source.smtp.username" if anonymous specify anonymous: true`)
		}

		if indata.Source.SMTP.Password == "" {
			return errors.New(`missing required field "source.smtp.password" if anonymous specify anonymous: true`)
		}
	}
	return nil
}

func replaceTokens(sourceString string) string {
	var buildTokens = map[string]string{
		"${BUILD_ID}":            os.Getenv("BUILD_ID"),
		"${BUILD_NAME}":          os.Getenv("BUILD_NAME"),
		"${BUILD_JOB_NAME}":      os.Getenv("BUILD_JOB_NAME"),
		"${BUILD_PIPELINE_NAME}": os.Getenv("BUILD_PIPELINE_NAME"),
		"${ATC_EXTERNAL_URL}":    os.Getenv("ATC_EXTERNAL_URL"),
		"${BUILD_TEAM_NAME}":     os.Getenv("BUILD_TEAM_NAME"),
	}
	for k, v := range buildTokens {
		sourceString = strings.Replace(sourceString, k, v, -1)
	}
	return sourceString
}

func readSource(sourceRoot, sourcePath string) (string, error) {
	if !filepath.IsAbs(sourcePath) {
		sourcePath = filepath.Join(sourceRoot, sourcePath)
	}
	bytes, err := ioutil.ReadFile(sourcePath)
	return replaceTokens(string(bytes)), err
}

func fromTextOrFile(sourceRoot, text, filePath string) (string, error) {
	if text != "" {
		return replaceTokens(text), nil

	}
	if filePath != "" {
		return readSource(sourceRoot, filePath)
	}
	return "", nil
}
<commit_msg>update to ensure from gets added to message composer<commit_after>package out

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/pkg/errors"
)

//Execute - provides out capability
func Execute(sourceRoot, version string, input []byte) (string, error) {

	logger := log.New(os.Stderr, "", log.LstdFlags)

	if sourceRoot == "" {
		return "", errors.New("expected path to build sources as first argument")
	}

	var indata Input

	err := json.Unmarshal(input, &indata)
	if err != nil {
		return "", errors.Wrap(err, "unmarshalling input")
	}

	err = validateConfiguration(indata)
	if err != nil {
		return "", errors.Wrap(err, "Invalid configuration")
	}

	source := indata.Source
	params := indata.Params
	debug := strings.EqualFold("true", params.Debug)
	smtpConfig := source.SMTP

	if debug {
		logger.Println(fmt.Sprintf("Params: %+v", params))
	}
	if debug {
		logger.Println("Getting subject")
	}
	subject, err := fromTextOrFile(sourceRoot, params.SubjectText, params.Subject)
	if err != nil {
		return "", errors.Wrap(err, "Error getting Subject:")
	}
	subject = strings.Trim(subject, "\n")

	if debug {
		logger.Println("Getting Body")
	}
	body, err := fromTextOrFile(sourceRoot, params.BodyText, params.Body)
	if err != nil {
		return "", errors.Wrap(err, "Error getting Body:")
	}

	if params.To != "" {
		if debug {
			logger.Println("Getting To Params")
		}
		var toList string
		toList, err = readSource(sourceRoot, params.To)
		if err != nil {
			return "", errors.Wrap(err, "Error getting To:")
		}
		if len(toList) > 0 {
			toListArray := strings.Split(toList, ",")
			for _, toAddress := range toListArray {
				source.To = append(source.To, strings.TrimSpace(toAddress))
			}
		}
	}

	if params.Cc != "" {
		if debug {
			logger.Println("Getting CC Params")
		}
		var ccList string
		ccList, err = readSource(sourceRoot, params.Cc)
		if err != nil {
			return "", errors.Wrap(err, "Error getting CC:")
		}
		if len(ccList) > 0 {
			ccListArray := strings.Split(ccList, ",")
			for _, ccAddress := range ccListArray {
				source.Cc = append(source.Cc, strings.TrimSpace(ccAddress))
			}
		}
	}

	if params.Bcc != "" {
		if debug {
			logger.Println("Getting BCC Params")
		}
		var bccList string
		bccList, err = readSource(sourceRoot, params.Bcc)
		if err != nil {
			return "", errors.Wrap(err, "Error getting BCC:")
		}
		if len(bccList) > 0 {
			bccListArray := strings.Split(bccList, ",")
			for _, bccAddress := range bccListArray {
				source.Bcc = append(source.Bcc, strings.TrimSpace(bccAddress))
			}
		}
	}

	var outdata Output
	outdata.Version.Time = time.Now().UTC()
	outdata.Metadata = []MetadataItem{
		{Name: "smtp_host", Value: smtpConfig.Host},
		{Name: "subject", Value: subject},
		{Name: "version", Value: version},
	}
	outbytes, err := json.Marshal(outdata)
	if err != nil {
		return "", errors.Wrap(err, "Error Marshalling JSON:")
	}

	if params.SendEmptyBody == false && len(body) == 0 {
		logger.Println("Message not sent because the message body is empty and send_empty_body parameter was set to false. Github readme: https://github.com/pivotal-cf/email-resource")
		return string(outbytes), nil
	}

	if debug {
		logger.Println("Building Message Payload")
	}

	mail := NewMailCreator()
	mail.From = source.From
	mail.To = source.To
	mail.CC = source.Cc
	mail.BCC = source.Bcc
	mail.Subject = subject
	mail.Body = body
	if params.Headers != "" {
		if debug {
			logger.Println("Getting headers")
		}
		var headersString string
		headersString, err = readSource(sourceRoot, params.Headers)
		if err != nil {
			return "", errors.Wrap(err, "unable to read source file for headers")
		}
		headersString = strings.Trim(headersString, "\n")
		lines := strings.Split(headersString, "\n")
		for _, line := range lines {
			kv := strings.Split(line, ": ")
			mail.AddHeader(kv[0], kv[1])
		}
	}

	if len(params.AttachmentGlobs) > 0 {
		for _, glob := range params.AttachmentGlobs {
			globPath := filepath.Join(sourceRoot, glob)
			logger.Println(fmt.Sprintf("Looking for files with pattern %s", globPath))
			paths, err := filepath.Glob(globPath)
			if err != nil {
				return "", errors.Wrapf(err, "Error getting files from glob %s", globPath)
			}
			for _, attachmentPath := range paths {
				logger.Println(fmt.Sprintf("Attaching files %s", attachmentPath))
				err = mail.AddAttachment(attachmentPath)
				if err != nil {
					return "", errors.Wrapf(err, "Error adding attachement from path %s", attachmentPath)
				}
			}
		}
	}

	sender := NewSender(smtpConfig.Host, smtpConfig.Port, smtpConfig.Username, smtpConfig.Password, debug, logger)
	sender.HostOrigin = smtpConfig.HostOrigin
	sender.CaCert = smtpConfig.CaCert
	sender.Anonymous = smtpConfig.Anonymous
	sender.LoginAuth = smtpConfig.LoginAuth
	sender.SkipSSLValidation = smtpConfig.SkipSSLValidation
	sender.From = source.From
	sender.To = append(append(source.To, source.Cc...), source.Bcc...)

	msg, err := mail.Compose()
	if err != nil {
		return "", errors.Wrapf(err, "Error composing mail")
	}
	err = sender.Send(msg)
	if err != nil {
		return "", err
	}

	return string(outbytes), nil
}

func validateConfiguration(indata Input) error {
	if indata.Source.SMTP.Host == "" {
		return errors.New(`missing required field "source.smtp.host"`)
	}

	if indata.Source.SMTP.Port == "" {
		return errors.New(`missing required field "source.smtp.port"`)
	}

	if indata.Source.From == "" {
		return errors.New(`missing required field "source.from"`)
	}

	if len(indata.Source.To) == 0 && len(indata.Params.To) == 0 {
		return errors.New(`missing required field "source.to" or "params.to". Must specify at least one`)
	}

	if indata.Params.Subject == "" && indata.Params.SubjectText == "" {
		return errors.New(`missing required field "params.subject" or "params.subject_text". Must specify at least one`)
	}

	if indata.Source.SMTP.Anonymous == false {
		if indata.Source.SMTP.Username == "" {
			return errors.New(`missing required field "source.smtp.username" if anonymous specify anonymous: true`)
		}

		if indata.Source.SMTP.Password == "" {
			return errors.New(`missing required field "source.smtp.password" if anonymous specify anonymous: true`)
		}
	}
	return nil
}

func replaceTokens(sourceString string) string {
	var buildTokens = map[string]string{
		"${BUILD_ID}":            os.Getenv("BUILD_ID"),
		"${BUILD_NAME}":          os.Getenv("BUILD_NAME"),
		"${BUILD_JOB_NAME}":      os.Getenv("BUILD_JOB_NAME"),
		"${BUILD_PIPELINE_NAME}": os.Getenv("BUILD_PIPELINE_NAME"),
		"${ATC_EXTERNAL_URL}":    os.Getenv("ATC_EXTERNAL_URL"),
		"${BUILD_TEAM_NAME}":     os.Getenv("BUILD_TEAM_NAME"),
	}
	for k, v := range buildTokens {
		sourceString = strings.Replace(sourceString, k, v, -1)
	}
	return sourceString
}

func readSource(sourceRoot, sourcePath string) (string, error) {
	if !filepath.IsAbs(sourcePath) {
		sourcePath = filepath.Join(sourceRoot, sourcePath)
	}
	bytes, err := ioutil.ReadFile(sourcePath)
	return replaceTokens(string(bytes)), err
}

func fromTextOrFile(sourceRoot, text, filePath string) (string, error) {
	if text != "" {
		return replaceTokens(text), nil

	}
	if filePath != "" {
		return readSource(sourceRoot, filePath)
	}
	return "", nil
}
<|endoftext|>


<commit_before>package redis

import (
	"errors"
	"fmt"
	"strconv"
)

func (c *Client) BLPop(key string, timeout int, keys ...string) ([]string, error) {
	var vals = []string{key}
	vals = append(vals, keys...)
	vals = append(vals, strconv.Itoa(timeout))
	resp, err := c.exec("BLPOP", vals...)
	if err != nil {
		return nil, err
	}
	return c.stringSlice(resp)
}

func (c *Client) BRPop(key string, timeout int, keys ...string) ([]string, error) {
	var vals = []string{key}
	vals = append(vals, keys...)
	vals = append(vals, strconv.Itoa(timeout))
	resp, err := c.exec("BRPOP", vals...)
	if err != nil {
		return nil, err
	}
	return c.stringSlice(resp)
}

func (c *Client) BRPopLPush(source, destination string, timeout int) (*string, error) {
	resp, err := c.exec("BRPOPLPUSH", source, destination, strconv.Itoa(timeout))
	if err != nil {
		return nil, err
	}
	return c.nillableBulkString(resp)
}

func (c *Client) LIndex(key string, index int) (*string, error) {
	resp, err := c.exec("LINDEX", key, strconv.Itoa(index))
	if err != nil {
		return nil, err
	}
	return c.nillableBulkString(resp)
}

type BeforeAfter string

const (
	BEFORE BeforeAfter = "BEFORE"
	AFTER  BeforeAfter = "AFTER"
)

func (b BeforeAfter) String() string { return string(b) }

// TODO(ttacon): value is interface so can use int, float or string
func (c *Client) LInsert(
	key string,
	insert BeforeAfter,
	pivot string,
	value interface{}) (int64, error) {

	var strVal string
	if s, ok := value.(string); ok {
		strVal = s
	} else if i, ok := value.(int); ok {
		strVal = strconv.Itoa(i)
	} else if f, ok := value.(float64); ok {
		strVal = strconv.FormatFloat(f, byte('f'), -1, 64)
	} else {
		return -1, errors.New(
			fmt.Sprintf("value must be a string, int or float64, got: %v", value))
	}

	resp, err := c.exec("LINSERT", key, insert.String(), pivot, strVal)
	if err != nil {
		return -1, err
	}
	return c.intResp(resp)
}

func (c *Client) LLen(key string) (int64, error) {
	resp, err := c.exec("LLEN", key)
	if err != nil {
		return -1, err
	}
	return c.intResp(resp)
}

func (c *Client) LPop(key string) (*string, error) {
	resp, err := c.exec("LPOP", key)
	if err != nil {
		return nil, err
	}
	return c.nillableBulkString(resp)
}

func (c *Client) LPush(key, value string, values ...string) (int64, error) {
	resp, err := c.exec("LPUSH", append([]string{key, value}, values...)...)
	if err != nil {
		return 0, err
	}
	return c.intResp(resp)
}

func (c *Client) LPushx(key, value string) (int64, error) {
	resp, err := c.exec("LPUSHX", key, value)
	if err != nil {
		return 0, err
	}
	return c.intResp(resp)
}

func (c *Client) LRange(key string, start, stop int) ([]string, error) {
	resp, err := c.exec("LRANGE", key, strconv.Itoa(start), strconv.Itoa(stop))
	if err != nil {
		return nil, err
	}
	return c.stringSlice(resp)
}

func (c *Client) LRem(key string, count int, value string) (int64, error) {
	resp, err := c.exec("LREM", key, strconv.Itoa(count), value)
	if err != nil {
		return 0, err
	}
	return c.intResp(resp)
}

func (c *Client) LSet(key string, index int, value string) (bool, error) {
	resp, err := c.exec("LSET", key, strconv.Itoa(index), value)
	if err != nil {
		return false, err
	}
	val, err := c.stringResp(resp)
	return val == "OK", err
}

func (c *Client) LTrim(key string, start, stop int) (bool, error) {
	resp, err := c.exec("LTRIM", key, strconv.Itoa(start), strconv.Itoa(stop))
	if err != nil {
		return false, err
	}
	val, err := c.stringResp(resp)
	return val == "OK", err
}

func (c *Client) RPop(key string) (*string, error) {
	resp, err := c.exec("RPOP", key)
	if err != nil {
		return nil, err
	}
	return c.nillableBulkString(resp)
}

func (c *Client) RPopLPush(source, destination string) (string, error) {
	resp, err := c.exec("RPOPLPUSH", source, destination)
	if err != nil {
		return "", err
	}
	return c.bulkString(resp)
}

func (c *Client) RPush(key, value string, values ...string) (int, error) {
	// TODO(ttacon): ✔
	return 0, nil
}

func (c *Client) RPushX(key, value string, values ...string) (int, error) {
	// TODO(ttacon): ✔
	return 0, nil
}
<commit_msg>RPUSH<commit_after>package redis

import (
	"errors"
	"fmt"
	"strconv"
)

func (c *Client) BLPop(key string, timeout int, keys ...string) ([]string, error) {
	var vals = []string{key}
	vals = append(vals, keys...)
	vals = append(vals, strconv.Itoa(timeout))
	resp, err := c.exec("BLPOP", vals...)
	if err != nil {
		return nil, err
	}
	return c.stringSlice(resp)
}

func (c *Client) BRPop(key string, timeout int, keys ...string) ([]string, error) {
	var vals = []string{key}
	vals = append(vals, keys...)
	vals = append(vals, strconv.Itoa(timeout))
	resp, err := c.exec("BRPOP", vals...)
	if err != nil {
		return nil, err
	}
	return c.stringSlice(resp)
}

func (c *Client) BRPopLPush(source, destination string, timeout int) (*string, error) {
	resp, err := c.exec("BRPOPLPUSH", source, destination, strconv.Itoa(timeout))
	if err != nil {
		return nil, err
	}
	return c.nillableBulkString(resp)
}

func (c *Client) LIndex(key string, index int) (*string, error) {
	resp, err := c.exec("LINDEX", key, strconv.Itoa(index))
	if err != nil {
		return nil, err
	}
	return c.nillableBulkString(resp)
}

type BeforeAfter string

const (
	BEFORE BeforeAfter = "BEFORE"
	AFTER  BeforeAfter = "AFTER"
)

func (b BeforeAfter) String() string { return string(b) }

// TODO(ttacon): value is interface so can use int, float or string
func (c *Client) LInsert(
	key string,
	insert BeforeAfter,
	pivot string,
	value interface{}) (int64, error) {

	var strVal string
	if s, ok := value.(string); ok {
		strVal = s
	} else if i, ok := value.(int); ok {
		strVal = strconv.Itoa(i)
	} else if f, ok := value.(float64); ok {
		strVal = strconv.FormatFloat(f, byte('f'), -1, 64)
	} else {
		return -1, errors.New(
			fmt.Sprintf("value must be a string, int or float64, got: %v", value))
	}

	resp, err := c.exec("LINSERT", key, insert.String(), pivot, strVal)
	if err != nil {
		return -1, err
	}
	return c.intResp(resp)
}

func (c *Client) LLen(key string) (int64, error) {
	resp, err := c.exec("LLEN", key)
	if err != nil {
		return -1, err
	}
	return c.intResp(resp)
}

func (c *Client) LPop(key string) (*string, error) {
	resp, err := c.exec("LPOP", key)
	if err != nil {
		return nil, err
	}
	return c.nillableBulkString(resp)
}

func (c *Client) LPush(key, value string, values ...string) (int64, error) {
	resp, err := c.exec("LPUSH", append([]string{key, value}, values...)...)
	if err != nil {
		return 0, err
	}
	return c.intResp(resp)
}

func (c *Client) LPushx(key, value string) (int64, error) {
	resp, err := c.exec("LPUSHX", key, value)
	if err != nil {
		return 0, err
	}
	return c.intResp(resp)
}

func (c *Client) LRange(key string, start, stop int) ([]string, error) {
	resp, err := c.exec("LRANGE", key, strconv.Itoa(start), strconv.Itoa(stop))
	if err != nil {
		return nil, err
	}
	return c.stringSlice(resp)
}

func (c *Client) LRem(key string, count int, value string) (int64, error) {
	resp, err := c.exec("LREM", key, strconv.Itoa(count), value)
	if err != nil {
		return 0, err
	}
	return c.intResp(resp)
}

func (c *Client) LSet(key string, index int, value string) (bool, error) {
	resp, err := c.exec("LSET", key, strconv.Itoa(index), value)
	if err != nil {
		return false, err
	}
	val, err := c.stringResp(resp)
	return val == "OK", err
}

func (c *Client) LTrim(key string, start, stop int) (bool, error) {
	resp, err := c.exec("LTRIM", key, strconv.Itoa(start), strconv.Itoa(stop))
	if err != nil {
		return false, err
	}
	val, err := c.stringResp(resp)
	return val == "OK", err
}

func (c *Client) RPop(key string) (*string, error) {
	resp, err := c.exec("RPOP", key)
	if err != nil {
		return nil, err
	}
	return c.nillableBulkString(resp)
}

func (c *Client) RPopLPush(source, destination string) (string, error) {
	resp, err := c.exec("RPOPLPUSH", source, destination)
	if err != nil {
		return "", err
	}
	return c.bulkString(resp)
}

func (c *Client) RPush(key, value string, values ...string) (int64, error) {
	resp, err := c.exec("LPUSH", append([]string{key, value}, values...)...)
	if err != nil {
		return 0, err
	}
	return c.intResp(resp)
}

func (c *Client) RPushX(key, value string, values ...string) (int, error) {
	// TODO(ttacon): ✔
	return 0, nil
}
<|endoftext|>


<commit_before>package main

import (
	"html/template"
	"log"
	"net/http"
	"strings"
)

func forceLogin(w http.ResponseWriter, req *http.Request, ses Session) {
	if ses.Get("username") == "" {
		w.Header().Set("Location", "login")
		w.WriteHeader(http.StatusFound)
	}
}

func displayLogin(w http.ResponseWriter, req *http.Request, ses Session) {
	loginTemplate, err := template.New("base.html").ParseFiles("templates/base.html", "templates/login.html")
	if err != nil {
		log.Printf("Template error: %s", err)
		return
	}

	type loginData struct {
		Title string
		Error string
	}
	data := loginData{Error: ses.Get("loginError"), Title: "Purger Login"}
	ses.Set("loginError", "")

	err = loginTemplate.Execute(w, data)
	if err != nil {
		log.Printf("Template Error: %s", err)
	}
}

func handleLogin(w http.ResponseWriter, req *http.Request, ses Session) {
	pass, errUser := conf.String("auth", strings.ToLower(strings.TrimSpace(req.PostFormValue("username"))))
	if req.PostFormValue("password") == pass && errUser == nil {
		ses.Set("username", strings.Title(req.PostFormValue("username")))

		w.Header().Set("Location", "purger")
		w.WriteHeader(http.StatusFound)

		return
	}

	ses.Set("loginError", "Invalid username or password.")

	w.Header().Set("Location", "login")
	w.WriteHeader(http.StatusFound)
}
<commit_msg>more title fix<commit_after>package main

import (
	"html/template"
	"log"
	"net/http"
	"strings"
)

func forceLogin(w http.ResponseWriter, req *http.Request, ses Session) {
	if ses.Get("username") == "" {
		w.Header().Set("Location", "login")
		w.WriteHeader(http.StatusFound)
	}
}

func displayLogin(w http.ResponseWriter, req *http.Request, ses Session) {
	loginTemplate, err := template.New("base.html").ParseFiles("templates/base.html", "templates/login.html")
	if err != nil {
		log.Printf("Template error: %s", err)
		return
	}

	type loginData struct {
		Title string
		Error string
	}
	data := loginData{Error: ses.Get("loginError"), Title: "SlopeMaker Login"}
	ses.Set("loginError", "")

	err = loginTemplate.Execute(w, data)
	if err != nil {
		log.Printf("Template Error: %s", err)
	}
}

func handleLogin(w http.ResponseWriter, req *http.Request, ses Session) {
	pass, errUser := conf.String("auth", strings.ToLower(strings.TrimSpace(req.PostFormValue("username"))))
	if req.PostFormValue("password") == pass && errUser == nil {
		ses.Set("username", strings.Title(req.PostFormValue("username")))

		w.Header().Set("Location", "purger")
		w.WriteHeader(http.StatusFound)

		return
	}

	ses.Set("loginError", "Invalid username or password.")

	w.Header().Set("Location", "login")
	w.WriteHeader(http.StatusFound)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
)

var cmdLogin = &Command{
	Run:   runLogin,
	Usage: "login",
	Short: "Log in to force.com",
	Long: `
Log in to force.com

Examples:

  force login -- for Production and DE orgs
  force login test -- for Sandbox orgs
  force login pre -- for Pre-release feature orgs

`,
}

func runLogin(cmd *Command, args []string) {
	var endpoint ForceEndpoint
	endpoint = EndpointProduction
	if len(args) > 0 {
		switch args[0] {
		case "test":
			endpoint = EndpointTest
		case "pre":
			endpoint = EndpointPrerelease
		default:
			ErrorAndExit("no such endpoint: %s", args[0])
		}
	}
	_, err := ForceLoginAndSave(endpoint)
	if err != nil {
		ErrorAndExit(err.Error())
	}
}

var cmdLogout = &Command{
	Run:   runLogout,
	Usage: "logout <account>",
	Short: "Log out from force.com",
	Long: `
Log out from force.com

Examples:

  force logout user@example.org
`,
}

func runLogout(cmd *Command, args []string) {
	if len(args) != 1 {
		ErrorAndExit("must specify account to log out")
	}
	account := args[0]
	Config.Delete("accounts", account)
	if active, _ := Config.Load("current", "account"); active == account {
		Config.Delete("current", "account")
		SetActiveAccountDefault()
	}
}

func ForceLoginAndSave(endpoint ForceEndpoint) (username string, err error) {
	creds, err := ForceLogin(endpoint)
	if err != nil {
		return
	}
	force := NewForce(creds)
	login, err := force.Get(creds.Id)
	if err != nil {
		return
	}
	body, err := json.Marshal(creds)
	if err != nil {
		return
	}
	username = login["username"].(string)
	Config.Save("accounts", username, string(body))
	Config.Save("current", "account", username)
	return
}
<commit_msg>Updated to have line returns between examples & have comments line up.<commit_after>package main

import (
	"encoding/json"
)

var cmdLogin = &Command{
	Run:   runLogin,
	Usage: "login",
	Short: "Log in to force.com",
	Long: `
Log in to force.com

Examples:

  force login 		# for Production and DE orgs

  force login test 	# for Sandbox orgs

  force login pre 	# for Pre-release feature orgs

`,
}

func runLogin(cmd *Command, args []string) {
	var endpoint ForceEndpoint
	endpoint = EndpointProduction
	if len(args) > 0 {
		switch args[0] {
		case "test":
			endpoint = EndpointTest
		case "pre":
			endpoint = EndpointPrerelease
		default:
			ErrorAndExit("no such endpoint: %s", args[0])
		}
	}
	_, err := ForceLoginAndSave(endpoint)
	if err != nil {
		ErrorAndExit(err.Error())
	}
}

var cmdLogout = &Command{
	Run:   runLogout,
	Usage: "logout <account>",
	Short: "Log out from force.com",
	Long: `
Log out from force.com

Examples:

  force logout user@example.org
`,
}

func runLogout(cmd *Command, args []string) {
	if len(args) != 1 {
		ErrorAndExit("must specify account to log out")
	}
	account := args[0]
	Config.Delete("accounts", account)
	if active, _ := Config.Load("current", "account"); active == account {
		Config.Delete("current", "account")
		SetActiveAccountDefault()
	}
}

func ForceLoginAndSave(endpoint ForceEndpoint) (username string, err error) {
	creds, err := ForceLogin(endpoint)
	if err != nil {
		return
	}
	force := NewForce(creds)
	login, err := force.Get(creds.Id)
	if err != nil {
		return
	}
	body, err := json.Marshal(creds)
	if err != nil {
		return
	}
	username = login["username"].(string)
	Config.Save("accounts", username, string(body))
	Config.Save("current", "account", username)
	return
}
<|endoftext|>