<commit_before>// Copyright (c) 2013 VividCortex. Please see the LICENSE file for license terms.

/*
This package provides an HTTP client to use with pm-enabled processes.
*/
package client

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"

	"github.com/VividCortex/pm"
)

type Client struct {
	*http.Client
	BaseURI string
	Headers map[string]string
}

// NewClient returns a new client set to connect to the given URI.
func NewClient(uri string) *Client {
	return &Client{
		Client:  &http.Client{},
		BaseURI: uri,
		Headers: map[string]string{
			"Accept":       "application/json",
			"Content-Type": "application/json",
			"User-Agent":   "go-pm",
		},
	}
}

func (c *Client) makeRequest(verb, endpoint string, body, result interface{}) error {
	buf := new(bytes.Buffer)
	if body != nil {
		if err := json.NewEncoder(buf).Encode(body); err != nil {
			return err
		}
	}
	req, err := http.NewRequest(verb, c.BaseURI+endpoint, buf)
	if err != nil {
		return err
	}
	for header, value := range c.Headers {
		req.Header.Add(header, value)
	}

	resp, err := c.Do(req)
	if err == nil && resp.StatusCode > 299 {
		msg := fmt.Sprintf("HTTP Status Code %d from %s %s\n", resp.Status, verb, c.BaseURI+endpoint)
		err = errors.New(msg)
	}

	if resp != nil {
		defer resp.Body.Close()
		if err == nil && result != nil {
			json.NewDecoder(resp.Body).Decode(result)
		}
	}
	return err
}

// Processes issues a GET to /proc, thus retrieving the full process list from
// the server. The result is provided as a ProcResponse.
func (c *Client) Processes() (*pm.ProcResponse, error) {
	var result pm.ProcResponse
	if err := c.makeRequest("GET", "/procs/", nil, &result); err != nil {
		return nil, err
	}
	return &result, nil
}

// History issues a GET to /proc/<id>/history for a given id, thus returning the
// complete history for the task <id> at the server.
func (c *Client) History(id string) (*pm.HistoryResponse, error) {
	var result pm.HistoryResponse
	endpoint := fmt.Sprintf("/procs/%s/history", id)

	if err := c.makeRequest("GET", endpoint, nil, &result); err != nil {
		return nil, err
	}
	return &result, nil
}

// Kill requests the cancellation of a given task. Note that it will effectively
// be cancelled as soon as the task reaches its next cancellation point.
func (c *Client) Kill(id, message string) error {
	body := pm.CancelRequest{Message: message}
	endpoint := fmt.Sprintf("/procs/%s", id)

	if err := c.makeRequest("DELETE", endpoint, body, nil); err != nil {
		return err
	}
	return nil
}
<commit_msg>Use StatusCode instead of Status as it was intended<commit_after>// Copyright (c) 2013 VividCortex. Please see the LICENSE file for license terms.

/*
This package provides an HTTP client to use with pm-enabled processes.
*/
package client

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"

	"github.com/VividCortex/pm"
)

type Client struct {
	*http.Client
	BaseURI string
	Headers map[string]string
}

// NewClient returns a new client set to connect to the given URI.
func NewClient(uri string) *Client {
	return &Client{
		Client:  &http.Client{},
		BaseURI: uri,
		Headers: map[string]string{
			"Accept":       "application/json",
			"Content-Type": "application/json",
			"User-Agent":   "go-pm",
		},
	}
}

func (c *Client) makeRequest(verb, endpoint string, body, result interface{}) error {
	buf := new(bytes.Buffer)
	if body != nil {
		if err := json.NewEncoder(buf).Encode(body); err != nil {
			return err
		}
	}
	req, err := http.NewRequest(verb, c.BaseURI+endpoint, buf)
	if err != nil {
		return err
	}
	for header, value := range c.Headers {
		req.Header.Add(header, value)
	}

	resp, err := c.Do(req)
	if err == nil && resp.StatusCode > 299 {
		msg := fmt.Sprintf("HTTP Status Code %d from %s %s\n", resp.StatusCode, verb, c.BaseURI+endpoint)
		err = errors.New(msg)
	}

	if resp != nil {
		defer resp.Body.Close()
		if err == nil && result != nil {
			json.NewDecoder(resp.Body).Decode(result)
		}
	}
	return err
}

// Processes issues a GET to /proc, thus retrieving the full process list from
// the server. The result is provided as a ProcResponse.
func (c *Client) Processes() (*pm.ProcResponse, error) {
	var result pm.ProcResponse
	if err := c.makeRequest("GET", "/procs/", nil, &result); err != nil {
		return nil, err
	}
	return &result, nil
}

// History issues a GET to /proc/<id>/history for a given id, thus returning the
// complete history for the task <id> at the server.
func (c *Client) History(id string) (*pm.HistoryResponse, error) {
	var result pm.HistoryResponse
	endpoint := fmt.Sprintf("/procs/%s/history", id)

	if err := c.makeRequest("GET", endpoint, nil, &result); err != nil {
		return nil, err
	}
	return &result, nil
}

// Kill requests the cancellation of a given task. Note that it will effectively
// be cancelled as soon as the task reaches its next cancellation point.
func (c *Client) Kill(id, message string) error {
	body := pm.CancelRequest{Message: message}
	endpoint := fmt.Sprintf("/procs/%s", id)

	if err := c.makeRequest("DELETE", endpoint, body, nil); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package kubefed

import (
	"io"

	"k8s.io/apiserver/pkg/util/flag"
	"k8s.io/client-go/tools/clientcmd"
	kubefedinit "k8s.io/kubernetes/federation/pkg/kubefed/init"
	"k8s.io/kubernetes/federation/pkg/kubefed/util"
	kubectl "k8s.io/kubernetes/pkg/kubectl/cmd"
	"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"

	"github.com/spf13/cobra"
)

// NewKubeFedCommand creates the `kubefed` command and its nested children.
func NewKubeFedCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer, defaultServerImage, defaultEtcdImage string) *cobra.Command {
	// Parent command to which all subcommands are added.
	cmds := &cobra.Command{
		Use:   "kubefed",
		Short: "kubefed controls a Kubernetes Cluster Federation",
		Long: templates.LongDesc(`
      kubefed controls a Kubernetes Cluster Federation.

      Find more information at https://github.com/kubernetes/kubernetes.`),
		Run: runHelp,
	}

	f.BindFlags(cmds.PersistentFlags())
	f.BindExternalFlags(cmds.PersistentFlags())

	// From this point and forward we get warnings on flags that contain "_" separators
	cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc)

	groups := templates.CommandGroups{
		{
			Message: "Basic Commands:",
			Commands: []*cobra.Command{
				kubefedinit.NewCmdInit(out, util.NewAdminConfig(clientcmd.NewDefaultPathOptions()), defaultServerImage, defaultEtcdImage),
				NewCmdJoin(f, out, util.NewAdminConfig(clientcmd.NewDefaultPathOptions())),
				NewCmdUnjoin(f, out, err, util.NewAdminConfig(clientcmd.NewDefaultPathOptions())),
			},
		},
	}
	groups.Add(cmds)

	filters := []string{
		"options",
	}
	templates.ActsAsRootCommand(cmds, filters, groups...)

	cmds.AddCommand(kubectl.NewCmdVersion(f, out))
	cmds.AddCommand(kubectl.NewCmdOptions(out))

	return cmds
}

func runHelp(cmd *cobra.Command, args []string) {
	cmd.Help()
}
<commit_msg>[Federation] Kubefed doc fix<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package kubefed

import (
	"io"

	"k8s.io/apiserver/pkg/util/flag"
	"k8s.io/client-go/tools/clientcmd"
	kubefedinit "k8s.io/kubernetes/federation/pkg/kubefed/init"
	"k8s.io/kubernetes/federation/pkg/kubefed/util"
	kubectl "k8s.io/kubernetes/pkg/kubectl/cmd"
	"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/util/i18n"

	"github.com/spf13/cobra"
)

var (
	kubefedVersionExample = templates.Examples(i18n.T(`
		# Print the client and server versions for the current context
		kubefed version`))
	kubefedOptionsExample = templates.Examples(i18n.T(`
		# Print flags inherited by all commands
		kubefed options`))
)

// NewKubeFedCommand creates the `kubefed` command and its nested children.
func NewKubeFedCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer, defaultServerImage, defaultEtcdImage string) *cobra.Command {
	// Parent command to which all subcommands are added.
	cmds := &cobra.Command{
		Use:   "kubefed",
		Short: "kubefed controls a Kubernetes Cluster Federation",
		Long: templates.LongDesc(`
      kubefed controls a Kubernetes Cluster Federation.

      Find more information at https://github.com/kubernetes/kubernetes.`),
		Run: runHelp,
	}

	f.BindFlags(cmds.PersistentFlags())
	f.BindExternalFlags(cmds.PersistentFlags())

	// From this point and forward we get warnings on flags that contain "_" separators
	cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc)

	groups := templates.CommandGroups{
		{
			Message: "Basic Commands:",
			Commands: []*cobra.Command{
				kubefedinit.NewCmdInit(out, util.NewAdminConfig(clientcmd.NewDefaultPathOptions()), defaultServerImage, defaultEtcdImage),
				NewCmdJoin(f, out, util.NewAdminConfig(clientcmd.NewDefaultPathOptions())),
				NewCmdUnjoin(f, out, err, util.NewAdminConfig(clientcmd.NewDefaultPathOptions())),
			},
		},
	}
	groups.Add(cmds)

	filters := []string{
		"options",
	}
	templates.ActsAsRootCommand(cmds, filters, groups...)

	cmdVersion := kubectl.NewCmdVersion(f, out)
	cmdVersion.Example = kubefedVersionExample
	cmds.AddCommand(cmdVersion)
	cmdOptions := kubectl.NewCmdOptions(out)
	cmdOptions.Example = kubefedOptionsExample
	cmds.AddCommand(cmdOptions)

	return cmds
}

func runHelp(cmd *cobra.Command, args []string) {
	cmd.Help()
}
<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package basic

import (
	"io"
	"os"
	"path/filepath"

	"github.com/juju/errors"

	"github.com/juju/utils/filestorage"
)

type fsStorage struct {
	dirname string
}

func NewRawFileStorage(dirname string) (filestorage.RawFileStorage, error) {
	stor := fsStorage{
		dirname: dirname,
	}
	if err := os.MkdirAll(dirname, 0777); err != nil {
		return nil, errors.Annotatef(err, "error while creating directory (%q)", dirname)
	}
	return &stor, nil
}

func (s *fsStorage) File(id string) (io.ReadCloser, error) {
	filename := filepath.Join(s.dirname, id)
	file, err := os.Open(filename)
	if err != nil {
		return nil, errors.Annotatef(err, "error while opening file (%q)", filename)
	}
	return file, nil
}

func (s *fsStorage) AddFile(id string, file io.Reader, size int64) error {
	filename := filepath.Join(s.dirname, id)
	target, err := os.Create(filename)
	if err != nil {
		return errors.Annotatef(err, "error while creating file (%q)", filename)
	}
	defer target.Close()
	_, err = io.Copy(target, file)
	if err != nil {
		return errors.Annotatef(err, "error while writing to file (%q)", filename)
	}
	return nil
}

func (s *fsStorage) RemoveFile(id string) error {
	filename := filepath.Join(s.dirname, id)
	err := os.Remove(filename)
	if os.IsNotExist(err) {
		return errors.NotFoundf(id)
	} else if err != nil {
		return errors.Annotatef(err, "error removing file (%q)", filename)
	}
	return nil
}

// Close implements io.Closer.Close.
func (s *fsStorage) Close() error {
	return nil
}
<commit_msg>Drop unnecessary parentheses.<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package basic

import (
	"io"
	"os"
	"path/filepath"

	"github.com/juju/errors"

	"github.com/juju/utils/filestorage"
)

type fsStorage struct {
	dirname string
}

func NewRawFileStorage(dirname string) (filestorage.RawFileStorage, error) {
	stor := fsStorage{
		dirname: dirname,
	}
	if err := os.MkdirAll(dirname, 0777); err != nil {
		return nil, errors.Annotatef(err, "error while creating directory %q", dirname)
	}
	return &stor, nil
}

func (s *fsStorage) File(id string) (io.ReadCloser, error) {
	filename := filepath.Join(s.dirname, id)
	file, err := os.Open(filename)
	if err != nil {
		return nil, errors.Annotatef(err, "error while opening file %q", filename)
	}
	return file, nil
}

func (s *fsStorage) AddFile(id string, file io.Reader, size int64) error {
	filename := filepath.Join(s.dirname, id)
	target, err := os.Create(filename)
	if err != nil {
		return errors.Annotatef(err, "error while creating file %q", filename)
	}
	defer target.Close()
	_, err = io.Copy(target, file)
	if err != nil {
		return errors.Annotatef(err, "error while writing to file %q", filename)
	}
	return nil
}

func (s *fsStorage) RemoveFile(id string) error {
	filename := filepath.Join(s.dirname, id)
	err := os.Remove(filename)
	if os.IsNotExist(err) {
		return errors.NotFoundf(id)
	} else if err != nil {
		return errors.Annotatef(err, "error removing file %q", filename)
	}
	return nil
}

// Close implements io.Closer.Close.
func (s *fsStorage) Close() error {
	return nil
}
<|endoftext|>


<commit_before>package model

import (
	"errors"
	"fmt"
	"time"

	"appengine"
	"appengine/datastore"
)

var (
	ErrClassExists   = errors.New("Class already exists")
	ErrClassNotEmpty = errors.New("Class is not empty")
)

type ClassFullError struct {
	Class string
}

func (e *ClassFullError) Error() string {
	return fmt.Sprintf("Class %s is full", e.Class)
}

func classFullError(class string) error {
	return &ClassFullError{class}
}

