<commit_before>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom

import (
	"bytes"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
)

type Chain struct {
	ChainID    string `json:"chainid"`
	FirstEntry *Entry `json:"firstentry"`
}

func NewChain(e *Entry) *Chain {
	c := new(Chain)
	c.FirstEntry = e

	// create the chainid from a series of hashes of the Entries ExtIDs
	hs := sha256.New()
	for _, id := range e.ExtIDs {
		h := sha256.Sum256(id)
		hs.Write(h[:])
	}
	c.ChainID = hex.EncodeToString(hs.Sum(nil))
	c.FirstEntry.ChainID = c.ChainID

	return c
}

// ComposeChainCommit creates a JSON2Request to commit a new Chain via the
// factomd web api. The request includes the marshaled MessageRequest with the
// Entry Credit Signature.
func ComposeChainCommit(c *Chain, ec *ECAddress) (*JSON2Request, error) {
	buf := new(bytes.Buffer)

	// 1 byte version
	buf.Write([]byte{0})

	// 6 byte milliTimestamp
	buf.Write(milliTime())

	e := c.FirstEntry

	// 32 byte ChainID Hash
	if p, err := hex.DecodeString(c.ChainID); err != nil {
		return nil, err
	} else {
		// double sha256 hash of ChainID
		buf.Write(shad(p))
	}

	// 32 byte Weld; sha256(sha256(EntryHash + ChainID))
	if cid, err := hex.DecodeString(c.ChainID); err != nil {
		return nil, err
	} else {
		s := append(e.Hash(), cid...)
		buf.Write(shad(s))
	}

	// 32 byte Entry Hash of the First Entry
	buf.Write(e.Hash())

	// 1 byte number of Entry Credits to pay
	if d, err := entryCost(e); err != nil {
		return nil, err
	} else {
		balance, err := GetECBalance(ec.String())
		if err != nil {
			return nil, err
		} else {
			if balance < int64(d + 10) {
				return nil, fmt.Errorf("The EC balance available (%d) is insufficent to create this Chain (%d)", balance, d + 10)
			} else {
				buf.WriteByte(byte(d + 10))
			}
		}
	}

	// 32 byte Entry Credit Address Public Key + 64 byte Signature
	sig := ec.Sign(buf.Bytes())
	buf.Write(ec.PubBytes())
	buf.Write(sig[:])

	params := messageRequest{Message: hex.EncodeToString(buf.Bytes())}
	req := NewJSON2Request("commit-chain", APICounter(), params)

	return req, nil
}

// ComposeChainReveal creates a JSON2Request to reveal the Chain via the factomd
// web api.
func ComposeChainReveal(c *Chain) (*JSON2Request, error) {
	p, err := c.FirstEntry.MarshalBinary()
	if err != nil {
		return nil, err
	}
	params := entryRequest{Entry: hex.EncodeToString(p)}

	req := NewJSON2Request("reveal-chain", APICounter(), params)
	return req, nil
}

// CommitChain sends the signed ChainID, the Entry Hash, and the Entry Credit
// public key to the factom network. Once the payment is verified and the
// network is commited to publishing the Chain it may be published by revealing
// the First Entry in the Chain.
func CommitChain(c *Chain, ec *ECAddress) (string, error) {
	type commitResponse struct {
		Message string `json:"message"`
		TxID    string `json:"txid"`
	}

	req, err := ComposeChainCommit(c, ec)
	if err != nil {
		return "", err
	}

	resp, err := factomdRequest(req)
	if err != nil {
		return "", err
	}
	if resp.Error != nil {
		return "", resp.Error
	}
	r := new(commitResponse)
	if err := json.Unmarshal(resp.JSONResult(), r); err != nil {
		return "", err
	}

	return r.TxID, nil
}

func RevealChain(c *Chain) (string, error) {
	type revealResponse struct {
		Message string `json:"message"`
		Entry   string `json:"entryhash"`
	}

	req, err := ComposeChainReveal(c)
	if err != nil {
		return "", err
	}

	resp, err := factomdRequest(req)
	if err != nil {
		return "", err
	}
	if resp.Error != nil {
		return "", resp.Error
	}

	r := new(revealResponse)
	if err := json.Unmarshal(resp.JSONResult(), r); err != nil {
		return "", err
	}
	return r.Entry, nil
}
<commit_msg>Revert "error message clarification"<commit_after>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom

import (
	"bytes"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
)

type Chain struct {
	ChainID    string `json:"chainid"`
	FirstEntry *Entry `json:"firstentry"`
}

func NewChain(e *Entry) *Chain {
	c := new(Chain)
	c.FirstEntry = e

	// create the chainid from a series of hashes of the Entries ExtIDs
	hs := sha256.New()
	for _, id := range e.ExtIDs {
		h := sha256.Sum256(id)
		hs.Write(h[:])
	}
	c.ChainID = hex.EncodeToString(hs.Sum(nil))
	c.FirstEntry.ChainID = c.ChainID

	return c
}

// ComposeChainCommit creates a JSON2Request to commit a new Chain via the
// factomd web api. The request includes the marshaled MessageRequest with the
// Entry Credit Signature.
func ComposeChainCommit(c *Chain, ec *ECAddress) (*JSON2Request, error) {
	buf := new(bytes.Buffer)

	// 1 byte version
	buf.Write([]byte{0})

	// 6 byte milliTimestamp
	buf.Write(milliTime())

	e := c.FirstEntry

	// 32 byte ChainID Hash
	if p, err := hex.DecodeString(c.ChainID); err != nil {
		return nil, err
	} else {
		// double sha256 hash of ChainID
		buf.Write(shad(p))
	}

	// 32 byte Weld; sha256(sha256(EntryHash + ChainID))
	if cid, err := hex.DecodeString(c.ChainID); err != nil {
		return nil, err
	} else {
		s := append(e.Hash(), cid...)
		buf.Write(shad(s))
	}

	// 32 byte Entry Hash of the First Entry
	buf.Write(e.Hash())

	// 1 byte number of Entry Credits to pay
	if d, err := entryCost(e); err != nil {
		return nil, err
	} else {
		balance, err := GetECBalance(ec.String())
		if err != nil {
			return nil, err
		} else {
			if balance < int64(d + 10) {
				return nil, fmt.Errorf("The EC balance available (%d) is insufficent for this Entry (%d)", balance, d + 10)
			} else {
				buf.WriteByte(byte(d + 10))
			}
		}
	}

	// 32 byte Entry Credit Address Public Key + 64 byte Signature
	sig := ec.Sign(buf.Bytes())
	buf.Write(ec.PubBytes())
	buf.Write(sig[:])

	params := messageRequest{Message: hex.EncodeToString(buf.Bytes())}
	req := NewJSON2Request("commit-chain", APICounter(), params)

	return req, nil
}

// ComposeChainReveal creates a JSON2Request to reveal the Chain via the factomd
// web api.
func ComposeChainReveal(c *Chain) (*JSON2Request, error) {
	p, err := c.FirstEntry.MarshalBinary()
	if err != nil {
		return nil, err
	}
	params := entryRequest{Entry: hex.EncodeToString(p)}

	req := NewJSON2Request("reveal-chain", APICounter(), params)
	return req, nil
}

// CommitChain sends the signed ChainID, the Entry Hash, and the Entry Credit
// public key to the factom network. Once the payment is verified and the
// network is commited to publishing the Chain it may be published by revealing
// the First Entry in the Chain.
func CommitChain(c *Chain, ec *ECAddress) (string, error) {
	type commitResponse struct {
		Message string `json:"message"`
		TxID    string `json:"txid"`
	}

	req, err := ComposeChainCommit(c, ec)
	if err != nil {
		return "", err
	}

	resp, err := factomdRequest(req)
	if err != nil {
		return "", err
	}
	if resp.Error != nil {
		return "", resp.Error
	}
	r := new(commitResponse)
	if err := json.Unmarshal(resp.JSONResult(), r); err != nil {
		return "", err
	}

	return r.TxID, nil
}

func RevealChain(c *Chain) (string, error) {
	type revealResponse struct {
		Message string `json:"message"`
		Entry   string `json:"entryhash"`
	}

	req, err := ComposeChainReveal(c)
	if err != nil {
		return "", err
	}

	resp, err := factomdRequest(req)
	if err != nil {
		return "", err
	}
	if resp.Error != nil {
		return "", resp.Error
	}

	r := new(revealResponse)
	if err := json.Unmarshal(resp.JSONResult(), r); err != nil {
		return "", err
	}
	return r.Entry, nil
}
<|endoftext|>


<commit_before>// Copyright 2015 The Cockroach 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.
//
// Author: Bram Gruneir (bram+code@cockroachlabs.com)

package acceptance

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"testing"
	"time"

	"github.com/cockroachdb/cockroach/acceptance/cluster"
	"github.com/cockroachdb/cockroach/roachpb"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/log"
	"github.com/cockroachdb/cockroach/util/retry"
)

type details struct {
	NodeID roachpb.NodeID `json:"nodeID"`
}

var retryOptions = retry.Options{
	InitialBackoff: 100 * time.Millisecond,
	MaxRetries:     4,
	Multiplier:     2,
}

// get performs an HTTPS GET to the specified path for a specific node.
func get(t *testing.T, base, rel string) []byte {
	// TODO(bram) #2059: Remove retry logic.
	url := fmt.Sprintf("%s/%s", base, rel)
	for r := retry.Start(retryOptions); r.Next(); {
		resp, err := cluster.HTTPClient.Get(url)
		if err != nil {
			log.Infof("could not GET %s - %s", url, err)
			continue
		}
		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Infof("could not read body for %s - %s", url, err)
			continue
		}
		if resp.StatusCode != http.StatusOK {
			log.Infof("could not GET %s - statuscode: %d - body: %s", url, resp.StatusCode, body)
			continue
		}
		if log.V(1) {
			log.Infof("OK response from %s", url)
		}
		return body
	}
	t.Fatalf("There was an error retrieving %s", url)
	return []byte("")
}

// checkNode checks all the endpoints of the status server hosted by node and
// requests info for the node with otherNodeID. That node could be the same
// other node, the same node or "local".
func checkNode(t *testing.T, c cluster.Cluster, i int, nodeID, otherNodeID, expectedNodeID string) {
	var detail details
	if err := getJSON(c.URL(i), "/_status/details/"+otherNodeID, &detail); err != nil {
		t.Fatal(util.ErrorfSkipFrames(1, "unable to parse details - %s", err))
	}
	if actualNodeID := detail.NodeID.String(); actualNodeID != expectedNodeID {
		t.Fatal(util.ErrorfSkipFrames(1, "%s calling %s: node ids don't match - expected %s, actual %s", nodeID, otherNodeID, expectedNodeID, actualNodeID))
	}

	get(t, c.URL(i), fmt.Sprintf("/_status/gossip/%s", otherNodeID))
	get(t, c.URL(i), fmt.Sprintf("/_status/logfiles/%s", otherNodeID))
	get(t, c.URL(i), fmt.Sprintf("/_status/logs/%s", otherNodeID))
	get(t, c.URL(i), fmt.Sprintf("/_status/stacks/%s", otherNodeID))
	get(t, c.URL(i), fmt.Sprintf("/_status/nodes/%s", otherNodeID))
}

// TestStatusServer starts up an N node cluster and tests the status server on
// each node.
func TestStatusServer(t *testing.T) {
	t.Skipf("TODO(pmattis): #4512")
	runTestOnConfigs(t, testStatusServerInner)
}

func testStatusServerInner(t *testing.T, c cluster.Cluster, cfg cluster.TestConfig) {
	// Get the ids for each node.
	idMap := make(map[int]string)
	for i := 0; i < c.NumNodes(); i++ {
		var detail details
		if err := getJSON(c.URL(i), "/_status/details/local", &detail); err != nil {
			t.Fatal(err)
		}
		idMap[i] = detail.NodeID.String()
	}

	// Check local response for the every node.
	for i := 0; i < c.NumNodes(); i++ {
		checkNode(t, c, i, idMap[i], "local", idMap[i])
		get(t, c.URL(i), "/_status/nodes")
		get(t, c.URL(i), "/_status/stores")
	}

	// Proxy from the first node to the last node.
	firstNode := 0
	lastNode := c.NumNodes() - 1
	firstID := idMap[firstNode]
	lastID := idMap[lastNode]
	checkNode(t, c, firstNode, firstID, lastID, lastID)

	// And from the last node to the first node.
	checkNode(t, c, lastNode, lastID, firstID, firstID)

	// And from the last node to the last node.
	checkNode(t, c, lastNode, lastID, lastID, lastID)
}
<commit_msg>acceptance: unskip a test whose bug is closed<commit_after>// Copyright 2015 The Cockroach 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.
//
// Author: Bram Gruneir (bram+code@cockroachlabs.com)

package acceptance

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"testing"
	"time"

	"github.com/cockroachdb/cockroach/acceptance/cluster"
	"github.com/cockroachdb/cockroach/roachpb"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/log"
	"github.com/cockroachdb/cockroach/util/retry"
)

type details struct {
	NodeID roachpb.NodeID `json:"nodeID"`
}

var retryOptions = retry.Options{
	InitialBackoff: 100 * time.Millisecond,
	MaxRetries:     4,
	Multiplier:     2,
}

// get performs an HTTPS GET to the specified path for a specific node.
func get(t *testing.T, base, rel string) []byte {
	// TODO(bram) #2059: Remove retry logic.
	url := fmt.Sprintf("%s/%s", base, rel)
	for r := retry.Start(retryOptions); r.Next(); {
		resp, err := cluster.HTTPClient.Get(url)
		if err != nil {
			log.Infof("could not GET %s - %s", url, err)
			continue
		}
		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Infof("could not read body for %s - %s", url, err)
			continue
		}
		if resp.StatusCode != http.StatusOK {
			log.Infof("could not GET %s - statuscode: %d - body: %s", url, resp.StatusCode, body)
			continue
		}
		if log.V(1) {
			log.Infof("OK response from %s", url)
		}
		return body
	}
	t.Fatalf("There was an error retrieving %s", url)
	return []byte("")
}

// checkNode checks all the endpoints of the status server hosted by node and
// requests info for the node with otherNodeID. That node could be the same
// other node, the same node or "local".
func checkNode(t *testing.T, c cluster.Cluster, i int, nodeID, otherNodeID, expectedNodeID string) {
	var detail details
	if err := getJSON(c.URL(i), "/_status/details/"+otherNodeID, &detail); err != nil {
		t.Fatal(util.ErrorfSkipFrames(1, "unable to parse details - %s", err))
	}
	if actualNodeID := detail.NodeID.String(); actualNodeID != expectedNodeID {
		t.Fatal(util.ErrorfSkipFrames(1, "%s calling %s: node ids don't match - expected %s, actual %s", nodeID, otherNodeID, expectedNodeID, actualNodeID))
	}

	get(t, c.URL(i), fmt.Sprintf("/_status/gossip/%s", otherNodeID))
	get(t, c.URL(i), fmt.Sprintf("/_status/logfiles/%s", otherNodeID))
	get(t, c.URL(i), fmt.Sprintf("/_status/logs/%s", otherNodeID))
	get(t, c.URL(i), fmt.Sprintf("/_status/stacks/%s", otherNodeID))
	get(t, c.URL(i), fmt.Sprintf("/_status/nodes/%s", otherNodeID))
}

// TestStatusServer starts up an N node cluster and tests the status server on
// each node.
func TestStatusServer(t *testing.T) {
	runTestOnConfigs(t, testStatusServerInner)
}

func testStatusServerInner(t *testing.T, c cluster.Cluster, cfg cluster.TestConfig) {
	// Get the ids for each node.
	idMap := make(map[int]string)
	for i := 0; i < c.NumNodes(); i++ {
		var detail details
		if err := getJSON(c.URL(i), "/_status/details/local", &detail); err != nil {
			t.Fatal(err)
		}
		idMap[i] = detail.NodeID.String()
	}

	// Check local response for the every node.
	for i := 0; i < c.NumNodes(); i++ {
		checkNode(t, c, i, idMap[i], "local", idMap[i])
		get(t, c.URL(i), "/_status/nodes")
	}

	// TODO(tamird): remove this after #5530. The `if` here is present to trick
	// `go vet`.
	if true {
		return
	}

	// Proxy from the first node to the last node.
	firstNode := 0
	lastNode := c.NumNodes() - 1
	firstID := idMap[firstNode]
	lastID := idMap[lastNode]
	checkNode(t, c, firstNode, firstID, lastID, lastID)

	// And from the last node to the first node.
	checkNode(t, c, lastNode, lastID, firstID, firstID)

	// And from the last node to the last node.
	checkNode(t, c, lastNode, lastID, lastID, lastID)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"time"

	"github.com/lowstz/slackhookgo"
)

type alertMessage struct {
	url     string
	text    string
	color   string
	channel string
}

type connection struct {
	protocol string
	address  string
}

func checkError(err error) bool {
	if err == nil {
		return false
	}
	log.Printf("error: %s", err)
	return true
}

func (c *connection) conn() (net.Conn, bool) {
	conn, err := net.DialTimeout(c.protocol, c.address, 3*time.Second)
	errBool := checkError(err)
	return conn, errBool
}

func (a *alertMessage) sentSlack() {
	msg := slackhookgo.NewSlackMessage(
		"Alert",
		a.channel,
	).AddAttachment(
		slackhookgo.MessageAttachment{
			Color: a.color,
			Text:  a.text,
			Title: "<!channel>",
		},
	)
	msg.IconEmoji = ":exclamation:"
	err := slackhookgo.Send(a.url, msg)
	checkError(err)
}

func main() {
	var (
		color     string
		status    string
		lastState bool
		protocol  = flag.String("protocol", "tcp", "protocol tcp/udp")
		host      = flag.String("host", "", "destination host")
		port      = flag.Uint("port", 80, "destination port")
		interval  = flag.Uint("interval", 15, "interval check seconds")
		url       = flag.String("url", "", "hook url")
		slack     = flag.Bool("slack", false, "use -slack for send alert in slack")
		channel   = flag.String("channel", "general", "slack channel")
	)

	flag.Parse()

	if len(os.Args) == 1 {
		flag.PrintDefaults()
		os.Exit(1)
	} else if *host == "" {
		log.Fatal("param '-host' is empty")
	} else if *slack == true {
		if *url == "" {
			log.Fatal("param '-url' is empty")
		}
	}

	c := connection{
		protocol: *protocol,
		address:  fmt.Sprintf("%s:%v", *host, *port),
	}

	for {
		conn, err := c.conn()
		if err != lastState {
			if err == false { // normal
				conn.Close()
				color = "good"
				status = "reachable"
			} else { // not normal
				color = "danger"
				status = "unreachable"
			}
			lastState = err // key of success
			if *slack == true {
				am := alertMessage{
					channel: *channel,
					color:   color,
					text:    fmt.Sprintf("Destination host %s:%v %s\n", *host, *port, status),
					url:     *url,
				}
				am.sentSlack()
			}
		}
		time.Sleep(time.Duration(*interval) * time.Second)
	}
}
<commit_msg>add recheck<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"time"

	"github.com/lowstz/slackhookgo"
)

type alertMessage struct {
	url     string
	text    string
	color   string
	channel string
}

type connection struct {
	protocol string
	address  string
}

func checkError(err error) bool {
	if err == nil {
		return false
	}
	log.Printf("error: %s", err)
	return true
}

func (c *connection) conn() (net.Conn, bool) {
	conn, err := net.DialTimeout(c.protocol, c.address, 3*time.Second)
	errBool := checkError(err)
	return conn, errBool
}

func (a *alertMessage) sentSlack() {
	msg := slackhookgo.NewSlackMessage(
		"Alert",
		a.channel,
	).AddAttachment(
		slackhookgo.MessageAttachment{
			Color: a.color,
			Text:  a.text,
			Title: "<!channel>",
		},
	)
	msg.IconEmoji = ":exclamation:"
	err := slackhookgo.Send(a.url, msg)
	checkError(err)
}

func main() {
	var (
		color     string
		status    string
		lastState bool
		protocol  = flag.String("protocol", "tcp", "protocol tcp/udp")
		host      = flag.String("host", "", "destination host")
		port      = flag.Uint("port", 80, "destination port")
		interval  = flag.Uint("interval", 15, "interval check seconds")
		url       = flag.String("url", "", "hook url")
		slack     = flag.Bool("slack", false, "use -slack for send alert in slack")
		channel   = flag.String("channel", "general", "slack channel")
	)

	flag.Parse()

	if len(os.Args) == 1 {
		flag.PrintDefaults()
		os.Exit(1)
	} else if *host == "" {
		log.Fatal("param '-host' is empty")
	} else if *slack == true {
		if *url == "" {
			log.Fatal("param '-url' is empty")
		}
	}

	c := connection{
		protocol: *protocol,
		address:  fmt.Sprintf("%s:%v", *host, *port),
	}

	for {
		conn, err := c.conn()
		if err != lastState {
			if err == false { // normal
				conn.Close()
				color = "good"
				status = "reachable"
			} else { // not normal
				time.Sleep(time.Duration(5) * time.Second)
				conn, errr := c.conn()
				if errr != false {
					color = "danger"
					status = "unreachable"
				} else {
					conn.Close()
				}
			}
			lastState = err // key of success
			if *slack == true {
				am := alertMessage{
					channel: *channel,
					color:   color,
					text:    fmt.Sprintf("Destination host %s:%v %s\n", *host, *port, status),
					url:     *url,
				}
				am.sentSlack()
			}
		}
		time.Sleep(time.Duration(*interval) * time.Second)
	}
}
<|endoftext|>


<commit_before>package service_test

import (
	"cf/api"
	. "cf/commands/service"
	"cf/models"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	testapi "testhelpers/api"
	testassert "testhelpers/assert"
	testcmd "testhelpers/commands"
	testconfig "testhelpers/configuration"
	testreq "testhelpers/requirements"
	testterm "testhelpers/terminal"
)

var _ = Describe("unbind-service command", func() {
	var (
		app models.Application
		serviceInstance models.ServiceInstance
		requirementsFactory *testreq.FakeReqFactory
		serviceBindingRepo *testapi.FakeServiceBindingRepo
	)

	BeforeEach(func() {
		app.Name = "my-app"
		app.Guid = "my-app-guid"

		serviceInstance.Name = "my-service"
		serviceInstance.Guid = "my-service-guid"

		requirementsFactory = &testreq.FakeReqFactory{}
		requirementsFactory.Application = app
		requirementsFactory.ServiceInstance = serviceInstance

		serviceBindingRepo = &testapi.FakeServiceBindingRepo{}
	})

	Context("when not logged in", func() {
		It("fails requirements when not logged in", func() {
			cmd := NewUnbindService(&testterm.FakeUI{}, testconfig.NewRepository(), serviceBindingRepo)
			testcmd.RunCommand(cmd, testcmd.NewContext("unbind-service", []string{"my-service", "my-app"}), requirementsFactory)
			Expect(testcmd.CommandDidPassRequirements).To(BeFalse())
		})
	})

	Context("when logged in", func() {
		BeforeEach(func() {
		    requirementsFactory.LoginSuccess = true
		})

		Context("when the service instance exists", func() {
			It("unbinds a service from an app", func() {
				ui := callUnbindService([]string{"my-app", "my-service"}, requirementsFactory, serviceBindingRepo)

				Expect(requirementsFactory.ApplicationName).To(Equal("my-app"))
				Expect(requirementsFactory.ServiceInstanceName).To(Equal("my-service"))

				testassert.SliceContains(ui.Outputs, testassert.Lines{
					{"Unbinding app", "my-service", "my-app", "my-org", "my-space", "my-user"},
					{"OK"},
				})
				Expect(serviceBindingRepo.DeleteServiceInstance).To(Equal(serviceInstance))
				Expect(serviceBindingRepo.DeleteApplicationGuid).To(Equal("my-app-guid"))
			})
		})

		Context("when the service instance does not exist", func() {
			BeforeEach(func() {
				serviceBindingRepo.DeleteBindingNotFound = true
			})

			It("warns the user the the service instance does not exist", func() {
				ui := callUnbindService([]string{"my-app", "my-service"}, requirementsFactory, serviceBindingRepo)

				Expect(requirementsFactory.ApplicationName).To(Equal("my-app"))
				Expect(requirementsFactory.ServiceInstanceName).To(Equal("my-service"))

				testassert.SliceContains(ui.Outputs, testassert.Lines{
					{"Unbinding app", "my-service", "my-app"},
					{"OK"},
					{"my-service", "my-app", "did not exist"},
				})
				Expect(serviceBindingRepo.DeleteServiceInstance).To(Equal(serviceInstance))
				Expect(serviceBindingRepo.DeleteApplicationGuid).To(Equal("my-app-guid"))
			})
		})

		It("when no parameters are given the command fails with usage", func() {
			ui := callUnbindService([]string{"my-service"}, requirementsFactory, serviceBindingRepo)
			Expect(ui.FailedWithUsage).To(BeTrue())

			ui = callUnbindService([]string{"my-app"}, requirementsFactory, serviceBindingRepo)
			Expect(ui.FailedWithUsage).To(BeTrue())

			ui = callUnbindService([]string{"my-app", "my-service"}, requirementsFactory, serviceBindingRepo)
			Expect(ui.FailedWithUsage).To(BeFalse())
		})
	})
})

func callUnbindService(args []string, reqFactory *testreq.FakeReqFactory, serviceBindingRepo api.ServiceBindingRepository) (fakeUI *testterm.FakeUI) {
	fakeUI = &testterm.FakeUI{}
	ctxt := testcmd.NewContext("unbind-service", args)

	config := testconfig.NewRepositoryWithDefaults()

	cmd := NewUnbindService(fakeUI, config, serviceBindingRepo)
	testcmd.RunCommand(cmd, ctxt, reqFactory)
	return
}
<commit_msg>cleanup tests for create-service<commit_after>package service_test

import (
	"cf/api"
	. "cf/commands/service"
	"cf/models"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	testapi "testhelpers/api"
	testassert "testhelpers/assert"
	testcmd "testhelpers/commands"
	testconfig "testhelpers/configuration"
	testreq "testhelpers/requirements"
	testterm "testhelpers/terminal"
)