type Class struct {
	Title       string `datastore: ",noindex"`
	Description string `datastore: ",noindex"`
	Teacher     string

	DayOfWeek     string
	StartTime     time.Time `datastore: ",noindex"`
	LengthMinutes int32     `datastore: ",noindex"`

	BeginDate time.Time
	EndDate   time.Time

	DropInOnly bool

	// The number of students who can register for the class.
	Capacity int32 `datastore: ",noindex"`
}

// NextClassTime returns the earliest start time of the class which starts strictly later than the
// given time.
func (c *Class) NextClassTime(after time.Time) time.Time {
	return time.Time{}
}

func (c *Class) key(ctx appengine.Context) *datastore.Key {
	return datastore.NewKey(ctx, "Class", c.Title, 0, nil)
}

// A Scheduler is responsible for manipulating classes.
type Scheduler interface {
	AddNew(c *Class) error
	ListClasses(activeOnly bool) []*Class
	DeleteClass(class string) error
}

type scheduler struct {
	appengine.Context
}

func (s *scheduler) AddNew(c *Class) error {
	key := c.key(s)
	err := datastore.RunInTransaction(s, func(context appengine.Context) error {
		old := &Class{}
		if err := datastore.Get(context, key, old); err != datastore.ErrNoSuchEntity {
			return ErrClassExists
		}
		_, err := datastore.Put(context, key, c)
		return err
	}, nil)
	if err != nil && err != ErrClassExists {
		return fmt.Errorf("Erorr inserting class %s: %s", c.Title, err)
	}
	return err
}

func (s *scheduler) ListClasses(activeOnly bool) []*Class {
	classes := []*Class{}
	q := datastore.NewQuery("Class")
	_, err := q.GetAll(s, &classes)
	if err != nil {
		s.Errorf("Error listing classes: %s", err)
		return nil
	}
	return classes
}

func (s *scheduler) DeleteClass(class string) error {
	key := datastore.NewKey(s, "Class", class, 0, nil)
	err := datastore.RunInTransaction(s, func(context appengine.Context) error {
		q := datastore.NewQuery("Registration").
			Ancestor(key).
			KeysOnly().
			Limit(1)
		keys, err := q.GetAll(context, nil)
		if err != nil {
			return err
		}
		if len(keys) > 0 {
			return ErrClassNotEmpty
		}
		if err := datastore.Delete(context, key); err != nil {
			return err
		}
		return nil
	}, nil)
	if err != nil && err != ErrClassNotEmpty {
		return fmt.Errorf("Error deleting %s: %s", class, err)
	}
	return err
}

func NewScheduler(c appengine.Context) Scheduler {
	return &scheduler{c}
}

// A Registration represents a reserved space in a class, either for the entire session or as a drop
// in.
type Registration struct {
	StudentID  string
	ClassTitle string

	// If this registration is a drop in, Date is the start time of the class to which it applies.
	Date time.Time
}

// A Registrar manages how students register for classes in the schedule.
type Registrar interface {
	LookupRegistration(class, studentID string) *Registration
}

func NewRegistrar(c appengine.Context) Registrar {
	return nil
}

type StudentRegistrar interface {
	ListRegistrations() []*Registration
	FilterRegisteredClasses(classes []*Class) ([]*Class, error)
	RegisterForClass(c *Class) (*Registration, error)
}

func NewStudentRegistrar(c appengine.Context, studentID string) StudentRegistrar {
	return nil
}
<commit_msg>Migrated registration flow to new model types.<commit_after>package model

import (
	"errors"
	"fmt"
	"time"

	"appengine"
	"appengine/datastore"
)

var (
	ErrClassFull         = errors.New("Class is full")
	ErrClassExists       = errors.New("Class already exists")
	ErrClassNotEmpty     = errors.New("Class is not empty")
	ErrAlreadyRegistered = errors.New("Student is already registered for class")
)

type ClassFullError struct {
	Class string
}

func (e *ClassFullError) Error() string {
	return fmt.Sprintf("Class %s is full", e.Class)
}

func classFullError(class string) error {
	return &ClassFullError{class}
}

type Class struct {
	ID          int64  `datastore: "-"`
	Title       string `datastore: ",noindex"`
	Description string `datastore: ",noindex"`
	Teacher     string

	DayOfWeek     string
	StartTime     time.Time `datastore: ",noindex"`
	LengthMinutes int32     `datastore: ",noindex"`

	BeginDate time.Time
	EndDate   time.Time
	Active    bool

	DropInOnly bool

	// The number of students who can register for the class.
	Capacity int32 `datastore: ",noindex"`
}

// NextClassTime returns the earliest start time of the class which starts strictly later than the
// given time.
func (c *Class) NextClassTime(after time.Time) time.Time {
	return time.Time{}
}

func (c *Class) key(ctx appengine.Context) *datastore.Key {
	return datastore.NewKey(ctx, "Class", "", c.ID, nil)
}

// A Scheduler is responsible for manipulating classes.
type Scheduler interface {
	AddNew(c *Class) error
	GetClass(id int64) *Class
	ListClasses(activeOnly bool) []*Class
	DeleteClass(c *Class) error
}

type scheduler struct {
	appengine.Context
}

func (s *scheduler) GetClass(id int64) *Class {
	key := datastore.NewKey(s, "Class", "", id, nil)
	class := &Class{}
	if err := datastore.Get(s, key, class); err != nil {
		s.Errorf("Error getting class %d: %s", id, err)
		return nil
	}
	class.ID = id
	return class
}

func (s *scheduler) AddNew(c *Class) error {
	key := datastore.NewIncompleteKey(s, "Class", nil)
	if _, err := datastore.Put(s, key, c); err != nil {
		return fmt.Errorf("Error writing class %s: %s", c.Title, err)
	}
	return nil
}

func (s *scheduler) ListClasses(activeOnly bool) []*Class {
	classes := []*Class{}
	q := datastore.NewQuery("Class")
	if activeOnly {
		q = q.Filter("Active =", true)
	}
	keys, err := q.GetAll(s, &classes)
	if err != nil {
		s.Errorf("Error listing classes: %s", err)
		return nil
	}
	for idx, key := range keys {
		classes[idx].ID = key.IntID()
	}
	return classes
}

func (s *scheduler) DeleteClass(c *Class) error {
	key := c.key(s)
	err := datastore.RunInTransaction(s, func(context appengine.Context) error {
		q := datastore.NewQuery("Registration").
			Ancestor(key).
			KeysOnly().
			Limit(1)
		keys, err := q.GetAll(context, nil)
		if err != nil {
			return err
		}
		if len(keys) > 0 {
			return ErrClassNotEmpty
		}
		if err := datastore.Delete(context, key); err != nil {
			return err
		}
		return nil
	}, nil)
	if err != nil && err != ErrClassNotEmpty {
		return fmt.Errorf("Error deleting class %d: %s", c.ID, err)
	}
	return err
}

func NewScheduler(c appengine.Context) Scheduler {
	return &scheduler{c}
}

// A Registration represents a reserved space in a class, either for the entire session or as a drop
// in.
type Registration struct {
	StudentID string
	ClassID   int64

	// If this registration is a drop in, Date is the start time of the class to which it applies.
	Date time.Time
}

func (r *Registration) key(c appengine.Context) *datastore.Key {
	classKey := datastore.NewKey(c, "Class", "", r.ClassID, nil)
	return datastore.NewKey(c, "Registration", r.StudentID, 0, classKey)
}

type Roster interface {
	LookupRegistration(studentID string) *Registration
	ListRegistrations() []*Registration
	AddStudent(studentID string) (*Registration, error)
	AddDropIn(studentID string, date time.Time) (*Registration, error)
}

type roster struct {
	appengine.Context
	class *Class
}

func NewRoster(c appengine.Context, class *Class) Roster {
	return &roster{c, class}
}

func (r *roster) ListRegistrations() []*Registration {
	q := datastore.NewQuery("Registration").
		Ancestor(r.class.key(r))
	rs := []*Registration{}
	if _, err := q.GetAll(r, rs); err != nil {
		r.Errorf("Error looking up registrations for class %d: %s", r.class.ID, err)
		return nil
	}
	return rs
}

func (r *roster) LookupRegistration(studentID string) *Registration {
	key := datastore.NewKey(r, "Registration", studentID, 0, r.class.key(r))
	reg := &Registration{}
	if err := datastore.Get(r, key, reg); err != nil {
		r.Errorf("Error looking up registration for student %s in class %d: %s", studentID, r.class.ID, err)
		return nil
	}
	return reg
}

func (r *roster) AddStudent(studentID string) (*Registration, error) {
	reg := &Registration{
		ClassID:   r.class.ID,
		StudentID: studentID,
	}
	err := datastore.RunInTransaction(r, func(ctx appengine.Context) error {
		key := reg.key(ctx)
		old := &Registration{}
		if err := datastore.Get(ctx, key, old); err != datastore.ErrNoSuchEntity {
			if err != nil {
				return fmt.Errorf("Error looking up registration %+v: %s", reg, err)
			}
			return ErrAlreadyRegistered
		}
		if _, err := datastore.Put(ctx, key, reg); err != nil {
			return fmt.Errorf("Error writing registration %+v: %s", reg, err)
		}
		return nil
	}, nil)
	if err != nil {
		return nil, err
	}
	return reg, nil
}

func (r *roster) AddDropIn(studentID string, date time.Time) (*Registration, error) {
	return nil, fmt.Errorf("Not yet implemented")
}

type Registrar interface {
	ListRegistrations() []*Registration
}

type registrar struct {
	appengine.Context
	studentID string
}

func NewRegistrar(c appengine.Context, studentID string) Registrar {
	return &registrar{c, studentID}
}

func (r *registrar) ListRegistrations() []*Registration {
	rs := []*Registration{}
	q := datastore.NewQuery("Registration").
		Filter("StudentID =", r.studentID)
	if _, err := q.GetAll(r, &rs); err != nil {
		return nil
	}
	return rs
}
<|endoftext|>


<commit_before>package model

import (
	gonet "code.google.com/p/go.net/html"
	"github.com/slyrz/newscat/html"
)

// A clusterMap groups clusters by HTML nodes.
type clusterMap map[*gonet.Node]*cluster

// A cluster stores a group of html.Chunks and their scores.
type cluster struct {
	Chunks  []*html.Chunk
	Scores  []float32
	Weights []float32
	// Unexported fields.
	average float32 // weighted average score
	changed bool    // denotes struct changes after average calculation
}

// newCluster creates and initalizes a new cluster.
func newCluster() *cluster {
	result := new(cluster)
	result.Chunks = make([]*html.Chunk, 0)
	result.Scores = make([]float32, 0)
	result.Weights = make([]float32, 0)
	return result
}

// Add adds the html.Chunk chunk to the cluster. The variadic float32 parameter
// args must either be (score,) or (score, weight).
func (cl *cluster) Add(chunk *html.Chunk, args ...float32) {
	var score float32 = 0.0
	var weight float32 = 0.0
	switch len(args) {
	case 2:
		score, weight = args[0], args[1]
	case 1:
		score, weight = args[0], 1.0
	default:
		panic("call Add(chunk, score) or Add(chunk, score, weight)")
	}
	cl.Chunks = append(cl.Chunks, chunk)
	cl.Scores = append(cl.Scores, score)
	cl.Weights = append(cl.Weights, weight)
	cl.changed = true
}

// Score calculates the weighted average of all chunk scores in cluster.
func (cl *cluster) Score() float32 {
	if cl.changed {
		var s float32 = 0.0
		var w float32 = 0.0
		for i := range cl.Chunks {
			s += cl.Weights[i] * cl.Scores[i]
			w += cl.Weights[i]
		}
		cl.average = s / w
		cl.changed = true
	}
	return cl.average
}

// newClusterMap creates and initalizes a new clusterMap.
func newClusterMap() clusterMap {
	return make(clusterMap)
}

// Add adds the html.Chunk chunk to the cluster indexed by key.
func (cl clusterMap) Add(key *gonet.Node, chunk *html.Chunk, args ...float32) {
	cluster, ok := cl[key]
	if !ok {
		cluster = newCluster()
		cl[key] = cluster
	}
	cluster.Add(chunk, args...)
}
<commit_msg>fixed bug which caused unnecessary calculations<commit_after>package model

import (
	gonet "code.google.com/p/go.net/html"
	"github.com/slyrz/newscat/html"
)

// A clusterMap groups clusters by HTML nodes.
type clusterMap map[*gonet.Node]*cluster

// A cluster stores a group of html.Chunks and their scores.
type cluster struct {
	Chunks  []*html.Chunk
	Scores  []float32
	Weights []float32
	// Unexported fields.
	average float32 // weighted average score
	changed bool    // denotes struct changes after average calculation
}

// newCluster creates and initalizes a new cluster.
func newCluster() *cluster {
	result := new(cluster)
	result.Chunks = make([]*html.Chunk, 0)
	result.Scores = make([]float32, 0)
	result.Weights = make([]float32, 0)
	return result
}

// Add adds the html.Chunk chunk to the cluster. The variadic float32 parameter
// args must either be (score,) or (score, weight).
func (cl *cluster) Add(chunk *html.Chunk, args ...float32) {
	var score float32 = 0.0
	var weight float32 = 0.0
	switch len(args) {
	case 2:
		score, weight = args[0], args[1]
	case 1:
		score, weight = args[0], 1.0
	default:
		panic("call Add(chunk, score) or Add(chunk, score, weight)")
	}
	cl.Chunks = append(cl.Chunks, chunk)
	cl.Scores = append(cl.Scores, score)
	cl.Weights = append(cl.Weights, weight)
	cl.changed = true
}

// Score calculates the weighted average of all chunk scores in cluster.
func (cl *cluster) Score() float32 {
	if cl.changed {
		var s float32 = 0.0
		var w float32 = 0.0
		for i := range cl.Chunks {
			s += cl.Weights[i] * cl.Scores[i]
			w += cl.Weights[i]
		}
		cl.average = s / w
		cl.changed = false
	}
	return cl.average
}