var _ = Describe("unbind-service command", func() {
	var (
		app                 models.Application
		serviceInstance     models.ServiceInstance
		requirementsFactory *testreq.FakeReqFactory
		serviceBindingRepo  *testapi.FakeServiceBindingRepo
	)

	BeforeEach(func() {
		app.Name = "my-app"
		app.Guid = "my-app-guid"

		serviceInstance.Name = "my-service"
		serviceInstance.Guid = "my-service-guid"

		requirementsFactory = &testreq.FakeReqFactory{}
		requirementsFactory.Application = app
		requirementsFactory.ServiceInstance = serviceInstance

		serviceBindingRepo = &testapi.FakeServiceBindingRepo{}
	})

	Context("when not logged in", func() {
		It("fails requirements when not logged in", func() {
			cmd := NewUnbindService(&testterm.FakeUI{}, testconfig.NewRepository(), serviceBindingRepo)
			testcmd.RunCommand(cmd, testcmd.NewContext("unbind-service", []string{"my-service", "my-app"}), requirementsFactory)
			Expect(testcmd.CommandDidPassRequirements).To(BeFalse())
		})
	})

	Context("when logged in", func() {
		BeforeEach(func() {
			requirementsFactory.LoginSuccess = true
		})

		Context("when the service instance exists", func() {
			It("unbinds a service from an app", func() {
				ui := callUnbindService([]string{"my-app", "my-service"}, requirementsFactory, serviceBindingRepo)

				Expect(requirementsFactory.ApplicationName).To(Equal("my-app"))
				Expect(requirementsFactory.ServiceInstanceName).To(Equal("my-service"))

				testassert.SliceContains(ui.Outputs, testassert.Lines{
					{"Unbinding app", "my-service", "my-app", "my-org", "my-space", "my-user"},
					{"OK"},
				})
				Expect(serviceBindingRepo.DeleteServiceInstance).To(Equal(serviceInstance))
				Expect(serviceBindingRepo.DeleteApplicationGuid).To(Equal("my-app-guid"))
			})
		})

		Context("when the service instance does not exist", func() {
			BeforeEach(func() {
				serviceBindingRepo.DeleteBindingNotFound = true
			})

			It("warns the user the the service instance does not exist", func() {
				ui := callUnbindService([]string{"my-app", "my-service"}, requirementsFactory, serviceBindingRepo)

				Expect(requirementsFactory.ApplicationName).To(Equal("my-app"))
				Expect(requirementsFactory.ServiceInstanceName).To(Equal("my-service"))

				testassert.SliceContains(ui.Outputs, testassert.Lines{
					{"Unbinding app", "my-service", "my-app"},
					{"OK"},
					{"my-service", "my-app", "did not exist"},
				})
				Expect(serviceBindingRepo.DeleteServiceInstance).To(Equal(serviceInstance))
				Expect(serviceBindingRepo.DeleteApplicationGuid).To(Equal("my-app-guid"))
			})
		})

		It("when no parameters are given the command fails with usage", func() {
			ui := callUnbindService([]string{"my-service"}, requirementsFactory, serviceBindingRepo)
			Expect(ui.FailedWithUsage).To(BeTrue())

			ui = callUnbindService([]string{"my-app"}, requirementsFactory, serviceBindingRepo)
			Expect(ui.FailedWithUsage).To(BeTrue())

			ui = callUnbindService([]string{"my-app", "my-service"}, requirementsFactory, serviceBindingRepo)
			Expect(ui.FailedWithUsage).To(BeFalse())
		})
	})
})

func callUnbindService(args []string, reqFactory *testreq.FakeReqFactory, serviceBindingRepo api.ServiceBindingRepository) (fakeUI *testterm.FakeUI) {
	fakeUI = &testterm.FakeUI{}
	ctxt := testcmd.NewContext("unbind-service", args)

	config := testconfig.NewRepositoryWithDefaults()

	cmd := NewUnbindService(fakeUI, config, serviceBindingRepo)
	testcmd.RunCommand(cmd, ctxt, reqFactory)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"sync"
	"time"
)

func produce(done <-chan struct{}, paths []string) (<-chan string, <-chan error) {
	psc := make(chan string)
	esc := make(chan error, 1)

	go func() {
		defer close(psc)
		defer close(esc)

		for _, p := range paths {
			select {
			case psc <- p:
			case <-done:
				esc <- errors.New("canceled")
				return
			}
		}
	}()

	return psc, esc
}

func digest(done <-chan struct{}, slow bool, fisc chan<- *fileInfo, psc <-chan string) {
	for p := range psc {
		if slow {
			select {
			case <-time.After(time.Second):
			case <-done:
				return
			}
		}

		fisc <- newFileInfo(p)
	}
}

func consume(done <-chan struct{}, slow bool, width int, psc <-chan string) <-chan *fileInfo {
	fisc := make(chan *fileInfo)

	go func() {
		defer close(fisc)

		var wg sync.WaitGroup
		wg.Add(width)

		for i := 0; i < width; i++ {
			go func() {
				digest(done, slow, fisc, psc)
				wg.Done()
			}()
		}

		wg.Wait()
	}()

	return fisc
}

func fileInfos(done <-chan struct{}, slow bool, width int, paths []string) (<-chan *fileInfo, func() error) {
	psc, esc := produce(done, paths)
	fisc := consume(done, slow, width, psc)

	return fisc, fileInfosErrorFunc(esc)
}

func fileInfosErrorFunc(esc <-chan error) func() error {
	var last error

	return func() error {
		if err := <-esc; err != nil {
			last = fmt.Errorf("cannot handle fileInfos: %s", err)
			return last
		}

		return last
	}
}
<commit_msg>Remove useless return.<commit_after>package main

import (
	"errors"
	"fmt"
	"sync"
	"time"
)

func produce(done <-chan struct{}, paths []string) (<-chan string, <-chan error) {
	psc := make(chan string)
	esc := make(chan error, 1)

	go func() {
		defer close(psc)
		defer close(esc)

		for _, p := range paths {
			select {
			case psc <- p:
			case <-done:
				esc <- errors.New("canceled")
				return
			}
		}
	}()

	return psc, esc
}

func digest(done <-chan struct{}, slow bool, fisc chan<- *fileInfo, psc <-chan string) {
	for p := range psc {
		if slow {
			select {
			case <-time.After(time.Second):
			case <-done:
				return
			}
		}

		fisc <- newFileInfo(p)
	}
}

func consume(done <-chan struct{}, slow bool, width int, psc <-chan string) <-chan *fileInfo {
	fisc := make(chan *fileInfo)

	go func() {
		defer close(fisc)

		var wg sync.WaitGroup
		wg.Add(width)

		for i := 0; i < width; i++ {
			go func() {
				digest(done, slow, fisc, psc)
				wg.Done()
			}()
		}

		wg.Wait()
	}()

	return fisc
}

func fileInfos(done <-chan struct{}, slow bool, width int, paths []string) (<-chan *fileInfo, func() error) {
	psc, esc := produce(done, paths)
	fisc := consume(done, slow, width, psc)

	return fisc, fileInfosErrorFunc(esc)
}

func fileInfosErrorFunc(esc <-chan error) func() error {
	var last error

	return func() error {
		if err := <-esc; err != nil {
			last = fmt.Errorf("cannot handle fileInfos: %s", err)
		}

		return last
	}
}
<|endoftext|>


<commit_before>// Copyright © 2013, S.Çağlar Onur
// Use of this source code is governed by a LGPLv2.1
// license that can be found in the LICENSE file.
//
// Authors:
// S.Çağlar Onur <caglar@10ur.org>

// +build linux

package lxc

const (
	// WaitForever timeout
	WaitForever int = iota - 1
	// DontWait timeout
	DontWait
)

const (
	// CloneKeepName means do not edit the rootfs to change the hostname
	CloneKeepName int = 1 << iota
	// CloneKeepMACAddr means do not change the mac address on network interfaces
	CloneKeepMACAddr
	// CloneSnapshot means snapshot the original filesystem(s)
	CloneSnapshot
)

const (
	errAlreadyDefined                = "container %q already defined"
	errAlreadyFrozen                 = "container %q is already frozen"
	errAlreadyRunning                = "container %q is already running"
	errAttachFailed                  = "attaching to the container %q failed"
	errClearingCgroupItemFailed      = "clearing cgroup item for the container %q failed (key: %s)"
	errCloneFailed                   = "cloning the container %q failed"
	errCloseAllFdsFailed             = "setting close_all_fds flag for container %q failed"
	errCreateFailed                  = "creating the container %q failed"
	errCreateSnapshotFailed          = "snapshotting the container %q failed"
	errDaemonizeFailed               = "setting daemonize flag for container %q failed"
	errDestroyFailed                 = "destroying the container %q failed"
	errDestroySnapshotFailed         = "destroying the snapshot %q failed"
	errExecuteFailed                 = "executing the command in a temporary container %q failed"
	errFreezeFailed                  = "freezing the container %q failed"
	errInsufficientNumberOfArguments = "insufficient number of arguments were supplied"
	errInterfaces                    = "getting interface names for the container %q failed"
	errIPAddresses                   = "getting IP addresses of the container %q failed"
	errIPAddress                     = "getting IP address on the interface %s of the container %q failed"
	errIPv4Addresses                 = "getting IPv4 addresses of the container %q failed"
	errIPv6Addresses                 = "getting IPv6 addresses of the container %q failed"
	errLoadConfigFailed              = "loading config file for the container %q failed (path: %s)"
	errMemLimit                      = "your kernel does not support cgroup memory controller"
	errNewFailed                     = "allocating the container %q failed"
	errNotDefined                    = "there is no container named %q"
	errNotFrozen                     = "container %q is not frozen"
	errNotRunning                    = "container %q is not running"
	errRebootFailed                  = "rebooting the container %q failed"
	errRenameFailed                  = "renaming the container %q failed"
	errRestoreSnapshotFailed         = "restoring the container %q failed"
	errSaveConfigFailed              = "saving config file for the container %q failed (path: %s)"
	errSettingCgroupItemFailed       = "setting cgroup item for the container %q failed (key: %s, value: %s)"
	errSettingConfigItemFailed       = "setting config item for the container %q failed (key: %s, value: %s)"
	errSettingConfigPathFailed       = "setting config file for the container %q failed (path: %s)"
	errSettingMemoryLimitFailed      = "setting memory limit for the container %q failed"
	errSettingSwapLimitFailed        = "setting swap limit for the container %q failed"
	errShutdownFailed                = "shutting down the container %q failed"
	errStartFailed                   = "starting the container %q failed"
	errStopFailed                    = "stopping the container %q failed"
	errSwapLimit                     = "your kernel does not support cgroup swap controller"
	errUnfreezeFailed                = "unfreezing the container %q failed"
)
<commit_msg>add new enums defined by LXC C API<commit_after>// Copyright © 2013, S.Çağlar Onur
// Use of this source code is governed by a LGPLv2.1
// license that can be found in the LICENSE file.
//
// Authors:
// S.Çağlar Onur <caglar@10ur.org>

// +build linux

package lxc

const (
	// WaitForever timeout
	WaitForever int = iota - 1
	// DontWait timeout
	DontWait
)

const (
	// CloneKeepName means do not edit the rootfs to change the hostname
	CloneKeepName int = 1 << iota
	// CloneKeepMACAddr means do not change the mac address on network interfaces
	CloneKeepMACAddr
	// CloneSnapshot means snapshot the original filesystem(s)
	CloneSnapshot
	// CloneKeepBdevType means use the same bdev type
	CloneKeepBdevType
	// CloneMaybeSnapshot means snapshot only if bdev supports it, else copy
	CloneMaybeSnapshot
)

const (
	errAlreadyDefined                = "container %q already defined"
	errAlreadyFrozen                 = "container %q is already frozen"
	errAlreadyRunning                = "container %q is already running"
	errAttachFailed                  = "attaching to the container %q failed"
	errClearingCgroupItemFailed      = "clearing cgroup item for the container %q failed (key: %s)"
	errCloneFailed                   = "cloning the container %q failed"
	errCloseAllFdsFailed             = "setting close_all_fds flag for container %q failed"
	errCreateFailed                  = "creating the container %q failed"
	errCreateSnapshotFailed          = "snapshotting the container %q failed"
	errDaemonizeFailed               = "setting daemonize flag for container %q failed"
	errDestroyFailed                 = "destroying the container %q failed"
	errDestroySnapshotFailed         = "destroying the snapshot %q failed"
	errExecuteFailed                 = "executing the command in a temporary container %q failed"
	errFreezeFailed                  = "freezing the container %q failed"
	errInsufficientNumberOfArguments = "insufficient number of arguments were supplied"
	errInterfaces                    = "getting interface names for the container %q failed"
	errIPAddresses                   = "getting IP addresses of the container %q failed"
	errIPAddress                     = "getting IP address on the interface %s of the container %q failed"
	errIPv4Addresses                 = "getting IPv4 addresses of the container %q failed"
	errIPv6Addresses                 = "getting IPv6 addresses of the container %q failed"
	errLoadConfigFailed              = "loading config file for the container %q failed (path: %s)"
	errMemLimit                      = "your kernel does not support cgroup memory controller"
	errNewFailed                     = "allocating the container %q failed"
	errNotDefined                    = "there is no container named %q"
	errNotFrozen                     = "container %q is not frozen"
	errNotRunning                    = "container %q is not running"
	errRebootFailed                  = "rebooting the container %q failed"
	errRenameFailed                  = "renaming the container %q failed"
	errRestoreSnapshotFailed         = "restoring the container %q failed"
	errSaveConfigFailed              = "saving config file for the container %q failed (path: %s)"
	errSettingCgroupItemFailed       = "setting cgroup item for the container %q failed (key: %s, value: %s)"
	errSettingConfigItemFailed       = "setting config item for the container %q failed (key: %s, value: %s)"
	errSettingConfigPathFailed       = "setting config file for the container %q failed (path: %s)"
	errSettingMemoryLimitFailed      = "setting memory limit for the container %q failed"
	errSettingSwapLimitFailed        = "setting swap limit for the container %q failed"
	errShutdownFailed                = "shutting down the container %q failed"
	errStartFailed                   = "starting the container %q failed"
	errStopFailed                    = "stopping the container %q failed"
	errSwapLimit                     = "your kernel does not support cgroup swap controller"
	errUnfreezeFailed                = "unfreezing the container %q failed"
)
<|endoftext|>


<commit_before>package main

import (
	"math"
)

type Body struct {
	Xs, Vs []Vector
	M      float64
}

// Shifts all the values in xs by one and puts x at the beginning.
func Shift(xs []Vector, x Vector) {

	for i := len(xs) - 1; i > 0; i-- {

		xs[i] = xs[i-1]
	}

	xs[0] = x
}

type Integrator func(xs, vs []Vector, a Vector, dt float64)

// Performs a step of an Euler integration
func Euler(xs, vs []Vector, a Vector, dt float64) {

	v := vs[0].Plus(a.Scale(dt))
	x := xs[0].Plus(v.Scale(dt))

	Shift(vs, v)
	Shift(xs, x)
}

// Performs a step of a Verlet integrator
//
// Note that v[0] will not be calculated until the next step
func Verlet(xs, vs []Vector, a Vector, dt float64) {

	xNext := xs[0].Scale(2).Minus(xs[1]).Plus(a.Scale(dt * dt))
	vs[0] = xNext.Minus(xs[1]).Scale(1 / (2 * dt))

	Shift(vs, NewZeroVector())
	Shift(xs, xNext)
}

type Spring struct {
	K, L0 float64
}

type Hooke struct {
	Springs [][]Spring
}

func (h Hooke) Accel(bs []Body, i int) (a Vector) {

	f := NewZeroVector()

	b := bs[i]

	for j, b2 := range bs {

		spring := h.Springs[i][j]

		dir, l := b2.Xs[0].Minus(b.Xs[0]).UnitAndNorm()

		f = f.Plus(dir.Scale(spring.K * (l - spring.L0)))
	}

	return f.Scale(1 / b.M)
}

type SingleHooke struct {
	K float64
}

func (sh SingleHooke) Accel(bs []Body, i int) (a Vector) {

	b := bs[i]

	return b.Xs[0].Scale(-sh.K / b.M)
}

type Force interface {
	Accel(bs []Body, i int) (a Vector)
}

type AnalyticSHM struct {
	K, M float64
	A    Vector
}

func (ashm AnalyticSHM) XVAt(t float64) (x, v Vector) {

	omega := math.Sqrt(ashm.K / ashm.M)

	x = ashm.A.Scale(math.Cos(omega * t))
	v = ashm.A.Negate().Scale(omega * math.Sin(omega*t))

	return
}

func main() {
}
<commit_msg>Add AnalyticSHM.Force<commit_after>package main

import (
	"math"
)

type Body struct {
	Xs, Vs []Vector
	M      float64
}

// Shifts all the values in xs by one and puts x at the beginning.
func Shift(xs []Vector, x Vector) {

	for i := len(xs) - 1; i > 0; i-- {

		xs[i] = xs[i-1]
	}

	xs[0] = x
}

type Integrator func(xs, vs []Vector, a Vector, dt float64)

// Performs a step of an Euler integration
func Euler(xs, vs []Vector, a Vector, dt float64) {

	v := vs[0].Plus(a.Scale(dt))
	x := xs[0].Plus(v.Scale(dt))

	Shift(vs, v)
	Shift(xs, x)
}

// Performs a step of a Verlet integrator
//
// Note that v[0] will not be calculated until the next step
func Verlet(xs, vs []Vector, a Vector, dt float64) {

	xNext := xs[0].Scale(2).Minus(xs[1]).Plus(a.Scale(dt * dt))
	vs[0] = xNext.Minus(xs[1]).Scale(1 / (2 * dt))

	Shift(vs, NewZeroVector())
	Shift(xs, xNext)
}

type Spring struct {
	K, L0 float64
}

type Hooke struct {
	Springs [][]Spring
}

func (h Hooke) Accel(bs []Body, i int) (a Vector) {

	f := NewZeroVector()

	b := bs[i]

	for j, b2 := range bs {

		spring := h.Springs[i][j]

		dir, l := b2.Xs[0].Minus(b.Xs[0]).UnitAndNorm()

		f = f.Plus(dir.Scale(spring.K * (l - spring.L0)))
	}

	return f.Scale(1 / b.M)
}

type SingleHooke struct {
	K float64
}

func (sh SingleHooke) Accel(bs []Body, i int) (a Vector) {

	b := bs[i]

	return b.Xs[0].Scale(-sh.K / b.M)
}

type Force interface {
	Accel(bs []Body, i int) (a Vector)
}

type AnalyticSHM struct {
	K, M float64
	A    Vector
}

func (ashm AnalyticSHM) XVAt(t float64) (x, v Vector) {

	omega := math.Sqrt(ashm.K / ashm.M)

	x = ashm.A.Scale(math.Cos(omega * t))
	v = ashm.A.Negate().Scale(omega * math.Sin(omega*t))

	return
}

func (ashm AnalyticSHM) Force() Force {

	return Force(SingleHooke{K: ashm.K})
}

func main() {
}
<|endoftext|>


<commit_before>package orm

import (
	"fmt"
	"reflect"
)

type manyModel struct {
	*sliceTableModel
	baseTable *Table
	rel       *Relation

	buf       []byte
	dstValues map[string][]reflect.Value
}

var _ tableModel = (*manyModel)(nil)

func newManyModel(j *join) *manyModel {
	baseTable := j.BaseModel.Table()
	joinModel := j.JoinModel.(*sliceTableModel)
	dstValues := dstValues(joinModel, baseTable.PKs)
	if len(dstValues) == 0 {
		return nil
	}
	m := manyModel{
		sliceTableModel: joinModel,
		baseTable:       baseTable,
		rel:             j.Rel,

		dstValues: dstValues,
	}
	if !m.sliceOfPtr {
		m.strct = reflect.New(m.table.Type).Elem()
	}
	return &m
}

func (m *manyModel) NewModel() ColumnScanner {
	if m.sliceOfPtr {
		m.strct = reflect.New(m.table.Type).Elem()
	} else {
		m.strct.Set(m.table.zeroStruct)
	}
	m.structInited = false
	m.structTableModel.NewModel()
	return m
}

func (m *manyModel) AddModel(model ColumnScanner) error {
	m.buf = modelId(m.buf[:0], m.strct, m.rel.FKs)
	dstValues, ok := m.dstValues[string(m.buf)]
	if !ok {
		return fmt.Errorf(
			"pg: relation=%q has no base model=%q with id=%q (check join conditions)",
			m.rel.Field.GoName, m.baseTable.TypeName, m.buf)
	}

	for _, v := range dstValues {
		if m.sliceOfPtr {
			v.Set(reflect.Append(v, m.strct.Addr()))
		} else {
			v.Set(reflect.Append(v, m.strct))
		}
	}

	return nil
}

func (m *manyModel) AfterQuery(db DB) error {
	if !m.rel.JoinTable.HasFlag(AfterQueryHookFlag) {
		return nil
	}

	var retErr error
	for _, slices := range m.dstValues {
		for _, slice := range slices {
			err := callAfterQueryHookSlice(slice, m.sliceOfPtr, db)
			if err != nil && retErr == nil {
				retErr = err
			}
		}
	}
	return retErr
}

func (m *manyModel) AfterSelect(db DB) error {
	return nil
}

func (m *manyModel) BeforeInsert(db DB) error {
	return nil
}

func (m *manyModel) AfterInsert(db DB) error {
	return nil
}

func (m *manyModel) BeforeUpdate(db DB) error {
	return nil
}

func (m *manyModel) AfterUpdate(db DB) error {
	return nil
}

func (m *manyModel) BeforeDelete(db DB) error {
	return nil
}

func (m *manyModel) AfterDelete(db DB) error {
	return nil
}
<commit_msg>orm: use Rel.FKValues in has many<commit_after>package orm

import (
	"fmt"
	"reflect"
)

type manyModel struct {
	*sliceTableModel
	baseTable *Table
	rel       *Relation

	buf       []byte
	dstValues map[string][]reflect.Value
}

var _ tableModel = (*manyModel)(nil)

func newManyModel(j *join) *manyModel {
	baseTable := j.BaseModel.Table()
	joinModel := j.JoinModel.(*sliceTableModel)
	dstValues := dstValues(joinModel, j.Rel.FKValues)
	if len(dstValues) == 0 {
		return nil
	}
	m := manyModel{
		sliceTableModel: joinModel,
		baseTable:       baseTable,
		rel:             j.Rel,

		dstValues: dstValues,
	}
	if !m.sliceOfPtr {
		m.strct = reflect.New(m.table.Type).Elem()
	}
	return &m
}

func (m *manyModel) NewModel() ColumnScanner {
	if m.sliceOfPtr {
		m.strct = reflect.New(m.table.Type).Elem()
	} else {
		m.strct.Set(m.table.zeroStruct)
	}
	m.structInited = false
	m.structTableModel.NewModel()
	return m
}

func (m *manyModel) AddModel(model ColumnScanner) error {
	m.buf = modelId(m.buf[:0], m.strct, m.rel.FKs)
	dstValues, ok := m.dstValues[string(m.buf)]
	if !ok {
		return fmt.Errorf(
			"pg: relation=%q has no base model=%q with id=%q (check join conditions)",
			m.rel.Field.GoName, m.baseTable.TypeName, m.buf)
	}

	for _, v := range dstValues {
		if m.sliceOfPtr {
			v.Set(reflect.Append(v, m.strct.Addr()))
		} else {
			v.Set(reflect.Append(v, m.strct))
		}
	}

	return nil
}

func (m *manyModel) AfterQuery(db DB) error {
	if !m.rel.JoinTable.HasFlag(AfterQueryHookFlag) {
		return nil
	}

	var retErr error
	for _, slices := range m.dstValues {
		for _, slice := range slices {
			err := callAfterQueryHookSlice(slice, m.sliceOfPtr, db)
			if err != nil && retErr == nil {
				retErr = err
			}
		}
	}
	return retErr
}

func (m *manyModel) AfterSelect(db DB) error {
	return nil
}

func (m *manyModel) BeforeInsert(db DB) error {
	return nil
}

func (m *manyModel) AfterInsert(db DB) error {
	return nil
}

func (m *manyModel) BeforeUpdate(db DB) error {
	return nil
}

func (m *manyModel) AfterUpdate(db DB) error {
	return nil
}

func (m *manyModel) BeforeDelete(db DB) error {
	return nil
}