// newClusterMap creates and initalizes a new clusterMap.
func newClusterMap() clusterMap {
	return make(clusterMap)
}

// Add adds the html.Chunk chunk to the cluster indexed by key.
func (cl clusterMap) Add(key *gonet.Node, chunk *html.Chunk, args ...float32) {
	cluster, ok := cl[key]
	if !ok {
		cluster = newCluster()
		cl[key] = cluster
	}
	cluster.Add(chunk, args...)
}
<|endoftext|>


<commit_before>package model

import (
	"io/ioutil"
	"os"

	"github.com/jakubknejzlik/kontena-git-cli/utils"

	yaml2 "gopkg.in/yaml.v2"
)

// KontenaSecret ...
type KontenaSecret struct {
	Secret string `yaml:"secret,omitempty"`
	Name   string `yaml:"name,omitempty"`
	Type   string `yaml:"type,omitempty"`
}

// KontenaDeploy ...
type KontenaDeploy struct {
	Strategy string `yaml:"strategy,omitempty"`
}

// KontenaService ...
type KontenaService struct {
	Instances *int   `yaml:"instances,omitempty"`
	Image     string `yaml:"image,omitempty"`
	Command   string `yaml:"command,omitempty"`
	// Entrypoint    string            `yaml:"entrypoint,omitempty"`
	Volumes     []string              `yaml:"volumes"`
	Labels      map[string]string     `yaml:"labels"`
	Environment []string              `yaml:"environment"`
	Links       []string              `yaml:"links"`
	Ports       []string              `yaml:"ports"`
	Secrets     []KontenaSecret       `yaml:"secrets"`
	Deploy      KontenaDeploy         `yaml:"deploy,omitempty"`
	Logging     KontenaServiceLogging `yaml:"logging,omitempty"`
	Stateful    bool                  `yaml:"stateful,omitempty"`
}

// KontenaServiceLogging ...
type KontenaServiceLogging struct {
	Driver  string            `yaml:"driver,omitempty"`
	Options map[string]string `yaml:"options,omitempty"`
}

// KontenaStack ...
type KontenaStack struct {
	Name     string                    `yaml:"stack,omitempty"`
	Version  string                    `yaml:"version,omitempty"`
	Services map[string]KontenaService `yaml:"services,omitempty"`
}

// KontenaLoad ...
func KontenaLoad(path string) (KontenaStack, error) {
	var dc KontenaStack
	data, err := ioutil.ReadFile(path)

	if err != nil {
		return dc, err
	}
	yaml2.Unmarshal(data, &dc)
	return dc, nil
}

// ExportTemporary ...
func (c KontenaStack) ExportTemporary(translateSecrets bool) (string, error) {
	var path string
	tmp, err := ioutil.TempFile(os.TempDir(), "kontena")
	if err != nil {
		return path, err
	}

	path = tmp.Name()
	stack := c

	if translateSecrets {
		newServices := map[string]KontenaService{}
		for i, service := range stack.Services {
			newSecrets := []KontenaSecret{}
			for _, secret := range service.Secrets {
				newSecrets = append(newSecrets, KontenaSecret{
					Secret: stack.Name + "_" + secret.Secret,
					Name:   secret.Name,
					Type:   secret.Type,
				})
			}
			service.Secrets = newSecrets
			newServices[i] = service
		}
		stack.Services = newServices
	}

	data, marshalError := yaml2.Marshal(stack)
	if marshalError != nil {
		return path, marshalError
	}

	utils.LogSection("exported kontena file", string(data))
	if err := ioutil.WriteFile(path, data, 0644); err != nil {
		return path, err
	}

	return path, nil
}
<commit_msg>Remove service labels<commit_after>package model

import (
	"io/ioutil"
	"os"

	"github.com/jakubknejzlik/kontena-git-cli/utils"

	yaml2 "gopkg.in/yaml.v2"
)

// KontenaSecret ...
type KontenaSecret struct {
	Secret string `yaml:"secret,omitempty"`
	Name   string `yaml:"name,omitempty"`
	Type   string `yaml:"type,omitempty"`
}

// KontenaDeploy ...
type KontenaDeploy struct {
	Strategy string `yaml:"strategy,omitempty"`
}

// KontenaService ...
type KontenaService struct {
	Instances *int   `yaml:"instances,omitempty"`
	Image     string `yaml:"image,omitempty"`
	Command   string `yaml:"command,omitempty"`
	// Entrypoint    string            `yaml:"entrypoint,omitempty"`
	Volumes     []string              `yaml:"volumes"`
	Environment []string              `yaml:"environment"`
	Links       []string              `yaml:"links"`
	Ports       []string              `yaml:"ports"`
	Secrets     []KontenaSecret       `yaml:"secrets"`
	Deploy      KontenaDeploy         `yaml:"deploy,omitempty"`
	Logging     KontenaServiceLogging `yaml:"logging,omitempty"`
	Stateful    bool                  `yaml:"stateful,omitempty"`
}

// KontenaServiceLogging ...
type KontenaServiceLogging struct {
	Driver  string            `yaml:"driver,omitempty"`
	Options map[string]string `yaml:"options,omitempty"`
}

// KontenaStack ...
type KontenaStack struct {
	Name     string                    `yaml:"stack,omitempty"`
	Version  string                    `yaml:"version,omitempty"`
	Services map[string]KontenaService `yaml:"services,omitempty"`
}

// KontenaLoad ...
func KontenaLoad(path string) (KontenaStack, error) {
	var dc KontenaStack
	data, err := ioutil.ReadFile(path)

	if err != nil {
		return dc, err
	}
	yaml2.Unmarshal(data, &dc)
	return dc, nil
}

// ExportTemporary ...
func (c KontenaStack) ExportTemporary(translateSecrets bool) (string, error) {
	var path string
	tmp, err := ioutil.TempFile(os.TempDir(), "kontena")
	if err != nil {
		return path, err
	}

	path = tmp.Name()
	stack := c

	if translateSecrets {
		newServices := map[string]KontenaService{}
		for i, service := range stack.Services {
			newSecrets := []KontenaSecret{}
			for _, secret := range service.Secrets {
				newSecrets = append(newSecrets, KontenaSecret{
					Secret: stack.Name + "_" + secret.Secret,
					Name:   secret.Name,
					Type:   secret.Type,
				})
			}
			service.Secrets = newSecrets
			newServices[i] = service
		}
		stack.Services = newServices
	}

	data, marshalError := yaml2.Marshal(stack)
	if marshalError != nil {
		return path, marshalError
	}

	utils.LogSection("exported kontena file", string(data))
	if err := ioutil.WriteFile(path, data, 0644); err != nil {
		return path, err
	}

	return path, nil
}
<|endoftext|>


<commit_before>package main

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

var stk = make([]int, 1)
var cr1 = 0
var cr2 = 0
var crc = 0

var cms = make([]string, 0)
var inp string
var ind = 0

var err = true

func input(prompt string) string {
    reader := bufio.NewReader(os.Stdin)
    fmt.Print(prompt)
    text, _ := reader.ReadString('\n')
    return text[:len(text) - 1]
}

func inform() {
    erl := "S#@" + string(37) + "! " + strconv.Itoa(ind)
    if err {
        fmt.Println("\n" + erl)
        os.Exit(1)
    }
}

func push(toPush int) {
    tempStk := make([]int, len(stk) + 1)
    for i, val := range stk {
        tempStk[i + 1] = val
    }
    tempStk[0] = toPush
    stk = tempStk
}

func pop() int {
    toPop := 0
    if len(stk) > 0 {
        toPop = stk[0]
        stk = stk[1:]
    } else {
        inform()
    }
    return toPop
}

func interpret(line string) {
    cur := 0
    if crc == 0 {
        cur = cr1
    } else if crc == 1 {
        cur = cr2
    }

    switch line {
    case "Wow!":
        cur++
    case "Close one!":
        cur--
    case "OMG!":
        crc = (crc + 1) % 2
        if crc == 0 {
            cur = cr1
        } else if crc == 1 {
            cur = cr2
        }
    case "Noooo!":
        push(0)
    case "Centering...":
        cur = pop()
    case "Defending...":
        push(cur)
    case "I got it!":
        fmt.Print(string(byte(cur)))
    case "Take the shot!":
        if len(inp) > 0 {
            cur = int(byte(inp[0]))
            inp = inp[1:]
        }
    case "Nice shot!":
        if cr1 != cr2 { ind++
            for starts := 1; starts > 0; ind++ {
                if cms[ind] == "Nice shot!" {
                    starts++
                } else if cms[ind] == "What a save!" {
                    starts--
                }
            }; ind--
        }
    case "Great pass!":
        if cur <= 0 { ind++
            for starts := 1; starts > 0; ind++ {
                if cms[ind] == "Great pass!" {
                    starts++
                } else if cms[ind] == "Thanks!" {
                    starts--
                }
            }; ind--
        }
    case "Thanks!":
        if cur > 0 { ind--
            for stops := 1; stops > 0; ind-- {
                if cms[ind] == "Thanks!" {
                    stops++
                } else if cms[ind] == "Great pass!" {
                    stops--
                }
            }; ind++
        }
    case "Sorry!":
        fmt.Println(stk, cr1, cr2, crc)
    case "No Problem.":
        err = !err
    case "Whoops...":
        if crc == 0 {
            cr2 = cr1
        } else if crc == 1 {
            cr1 = cr2
        }
    }

    if crc == 0 {
        cr1 = cur
    } else if crc == 1 {
        cr2 = cur
    }
}

func main() {
    path := ""
    if len(os.Args) > 1 {
        path = os.Args[1]
    } else {
        inform()
    }
    barray, _ := ioutil.ReadFile(path)
    cms = strings.Split(string(barray), "\n")
    for _, cm := range cms {
        if cm == "Take the shot!" {
            inp = input("Input: ")
            break
        }
    }
    for ind < len(cms) {
        interpret(cms[ind])
        ind++
    }
}<commit_msg>Improved stuff<commit_after>package main

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

var stk = make([]int, 1)
var cr1 = 0
var cr2 = 0
var crc = 0

var cms = make([]string, 0)
var inp string
var ind = 0

var err = true

func input(prompt string) string {
    reader := bufio.NewReader(os.Stdin)
    fmt.Print(prompt)
    text, _ := reader.ReadString('\n')
    return text[:len(text) - 1]
}

func inform() {
    secStr := " second"
    if ind != 0 {
        secStr = secStr + "s"
    }
    erl := "S#@" + string(37) + "!\nChat disabled for " + strconv.Itoa(ind + 1) + secStr + ".\n"
    if err {
        fmt.Println("\n" + erl)
        os.Exit(1)
    }
}

func push(toPush int) {
    tempStk := make([]int, len(stk) + 1)
    for i, val := range stk {
        tempStk[i + 1] = val
    }
    tempStk[0] = toPush
    stk = tempStk
}

func pop() int {
    toPop := 0
    if len(stk) > 0 {
        toPop = stk[0]
        stk = stk[1:]
    } else {
        inform()
    }
    return toPop
}

func interpret(line string) {
    cur := 0
    if crc == 0 {
        cur = cr1
    } else if crc == 1 {
        cur = cr2
    }

    switch line {
    case "Wow!":
        cur++
    case "Close one!":
        cur--
    case "OMG!":
        crc = (crc + 1) % 2
        if crc == 0 {
            cur = cr1
        } else if crc == 1 {
            cur = cr2
        }
    case "Noooo!":
        push(0)
    case "Centering...":
        cur = pop()
    case "Defending...":
        push(cur)
    case "I got it!":
        fmt.Print(string(byte(cur)))
    case "Take the shot!":
        if len(inp) > 0 {
            cur = int(byte(inp[0]))
            inp = inp[1:]
        }
    case "Nice shot!":
        if cr1 != cr2 { ind++
            for starts := 1; starts > 0; ind++ {
                if cms[ind] == "Nice shot!" {
                    starts++
                } else if cms[ind] == "What a save!" {
                    starts--
                }
            }; ind--
        }
    case "Great pass!":
        if cur <= 0 { ind++
            for starts := 1; starts > 0; ind++ {
                if cms[ind] == "Great pass!" {
                    starts++
                } else if cms[ind] == "Thanks!" {
                    starts--
                }
            }; ind--
        }
    case "Thanks!":
        if cur > 0 { ind--
            for stops := 1; stops > 0; ind-- {
                if cms[ind] == "Thanks!" {
                    stops++
                } else if cms[ind] == "Great pass!" {
                    stops--
                }
            }; ind++
        }
    case "Sorry!":
        fmt.Println(stk, cr1, cr2, crc)
    case "No Problem.":
        err = !err
    case "Whoops...":
        if crc == 0 {
            cr2 = cr1
        } else if crc == 1 {
            cr1 = cr2
        }
    }

    if crc == 0 {
        cr1 = cur
    } else if crc == 1 {
        cr2 = cur
    }
}

func main() {
    path := ""
    if len(os.Args) > 1 {
        path = os.Args[1]
    } else {
        inform()
    }
    barray, _ := ioutil.ReadFile(path)
    cms = strings.Split(string(barray), "\n")
    for _, cm := range cms {
        if cm == "Take the shot!" {
            inp = input("Input: ")
            break
        }
    }
    for ind < len(cms) {
        interpret(cms[ind])
        ind++
    }
}<|endoftext|>


<commit_before>package raft

// StableStore is used to provide stable storage
// of key configurations to ensure safety.
type StableStore interface {
	Set(key []byte, val []byte) error
	Get(key []byte) ([]byte, error)

	SetUint64(key []byte, val uint64) error
	GetUint64(key []byte) (uint64, error)
}
<commit_msg>Update StableStore documentation based on #29<commit_after>package raft