func (m *manyModel) AfterDelete(db DB) error {
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Vadim Kravcenko
//
// 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 gojenkins

type Executor struct {
	Raw     *ExecutorResponse
	Jenkins *Jenkins
}
type ViewData struct {
	Name string `json:"name"`
	URL  string `json:"url"`
}
type ExecutorResponse struct {
	AssignedLabels  []struct{}  `json:"assignedLabels"`
	Description     interface{} `json:"description"`
	Jobs            []InnerJob  `json:"jobs"`
	Mode            string      `json:"mode"`
	NodeDescription string      `json:"nodeDescription"`
	NodeName        string      `json:"nodeName"`
	NumExecutors    int64       `json:"numExecutors"`
	OverallLoad     struct{}    `json:"overallLoad"`
	PrimaryView     struct {
		Name string `json:"name"`
		URL  string `json:"url"`
	} `json:"primaryView"`
	QuietingDown   bool       `json:"quietingDown"`
	SlaveAgentPort int64      `json:"slaveAgentPort"`
	UnlabeledLoad  struct{}   `json:"unlabeledLoad"`
	UseCrumbs      bool       `json:"useCrumbs"`
	UseSecurity    bool       `json:"useSecurity"`
	Views          []ViewData `json:"views"`
}
<commit_msg>Adding map type to ExecutorResponse -> AssignedLabels<commit_after>// Copyright 2015 Vadim Kravcenko
//
// 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 gojenkins

type Executor struct {
	Raw     *ExecutorResponse
	Jenkins *Jenkins
}
type ViewData struct {
	Name string `json:"name"`
	URL  string `json:"url"`
}
type ExecutorResponse struct {
	AssignedLabels  []map[string]string `json:"assignedLabels"`
	Description     interface{}         `json:"description"`
	Jobs            []InnerJob          `json:"jobs"`
	Mode            string              `json:"mode"`
	NodeDescription string              `json:"nodeDescription"`
	NodeName        string              `json:"nodeName"`
	NumExecutors    int64               `json:"numExecutors"`
	OverallLoad     struct{}            `json:"overallLoad"`
	PrimaryView     struct {
		Name string `json:"name"`
		URL  string `json:"url"`
	} `json:"primaryView"`
	QuietingDown   bool       `json:"quietingDown"`
	SlaveAgentPort int64      `json:"slaveAgentPort"`
	UnlabeledLoad  struct{}   `json:"unlabeledLoad"`
	UseCrumbs      bool       `json:"useCrumbs"`
	UseSecurity    bool       `json:"useSecurity"`
	Views          []ViewData `json:"views"`
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
	"sort"
	"strconv"
	"strings"

	"github.com/bwmarrin/discordgo"
	redis "gopkg.in/redis.v5"
)

///////////////////////////////////////////////////////////////////////////////
// CRBot is a call-and-response bot. It is taught to learn a call and
// response. When it sees the call, it replays the response. Look at the ?help
// documentation for a full list of commands.
//
// Licensed under MIT license, at project root.
///////////////////////////////////////////////////////////////////////////////

func main() {
	var filename = flag.String("filename", "secret.json", "Filename of configuration json")
	flag.Parse()

	redisClient := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})

	_, err := redisClient.Ping().Result()
	if err != nil {
		fatal("Could not ping Redis", err)
	}

	secret, e := ParseSecret(*filename)
	if e != nil {
		fatal("Secret parsing failed", e)
	}

	discord, err := discordgo.New("Bot " + secret.BotToken)
	if err != nil {
		fatal("Error initializing Discord client library", e)
	}

	discord.AddHandler(getHandleMessage(redisClient))

	if err := discord.Open(); err != nil {
		fatal("Error opening Discord session", err)
	}

	fmt.Println("CRBot running.")

	<-make(chan interface{})
}

///////////////////////////////////////////////////////////////////////////////
// Utility methods
///////////////////////////////////////////////////////////////////////////////

// fatal handles a non-recoverable error.
func fatal(msg string, err error) {
	panic(msg + ": " + err.Error())
}

func info(msg string, err error) {
	fmt.Printf(msg+": %v\n", err.Error())
}

///////////////////////////////////////////////////////////////////////////////
// Constants
///////////////////////////////////////////////////////////////////////////////

const (
	Type_None = iota
	Type_Unrecognized
	Type_Help
	Type_Learn
	Type_Custom
	Type_List

	Name_Help  = "?help"
	Name_Learn = "?learn"
	Name_List  = "?list"

	Redis_Hash = "crbot-custom-commands"
)

// TypeToString maps builtin types to their string names.
var TypeToString map[int]string = map[int]string{
	Type_Help:  Name_Help,
	Type_Learn: Name_Learn,
	Type_List:  Name_List,
}

// StringToType maps builtin names to their types.
var StringToType map[string]int = map[string]int{
	Name_Help:  Type_Help,
	Name_Learn: Type_Learn,
	Name_List:  Type_List,
}

// Tries to get a value from s and ?s
func getUserStringToType(s string) int {
	if t, ok := StringToType[s]; ok {
		return t
	} else if t, ok := StringToType["?"+s]; ok {
		return t
	}
	return Type_None
}

///////////////////////////////////////////////////////////////////////////////
// Configuration handling
///////////////////////////////////////////////////////////////////////////////

// Secret holds the serialized bot token.
type Secret struct {
	BotToken string `json:"bot_token"`
}

// ParseSecret reads the config from the given filename.
func ParseSecret(filename string) (*Secret, error) {
	f, e := ioutil.ReadFile(filename)
	if e != nil {
		return nil, e
	}
	var config Secret
	e = json.Unmarshal(f, &config)
	return &config, e
}

///////////////////////////////////////////////////////////////////////////////
// Controller methods
///////////////////////////////////////////////////////////////////////////////

// getHandleMessage returns a function to parse and handle incoming messages.
func getHandleMessage(redisClient *redis.Client) func(*discordgo.Session, *discordgo.MessageCreate) {
	return func(s *discordgo.Session, m *discordgo.MessageCreate) {

		// Never reply to a bot.
		if m.Author.Bot {
			return
		}

		command, err := parseCommand(redisClient, m.Content)
		if err != nil {
			info("Error processing command", err)
		}

		switch command.Type {
		case Type_Help:
			sendHelp(s, m.ChannelID, command)
		case Type_Learn:
			sendLearn(redisClient, s, m.ChannelID, command)
		case Type_Custom:
			sendCustom(redisClient, s, m.ChannelID, command)
		case Type_List:
			sendList(redisClient, s, m.ChannelID, command)
		}
	}
}

///////////////////////////////////////////////////////////////////////////////
// User message parsing
///////////////////////////////////////////////////////////////////////////////

// HelpData holds data for Help commands.
type HelpData struct {
	Type int
}

type LearnData struct {
	CallOpen bool
	Call     string
	Response string
}

type CustomData struct {
	Call string
	Args string
}

type Command struct {
	Type   int
	Help   *HelpData
	Learn  *LearnData
	Custom *CustomData
}

// Parses the raw text string from the user. Returns an executable command.
func parseCommand(redisClient *redis.Client, content string) (*Command, error) {
	if !strings.HasPrefix(content, "?") {
		return &Command{
			Type: Type_None,
		}, nil
	}
	splitContent := strings.Split(content, " ")

	// Parse builtins.
	switch splitContent[0] {
	case Name_Help:
		return parseHelp(splitContent)
	case Name_Learn:
		return parseLearn(redisClient, splitContent)
	case Name_List:
		return &Command{Type: Type_List}, nil
	}

	// See if it's a custom command.
	if redisClient.HExists(Redis_Hash, splitContent[0][1:]).Val() {
		return parseCustom(redisClient, splitContent)
	}

	// No such command!
	return &Command{
		Type: Type_Unrecognized,
	}, nil
}

func parseHelp(splitContent []string) (*Command, error) {
	if splitContent[0] != Name_Help {
		fatal("parseHelp called with non-help command", errors.New("wat"))
	}
	userType := Type_Unrecognized
	if len(splitContent) > 1 {
		userType = getUserStringToType(splitContent[1])
	}
	return &Command{
		Type: Type_Help,
		Help: &HelpData{
			Type: userType,
		},
	}, nil
}

func parseLearn(redisClient *redis.Client, splitContent []string) (*Command, error) {
	if splitContent[0] != Name_Learn {
		fatal("parseLearn called with non-learn command", errors.New("wat"))
	}

	callRegexp := regexp.MustCompile("(?s)^[[:alnum:]].*$")
	responseRegexp := regexp.MustCompile("(?s)^[^/?!].*$")

	// Show help when not enough data is present, or malicious data is present.
	if len(splitContent) < 3 || !callRegexp.MatchString(splitContent[1]) || !responseRegexp.MatchString(splitContent[2]) {
		return &Command{
			Type: Type_Help,
			Help: &HelpData{
				Type: Type_Learn,
			},
		}, nil
	}

	// Don't overwrite old or builtin commands.
	if redisClient.HExists(Redis_Hash, splitContent[1]).Val() || getUserStringToType(splitContent[1]) != Type_None {
		return &Command{
			Type: Type_Learn,
			Learn: &LearnData{
				CallOpen: false,
				Call:     splitContent[1],
			},
		}, nil
	}

	// Everything is good.
	response := strings.Join(splitContent[2:], " ")
	return &Command{
		Type: Type_Learn,
		Learn: &LearnData{
			CallOpen: true,
			Call:     splitContent[1],
			Response: response,
		},
	}, nil
}

func parseCustom(redisClient *redis.Client, splitContent []string) (*Command, error) {
	if !redisClient.HExists(Redis_Hash, splitContent[0][1:]).Val() {
		fatal("parseCustom called with non-custom command", errors.New("wat"))
	}
	return &Command{
		Type: Type_Custom,
		Custom: &CustomData{
			Call: splitContent[0][1:],
			Args: strings.Join(splitContent[1:], " "),
		},
	}, nil
}

///////////////////////////////////////////////////////////////////////////////
// User-visible messages
///////////////////////////////////////////////////////////////////////////////

const (
	MsgCustomNeedsArgs   = "This command takes args. Please type `?command <more text>` instead of `?command`"
	MsgDefaultHelp       = "Type `?help` for this message, `?list` to list all commands, or `?help <command>` to get help for a particular command."
	MsgGistAddress       = "The list of commands is here: "
	MsgGistPostFail      = "Unable to connect to Gist service. Give it a few minutes and try again"
	MsgGistResponseFail  = "Failure reading response from Gist service"
	MsgGistSerializeFail = "Unable to serialize Gist"
	MsgGistStatusCode    = "Failed to upload Gist :("
	MsgGistUrlFail       = "Failed getting url from Gist service"
	MsgHelpHelp          = "You're probably right. I probably didn't think of this case."
	MsgHelpLearn         = "Type `?learn <call> <the response the bot should read>`. When you type `?call`, the bot will reply with the response.\n\nThe first character of the call and response must not begin with /, ?, or !\n\nUse $1 in the response to substitute all arguments"
	MsgHelpList          = "Type `?list` to get the URL of a Gist with all builtin and learned commands"
	MsgLearnFail         = "I already know ?%s"
	MsgLearnSuccess      = "Learned about %s"
	MsgListBuiltins      = "List of builtins:"
	MsgListCustom        = "List of learned commands:"
)

///////////////////////////////////////////////////////////////////////////////
// Response
///////////////////////////////////////////////////////////////////////////////

func sendHelp(s *discordgo.Session, channel string, command *Command) {
	if command.Help == nil {
		fatal("Incorrectly generated help command", errors.New("wat"))
	}
	switch command.Help.Type {
	default:
		if _, err := s.ChannelMessageSend(channel, MsgDefaultHelp); err != nil {
			info("Failed to send default help message", err)
		}
	case Type_Help:
		s.ChannelMessageSend(channel, MsgHelpHelp)
	case Type_Learn:
		s.ChannelMessageSend(channel, MsgHelpLearn)
	case Type_List:
		s.ChannelMessageSend(channel, MsgHelpList)
	}
}

func sendLearn(redisClient *redis.Client, s *discordgo.Session, channel string, command *Command) {
	if command.Learn == nil {
		fatal("Incorrectly generated learn command", errors.New("wat"))
	}
	if !command.Learn.CallOpen {
		s.ChannelMessageSend(channel, fmt.Sprintf(MsgLearnFail, command.Learn.Call))
		return
	}

	// Teach the command.
	if redisClient.HExists(Redis_Hash, command.Learn.Call).Val() {
		fatal("Collision when adding a call for "+command.Learn.Call, errors.New("wat"))
	}
	redisClient.HSet(Redis_Hash, command.Learn.Call, command.Learn.Response)

	// Send ack.
	s.ChannelMessageSend(channel, fmt.Sprintf(MsgLearnSuccess, command.Learn.Call))
}

func sendCustom(redisClient *redis.Client, s *discordgo.Session, channel string, command *Command) {
	if command.Custom == nil {
		fatal("Incorrectly generated learn command", errors.New("wat"))
	}

	if !redisClient.HExists(Redis_Hash, command.Custom.Call).Val() {
		fatal("Accidentally found a mismatched call/response pair", errors.New("Call response mismatch"))
	}

	response := redisClient.HGet(Redis_Hash, command.Custom.Call).Val()

	if strings.Contains(response, "$1") {
		if command.Custom.Args == "" {
			s.ChannelMessageSend(channel, MsgCustomNeedsArgs)
			return
		}
		response = strings.Replace(response, "$1", command.Custom.Args, 1)
	}
	s.ChannelMessageSend(channel, response)
}

func sendList(redisClient *redis.Client, s *discordgo.Session, channel string, command *Command) {
	builtins := []string{}
	for name := range StringToType {
		builtins = append(builtins, name)
	}

	custom := []string{}
	for name := range redisClient.HGetAll(Redis_Hash).Val() {
		custom = append(custom, name)
	}

	sort.Strings(builtins)
	sort.Strings(custom)

	var buffer bytes.Buffer
	buffer.WriteString(MsgListBuiltins)
	buffer.WriteString("\n")
	for _, name := range builtins {
		buffer.WriteString(" - ")
		buffer.WriteString(name)
		buffer.WriteString("\n")
	}

	buffer.WriteString("\n")

	buffer.WriteString(MsgListCustom)
	buffer.WriteString("\n")
	for _, name := range custom {
		buffer.WriteString(" - ?")
		buffer.WriteString(name)
		buffer.WriteString("\n")
	}

	url, err := uploadCommandList(buffer.String())
	if err != nil {
		s.ChannelMessageSend(channel, err.Error())
		return
	}
	s.ChannelMessageSend(channel, MsgGistAddress+": "+url)
}

///////////////////////////////////////////////////////////////////////////////
// Gist handling
///////////////////////////////////////////////////////////////////////////////
type Gist struct {
	Description string           `json:"description"`
	Public      bool             `json:"public"`
	Files       map[string]*File `json:"files"`
}

// A file represents the contents of a Gist.
type File struct {
	Content string `json:"content"`
}

// simpleGist returns a Gist object with just the given contents.
func simpleGist(contents string) *Gist {
	return &Gist{
		Public:      false,
		Description: "CRBot command list",
		Files: map[string]*File{
			"commands": &File{
				Content: contents,
			},
		},
	}
}

func uploadCommandList(contents string) (string, error) {
	gist := simpleGist(contents)
	serializedGist, err := json.Marshal(gist)
	if err != nil {
		info("Error marshalling gist", err)
		return "", errors.New(MsgGistSerializeFail)
	}
	response, err := http.Post(
		"https://api.github.com/gists", "application/json", bytes.NewBuffer(serializedGist))
	if err != nil {
		info("Error POSTing gist", err)
		return "", errors.New(MsgGistPostFail)
	} else if response.StatusCode != 201 {
		info("Bad status code", errors.New("Code: "+strconv.Itoa(response.StatusCode)))
		return "", errors.New(MsgGistStatusCode)
	}

	responseMap := map[string]interface{}{}
	if err := json.NewDecoder(response.Body).Decode(&responseMap); err != nil {
		info("Error reading gist response", err)
		return "", errors.New(MsgGistResponseFail)
	}

	if finalUrl, ok := responseMap["html_url"]; ok {
		return finalUrl.(string), nil
	}
	return "", errors.New(MsgGistUrlFail)
}
<commit_msg>Makes the docs slightly more accurate<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
	"sort"
	"strconv"
	"strings"

	"github.com/bwmarrin/discordgo"
	redis "gopkg.in/redis.v5"
)

///////////////////////////////////////////////////////////////////////////////
// CRBot is a call-and-response bot. It is taught to learn a call and
// response. When it sees the call, it replays the response. Look at the ?help
// documentation for a full list of commands.
//
// Licensed under MIT license, at project root.
///////////////////////////////////////////////////////////////////////////////

func main() {
	var filename = flag.String("filename", "secret.json", "Filename of configuration json")
	flag.Parse()

	redisClient := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})

	_, err := redisClient.Ping().Result()
	if err != nil {
		fatal("Could not ping Redis", err)
	}

	secret, e := ParseSecret(*filename)
	if e != nil {
		fatal("Secret parsing failed", e)
	}

	discord, err := discordgo.New("Bot " + secret.BotToken)
	if err != nil {
		fatal("Error initializing Discord client library", e)
	}

	discord.AddHandler(getHandleMessage(redisClient))

	if err := discord.Open(); err != nil {
		fatal("Error opening Discord session", err)
	}

	fmt.Println("CRBot running.")

	<-make(chan interface{})
}

///////////////////////////////////////////////////////////////////////////////
// Utility methods
///////////////////////////////////////////////////////////////////////////////

// fatal handles a non-recoverable error.
func fatal(msg string, err error) {
	panic(msg + ": " + err.Error())
}

func info(msg string, err error) {
	fmt.Printf(msg+": %v\n", err.Error())
}

///////////////////////////////////////////////////////////////////////////////
// Constants
///////////////////////////////////////////////////////////////////////////////

const (
	Type_None = iota
	Type_Unrecognized
	Type_Help
	Type_Learn
	Type_Custom
	Type_List

	Name_Help  = "?help"
	Name_Learn = "?learn"
	Name_List  = "?list"

	Redis_Hash = "crbot-custom-commands"
)

// TypeToString maps builtin types to their string names.
var TypeToString map[int]string = map[int]string{
	Type_Help:  Name_Help,
	Type_Learn: Name_Learn,
	Type_List:  Name_List,
}

// StringToType maps builtin names to their types.
var StringToType map[string]int = map[string]int{
	Name_Help:  Type_Help,
	Name_Learn: Type_Learn,
	Name_List:  Type_List,
}

// Tries to get a value from s and ?s
func getUserStringToType(s string) int {
	if t, ok := StringToType[s]; ok {
		return t
	} else if t, ok := StringToType["?"+s]; ok {
		return t
	}
	return Type_None
}

///////////////////////////////////////////////////////////////////////////////
// Configuration handling
///////////////////////////////////////////////////////////////////////////////

// Secret holds the serialized bot token.
type Secret struct {
	BotToken string `json:"bot_token"`
}

// ParseSecret reads the config from the given filename.
func ParseSecret(filename string) (*Secret, error) {
	f, e := ioutil.ReadFile(filename)
	if e != nil {
		return nil, e
	}
	var config Secret
	e = json.Unmarshal(f, &config)
	return &config, e
}

///////////////////////////////////////////////////////////////////////////////
// Controller methods
///////////////////////////////////////////////////////////////////////////////

// getHandleMessage returns a function to parse and handle incoming messages.
func getHandleMessage(redisClient *redis.Client) func(*discordgo.Session, *discordgo.MessageCreate) {
	return func(s *discordgo.Session, m *discordgo.MessageCreate) {

		// Never reply to a bot.
		if m.Author.Bot {
			return
		}

		command, err := parseCommand(redisClient, m.Content)
		if err != nil {
			info("Error processing command", err)
		}

		switch command.Type {
		case Type_Help:
			sendHelp(s, m.ChannelID, command)
		case Type_Learn:
			sendLearn(redisClient, s, m.ChannelID, command)
		case Type_Custom:
			sendCustom(redisClient, s, m.ChannelID, command)
		case Type_List:
			sendList(redisClient, s, m.ChannelID, command)
		}
	}
}

///////////////////////////////////////////////////////////////////////////////
// User message parsing
///////////////////////////////////////////////////////////////////////////////

// HelpData holds data for Help commands.
type HelpData struct {
	Type int
}

type LearnData struct {
	CallOpen bool
	Call     string
	Response string
}

type CustomData struct {
	Call string
	Args string
}

type Command struct {
	Type   int
	Help   *HelpData
	Learn  *LearnData
	Custom *CustomData
}

// Parses the raw text string from the user. Returns an executable command.
func parseCommand(redisClient *redis.Client, content string) (*Command, error) {
	if !strings.HasPrefix(content, "?") {
		return &Command{
			Type: Type_None,
		}, nil
	}
	splitContent := strings.Split(content, " ")

	// Parse builtins.
	switch splitContent[0] {
	case Name_Help:
		return parseHelp(splitContent)
	case Name_Learn:
		return parseLearn(redisClient, splitContent)
	case Name_List:
		return &Command{Type: Type_List}, nil
	}

	// See if it's a custom command.
	if redisClient.HExists(Redis_Hash, splitContent[0][1:]).Val() {
		return parseCustom(redisClient, splitContent)
	}

	// No such command!
	return &Command{
		Type: Type_Unrecognized,
	}, nil
}

func parseHelp(splitContent []string) (*Command, error) {
	if splitContent[0] != Name_Help {
		fatal("parseHelp called with non-help command", errors.New("wat"))
	}
	userType := Type_Unrecognized
	if len(splitContent) > 1 {
		userType = getUserStringToType(splitContent[1])
	}
	return &Command{
		Type: Type_Help,
		Help: &HelpData{
			Type: userType,
		},
	}, nil
}

func parseLearn(redisClient *redis.Client, splitContent []string) (*Command, error) {
	if splitContent[0] != Name_Learn {
		fatal("parseLearn called with non-learn command", errors.New("wat"))
	}

	callRegexp := regexp.MustCompile("(?s)^[[:alnum:]].*$")
	responseRegexp := regexp.MustCompile("(?s)^[^/?!].*$")

	// Show help when not enough data is present, or malicious data is present.
	if len(splitContent) < 3 || !callRegexp.MatchString(splitContent[1]) || !responseRegexp.MatchString(splitContent[2]) {
		return &Command{
			Type: Type_Help,
			Help: &HelpData{
				Type: Type_Learn,
			},
		}, nil
	}

	// Don't overwrite old or builtin commands.
	if redisClient.HExists(Redis_Hash, splitContent[1]).Val() || getUserStringToType(splitContent[1]) != Type_None {
		return &Command{
			Type: Type_Learn,
			Learn: &LearnData{
				CallOpen: false,
				Call:     splitContent[1],
			},
		}, nil
	}

	// Everything is good.
	response := strings.Join(splitContent[2:], " ")
	return &Command{
		Type: Type_Learn,
		Learn: &LearnData{
			CallOpen: true,
			Call:     splitContent[1],
			Response: response,
		},
	}, nil
}

func parseCustom(redisClient *redis.Client, splitContent []string) (*Command, error) {
	if !redisClient.HExists(Redis_Hash, splitContent[0][1:]).Val() {
		fatal("parseCustom called with non-custom command", errors.New("wat"))
	}
	return &Command{
		Type: Type_Custom,
		Custom: &CustomData{
			Call: splitContent[0][1:],
			Args: strings.Join(splitContent[1:], " "),
		},
	}, nil
}

///////////////////////////////////////////////////////////////////////////////
// User-visible messages
///////////////////////////////////////////////////////////////////////////////

const (
	MsgCustomNeedsArgs   = "This command takes args. Please type `?command <more text>` instead of `?command`"
	MsgDefaultHelp       = "Type `?help` for this message, `?list` to list all commands, or `?help <command>` to get help for a particular command."
	MsgGistAddress       = "The list of commands is here: "
	MsgGistPostFail      = "Unable to connect to Gist service. Give it a few minutes and try again"
	MsgGistResponseFail  = "Failure reading response from Gist service"
	MsgGistSerializeFail = "Unable to serialize Gist"
	MsgGistStatusCode    = "Failed to upload Gist :("
	MsgGistUrlFail       = "Failed getting url from Gist service"
	MsgHelpHelp          = "You're probably right. I probably didn't think of this case."
	MsgHelpLearn         = "Type `?learn <call> <the response the bot should read>`. When you type `?call`, the bot will reply with the response.\n\nThe first character of the call must be alphanumeric, and the first character of the response must not begin with /, ?, or !\n\nUse $1 in the response to substitute all arguments"
	MsgHelpList          = "Type `?list` to get the URL of a Gist with all builtin and learned commands"
	MsgLearnFail         = "I already know ?%s"
	MsgLearnSuccess      = "Learned about %s"
	MsgListBuiltins      = "List of builtins:"
	MsgListCustom        = "List of learned commands:"
)

///////////////////////////////////////////////////////////////////////////////
// Response
///////////////////////////////////////////////////////////////////////////////

func sendHelp(s *discordgo.Session, channel string, command *Command) {
	if command.Help == nil {
		fatal("Incorrectly generated help command", errors.New("wat"))
	}
	switch command.Help.Type {
	default:
		if _, err := s.ChannelMessageSend(channel, MsgDefaultHelp); err != nil {
			info("Failed to send default help message", err)
		}
	case Type_Help:
		s.ChannelMessageSend(channel, MsgHelpHelp)
	case Type_Learn:
		s.ChannelMessageSend(channel, MsgHelpLearn)
	case Type_List:
		s.ChannelMessageSend(channel, MsgHelpList)
	}
}

func sendLearn(redisClient *redis.Client, s *discordgo.Session, channel string, command *Command) {
	if command.Learn == nil {
		fatal("Incorrectly generated learn command", errors.New("wat"))
	}
	if !command.Learn.CallOpen {
		s.ChannelMessageSend(channel, fmt.Sprintf(MsgLearnFail, command.Learn.Call))
		return
	}

	// Teach the command.
	if redisClient.HExists(Redis_Hash, command.Learn.Call).Val() {
		fatal("Collision when adding a call for "+command.Learn.Call, errors.New("wat"))
	}
	redisClient.HSet(Redis_Hash, command.Learn.Call, command.Learn.Response)

	// Send ack.
	s.ChannelMessageSend(channel, fmt.Sprintf(MsgLearnSuccess, command.Learn.Call))
}

func sendCustom(redisClient *redis.Client, s *discordgo.Session, channel string, command *Command) {
	if command.Custom == nil {
		fatal("Incorrectly generated learn command", errors.New("wat"))
	}

	if !redisClient.HExists(Redis_Hash, command.Custom.Call).Val() {
		fatal("Accidentally found a mismatched call/response pair", errors.New("Call response mismatch"))
	}

	response := redisClient.HGet(Redis_Hash, command.Custom.Call).Val()

	if strings.Contains(response, "$1") {
		if command.Custom.Args == "" {
			s.ChannelMessageSend(channel, MsgCustomNeedsArgs)
			return
		}
		response = strings.Replace(response, "$1", command.Custom.Args, 1)
	}
	s.ChannelMessageSend(channel, response)
}

func sendList(redisClient *redis.Client, s *discordgo.Session, channel string, command *Command) {
	builtins := []string{}
	for name := range StringToType {
		builtins = append(builtins, name)
	}

	custom := []string{}
	for name := range redisClient.HGetAll(Redis_Hash).Val() {
		custom = append(custom, name)
	}

	sort.Strings(builtins)
	sort.Strings(custom)

	var buffer bytes.Buffer
	buffer.WriteString(MsgListBuiltins)
	buffer.WriteString("\n")
	for _, name := range builtins {
		buffer.WriteString(" - ")
		buffer.WriteString(name)
		buffer.WriteString("\n")
	}

	buffer.WriteString("\n")

	buffer.WriteString(MsgListCustom)
	buffer.WriteString("\n")
	for _, name := range custom {
		buffer.WriteString(" - ?")
		buffer.WriteString(name)
		buffer.WriteString("\n")
	}

	url, err := uploadCommandList(buffer.String())
	if err != nil {
		s.ChannelMessageSend(channel, err.Error())
		return
	}
	s.ChannelMessageSend(channel, MsgGistAddress+": "+url)
}