// StableStore is used to provide stable storage
// of key configurations to ensure safety.
type StableStore interface {
	Set(key []byte, val []byte) error

	// Get returns the value for key, or an empty byte slice if key was not found.
	Get(key []byte) ([]byte, error)

	SetUint64(key []byte, val uint64) error

	// GetUint64 returns the uint64 value for key, or 0 if key was not found.
	GetUint64(key []byte) (uint64, error)
}
<|endoftext|>


<commit_before>package sqsadaptor

import "time"

// AggData type
type AggData struct {
	TotalReqs      int            `json:"total-reqs"`
	TotalTimedOut  int            `json:"total-timed-out"`
	AveTimeToFirst int64          `json:"ave-time-to-first"`
	TotBytesRead   int            `json:"tot-bytes-read"`
	Statuses       map[string]int `json:"statuses"`
	AveTimeForReq  int64          `json:"ave-time-for-req"`
	AveReqPerSec   int            `json:"ave-req-per-sec"`
	Slowest        int64          `json:"slowest"`
	Fastest        int64          `json:"fastest"`
	Region         string         `json:"region"`
}

// RegionsAggData type
type RegionsAggData struct {
	Regions map[string]AggData
}

func addResult(data *AggData, result *AggData) {
	data.TotalReqs += result.TotalReqs
	data.TotalTimedOut += result.TotalTimedOut
	dataTot64 := int64(data.TotalReqs)
	resultTot64 := int64(result.TotalReqs)
	data.AveTimeToFirst = (data.AveTimeToFirst*dataTot64 + result.AveTimeToFirst*resultTot64) / dataTot64
	data.TotBytesRead += result.TotBytesRead

	for key, value := range result.Statuses {
		data.Statuses[key] += value
	}
	data.AveTimeForReq = (data.AveTimeForReq*dataTot64 + result.AveTimeForReq*resultTot64) / dataTot64
	data.AveReqPerSec = (data.AveReqPerSec*data.TotalReqs + result.AveReqPerSec*result.TotalReqs) / data.TotalReqs
	if result.Slowest > data.Slowest {
		data.Slowest = result.Slowest
	}
	if result.Fastest < data.Fastest {
		data.Fastest = result.Fastest
	}
}

// Aggregate listens for results and sends totals, closing the channel when done
func Aggregate(outChan chan RegionsAggData, queueURL string, totalExpectedRequests uint) {
	defer close(outChan)
	data := RegionsAggData{make(map[string]AggData)}

	adaptor := NewSQSAdaptor(queueURL)
	timeoutStart := time.Now()
	for {
		result := adaptor.Receive()
		if result != nil {
			regionData := data.Regions[result.Region]
			addResult(&regionData, result)

			outChan <- data
			timeoutStart = time.Now()
		} else {
			waited := time.Since(timeoutStart)
			if waited.Seconds() > 20 {
				break
			}
		}
	}
}
<commit_msg>Fix uninitialised map<commit_after>package sqsadaptor

import "time"

// AggData type
type AggData struct {
	TotalReqs      int            `json:"total-reqs"`
	TotalTimedOut  int            `json:"total-timed-out"`
	AveTimeToFirst int64          `json:"ave-time-to-first"`
	TotBytesRead   int            `json:"tot-bytes-read"`
	Statuses       map[string]int `json:"statuses"`
	AveTimeForReq  int64          `json:"ave-time-for-req"`
	AveReqPerSec   int            `json:"ave-req-per-sec"`
	Slowest        int64          `json:"slowest"`
	Fastest        int64          `json:"fastest"`
	Region         string         `json:"region"`
}

// RegionsAggData type
type RegionsAggData struct {
	Regions map[string]AggData
}

func addResult(data *AggData, result *AggData) {
	data.TotalReqs += result.TotalReqs
	data.TotalTimedOut += result.TotalTimedOut
	dataTot64 := int64(data.TotalReqs)
	resultTot64 := int64(result.TotalReqs)
	data.AveTimeToFirst = (data.AveTimeToFirst*dataTot64 + result.AveTimeToFirst*resultTot64) / dataTot64
	data.TotBytesRead += result.TotBytesRead

	for key, value := range result.Statuses {
		data.Statuses[key] += value
	}
	data.AveTimeForReq = (data.AveTimeForReq*dataTot64 + result.AveTimeForReq*resultTot64) / dataTot64
	data.AveReqPerSec = (data.AveReqPerSec*data.TotalReqs + result.AveReqPerSec*result.TotalReqs) / data.TotalReqs
	if result.Slowest > data.Slowest {
		data.Slowest = result.Slowest
	}
	if result.Fastest < data.Fastest {
		data.Fastest = result.Fastest
	}
}