///////////////////////////////////////////////////////////////////////////////
// Gist handling
///////////////////////////////////////////////////////////////////////////////
type Gist struct {
	Description string           `json:"description"`
	Public      bool             `json:"public"`
	Files       map[string]*File `json:"files"`
}

// A file represents the contents of a Gist.
type File struct {
	Content string `json:"content"`
}

// simpleGist returns a Gist object with just the given contents.
func simpleGist(contents string) *Gist {
	return &Gist{
		Public:      false,
		Description: "CRBot command list",
		Files: map[string]*File{
			"commands": &File{
				Content: contents,
			},
		},
	}
}

func uploadCommandList(contents string) (string, error) {
	gist := simpleGist(contents)
	serializedGist, err := json.Marshal(gist)
	if err != nil {
		info("Error marshalling gist", err)
		return "", errors.New(MsgGistSerializeFail)
	}
	response, err := http.Post(
		"https://api.github.com/gists", "application/json", bytes.NewBuffer(serializedGist))
	if err != nil {
		info("Error POSTing gist", err)
		return "", errors.New(MsgGistPostFail)
	} else if response.StatusCode != 201 {
		info("Bad status code", errors.New("Code: "+strconv.Itoa(response.StatusCode)))
		return "", errors.New(MsgGistStatusCode)
	}

	responseMap := map[string]interface{}{}
	if err := json.NewDecoder(response.Body).Decode(&responseMap); err != nil {
		info("Error reading gist response", err)
		return "", errors.New(MsgGistResponseFail)
	}

	if finalUrl, ok := responseMap["html_url"]; ok {
		return finalUrl.(string), nil
	}
	return "", errors.New(MsgGistUrlFail)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/xml"
	"fmt"
	"io"
	"strings"

	"github.com/beevik/etree"
	"github.com/golang/glog"
)

type aggregator struct {
	XMLName  xml.Name `xml:"EntitiesDescriptor"`
	Entities map[string]*etree.Element
	xmlns    map[string]etree.Attr
}

const (
	metadataNamespaceURN = "urn:oasis:names:tc:SAML:2.0:metadata"

	xmlns = "xmlns"
)

func (a *aggregator) add(r io.Reader) error {

	if a.Entities == nil {
		a.Entities = map[string]*etree.Element{}
		a.xmlns = map[string]etree.Attr{}
	}

	d := etree.NewDocument()
	if _, err := d.ReadFrom(r); err != nil {
		return err
	}

	root := d.Root()

	if root == nil {
		return fmt.Errorf("Nil root element")
	}

	for _, attr := range root.Attr {
		if attr.Key == xmlns || attr.Space == xmlns {
			a.xmlns[strings.Join([]string{attr.Space, attr.Key}, ":")] = attr
		}
	}

	switch root.Tag {
	case "EntitiesDescriptor":
		for _, child := range root.ChildElements() {
			fmt.Printf("child = %+v\n", child)
			a.addElement(child)
		}
	case "EntityDescriptor":
		a.addElement(root)
	}

	return nil
}

func (a *aggregator) addElement(e *etree.Element) {
	k := e.SelectAttrValue("entityID", "")
	glog.Infof("Adding entity id \"%s\".\n", k)
	if k != "" {
		a.Entities[k] = e
	}
}

func (a *aggregator) Doc() *etree.Document {
	a.xmlns[":xmlns"] = etree.Attr{Key: xmlns, Value: metadataNamespaceURN}

	d := etree.NewDocument()
	ele := etree.NewElement("EntitiesDescriptor")
	ele.Attr = make([]etree.Attr, 0, len(a.xmlns))

	for _, attr := range a.xmlns {
		ele.Attr = append(ele.Attr, attr)
	}

	for _, entity := range a.Entities {
		ele.AddChild(entity)
	}

	d.SetRoot(ele)

	return d
}

func (a *aggregator) WriteTo(w io.Writer) (int64, error) {
	return a.Doc().WriteTo(w)
}
<commit_msg>Update aggregator<commit_after>package main

import (
	"encoding/xml"
	"fmt"
	"io"
	"strings"

	"github.com/beevik/etree"
	"github.com/golang/glog"
)

type aggregator struct {
	XMLName  xml.Name `xml:"EntitiesDescriptor"`
	Entities map[string]*etree.Element
	xmlns    map[string]etree.Attr
}

const (
	metadataNamespaceURN = "urn:oasis:names:tc:SAML:2.0:metadata"

	xmlns = "xmlns"
)

func (a *aggregator) init() {
	if a.Entities == nil {
		a.Entities = map[string]*etree.Element{}
	}
	if a.xmlns == nil {
		a.xmlns = map[string]etree.Attr{}
	}
}

func (a *aggregator) add(r io.Reader) error {
	a.init()

	d := etree.NewDocument()
	if _, err := d.ReadFrom(r); err != nil {
		return err
	}

	root := d.Root()

	if root == nil {
		return fmt.Errorf("Nil root element")
	}

	for _, attr := range root.Attr {
		if attr.Key == xmlns || attr.Space == xmlns {
			a.xmlns[strings.Join([]string{attr.Space, attr.Key}, ":")] = attr
		}
	}

	switch root.Tag {
	case "EntitiesDescriptor":
		for _, child := range root.ChildElements() {
			fmt.Printf("child = %+v\n", child)
			a.addElement(child)
		}
	case "EntityDescriptor":
		a.addElement(root)
	}

	return nil
}

func (a *aggregator) addElement(e *etree.Element) {
	a.init()

	k := e.SelectAttrValue("entityID", "")
	glog.Infof("Adding entity id \"%s\".\n", k)
	if k != "" {
		a.Entities[k] = e
	}
}

func (a *aggregator) Doc() *etree.Document {
	a.init()
	a.xmlns[":xmlns"] = etree.Attr{Key: xmlns, Value: metadataNamespaceURN}

	d := etree.NewDocument()
	ele := etree.NewElement("EntitiesDescriptor")
	ele.Attr = make([]etree.Attr, 0, len(a.xmlns))

	for _, attr := range a.xmlns {
		ele.Attr = append(ele.Attr, attr)
	}

	for _, entity := range a.Entities {
		ele.AddChild(entity)
	}

	d.SetRoot(ele)

	return d
}

func (a *aggregator) WriteTo(w io.Writer) (int64, error) {
	a.init()
	return a.Doc().WriteTo(w)
}
<|endoftext|>


<commit_before>package aini

import (
	"strings"
	"testing"
)

func input1() string {
	return `
myhost1
[dbs]
dbhost1
dbhost2

[apps]
my-app-server1
my-app-server2:3000

`
}

func createHosts(input string) Hosts {
	testInput := strings.NewReader(input)
	v, _ := NewParser(testInput)
	v.Parse()
	return *v
}

func TestGroupExists(t *testing.T) {
	v := createHosts(input1())
	matched := false
	if _, ok := v.Groups["dbs"]; ok {
		matched = true
	}
	if !matched {
		t.Error("Expected to find the group \"dbs\"")
	}
}

func TestHostExistsInGroups(t *testing.T) {
	v := createHosts(input1())
	exportedHosts := map[string][]Host{
		"dbs": []Host{Host{Name: "dbhost1", Port: 22},
			Host{Name: "dbhost2", Port: 22}},
		"ungrouped": []Host{Host{Name: "myhost1", Port: 22}},
		"apps":      []Host{Host{Name: "my-app-server2", Port: 3000}},
	}

	for group, ehosts := range exportedHosts {
		for _, ehost := range ehosts {
			if hosts, ok := v.Groups[group]; ok {
				matched := false
				for _, host := range hosts {
					if host.Name == ehost.Name {
						matched = true
						if host.Port != ehost.Port {
							t.Errorf("Host port %v does not match expected port %v", host.Port, ehost.Port)
						}
					}
				}
				if !matched {
					t.Error("Server ", ehost.Name, " was not found in ", group)
				}
			} else {
				t.Error(group, " group doesn't exist")
			}
		}

	}
}
<commit_msg>Clean up tests<commit_after>package aini

import (
	"strings"
	"testing"
)

var input1 string = `
myhost1

[dbs]
dbhost1
dbhost2

[apps]
my-app-server1
my-app-server2:3000

`

func createHosts(input string) Hosts {
	testInput := strings.NewReader(input)
	v, _ := NewParser(testInput)
	v.Parse()
	return *v
}

func TestGroupExists(t *testing.T) {
	v := createHosts(input1)
	matched := false
	if _, ok := v.Groups["dbs"]; ok {
		matched = true
	}
	if !matched {
		t.Error("Expected to find the group \"dbs\"")
	}
}

func TestHostExistsInGroups(t *testing.T) {
	v := createHosts(input1)
	exportedHosts := map[string][]Host{
		"dbs": []Host{Host{Name: "dbhost1", Port: 22},
			Host{Name: "dbhost2", Port: 22}},
		"ungrouped": []Host{Host{Name: "myhost1", Port: 22}},
		"apps":      []Host{Host{Name: "my-app-server2", Port: 3000}},
	}

	for group, ehosts := range exportedHosts {
		for _, ehost := range ehosts {
			if hosts, ok := v.Groups[group]; ok {
				matched := false
				for _, host := range hosts {
					if host.Name == ehost.Name {
						matched = true
						if host.Port != ehost.Port {
							t.Errorf("Host port '%v' does not match expected port of '%v'.\n", host.Port, ehost.Port)
						}
					}
				}
				if !matched {
					t.Errorf("Server '%+v' was not found in '%+v'.\n", ehost.Name, group)
				}
			} else {
				t.Errorf("'%v' group doesn't exist.\n", group)
			}
		}

	}
}
<|endoftext|>


<commit_before>package models

// DeploymentManifest describes all the configuration for any BOSH deployment
type DeploymentManifest struct {
	Meta          map[string]interface{}
	Name          string
	DirectorUUID  string `yaml:"director_uuid"`
	Releases      []*NameVersion
	Compilation   *manifestCompilation
	Update        *manifestUpdate
	Networks      []*manifestNetwork
	ResourcePools []*manifestResourcePool `yaml:"resource_pools"`
	Jobs          []*ManifestJob
	Properties    *map[string]interface{}
}

type manifestCompilation struct {
	Workers             int                     `yaml:"workers"`
	NetworkName         string                  `yaml:"network"`
	ReuseCompilationVMs bool                    `yaml:"reuse_compilation_vms"`
	CloudProperties     *map[string]interface{} `yaml:"cloud_properties"`
}

type manifestUpdate struct {
	Canaries        int
	MaxInFlight     int    `yaml:"max_in_flight"`
	CanaryWatchTime string `yaml:"canary_watch_time"`
	UpdateWatchTime string `yaml:"update_watch_time"`
	Serial          bool
}

type manifestNetwork struct {
	Name            string
	Type            string
	CloudProperties *map[string]interface{} `yaml:"cloud_properties"`
	Subnets         interface{}
}

type manifestResourcePool struct {
	Name            string
	NetworkName     string `yaml:"network"`
	Stemcell        string
	CloudProperties string `yaml:"cloud_properties"`
}

// ManifestJob describes a cluster of VMs each running the same set of job templates
type ManifestJob struct {
	Name             string
	JobTemplates     []*ManifestJobTemplate `yaml:"templates"`
	Instances        int                    `yaml:"instances,omitempty"`
	ResourcePoolName string                 `yaml:"resource_pool"`
	PersistentDisk   int                    `yaml:"persistent_disk,omitempty"`
	Lifecycle        string                 `yaml:"lifecycle,omitempty"`
	Update           *manifestUpdate        `yaml:"update"`
	Networks         []*manifestJobNetwork
	Properties       *map[string]interface{} `yaml:"properties"`
}

// ManifestJobTemplate describes a job template included in a ManifestJob
type ManifestJobTemplate struct {
	Name    string
	Release string
}

type manifestJobNetwork struct {
	Name      string
	Default   *[]string `yaml:"default"`
	StaticIPs *[]string `yaml:"static_ips"`
}

// FindByJobTemplates returns the subnet of ManifestJobs that include a specific job template
func (manifest *DeploymentManifest) FindByJobTemplates(jobTemplateName string) (jobs []*ManifestJob) {
	jobs = []*ManifestJob{}
	for _, job := range manifest.Jobs {
		for _, jobTemplate := range job.JobTemplates {
			if jobTemplate.Name == jobTemplateName {
				jobs = append(jobs, job)
			}
		}
	}
	return
}
<commit_msg>resource_pools[].stemcell has .name/.version<commit_after>package models

// DeploymentManifest describes all the configuration for any BOSH deployment
type DeploymentManifest struct {
	Meta          map[string]interface{}
	Name          string
	DirectorUUID  string `yaml:"director_uuid"`
	Releases      []*NameVersion
	Compilation   *manifestCompilation
	Update        *manifestUpdate
	Networks      []*manifestNetwork
	ResourcePools []*manifestResourcePool `yaml:"resource_pools"`
	Jobs          []*ManifestJob
	Properties    *map[string]interface{}
}

type manifestCompilation struct {
	Workers             int                     `yaml:"workers"`
	NetworkName         string                  `yaml:"network"`
	ReuseCompilationVMs bool                    `yaml:"reuse_compilation_vms"`
	CloudProperties     *map[string]interface{} `yaml:"cloud_properties"`
}

type manifestUpdate struct {
	Canaries        int
	MaxInFlight     int    `yaml:"max_in_flight"`
	CanaryWatchTime string `yaml:"canary_watch_time"`
	UpdateWatchTime string `yaml:"update_watch_time"`
	Serial          bool
}

type manifestNetwork struct {
	Name            string
	Type            string
	CloudProperties *map[string]interface{} `yaml:"cloud_properties"`
	Subnets         interface{}
}

type manifestResourcePool struct {
	Name            string
	NetworkName     string `yaml:"network"`
	Stemcell        *manifestStemcell
	CloudProperties *map[string]interface{} `yaml:"cloud_properties"`
}

// ManifestJob describes a cluster of VMs each running the same set of job templates
type ManifestJob struct {
	Name             string
	JobTemplates     []*ManifestJobTemplate `yaml:"templates"`
	Instances        int                    `yaml:"instances,omitempty"`
	ResourcePoolName string                 `yaml:"resource_pool"`
	PersistentDisk   int                    `yaml:"persistent_disk,omitempty"`
	Lifecycle        string                 `yaml:"lifecycle,omitempty"`
	Update           *manifestUpdate        `yaml:"update"`
	Networks         []*manifestJobNetwork
	Properties       *map[string]interface{} `yaml:"properties"`
}

// ManifestJobTemplate describes a job template included in a ManifestJob
type ManifestJobTemplate struct {
	Name    string
	Release string
}

type manifestJobNetwork struct {
	Name      string
	Default   *[]string `yaml:"default"`
	StaticIPs *[]string `yaml:"static_ips"`
}

type manifestStemcell struct {
	Name    string
	Version string
}

// FindByJobTemplates returns the subnet of ManifestJobs that include a specific job template
func (manifest *DeploymentManifest) FindByJobTemplates(jobTemplateName string) (jobs []*ManifestJob) {
	jobs = []*ManifestJob{}
	for _, job := range manifest.Jobs {
		for _, jobTemplate := range job.JobTemplates {
			if jobTemplate.Name == jobTemplateName {
				jobs = append(jobs, job)
			}
		}
	}
	return
}
<|endoftext|>


<commit_before>package stack

import (
	"container/list"
	"errors"
)

//Stack represents the LIFO data structure
type Stack struct {
	stack *list.List
}

//Constructor for Stack
//If params is empty, it will new a empty Stack
//Or you can pass a List to initialize the Stack
func New(params ...*list.List) (*Stack, error) {
	sta := new(Stack)
	var err error = nil
	switch len(params) {
	case 0:
		sta.stack = list.New()
	case 1:
		sta.stack = params[0]
	default:
		err = errors.New("The parameter is incorrect")
	}
	return sta, err
}

//Get the Stack size
func (sta *Stack) Size() int {
	return sta.stack.Len()
}

//Check the Stack is empty or not
func (sta *Stack) Empty() bool {
	return sta.stack.Len() == 0
}

//Insert the value above the top
func (sta *Stack) Push(val interface{}) {
	sta.stack.PushBack(val)
}

//Delete the top value in Stack
//If the Stack is empty, it will do nothing
func (sta *Stack) Pop() {
	if !sta.Empty() {
		sta.stack.Remove(sta.stack.Back())
	}
}

//Get the top value in Stack
//If the Stack is empty, you will get nil
func (sta *Stack) Top() interface{} {
	if sta.Empty() {
		return nil
	} else {
		return sta.stack.Back().Value
	}
}

//Reverse the contents in the Stack
func (sta *Stack) Reverse() {
	tmp := list.New()
	for !sta.Empty() {
		tmp.PushBack(sta.Top())
		sta.Pop()
	}
	sta.stack = tmp
}

//Swap the contents of two Stacks
func (sta1 *Stack) Swap(sta2 *Stack) {
	tmp := sta1.stack
	sta1.stack = sta2.stack
	sta2.stack = tmp
}
<commit_msg>comment revised<commit_after>package stack

import (
	"container/list"
	"errors"
)

//Stack represents the LIFO data structure.
type Stack struct {
	stack *list.List
}

//Constructor for Stack.
//If params is empty, it will new a empty Stack.
//Or you can pass a List to initialize the Stack.
func New(params ...*list.List) (*Stack, error) {
	sta := new(Stack)
	var err error = nil
	switch len(params) {
	case 0:
		sta.stack = list.New()
	case 1:
		sta.stack = params[0]
	default:
		err = errors.New("The parameter is incorrect")
	}
	return sta, err
}

//Get the Stack size.
func (sta *Stack) Size() int {
	return sta.stack.Len()
}

//Check whether tthe Stack is empty or not.
func (sta *Stack) Empty() bool {
	return sta.stack.Len() == 0
}

//Insert the value above the top.
func (sta *Stack) Push(val interface{}) {
	sta.stack.PushBack(val)
}

//Delete the top value in Stack.
//If the Stack is empty, it will do nothing.
func (sta *Stack) Pop() {
	if !sta.Empty() {
		sta.stack.Remove(sta.stack.Back())
	}
}

//Get the top value in Stack.
//If the Stack is empty, you will get nil.
func (sta *Stack) Top() interface{} {
	if sta.Empty() {
		return nil
	} else {
		return sta.stack.Back().Value
	}
}

//Reverse the contents in the Stack.
func (sta *Stack) Reverse() {
	tmp := list.New()
	for !sta.Empty() {
		tmp.PushBack(sta.Top())
		sta.Pop()
	}
	sta.stack = tmp
}

//Swap the contents of two Stacks.
func (sta1 *Stack) Swap(sta2 *Stack) {
	tmp := sta1.stack
	sta1.stack = sta2.stack
	sta2.stack = tmp
}
<|endoftext|>


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

// Package gmail provides a gmail barista module.
package gmail // import "barista.run/modules/gsuite/gmail"

import (
	"net/http"
	"time"

	"barista.run/bar"
	"barista.run/base/value"
	"barista.run/oauth"
	"barista.run/outputs"
	"barista.run/timing"

	"golang.org/x/oauth2/google"
	gmail "google.golang.org/api/gmail/v1"
)

type Info struct {
	Threads map[string]int64
	Unread  map[string]int64
}

func (i Info) TotalUnread() int64 {
	t := int64(0)
	for _, u := range i.Unread {
		t += u
	}
	return t
}

func (i Info) TotalThreads() int64 {
	t := int64(0)
	for _, c := range i.Threads {
		t += c
	}
	return t
}

type Module struct {
	config     *oauth.Config
	labels     []string
	scheduler  timing.Scheduler
	outputFunc value.Value // of func(Info) bar.Output
}

func New(clientConfig []byte, labels ...string) *Module {
	config, err := google.ConfigFromJSON(clientConfig, gmail.GmailLabelsScope)
	if err != nil {
		panic("Bad client config: " + err.Error())
	}
	if len(labels) == 0 {
		labels = []string{"INBOX"}
	}
	m := &Module{
		config:    oauth.Register(config),
		labels:    labels,
		scheduler: timing.NewScheduler(),
	}
	m.RefreshInterval(5 * time.Minute)
	m.Output(func(i Info) bar.Output {
		if i.TotalUnread() == 0 {
			return nil
		}
		return outputs.Textf("Gmail: %d", i.TotalUnread())
	})
	return m
}

// for tests, to wrap the client in a transport that redirects requests.
var wrapForTest func(*http.Client)

func (m *Module) Stream(sink bar.Sink) {
	client, _ := m.config.Client()
	if wrapForTest != nil {
		wrapForTest(client)
	}
	srv, err := gmail.New(client)
	if sink.Error(err) {
		return
	}
	r, err := srv.Users.Labels.List("me").Do()
	if sink.Error(err) {
		return
	}
	labelIDs := map[string]string{}
	for _, l := range r.Labels {
		labelIDs[l.Name] = l.Id
	}
	i, err := m.fetch(srv, labelIDs)
	outf := m.outputFunc.Get().(func(Info) bar.Output)
	nextOutputFunc := m.outputFunc.Next()
	for {
		if sink.Error(err) {
			return
		}
		sink.Output(outf(i))
		select {
		case <-nextOutputFunc:
			nextOutputFunc = m.outputFunc.Next()
			outf = m.outputFunc.Get().(func(Info) bar.Output)
		case <-m.scheduler.Tick():
			i, err = m.fetch(srv, labelIDs)
		}
	}
}

func (m *Module) fetch(srv *gmail.Service, labelIDs map[string]string) (Info, error) {
	i := Info{
		Threads: map[string]int64{},
		Unread:  map[string]int64{},
	}
	for _, l := range m.labels {
		r, err := srv.Users.Labels.Get("me", labelIDs[l]).Do()
		if err != nil {
			return i, err
		}
		i.Threads[l] = r.ThreadsTotal
		i.Unread[l] = r.ThreadsUnread
	}
	return i, nil
}

func (m *Module) Output(outputFunc func(Info) bar.Output) *Module {
	m.outputFunc.Set(outputFunc)
	return m
}

func (m *Module) RefreshInterval(interval time.Duration) *Module {
	m.scheduler.Every(interval)
	return m
}
<commit_msg>Cleanup: make gmail fetch method standalone<commit_after>// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package gmail provides a gmail barista module.
package gmail // import "barista.run/modules/gsuite/gmail"

import (
	"net/http"
	"time"

	"barista.run/bar"
	"barista.run/base/value"
	"barista.run/oauth"
	"barista.run/outputs"
	"barista.run/timing"

	"golang.org/x/oauth2/google"
	gmail "google.golang.org/api/gmail/v1"
)

type Info struct {
	Threads map[string]int64
	Unread  map[string]int64
}

func (i Info) TotalUnread() int64 {
	t := int64(0)
	for _, u := range i.Unread {
		t += u
	}
	return t
}

func (i Info) TotalThreads() int64 {
	t := int64(0)
	for _, c := range i.Threads {
		t += c
	}
	return t
}

type Module struct {
	config     *oauth.Config
	labels     []string
	scheduler  timing.Scheduler
	outputFunc value.Value // of func(Info) bar.Output
}

func New(clientConfig []byte, labels ...string) *Module {
	config, err := google.ConfigFromJSON(clientConfig, gmail.GmailLabelsScope)
	if err != nil {
		panic("Bad client config: " + err.Error())
	}
	if len(labels) == 0 {
		labels = []string{"INBOX"}
	}
	m := &Module{
		config:    oauth.Register(config),
		labels:    labels,
		scheduler: timing.NewScheduler(),
	}
	m.RefreshInterval(5 * time.Minute)
	m.Output(func(i Info) bar.Output {
		if i.TotalUnread() == 0 {
			return nil
		}
		return outputs.Textf("Gmail: %d", i.TotalUnread())
	})
	return m
}

// for tests, to wrap the client in a transport that redirects requests.
var wrapForTest func(*http.Client)

func (m *Module) Stream(sink bar.Sink) {
	client, _ := m.config.Client()
	if wrapForTest != nil {
		wrapForTest(client)
	}
	srv, err := gmail.New(client)
	if sink.Error(err) {
		return
	}
	r, err := srv.Users.Labels.List("me").Do()
	if sink.Error(err) {
		return
	}
	labelIDs := map[string]string{}
	for _, l := range r.Labels {
		labelIDs[l.Name] = l.Id
	}
	i, err := fetch(srv, m.labels, labelIDs)
	outf := m.outputFunc.Get().(func(Info) bar.Output)
	nextOutputFunc := m.outputFunc.Next()
	for {
		if sink.Error(err) {
			return
		}
		sink.Output(outf(i))
		select {
		case <-nextOutputFunc:
			nextOutputFunc = m.outputFunc.Next()
			outf = m.outputFunc.Get().(func(Info) bar.Output)
		case <-m.scheduler.Tick():
			i, err = fetch(srv, m.labels, labelIDs)
		}
	}
}

func fetch(srv *gmail.Service, labels []string, labelIDs map[string]string) (Info, error) {
	i := Info{
		Threads: map[string]int64{},
		Unread:  map[string]int64{},
	}
	for _, l := range labels {
		r, err := srv.Users.Labels.Get("me", labelIDs[l]).Do()
		if err != nil {
			return i, err
		}
		i.Threads[l] = r.ThreadsTotal
		i.Unread[l] = r.ThreadsUnread
	}
	return i, nil
}

func (m *Module) Output(outputFunc func(Info) bar.Output) *Module {
	m.outputFunc.Set(outputFunc)
	return m
}

func (m *Module) RefreshInterval(interval time.Duration) *Module {
	m.scheduler.Every(interval)
	return m
}
<|endoftext|>