// Aggregate listens for results and sends totals, closing the channel when done
func Aggregate(outChan chan RegionsAggData, queueURL string, totalExpectedRequests uint) {
	defer close(outChan)
	data := RegionsAggData{make(map[string]AggData)}

	adaptor := NewSQSAdaptor(queueURL)
	timeoutStart := time.Now()
	for {
		result := adaptor.Receive()
		if result != nil {
			regionData := data.Regions[result.Region]
			if regionData.Region == "" {
				regionData.Statuses = make(map[string]int)
				regionData.Region = result.Region
			}
			addResult(&regionData, result)

			outChan <- data
			timeoutStart = time.Now()
		} else {
			waited := time.Since(timeoutStart)
			if waited.Seconds() > 20 {
				break
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"configuration"
	"coordinator"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"server"
	"strconv"
	"time"

	"github.com/jmhodges/levigo"

	log "code.google.com/p/log4go"
)

func setupLogging(loggingLevel, logFile string) {
	level := log.DEBUG
	switch loggingLevel {
	case "info":
		level = log.INFO
	case "warn":
		level = log.WARNING
	case "error":
		level = log.ERROR
	}

	for _, filter := range log.Global {
		filter.Level = level
	}

	if logFile == "stdout" {
		flw := log.NewConsoleLogWriter()
		log.AddFilter("stdout", level, flw)

	} else {
		logFileDir := filepath.Dir(logFile)
		os.MkdirAll(logFileDir, 0744)

		flw := log.NewFileLogWriter(logFile, false)
		log.AddFilter("file", level, flw)

		flw.SetFormat("[%D %T] [%L] (%S) %M")
		flw.SetRotate(true)
		flw.SetRotateSize(0)
		flw.SetRotateLines(0)
		flw.SetRotateDaily(true)
	}

	log.Info("Redirectoring logging to %s", logFile)
}

func main() {
	fileName := flag.String("config", "config.toml.sample", "Config file")
	wantsVersion := flag.Bool("v", false, "Get version number")
	resetRootPassword := flag.Bool("reset-root", false, "Reset root password")
	pidFile := flag.String("pidfile", "", "the pid file")

	runtime.GOMAXPROCS(runtime.NumCPU())
	flag.Parse()

	if wantsVersion != nil && *wantsVersion {
		fmt.Printf("InfluxDB v%s (git: %s) (leveldb: %d.%d)\n", version, gitSha, levigo.GetLevelDBMajorVersion(), levigo.GetLevelDBMinorVersion())
		return
	}
	config := configuration.LoadConfiguration(*fileName)
	setupLogging(config.LogLevel, config.LogFile)

	if pidFile != nil && *pidFile != "" {
		pid := strconv.Itoa(os.Getpid())
		if err := ioutil.WriteFile(*pidFile, []byte(pid), 0644); err != nil {
			panic(err)
		}
	}

	if config.BindAddress == "" {
		log.Info("Starting Influx Server...")
	} else {
		log.Info("Starting Influx Server bound to %s ...", config.BindAddress)
	}
	log.Info(`
+---------------------------------------------+
|  _____        __ _            _____  ____   |
| |_   _|      / _| |          |  __ \|  _ \  |
|   | |  _ __ | |_| |_   ___  _| |  | | |_) | |
|   | | | '_ \|  _| | | | \ \/ / |  | |  _ <  |
|  _| |_| | | | | | | |_| |>  <| |__| | |_) | |
| |_____|_| |_|_| |_|\__,_/_/\_\_____/|____/  |
+---------------------------------------------+

`)
	os.MkdirAll(config.RaftDir, 0744)
	os.MkdirAll(config.DataDir, 0744)
	server, err := server.NewServer(config)
	if err != nil {
		// sleep for the log to flush
		time.Sleep(time.Second)
		panic(err)
	}

	if err := startProfiler(server); err != nil {
		panic(err)
	}

	if *resetRootPassword {
		// TODO: make this not suck
		// This is ghetto as hell, but it'll work for now.
		go func() {
			time.Sleep(2 * time.Second) // wait for the raft server to join the cluster

			log.Warn("Resetting root's password to %s", coordinator.DEFAULT_ROOT_PWD)
			if err := server.RaftServer.CreateRootUser(); err != nil {
				panic(err)
			}
		}()
	}
	err = server.ListenAndServe()
	if err != nil {
		log.Error("ListenAndServe failed: ", err)
	}
}
<commit_msg>add an option to repair leveldb databases<commit_after>package main

import (
	"configuration"
	"coordinator"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"server"
	"strconv"
	"time"

	"github.com/jmhodges/levigo"

	log "code.google.com/p/log4go"
)

func setupLogging(loggingLevel, logFile string) {
	level := log.DEBUG
	switch loggingLevel {
	case "info":
		level = log.INFO
	case "warn":
		level = log.WARNING
	case "error":
		level = log.ERROR
	}

	for _, filter := range log.Global {
		filter.Level = level
	}

	if logFile == "stdout" {
		flw := log.NewConsoleLogWriter()
		log.AddFilter("stdout", level, flw)

	} else {
		logFileDir := filepath.Dir(logFile)
		os.MkdirAll(logFileDir, 0744)

		flw := log.NewFileLogWriter(logFile, false)
		log.AddFilter("file", level, flw)

		flw.SetFormat("[%D %T] [%L] (%S) %M")
		flw.SetRotate(true)
		flw.SetRotateSize(0)
		flw.SetRotateLines(0)
		flw.SetRotateDaily(true)
	}

	log.Info("Redirectoring logging to %s", logFile)
}

func main() {
	fileName := flag.String("config", "config.toml.sample", "Config file")
	wantsVersion := flag.Bool("v", false, "Get version number")
	resetRootPassword := flag.Bool("reset-root", false, "Reset root password")
	pidFile := flag.String("pidfile", "", "the pid file")
	repairLeveldb := flag.Bool("repair-ldb", false, "set to true to repair the leveldb files")

	runtime.GOMAXPROCS(runtime.NumCPU())
	flag.Parse()

	if wantsVersion != nil && *wantsVersion {
		fmt.Printf("InfluxDB v%s (git: %s) (leveldb: %d.%d)\n", version, gitSha, levigo.GetLevelDBMajorVersion(), levigo.GetLevelDBMinorVersion())
		return
	}
	config := configuration.LoadConfiguration(*fileName)
	setupLogging(config.LogLevel, config.LogFile)

	if *repairLeveldb {
		log.Info("Repairing leveldb")
		files, err := ioutil.ReadDir(config.DataDir)
		if err != nil {
			panic(err)
		}
		o := levigo.NewOptions()
		defer o.Close()
		for _, f := range files {
			p := path.Join(config.DataDir, f.Name())
			log.Info("Repairing %s", p)
			if err := levigo.RepairDatabase(p, o); err != nil {
				panic(err)
			}
		}
	}

	if pidFile != nil && *pidFile != "" {
		pid := strconv.Itoa(os.Getpid())
		if err := ioutil.WriteFile(*pidFile, []byte(pid), 0644); err != nil {
			panic(err)
		}
	}

	if config.BindAddress == "" {
		log.Info("Starting Influx Server...")
	} else {
		log.Info("Starting Influx Server bound to %s ...", config.BindAddress)
	}
	log.Info(`
+---------------------------------------------+
|  _____        __ _            _____  ____   |
| |_   _|      / _| |          |  __ \|  _ \  |
|   | |  _ __ | |_| |_   ___  _| |  | | |_) | |
|   | | | '_ \|  _| | | | \ \/ / |  | |  _ <  |
|  _| |_| | | | | | | |_| |>  <| |__| | |_) | |
| |_____|_| |_|_| |_|\__,_/_/\_\_____/|____/  |
+---------------------------------------------+

`)
	os.MkdirAll(config.RaftDir, 0744)
	os.MkdirAll(config.DataDir, 0744)
	server, err := server.NewServer(config)
	if err != nil {
		// sleep for the log to flush
		time.Sleep(time.Second)
		panic(err)
	}

	if err := startProfiler(server); err != nil {
		panic(err)
	}

	if *resetRootPassword {
		// TODO: make this not suck
		// This is ghetto as hell, but it'll work for now.
		go func() {
			time.Sleep(2 * time.Second) // wait for the raft server to join the cluster

			log.Warn("Resetting root's password to %s", coordinator.DEFAULT_ROOT_PWD)
			if err := server.RaftServer.CreateRootUser(); err != nil {
				panic(err)
			}
		}()
	}
	err = server.ListenAndServe()
	if err != nil {
		log.Error("ListenAndServe failed: ", err)
	}
}
<|endoftext|>


<commit_before>package response

import "fmt"

type Item struct {
	Body      string `json:"body"`
	Coediting bool   `json:"coediting"`
	CreatedAt string `json:"created_at"`
	ID        string `json:"id"`
	Private   bool   `json:"private"`
	Tags      []struct {
		IconURL  string        `json:"icon_url"`
		Name     string        `json:"name"`
		Versions []interface{} `json:"versions"`
	} `json:"tags"`
	Title     string `json:"title"`
	UpdatedAt string `json:"updated_at"`
	User      struct {
		Description       string  `json:"description"`
		FacebookID        string  `json:"facebook_id"`
		FolloweesCount    float64 `json:"followees_count"`
		FollowersCount    float64 `json:"followers_count"`
		GithubLoginName   string  `json:"github_login_name"`
		ID                string  `json:"id"`
		ItemsCount        float64 `json:"items_count"`
		LinkedinID        string  `json:"linkedin_id"`
		Location          string  `json:"location"`
		Name              string  `json:"name"`
		Organization      string  `json:"organization"`
		ProfileImageURL   string  `json:"profile_image_url"`
		TwitterScreenName string  `json:"twitter_screen_name"`
		WebsiteURL        string  `json:"website_url"`
	} `json:"user"`
}

func (item Item) Url(teamKey string) string {
	return fmt.Sprintf("https://%sqiita.com/%s/items/%s", teamKey, item.User.ID, item.ID)
}
<commit_msg>time型にした<commit_after>package response

import (
	"fmt"
	"time"
)

type Item struct {
	Body      string `json:"body"`
	Coediting bool   `json:"coediting"`
	CreatedAt time.Time `json:"created_at"`
	ID        string `json:"id"`
	Private   bool   `json:"private"`
	Tags      []struct {
		IconURL  string        `json:"icon_url"`
		Name     string        `json:"name"`
		Versions []interface{} `json:"versions"`
	} `json:"tags"`
	Title     string `json:"title"`
	UpdatedAt string `json:"updated_at"`
	User      struct {
		Description       string  `json:"description"`
		FacebookID        string  `json:"facebook_id"`
		FolloweesCount    float64 `json:"followees_count"`
		FollowersCount    float64 `json:"followers_count"`
		GithubLoginName   string  `json:"github_login_name"`
		ID                string  `json:"id"`
		ItemsCount        float64 `json:"items_count"`
		LinkedinID        string  `json:"linkedin_id"`
		Location          string  `json:"location"`
		Name              string  `json:"name"`
		Organization      string  `json:"organization"`
		ProfileImageURL   string  `json:"profile_image_url"`
		TwitterScreenName string  `json:"twitter_screen_name"`
		WebsiteURL        string  `json:"website_url"`
	} `json:"user"`
}

func (item Item) Url(teamKey string) string {
	return fmt.Sprintf("https://%sqiita.com/%s/items/%s", teamKey, item.User.ID, item.ID)
}
<|endoftext|>


<commit_before>package vm

type List struct {
	first *Thunk
	rest  *Thunk
}

var emptyList = List{nil, nil}

func NewList(ts ...*Thunk) List {
	return App(Prepend, append(ts, Normal(emptyList))...).Eval().(List)
}

func ListThunk(ts ...*Thunk) *Thunk {
	return Normal(NewList(ts...))
}

func (l1 List) Equal(e Equalable) Object {
	l2 := e.(List)

	if l1 == emptyList || l2 == emptyList {
		return rawBool(l1 == l2)
	}

	for _, t := range []*Thunk{
		// Don't evaluate these parallely for short circuit behavior.
		App(Equal, l1.first, l2.first),
		App(Equal, l1.rest, l2.rest),
	} {
		o := t.Eval()
		b, ok := o.(boolType)

		if !ok {
			return notBoolError(o)
		} else if !b {
			return False
		}
	}

	return True
}

var Prepend = NewLazyFunction(prepend)

func prepend(ts ...*Thunk) Object {
	switch len(ts) {
	case 0:
		return numArgsError("prepend", "> 1")
	case 1:
		return ts[0]
	}

	last := len(ts) - 1
	l := cons(ts[last-1], ts[last])

	for i := last - 2; i >= 0; i-- {
		l = cons(ts[i], Normal(l))
	}

	return l
}

func cons(t1, t2 *Thunk) List {
	return List{t1, t2}
}

var First = NewStrictFunction(first)

func first(os ...Object) Object {
	if len(os) != 1 {
		return numArgsError("first", "1")
	}

	o := os[0]
	l, ok := o.(List)

	if !ok {
		return notListError(o)
	} else if l == emptyList {
		return emptyListError()
	}

	return l.first
}

var Rest = NewStrictFunction(rest)

func rest(os ...Object) Object {
	if len(os) != 1 {
		return numArgsError("rest", "1")
	}

	o := os[0]
	l, ok := o.(List)

	if !ok {
		return notListError(o)
	} else if l == emptyList {
		return emptyListError()
	}

	return l.rest
}

func notListError(o Object) *Thunk {
	return typeError(o, "List")
}

func emptyListError() *Thunk {
	return valueError("The list is empty. You cannot apply rest.")
}
<commit_msg>s/List/listType/g<commit_after>package vm

type listType struct {
	first *Thunk
	rest  *Thunk
}

var emptyList = listType{nil, nil}

func NewList(ts ...*Thunk) listType {
	return App(Prepend, append(ts, Normal(emptyList))...).Eval().(listType)
}

func ListThunk(ts ...*Thunk) *Thunk {
	return Normal(NewList(ts...))
}

func (l1 listType) Equal(e Equalable) Object {
	l2 := e.(listType)

	if l1 == emptyList || l2 == emptyList {
		return rawBool(l1 == l2)
	}

	for _, t := range []*Thunk{
		// Don't evaluate these parallely for short circuit behavior.
		App(Equal, l1.first, l2.first),
		App(Equal, l1.rest, l2.rest),
	} {
		o := t.Eval()
		b, ok := o.(boolType)

		if !ok {
			return notBoolError(o)
		} else if !b {
			return False
		}
	}

	return True
}

var Prepend = NewLazyFunction(prepend)

func prepend(ts ...*Thunk) Object {
	switch len(ts) {
	case 0:
		return numArgsError("prepend", "> 1")
	case 1:
		return ts[0]
	}

	last := len(ts) - 1
	l := cons(ts[last-1], ts[last])

	for i := last - 2; i >= 0; i-- {
		l = cons(ts[i], Normal(l))
	}

	return l
}

func cons(t1, t2 *Thunk) listType {
	return listType{t1, t2}
}

var First = NewStrictFunction(first)

func first(os ...Object) Object {
	if len(os) != 1 {
		return numArgsError("first", "1")
	}

	o := os[0]
	l, ok := o.(listType)

	if !ok {
		return notListError(o)
	} else if l == emptyList {
		return emptyListError()
	}

	return l.first
}

var Rest = NewStrictFunction(rest)

func rest(os ...Object) Object {
	if len(os) != 1 {
		return numArgsError("rest", "1")
	}

	o := os[0]
	l, ok := o.(listType)

	if !ok {
		return notListError(o)
	} else if l == emptyList {
		return emptyListError()
	}

	return l.rest
}

func notListError(o Object) *Thunk {
	return typeError(o, "List")
}

func emptyListError() *Thunk {
	return valueError("The list is empty. You cannot apply rest.")
}
<|endoftext|>


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

package rnd

import (
	"github.com/cpmech/gosl/chk"
	"github.com/cpmech/gosl/io"
	"github.com/cpmech/gosl/utl"
)

// TextHist prints a text histogram
//  Input:
//   labels -- labels
//   counts -- frequencies
func TextHist(labels []string, counts []int, barlen int) string {

	// check
	chk.IntAssert(len(labels), len(counts))
	if len(counts) < 2 {
		return "counts slice is too short\n"
	}

	// scale
	fmax := counts[0]
	lmax := 0
	Lmax := 0
	for i, f := range counts {
		fmax = imax(fmax, f)
		lmax = imax(lmax, len(labels[i]))
		Lmax = imax(Lmax, len(io.Sf("%d", f)))
	}
	if fmax < 1 {
		return io.Sf("max frequency is too small: fmax=%d\n", fmax)
	}
	scale := float64(barlen) / float64(fmax)

	// print
	sz := io.Sf("%d", lmax+1)
	Sz := io.Sf("%d", Lmax+1)
	l := ""
	total := 0
	for i, f := range counts {
		l += io.Sf("%"+sz+"s | %"+Sz+"d ", labels[i], f)
		n := int(float64(f) * scale)
		for j := 0; j < n; j++ {
			l += "#"
		}
		l += "\n"
		total += f
	}
	l += io.Sf("%"+sz+"s   %"+Sz+"d\n", "", total)
	return l
}

// BuildTextHist builds a text histogram
//  Input:
//   xmin      -- station xmin
//   xmax      -- station xmax
//   nstations -- number of stations
//   values    -- values to be counted
//   numfmt    -- number format
//   barlen    -- max length of bar
func BuildTextHist(xmin, xmax float64, nstations int, values []float64, numfmt string, barlen int) string {
	hist := Histogram{Stations: utl.LinSpace(xmin, xmax, nstations)}
	hist.Count(values, true)
	return TextHist(hist.GenLabels(numfmt), hist.Counts, 60)
}

// Histogram holds data for computing/plotting histograms
//
//  bin[i] corresponds to station[i] <= x < station[i+1]
//
//       [ bin[0] )[ bin[1] )[ bin[2] )[ bin[3] )[ bin[4] )
//    ---|---------|---------|---------|---------|---------|---  x
//     s[0]      s[1]      s[2]      s[3]      s[4]      s[5]
//
type Histogram struct {
	Stations []float64 // stations
	Counts   []int     // counts
}

// FindBin finds where x falls in
// returns -1 if x is outside the range
func (o Histogram) FindBin(x float64) int {

	// check
	if len(o.Stations) < 2 {
		chk.Panic("Histogram must have at least 2 stations")
	}
	if x < o.Stations[0] {
		return -1
	}
	if x >= o.Stations[len(o.Stations)-1] {
		return -1
	}

	// perform binary search
	upper := len(o.Stations)
	lower := 0
	mid := 0
	for upper-lower > 1 {
		mid = (upper + lower) / 2
		if x >= o.Stations[mid] {
			lower = mid
		} else {
			upper = mid
		}
	}
	return lower
}

// Count counts how many items fall within each bin
func (o *Histogram) Count(vals []float64, clear bool) {

	// check
	if len(o.Stations) < 2 {
		chk.Panic("Histogram must have at least 2 stations")
	}

	// allocate/clear counts
	nbins := len(o.Stations) - 1
	if len(o.Counts) != nbins {
		o.Counts = make([]int, nbins)
	} else if clear {
		for i := 0; i < nbins; i++ {
			o.Counts[i] = 0
		}
	}

	// add entries to bins
	for _, x := range vals {
		idx := o.FindBin(x)
		if idx >= 0 {
			o.Counts[idx] += 1
		}
	}
}

// GenLabels generate nice labels identifying bins
func (o Histogram) GenLabels(numfmt string) (labels []string) {
	if len(o.Stations) < 2 {
		chk.Panic("Histogram must have at least 2 stations")
	}
	nbins := len(o.Stations) - 1
	labels = make([]string, nbins)
	for i := 0; i < nbins; i++ {
		labels[i] = io.Sf("["+numfmt+","+numfmt+")", o.Stations[i], o.Stations[i+1])
	}
	return
}

// IntHistogram holds data for computing/plotting histograms with integers
//
//  bin[i] corresponds to station[i] <= x < station[i+1]
//
//       [ bin[0] )[ bin[1] )[ bin[2] )[ bin[3] )[ bin[4] )
//    ---|---------|---------|---------|---------|---------|---  x
//     s[0]      s[1]      s[2]      s[3]      s[4]      s[5]
//
type IntHistogram struct {
	Stations []int // stations
	Counts   []int // counts
}

// FindBin finds where x falls in
// returns -1 if x is outside the range
func (o IntHistogram) FindBin(x int) int {

	// check
	if len(o.Stations) < 2 {
		chk.Panic("IntHistogram must have at least 2 stations")
	}
	if x < o.Stations[0] {
		return -1
	}
	if x >= o.Stations[len(o.Stations)-1] {
		return -1
	}

	// perform binary search
	upper := len(o.Stations)
	lower := 0
	mid := 0
	for upper-lower > 1 {
		mid = (upper + lower) / 2
		if x >= o.Stations[mid] {
			lower = mid
		} else {
			upper = mid
		}
	}
	return lower
}

// Count counts how many items fall within each bin
func (o *IntHistogram) Count(vals []int, clear bool) {

	// check
	if len(o.Stations) < 2 {
		chk.Panic("IntHistogram must have at least 2 stations")
	}

	// allocate/clear counts
	nbins := len(o.Stations) - 1
	if len(o.Counts) != nbins {
		o.Counts = make([]int, nbins)
	} else if clear {
		for i := 0; i < nbins; i++ {
			o.Counts[i] = 0
		}
	}

	// add entries to bins
	for _, x := range vals {
		idx := o.FindBin(x)
		if idx >= 0 {
			o.Counts[idx] += 1
		}
	}
}

// GenLabels generate nice labels identifying bins
func (o IntHistogram) GenLabels(numfmt string) (labels []string) {
	if len(o.Stations) < 2 {
		chk.Panic("IntHistogram must have at least 2 stations")
	}
	nbins := len(o.Stations) - 1
	labels = make([]string, nbins)
	for i := 0; i < nbins; i++ {
		labels[i] = io.Sf("["+numfmt+","+numfmt+")", o.Stations[i], o.Stations[i+1])
	}
	return
}
<commit_msg>print histogram now adds 1 # for all counts greater than zero<commit_after>// Copyright 2012 Dorival de Moraes Pedroso. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rnd

import (
	"github.com/cpmech/gosl/chk"
	"github.com/cpmech/gosl/io"
	"github.com/cpmech/gosl/utl"
)

// TextHist prints a text histogram
//  Input:
//   labels -- labels
//   counts -- frequencies
func TextHist(labels []string, counts []int, barlen int) string {

	// check
	chk.IntAssert(len(labels), len(counts))
	if len(counts) < 2 {
		return "counts slice is too short\n"
	}

	// scale
	fmax := counts[0]
	lmax := 0
	Lmax := 0
	for i, f := range counts {
		fmax = imax(fmax, f)
		lmax = imax(lmax, len(labels[i]))
		Lmax = imax(Lmax, len(io.Sf("%d", f)))
	}
	if fmax < 1 {
		return io.Sf("max frequency is too small: fmax=%d\n", fmax)
	}
	scale := float64(barlen) / float64(fmax)

	// print
	sz := io.Sf("%d", lmax+1)
	Sz := io.Sf("%d", Lmax+1)
	l := ""
	total := 0
	for i, f := range counts {
		l += io.Sf("%"+sz+"s | %"+Sz+"d ", labels[i], f)
		n := int(float64(f) * scale)
		if f > 0 { // TODO: improve this
			n += 1
		}
		for j := 0; j < n; j++ {
			l += "#"
		}
		l += "\n"
		total += f
	}
	l += io.Sf("%"+sz+"s   %"+Sz+"d\n", "", total)
	return l
}

// BuildTextHist builds a text histogram
//  Input:
//   xmin      -- station xmin
//   xmax      -- station xmax
//   nstations -- number of stations
//   values    -- values to be counted
//   numfmt    -- number format
//   barlen    -- max length of bar
func BuildTextHist(xmin, xmax float64, nstations int, values []float64, numfmt string, barlen int) string {
	hist := Histogram{Stations: utl.LinSpace(xmin, xmax, nstations)}
	hist.Count(values, true)
	return TextHist(hist.GenLabels(numfmt), hist.Counts, barlen)
}

// Histogram holds data for computing/plotting histograms
//
//  bin[i] corresponds to station[i] <= x < station[i+1]
//
//       [ bin[0] )[ bin[1] )[ bin[2] )[ bin[3] )[ bin[4] )
//    ---|---------|---------|---------|---------|---------|---  x
//     s[0]      s[1]      s[2]      s[3]      s[4]      s[5]
//
type Histogram struct {
	Stations []float64 // stations
	Counts   []int     // counts
}

// FindBin finds where x falls in
// returns -1 if x is outside the range
func (o Histogram) FindBin(x float64) int {

	// check
	if len(o.Stations) < 2 {
		chk.Panic("Histogram must have at least 2 stations")
	}
	if x < o.Stations[0] {
		return -1
	}
	if x >= o.Stations[len(o.Stations)-1] {
		return -1
	}

	// perform binary search
	upper := len(o.Stations)
	lower := 0
	mid := 0
	for upper-lower > 1 {
		mid = (upper + lower) / 2
		if x >= o.Stations[mid] {
			lower = mid
		} else {
			upper = mid
		}
	}
	return lower
}

// Count counts how many items fall within each bin
func (o *Histogram) Count(vals []float64, clear bool) {

	// check
	if len(o.Stations) < 2 {
		chk.Panic("Histogram must have at least 2 stations")
	}

	// allocate/clear counts
	nbins := len(o.Stations) - 1
	if len(o.Counts) != nbins {
		o.Counts = make([]int, nbins)
	} else if clear {
		for i := 0; i < nbins; i++ {
			o.Counts[i] = 0
		}
	}

	// add entries to bins
	for _, x := range vals {
		idx := o.FindBin(x)
		if idx >= 0 {
			o.Counts[idx] += 1
		}
	}
}

// GenLabels generate nice labels identifying bins
func (o Histogram) GenLabels(numfmt string) (labels []string) {
	if len(o.Stations) < 2 {
		chk.Panic("Histogram must have at least 2 stations")
	}
	nbins := len(o.Stations) - 1
	labels = make([]string, nbins)
	for i := 0; i < nbins; i++ {
		labels[i] = io.Sf("["+numfmt+","+numfmt+")", o.Stations[i], o.Stations[i+1])
	}
	return
}

// IntHistogram holds data for computing/plotting histograms with integers
//
//  bin[i] corresponds to station[i] <= x < station[i+1]
//
//       [ bin[0] )[ bin[1] )[ bin[2] )[ bin[3] )[ bin[4] )
//    ---|---------|---------|---------|---------|---------|---  x
//     s[0]      s[1]      s[2]      s[3]      s[4]      s[5]
//
type IntHistogram struct {
	Stations []int // stations
	Counts   []int // counts
}

// FindBin finds where x falls in
// returns -1 if x is outside the range
func (o IntHistogram) FindBin(x int) int {

	// check
	if len(o.Stations) < 2 {
		chk.Panic("IntHistogram must have at least 2 stations")
	}
	if x < o.Stations[0] {
		return -1
	}
	if x >= o.Stations[len(o.Stations)-1] {
		return -1
	}

	// perform binary search
	upper := len(o.Stations)
	lower := 0
	mid := 0
	for upper-lower > 1 {
		mid = (upper + lower) / 2
		if x >= o.Stations[mid] {
			lower = mid
		} else {
			upper = mid
		}
	}
	return lower
}

// Count counts how many items fall within each bin
func (o *IntHistogram) Count(vals []int, clear bool) {

	// check
	if len(o.Stations) < 2 {
		chk.Panic("IntHistogram must have at least 2 stations")
	}

	// allocate/clear counts
	nbins := len(o.Stations) - 1
	if len(o.Counts) != nbins {
		o.Counts = make([]int, nbins)
	} else if clear {
		for i := 0; i < nbins; i++ {
			o.Counts[i] = 0
		}
	}

	// add entries to bins
	for _, x := range vals {
		idx := o.FindBin(x)
		if idx >= 0 {
			o.Counts[idx] += 1
		}
	}
}

// GenLabels generate nice labels identifying bins
func (o IntHistogram) GenLabels(numfmt string) (labels []string) {
	if len(o.Stations) < 2 {
		chk.Panic("IntHistogram must have at least 2 stations")
	}
	nbins := len(o.Stations) - 1
	labels = make([]string, nbins)
	for i := 0; i < nbins; i++ {
		labels[i] = io.Sf("["+numfmt+","+numfmt+")", o.Stations[i], o.Stations[i+1])
	}
	return
}
<|endoftext|>


<commit_before>package effio

import (
	"code.google.com/p/plotinum/plot"
	"code.google.com/p/plotinum/plotter"
	"code.google.com/p/plotinum/vg"
	//	"code.google.com/p/plotinum/plotutil"
	"fmt"
	"log"
	"os"
	"path"
)

func (suite *Suite) Graph(spath string) {
	wd, err := os.Getwd()
	if err != nil {
		log.Fatalf("Could not get working directory: %s\n", err)
	}

	for _, test := range suite.Tests {
		log.Printf("Graphing test %s ...\n", test.Name)
		test.GraphAll(path.Join(wd, spath))
	}
}

func (test *Test) GraphAll(spath string) {
	tpath := path.Join(spath, test.Dir)
	err := os.Chdir(tpath)
	if err != nil {
		log.Fatalf("Could not chdir to '%s': %s\n", tpath, err)
	}

	// fio insists on adding the _lat.log and I can't find an option to disable it
	latlog := LoadCSV(fmt.Sprintf("%s_lat.log", test.FioLatLog))
	// latlog is huge on fast devices, trim it down so plotinum doesn't freak out
	//func (lrs LatRecs) Histogram(sz int) (out LatRecs) {
	hgram := latlog.Histogram(200)
	test.LineGraph(hgram, "Time", "Latency (usec)")
}

func (test *Test) LineGraph(data plotter.XYer, xlabel string, ylabel string) {
	p, err := plot.New()
	if err != nil {
		log.Fatalf("Error creating new plot: %s\n", err)
	}

	p.Title.Text = fmt.Sprintf("Latency %s", test.Device)
	p.X.Label.Text = xlabel
	p.Y.Label.Text = ylabel

	p.Add(plotter.NewGrid())

	log.Printf("Adding data with l, err := plotter.NewLine(data)\n")
	l, err := plotter.NewLine(data)
	if err != nil {
		log.Fatalf("Error adding line to plot: %s\n", err)
	}
	l.LineStyle.Width = vg.Points(1)

	p.Add(l)

	log.Printf("saving graph to linegraph.png\n")
	err = p.Save(10, 10, "linegraph.png")
	if err != nil {
		log.Fatalf("Failed to save linegraph.png: %s\n", err)
	}
	log.Printf("all done\n")
}
<commit_msg>Don't crash on empty/short logs.<commit_after>package effio

import (
	"code.google.com/p/plotinum/plot"
	"code.google.com/p/plotinum/plotter"
	"code.google.com/p/plotinum/vg"
	//	"code.google.com/p/plotinum/plotutil"
	"fmt"
	"log"
	"os"
	"path"
)

func (suite *Suite) Graph(spath string) {
	wd, err := os.Getwd()
	if err != nil {
		log.Fatalf("Could not get working directory: %s\n", err)
	}

	for _, test := range suite.Tests {
		log.Printf("Graphing test %s ...\n", test.Name)
		test.GraphAll(path.Join(wd, spath))
	}
}

func (test *Test) GraphAll(spath string) {
	tpath := path.Join(spath, test.Dir)
	err := os.Chdir(tpath)
	if err != nil {
		log.Fatalf("Could not chdir to '%s': %s\n", tpath, err)
	}

	// fio insists on adding the _lat.log and I can't find an option to disable it
	latlog := LoadCSV(fmt.Sprintf("%s_lat.log", test.FioLatLog))
	if len(latlog) < 200 {
		log.Printf("Empty/truncated logfile. Skipping rendering of %s\n", test.Name)
		return
	}
	// latlog is huge on fast devices, trim it down so plotinum doesn't freak out
	//func (lrs LatRecs) Histogram(sz int) (out LatRecs) {
	hgram := latlog.Histogram(200)
	test.LineGraph(hgram, "Time", "Latency (usec)")
}

func (test *Test) LineGraph(data plotter.XYer, xlabel string, ylabel string) {
	p, err := plot.New()
	if err != nil {
		log.Fatalf("Error creating new plot: %s\n", err)
	}

	p.Title.Text = fmt.Sprintf("Latency %s", test.Device)
	p.X.Label.Text = xlabel
	p.Y.Label.Text = ylabel

	p.Add(plotter.NewGrid())

	log.Printf("Adding data with l, err := plotter.NewLine(data)\n")
	l, err := plotter.NewLine(data)
	if err != nil {
		log.Fatalf("Error adding line to plot: %s\n", err)
	}
	l.LineStyle.Width = vg.Points(1)

	p.Add(l)

	log.Printf("saving graph to linegraph.png\n")
	err = p.Save(10, 10, "linegraph.png")
	if err != nil {
		log.Fatalf("Failed to save linegraph.png: %s\n", err)
	}
	log.Printf("all done\n")
}
<|endoftext|>


<commit_before>package router

import (
	"net/http"

	"github.com/NyaaPantsu/nyaa/config"
	"github.com/NyaaPantsu/nyaa/service/captcha"
	"github.com/gorilla/csrf"
	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
)

// Router variable for exporting the route configuration
var Router *mux.Router

func init() {
	// Static file handlers
	cssHandler := http.FileServer(http.Dir("./public/css/"))
	jsHandler := http.FileServer(http.Dir("./public/js/"))
	imgHandler := http.FileServer(http.Dir("./public/img/"))
	// TODO Use config from cli
	// TODO Make sure the directory exists
	dumpsHandler := http.FileServer(http.Dir(DatabaseDumpPath))
	// TODO Use config from cli
	// TODO Make sure the directory exists
	gpgKeyHandler := http.FileServer(http.Dir(GPGPublicKeyPath))
	gzipHomeHandler := http.HandlerFunc(HomeHandler)
	gzipAPIHandler := http.HandlerFunc(APIHandler)
	gzipAPIViewHandler := http.HandlerFunc(APIViewHandler)
	gzipViewHandler := http.HandlerFunc(ViewHandler)
	gzipUserProfileHandler := http.HandlerFunc(UserProfileHandler)
	gzipUserAPIKeyResetHandler := http.HandlerFunc(UserAPIKeyResetHandler)
	gzipUserDetailsHandler := http.HandlerFunc(UserDetailsHandler)
	downloadTorrentHandler := http.HandlerFunc(DownloadTorrent)
	gzipUserProfileFormHandler := http.HandlerFunc(UserProfileFormHandler)
	gzipUserNotificationsHandler := http.HandlerFunc(UserNotificationsHandler)
	gzipDumpsHandler := handlers.CompressHandler(dumpsHandler)
	gzipGpgKeyHandler := handlers.CompressHandler(gpgKeyHandler)
	gzipDatabaseDumpHandler := handlers.CompressHandler(http.HandlerFunc(DatabaseDumpHandler))

	Router = mux.NewRouter()
	http.Handle("/css/", http.StripPrefix("/css/", cssHandler))
	http.Handle("/js/", http.StripPrefix("/js/", jsHandler))
	http.Handle("/img/", http.StripPrefix("/img/", imgHandler))
	http.Handle("/dbdumps/", http.StripPrefix("/dbdumps/", wrapHandler(gzipDumpsHandler)))
	http.Handle("/gpg/", http.StripPrefix("/gpg/", wrapHandler(gzipGpgKeyHandler)))

	// We don't need CSRF here
	Router.Handle("/", gzipHomeHandler).Name("home")
	Router.Handle("/page/{page:[0-9]+}", wrapHandler(gzipHomeHandler)).Name("home_page")
	Router.HandleFunc("/search", SearchHandler).Name("search")
	Router.HandleFunc("/search/{page}", SearchHandler).Name("search_page")
	Router.HandleFunc("/verify/email/{token}", UserVerifyEmailHandler).Name("user_verify").Methods("GET")
	Router.HandleFunc("/faq", FaqHandler).Name("faq")
	Router.HandleFunc("/feed", RSSHandler).Name("feed")
	Router.HandleFunc("/feed/{page}", RSSHandler).Name("feed_page")

	// !!! This line need to have the same download location as the one define in config.TorrentStorageLink !!!
	Router.Handle("/download/{hash}", wrapHandler(downloadTorrentHandler)).Name("torrent_download")

	// For now, no CSRF protection here, as API is not usable for uploads
	Router.HandleFunc("/upload", UploadHandler).Name("upload")

	torrentViewRoutes := Router.PathPrefix("/view").Subrouter()
	torrentViewRoutes.Handle("/{id}", wrapHandler(gzipViewHandler)).Methods("GET").Name("view_torrent")
	torrentViewRoutes.HandleFunc("/{id}", ViewHeadHandler).Methods("HEAD")
	torrentViewRoutes.HandleFunc("/{id}", PostCommentHandler).Methods("POST").Name("post_comment")

	torrentRoutes := Router.PathPrefix("/torrent").Subrouter()
	torrentRoutes.HandleFunc("/", TorrentEditUserPanel).Methods("GET").Name("user_torrent_edit")
	torrentRoutes.HandleFunc("/", TorrentPostEditUserPanel).Methods("POST").Name("user_torrent_edit")
	torrentRoutes.HandleFunc("/delete", TorrentDeleteUserPanel).Methods("GET").Name("user_torrent_delete")

	userRoutes := Router.PathPrefix("/user").Subrouter()
	userRoutes.HandleFunc("/register", UserRegisterFormHandler).Name("user_register").Methods("GET")
	userRoutes.HandleFunc("/login", UserLoginFormHandler).Name("user_login").Methods("GET")
	userRoutes.HandleFunc("/register", UserRegisterPostHandler).Name("user_register").Methods("POST")
	userRoutes.HandleFunc("/login", UserLoginPostHandler).Name("user_login").Methods("POST")
	userRoutes.HandleFunc("/logout", UserLogoutHandler).Name("user_logout")
	userRoutes.Handle("/{id}/{username}", wrapHandler(gzipUserProfileHandler)).Name("user_profile").Methods("GET")
	userRoutes.HandleFunc("/{id}/{username}/follow", UserFollowHandler).Name("user_follow").Methods("GET")
	userRoutes.Handle("/{id}/{username}/edit", wrapHandler(gzipUserDetailsHandler)).Name("user_profile_details").Methods("GET")
	userRoutes.Handle("/{id}/{username}/edit", wrapHandler(gzipUserProfileFormHandler)).Name("user_profile_edit").Methods("POST")
	userRoutes.Handle("/{id}/{username}/apireset", wrapHandler(gzipUserAPIKeyResetHandler)).Name("user_profile_apireset").Methods("GET")
	userRoutes.Handle("/notifications", wrapHandler(gzipUserNotificationsHandler)).Name("user_notifications")
	userRoutes.HandleFunc("/{id}/{username}/feed", RSSHandler).Name("feed_user")
	userRoutes.HandleFunc("/{id}/{username}/feed/{page}", RSSHandler).Name("feed_user_page")

	// Please make EnableSecureCSRF to false when testing locally
	if config.EnableSecureCSRF {
		userRoutes.Handle("/", csrf.Protect(config.CSRFTokenHashKey)(userRoutes))
		torrentRoutes.Handle("/", csrf.Protect(config.CSRFTokenHashKey)(torrentRoutes))
		torrentViewRoutes.Handle("/", csrf.Protect(config.CSRFTokenHashKey)(torrentViewRoutes))
	} else {
		userRoutes.Handle("/", csrf.Protect(config.CSRFTokenHashKey, csrf.Secure(false))(userRoutes))
		torrentRoutes.Handle("/", csrf.Protect(config.CSRFTokenHashKey, csrf.Secure(false))(torrentRoutes))
		torrentViewRoutes.Handle("/", csrf.Protect(config.CSRFTokenHashKey, csrf.Secure(false))(torrentViewRoutes))
	}

	// We don't need CSRF here
	api := Router.PathPrefix("/api").Subrouter()
	api.Handle("", wrapHandler(gzipAPIHandler)).Methods("GET")
	api.Handle("/", wrapHandler(gzipAPIHandler)).Methods("GET")
	api.Handle("/{page:[0-9]*}", wrapHandler(gzipAPIHandler)).Methods("GET")
	api.Handle("/view/{id}", wrapHandler(gzipAPIViewHandler)).Methods("GET")
	api.HandleFunc("/view/{id}", APIViewHeadHandler).Methods("HEAD")
	api.HandleFunc("/upload", APIUploadHandler).Methods("POST")
	api.HandleFunc("/search", APISearchHandler)
	api.HandleFunc("/search/{page}", APISearchHandler)
	api.HandleFunc("/update", APIUpdateHandler).Methods("PUT")

	// INFO Everything under /mod should be wrapped by wrapModHandler. This make
	// sure the page is only accessible by moderators
	// We don't need CSRF here
	// TODO Find a native mux way to add a 'prehook' for route /mod
	Router.HandleFunc("/mod", wrapModHandler(IndexModPanel)).Name("mod_index")
	Router.HandleFunc("/mod/torrents", wrapModHandler(TorrentsListPanel)).Name("mod_tlist").Methods("GET")
	Router.HandleFunc("/mod/torrents/{page:[0-9]+}", wrapModHandler(TorrentsListPanel)).Name("mod_tlist_page").Methods("GET")
	Router.HandleFunc("/mod/torrents", wrapModHandler(TorrentsPostListPanel)).Methods("POST")
	Router.HandleFunc("/mod/torrents/{page:[0-9]+}", wrapModHandler(TorrentsPostListPanel)).Methods("POST")
	Router.HandleFunc("/mod/torrents/deleted", wrapModHandler(DeletedTorrentsModPanel)).Name("mod_tlist_deleted").Methods("GET")
	Router.HandleFunc("/mod/torrents/deleted/{page:[0-9]+}", wrapModHandler(DeletedTorrentsModPanel)).Name("mod_tlist_deleted_page").Methods("GET")
	Router.HandleFunc("/mod/torrents/deleted", wrapModHandler(DeletedTorrentsPostPanel)).Name("mod_tlist_deleted").Methods("POST")
	Router.HandleFunc("/mod/torrents/deleted/{page:[0-9]+}", wrapModHandler(DeletedTorrentsPostPanel)).Name("mod_tlist_deleted_page").Methods("POST")
	Router.HandleFunc("/mod/reports", wrapModHandler(TorrentReportListPanel)).Name("mod_trlist")
	Router.HandleFunc("/mod/reports/{page}", wrapModHandler(TorrentReportListPanel)).Name("mod_trlist_page")
	Router.HandleFunc("/mod/users", wrapModHandler(UsersListPanel)).Name("mod_ulist")
	Router.HandleFunc("/mod/users/{page}", wrapModHandler(UsersListPanel)).Name("mod_ulist_page")
	Router.HandleFunc("/mod/comments", wrapModHandler(CommentsListPanel)).Name("mod_clist")
	Router.HandleFunc("/mod/comments/{page}", wrapModHandler(CommentsListPanel)).Name("mod_clist_page")
	Router.HandleFunc("/mod/comment", wrapModHandler(CommentsListPanel)).Name("mod_cedit") // TODO
	Router.HandleFunc("/mod/torrent/", wrapModHandler(TorrentEditModPanel)).Name("mod_tedit").Methods("GET")
	Router.HandleFunc("/mod/torrent/", wrapModHandler(TorrentPostEditModPanel)).Name("mod_ptedit").Methods("POST")
	Router.HandleFunc("/mod/torrent/delete", wrapModHandler(TorrentDeleteModPanel)).Name("mod_tdelete")
	Router.HandleFunc("/mod/torrent/block", wrapModHandler(TorrentBlockModPanel)).Name("mod_tblock")
	Router.HandleFunc("/mod/report/delete", wrapModHandler(TorrentReportDeleteModPanel)).Name("mod_trdelete")
	Router.HandleFunc("/mod/comment/delete", wrapModHandler(CommentDeleteModPanel)).Name("mod_cdelete")
	Router.HandleFunc("/mod/reassign", wrapModHandler(TorrentReassignModPanel)).Name("mod_treassign").Methods("GET")
	Router.HandleFunc("/mod/reassign", wrapModHandler(TorrentPostReassignModPanel)).Name("mod_treassign").Methods("POST")

	apiMod := Router.PathPrefix("/mod/api").Subrouter()
	apiMod.HandleFunc("/torrents", wrapModHandler(APIMassMod)).Name("mod_tapi").Methods("POST")

	//reporting a torrent
	Router.HandleFunc("/report/{id}", ReportTorrentHandler).Methods("POST").Name("torrent_report")

	Router.PathPrefix("/captcha").Methods("GET").HandlerFunc(captcha.ServeFiles)

	Router.Handle("/dumps", gzipDatabaseDumpHandler).Name("dump").Methods("GET")

	Router.HandleFunc("/settings", SeePublicSettingsHandler).Methods("GET").Name("see_languages")
	Router.HandleFunc("/settings", ChangePublicSettingsHandler).Methods("POST").Name("see_languages")

	Router.NotFoundHandler = http.HandlerFunc(NotFoundHandler)
}
<commit_msg>Forgot that they also login through the login form<commit_after>package router

import (
	"net/http"

	"github.com/NyaaPantsu/nyaa/config"
	"github.com/NyaaPantsu/nyaa/service/captcha"
	"github.com/gorilla/csrf"
	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
)

// Router variable for exporting the route configuration
var Router *mux.Router

func init() {
	// Static file handlers
	cssHandler := http.FileServer(http.Dir("./public/css/"))
	jsHandler := http.FileServer(http.Dir("./public/js/"))
	imgHandler := http.FileServer(http.Dir("./public/img/"))
	// TODO Use config from cli
	// TODO Make sure the directory exists
	dumpsHandler := http.FileServer(http.Dir(DatabaseDumpPath))
	// TODO Use config from cli
	// TODO Make sure the directory exists
	gpgKeyHandler := http.FileServer(http.Dir(GPGPublicKeyPath))
	gzipHomeHandler := http.HandlerFunc(HomeHandler)
	gzipAPIHandler := http.HandlerFunc(APIHandler)
	gzipAPIViewHandler := http.HandlerFunc(APIViewHandler)
	gzipViewHandler := http.HandlerFunc(ViewHandler)
	gzipUserProfileHandler := http.HandlerFunc(UserProfileHandler)
	gzipUserAPIKeyResetHandler := http.HandlerFunc(UserAPIKeyResetHandler)
	gzipUserDetailsHandler := http.HandlerFunc(UserDetailsHandler)
	downloadTorrentHandler := http.HandlerFunc(DownloadTorrent)
	gzipUserProfileFormHandler := http.HandlerFunc(UserProfileFormHandler)
	gzipUserNotificationsHandler := http.HandlerFunc(UserNotificationsHandler)
	gzipDumpsHandler := handlers.CompressHandler(dumpsHandler)
	gzipGpgKeyHandler := handlers.CompressHandler(gpgKeyHandler)
	gzipDatabaseDumpHandler := handlers.CompressHandler(http.HandlerFunc(DatabaseDumpHandler))

	Router = mux.NewRouter()
	http.Handle("/css/", http.StripPrefix("/css/", cssHandler))
	http.Handle("/js/", http.StripPrefix("/js/", jsHandler))
	http.Handle("/img/", http.StripPrefix("/img/", imgHandler))
	http.Handle("/dbdumps/", http.StripPrefix("/dbdumps/", wrapHandler(gzipDumpsHandler)))
	http.Handle("/gpg/", http.StripPrefix("/gpg/", wrapHandler(gzipGpgKeyHandler)))

	// We don't need CSRF here
	Router.Handle("/", gzipHomeHandler).Name("home")
	Router.Handle("/page/{page:[0-9]+}", wrapHandler(gzipHomeHandler)).Name("home_page")
	Router.HandleFunc("/search", SearchHandler).Name("search")
	Router.HandleFunc("/search/{page}", SearchHandler).Name("search_page")
	Router.HandleFunc("/verify/email/{token}", UserVerifyEmailHandler).Name("user_verify").Methods("GET")
	Router.HandleFunc("/faq", FaqHandler).Name("faq")
	Router.HandleFunc("/feed", RSSHandler).Name("feed")
	Router.HandleFunc("/feed/{page}", RSSHandler).Name("feed_page")

	// !!! This line need to have the same download location as the one define in config.TorrentStorageLink !!!
	Router.Handle("/download/{hash}", wrapHandler(downloadTorrentHandler)).Name("torrent_download")

	// For now, no CSRF protection here, as API is not usable for uploads
	Router.HandleFunc("/upload", UploadHandler).Name("upload")
	Router.HandleFunc("/user/login", UserLoginPostHandler).Name("user_login").Methods("POST")

	torrentViewRoutes := Router.PathPrefix("/view").Subrouter()
	torrentViewRoutes.Handle("/{id}", wrapHandler(gzipViewHandler)).Methods("GET").Name("view_torrent")
	torrentViewRoutes.HandleFunc("/{id}", ViewHeadHandler).Methods("HEAD")
	torrentViewRoutes.HandleFunc("/{id}", PostCommentHandler).Methods("POST").Name("post_comment")

	torrentRoutes := Router.PathPrefix("/torrent").Subrouter()
	torrentRoutes.HandleFunc("/", TorrentEditUserPanel).Methods("GET").Name("user_torrent_edit")
	torrentRoutes.HandleFunc("/", TorrentPostEditUserPanel).Methods("POST").Name("user_torrent_edit")
	torrentRoutes.HandleFunc("/delete", TorrentDeleteUserPanel).Methods("GET").Name("user_torrent_delete")

	userRoutes := Router.PathPrefix("/user").Subrouter()
	userRoutes.HandleFunc("/register", UserRegisterFormHandler).Name("user_register").Methods("GET")
	userRoutes.HandleFunc("/login", UserLoginFormHandler).Name("user_login").Methods("GET")
	userRoutes.HandleFunc("/register", UserRegisterPostHandler).Name("user_register").Methods("POST")
	userRoutes.HandleFunc("/logout", UserLogoutHandler).Name("user_logout")
	userRoutes.Handle("/{id}/{username}", wrapHandler(gzipUserProfileHandler)).Name("user_profile").Methods("GET")
	userRoutes.HandleFunc("/{id}/{username}/follow", UserFollowHandler).Name("user_follow").Methods("GET")
	userRoutes.Handle("/{id}/{username}/edit", wrapHandler(gzipUserDetailsHandler)).Name("user_profile_details").Methods("GET")
	userRoutes.Handle("/{id}/{username}/edit", wrapHandler(gzipUserProfileFormHandler)).Name("user_profile_edit").Methods("POST")
	userRoutes.Handle("/{id}/{username}/apireset", wrapHandler(gzipUserAPIKeyResetHandler)).Name("user_profile_apireset").Methods("GET")
	userRoutes.Handle("/notifications", wrapHandler(gzipUserNotificationsHandler)).Name("user_notifications")
	userRoutes.HandleFunc("/{id}/{username}/feed", RSSHandler).Name("feed_user")
	userRoutes.HandleFunc("/{id}/{username}/feed/{page}", RSSHandler).Name("feed_user_page")

	// Please make EnableSecureCSRF to false when testing locally
	if config.EnableSecureCSRF {
		userRoutes.Handle("/", csrf.Protect(config.CSRFTokenHashKey)(userRoutes))
		torrentRoutes.Handle("/", csrf.Protect(config.CSRFTokenHashKey)(torrentRoutes))
		torrentViewRoutes.Handle("/", csrf.Protect(config.CSRFTokenHashKey)(torrentViewRoutes))
	} else {
		userRoutes.Handle("/", csrf.Protect(config.CSRFTokenHashKey, csrf.Secure(false))(userRoutes))
		torrentRoutes.Handle("/", csrf.Protect(config.CSRFTokenHashKey, csrf.Secure(false))(torrentRoutes))
		torrentViewRoutes.Handle("/", csrf.Protect(config.CSRFTokenHashKey, csrf.Secure(false))(torrentViewRoutes))
	}

	// We don't need CSRF here
	api := Router.PathPrefix("/api").Subrouter()
	api.Handle("", wrapHandler(gzipAPIHandler)).Methods("GET")
	api.Handle("/", wrapHandler(gzipAPIHandler)).Methods("GET")
	api.Handle("/{page:[0-9]*}", wrapHandler(gzipAPIHandler)).Methods("GET")
	api.Handle("/view/{id}", wrapHandler(gzipAPIViewHandler)).Methods("GET")
	api.HandleFunc("/view/{id}", APIViewHeadHandler).Methods("HEAD")
	api.HandleFunc("/upload", APIUploadHandler).Methods("POST")
	api.HandleFunc("/search", APISearchHandler)
	api.HandleFunc("/search/{page}", APISearchHandler)
	api.HandleFunc("/update", APIUpdateHandler).Methods("PUT")

	// INFO Everything under /mod should be wrapped by wrapModHandler. This make
	// sure the page is only accessible by moderators
	// We don't need CSRF here
	// TODO Find a native mux way to add a 'prehook' for route /mod
	Router.HandleFunc("/mod", wrapModHandler(IndexModPanel)).Name("mod_index")
	Router.HandleFunc("/mod/torrents", wrapModHandler(TorrentsListPanel)).Name("mod_tlist").Methods("GET")
	Router.HandleFunc("/mod/torrents/{page:[0-9]+}", wrapModHandler(TorrentsListPanel)).Name("mod_tlist_page").Methods("GET")
	Router.HandleFunc("/mod/torrents", wrapModHandler(TorrentsPostListPanel)).Methods("POST")
	Router.HandleFunc("/mod/torrents/{page:[0-9]+}", wrapModHandler(TorrentsPostListPanel)).Methods("POST")
	Router.HandleFunc("/mod/torrents/deleted", wrapModHandler(DeletedTorrentsModPanel)).Name("mod_tlist_deleted").Methods("GET")
	Router.HandleFunc("/mod/torrents/deleted/{page:[0-9]+}", wrapModHandler(DeletedTorrentsModPanel)).Name("mod_tlist_deleted_page").Methods("GET")
	Router.HandleFunc("/mod/torrents/deleted", wrapModHandler(DeletedTorrentsPostPanel)).Name("mod_tlist_deleted").Methods("POST")
	Router.HandleFunc("/mod/torrents/deleted/{page:[0-9]+}", wrapModHandler(DeletedTorrentsPostPanel)).Name("mod_tlist_deleted_page").Methods("POST")
	Router.HandleFunc("/mod/reports", wrapModHandler(TorrentReportListPanel)).Name("mod_trlist")
	Router.HandleFunc("/mod/reports/{page}", wrapModHandler(TorrentReportListPanel)).Name("mod_trlist_page")
	Router.HandleFunc("/mod/users", wrapModHandler(UsersListPanel)).Name("mod_ulist")
	Router.HandleFunc("/mod/users/{page}", wrapModHandler(UsersListPanel)).Name("mod_ulist_page")
	Router.HandleFunc("/mod/comments", wrapModHandler(CommentsListPanel)).Name("mod_clist")
	Router.HandleFunc("/mod/comments/{page}", wrapModHandler(CommentsListPanel)).Name("mod_clist_page")
	Router.HandleFunc("/mod/comment", wrapModHandler(CommentsListPanel)).Name("mod_cedit") // TODO
	Router.HandleFunc("/mod/torrent/", wrapModHandler(TorrentEditModPanel)).Name("mod_tedit").Methods("GET")
	Router.HandleFunc("/mod/torrent/", wrapModHandler(TorrentPostEditModPanel)).Name("mod_ptedit").Methods("POST")
	Router.HandleFunc("/mod/torrent/delete", wrapModHandler(TorrentDeleteModPanel)).Name("mod_tdelete")
	Router.HandleFunc("/mod/torrent/block", wrapModHandler(TorrentBlockModPanel)).Name("mod_tblock")
	Router.HandleFunc("/mod/report/delete", wrapModHandler(TorrentReportDeleteModPanel)).Name("mod_trdelete")
	Router.HandleFunc("/mod/comment/delete", wrapModHandler(CommentDeleteModPanel)).Name("mod_cdelete")
	Router.HandleFunc("/mod/reassign", wrapModHandler(TorrentReassignModPanel)).Name("mod_treassign").Methods("GET")
	Router.HandleFunc("/mod/reassign", wrapModHandler(TorrentPostReassignModPanel)).Name("mod_treassign").Methods("POST")

	apiMod := Router.PathPrefix("/mod/api").Subrouter()
	apiMod.HandleFunc("/torrents", wrapModHandler(APIMassMod)).Name("mod_tapi").Methods("POST")

	//reporting a torrent
	Router.HandleFunc("/report/{id}", ReportTorrentHandler).Methods("POST").Name("torrent_report")

	Router.PathPrefix("/captcha").Methods("GET").HandlerFunc(captcha.ServeFiles)

	Router.Handle("/dumps", gzipDatabaseDumpHandler).Name("dump").Methods("GET")

	Router.HandleFunc("/settings", SeePublicSettingsHandler).Methods("GET").Name("see_languages")
	Router.HandleFunc("/settings", ChangePublicSettingsHandler).Methods("POST").Name("see_languages")

	Router.NotFoundHandler = http.HandlerFunc(NotFoundHandler)
}
<|endoftext|>


<commit_before>package router

import (
	"crypto/md5"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/orange-jacky/albums/data"
	"github.com/orange-jacky/albums/db"
	"github.com/orange-jacky/albums/util"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

// UpLoad 上传图片到相册
func UpLoad(c *gin.Context) {
	conf := util.Configure("")
	//log := util.Mylog("")

	//新建一个图片库连接
	gridfs := db.NewMongoGridfs()
	gridfs.Connect(conf.Mongo.Hosts, conf.Mongo.Image.Db)
	gridfs.OpenDb(conf.Mongo.Image.Db)
	gridfs.OpenTable("fs")
	defer gridfs.Close()

	//先缓存文件
	images, _ := cacheFile(c)
	defer clearCache(c)
	//提取图片信息
	getImageInfo(c, &images)
	//入库
	gridfs.Insert(images)

	c.String(http.StatusOK, "%s", "upload")
}

func getUser(c *gin.Context) string {
	user := c.PostForm("user")
	if user == "" {
		user = "default"
	}
	return user
}

func getAlbum(c *gin.Context) string {
	album := c.PostForm("album")
	if album == "" {
		album = "default"
	}
	return album
}

func clearCache(c *gin.Context) {
	user := getUser(c)
	album := getAlbum(c)
	os.RemoveAll(fmt.Sprintf("%s%s%s", user, util.DirSeg(), album))
}

// cacheFile 先把上传文件缓存到本地磁盘
func cacheFile(c *gin.Context) (images data.Images, err error) {
	r := c.Request
	//POST takes the uploaded file(s) and saves it to disk.
	//parse the multipart form in the request
	err = r.ParseMultipartForm(100000)
	if err != nil {
		return images, err
	}
	//get a ref to the parsed multipart form
	m := r.MultipartForm
	//get the *fileheaders
	files := m.File["images"] //表单的name,id

	//post 没有文件直接返回
	if len(files) == 0 {
		return images, nil
	}
	//创建临时缓存目录
	user := getUser(c)
	album := getAlbum(c)
	dir := fmt.Sprintf("%s%s%s", user, util.DirSeg(), album)
	err = os.MkdirAll(dir, os.ModePerm)
	if err != nil {
		return images, err
	}
	//取所有上传文件
	for i, _ := range files {
		//for each fileheader, get a handle to the actual file
		src, err := files[i].Open()
		if err != nil {
			continue
		}
		defer src.Close()
		//create destination file making sure the path is writeable.
		dst, err := os.Create(fmt.Sprintf("%s%s%s", dir, util.DirSeg(), files[i].Filename))
		if err != nil {
			continue
		}
		defer dst.Close()
		io.Copy(dst, src)
	}
	return images, nil
}

func getImageInfo(c *gin.Context, images *data.Images) {
	user := getUser(c)
	album := getAlbum(c)
	dir := fmt.Sprintf("%s%s%s", user, util.DirSeg(), album)
	filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		//跳过目录
		if info.IsDir() {
			return nil
		}
		filename := filepath.Base(path)
		img := &data.Imagedata{}
		img.User = user
		img.Album = album
		img.Name = filename
		sli := strings.Split(filename, ".")
		ext := strings.ToLower(sli[len(sli)-1])
		img.Type = ext
		img.Updatetime = util.GetMills()
		img.Filename = filename
		img.ContentType = fmt.Sprintf("image/%s", ext)
		img.Id = fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%s%s%s%v", user, album, filename, img.Updatetime))))

		*images = append(*images, img)
		return nil
	})
}
<commit_msg>修改上传接口 返回格式<commit_after>package router

import (
	"crypto/md5"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/orange-jacky/albums/data"
	"github.com/orange-jacky/albums/db"
	"github.com/orange-jacky/albums/util"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

// UpLoad 上传图片到相册
func UpLoad(c *gin.Context) {
	conf := util.Configure("")
	//log := util.Mylog("")

	//新建一个图片库连接
	gridfs := db.NewMongoGridfs()
	gridfs.Connect(conf.Mongo.Hosts, conf.Mongo.Image.Db)
	gridfs.OpenDb(conf.Mongo.Image.Db)
	gridfs.OpenTable("fs")
	defer gridfs.Close()

	//先缓存文件
	images, _ := cacheFile(c)
	defer clearCache(c)
	//提取图片信息
	getImageInfo(c, &images)
	//入库
	gridfs.Insert(images)

	resp := data.Response{}
	resp.Data = images
	c.JSON(http.StatusOK, resp)
	//c.String(http.StatusOK, "%s", "upload")
}

func getUser(c *gin.Context) string {
	user := c.PostForm("user")
	if user == "" {
		user = "default"
	}
	return user
}

func getAlbum(c *gin.Context) string {
	album := c.PostForm("album")
	if album == "" {
		album = "default"
	}
	return album
}

func clearCache(c *gin.Context) {
	user := getUser(c)
	album := getAlbum(c)
	os.RemoveAll(fmt.Sprintf("%s%s%s", user, util.DirSeg(), album))
}

// cacheFile 先把上传文件缓存到本地磁盘
func cacheFile(c *gin.Context) (images data.Images, err error) {
	r := c.Request
	//POST takes the uploaded file(s) and saves it to disk.
	//parse the multipart form in the request
	err = r.ParseMultipartForm(100000)
	if err != nil {
		return images, err
	}
	//get a ref to the parsed multipart form
	m := r.MultipartForm
	//get the *fileheaders
	files := m.File["images"] //表单的name,id

	//post 没有文件直接返回
	if len(files) == 0 {
		return images, nil
	}
	//创建临时缓存目录
	user := getUser(c)
	album := getAlbum(c)
	dir := fmt.Sprintf("%s%s%s", user, util.DirSeg(), album)
	err = os.MkdirAll(dir, os.ModePerm)
	if err != nil {
		return images, err
	}
	//取所有上传文件
	for i, _ := range files {
		//for each fileheader, get a handle to the actual file
		src, err := files[i].Open()
		if err != nil {
			continue
		}
		defer src.Close()
		//create destination file making sure the path is writeable.
		dst, err := os.Create(fmt.Sprintf("%s%s%s", dir, util.DirSeg(), files[i].Filename))
		if err != nil {
			continue
		}
		defer dst.Close()
		io.Copy(dst, src)
	}
	return images, nil
}

func getImageInfo(c *gin.Context, images *data.Images) {
	user := getUser(c)
	album := getAlbum(c)
	dir := fmt.Sprintf("%s%s%s", user, util.DirSeg(), album)
	filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		//跳过目录
		if info.IsDir() {
			return nil
		}
		filename := filepath.Base(path)
		img := &data.Imagedata{}
		img.User = user
		img.Album = album
		img.Name = filename
		sli := strings.Split(filename, ".")
		ext := strings.ToLower(sli[len(sli)-1])
		img.Type = ext
		img.Updatetime = util.GetMills()
		img.Filename = filename
		img.ContentType = fmt.Sprintf("image/%s", ext)
		img.Id = fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%s%s%s%v", user, album, filename, img.Updatetime))))

		*images = append(*images, img)
		return nil
	})
}
<|endoftext|>