<commit_before>// This file is part of Monsti, a web content management system.
// Copyright 2012-2013 Christian Neumann
//
// Monsti is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any
// later version.
//
// Monsti is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Monsti.  If not, see <http://www.gnu.org/licenses/>.

package service

import (
	"fmt"
	"log"
	"sync"
)

// ActionHandler processes incoming requests for some node action.
type ActionHandler func(req Request, res *Response,
	infoServ *InfoClient)

// NodeTypeHandler handles requests for some node type.
type NodeTypeHandler struct {
	Name                   string
	EditAction, ViewAction ActionHandler
}

// NodeProvider provides Node services for one ore more content types.
type NodeProvider struct {
	// Logger to be used
	Logger *log.Logger
	// Info service to be used
	Info  *InfoClient
	types map[string]*NodeTypeHandler
}

func NewNodeProvider(logger *log.Logger, info *InfoClient) *NodeProvider {
	p := NodeProvider{
		Logger: logger,
		Info: info,
		types: make(map[string]*NodeTypeHandler),
	}
	return &p
}

// AddNodeType adds a handler for a node type to be served.
func (p *NodeProvider) AddNodeType(h *NodeTypeHandler) {
	p.types[h.Name] = h
}

// Serve registers and serves the node types at the given Node service path.
func (p *NodeProvider) Serve(path string) error {
	// Start own NODE service
	var waitGroup sync.WaitGroup
	p.Logger.Println("Starting Node service")
	waitGroup.Add(1)
	go func() {
		defer waitGroup.Done()
		var provider Provider
		var node_ nodeService
		provider.Logger = p.Logger
		if err := provider.Serve(path, "Node", &node_); err != nil {
			p.Logger.Printf("node: Could not start Node service: %v", err)
		}
	}()

	if err := p.Info.PublishService("Node", path); err != nil {
		return fmt.Errorf("node: Could not publish node service: %v", err)
	}
	waitGroup.Wait()
	return nil
}

type nodeService struct {
	Info     *InfoClient
	Provider *NodeProvider
}

func (i nodeService) Request(req Request,
	reply *Response) error {
	nodeType := req.Node.Type
	var f ActionHandler
	switch req.Action {
	case "edit":
		f = i.Provider.types[nodeType].EditAction
	default:
		f = i.Provider.types[nodeType].ViewAction
	}
	f(req, reply, i.Info)
	return nil
}

func (i *nodeService) GetNodeTypes(req int,
	reply *[]string) error {
	*reply = make([]string, 0)
	for key, _ := range i.Provider.types {
		*reply = append(*reply, key)
	}
	return nil
}
<commit_msg>Fix initialization of node service.<commit_after>// This file is part of Monsti, a web content management system.
// Copyright 2012-2013 Christian Neumann
//
// Monsti is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any
// later version.
//
// Monsti is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Monsti.  If not, see <http://www.gnu.org/licenses/>.

package service

import (
	"fmt"
	"log"
	"sync"
)

// ActionHandler processes incoming requests for some node action.
type ActionHandler func(req Request, res *Response,
	infoServ *InfoClient)

// NodeTypeHandler handles requests for some node type.
type NodeTypeHandler struct {
	Name                   string
	EditAction, ViewAction ActionHandler
}

// NodeProvider provides Node services for one ore more content types.
type NodeProvider struct {
	// Logger to be used
	Logger *log.Logger
	// Info service to be used
	Info  *InfoClient
	types map[string]*NodeTypeHandler
}

func NewNodeProvider(logger *log.Logger, info *InfoClient) *NodeProvider {
	p := NodeProvider{
		Logger: logger,
		Info:   info,
		types:  make(map[string]*NodeTypeHandler),
	}
	return &p
}

// AddNodeType adds a handler for a node type to be served.
func (p *NodeProvider) AddNodeType(h *NodeTypeHandler) {
	p.types[h.Name] = h
}

// Serve registers and serves the node types at the given Node service path.
func (p *NodeProvider) Serve(path string) error {
	// Start own NODE service
	var waitGroup sync.WaitGroup
	p.Logger.Println("Starting Node service")
	waitGroup.Add(1)
	go func() {
		defer waitGroup.Done()
		var provider Provider
		var node_ nodeService
		node_.Provider = p
		node_.Info = p.Info
		provider.Logger = p.Logger
		if err := provider.Serve(path, "Node", &node_); err != nil {
			p.Logger.Printf("node: Could not start Node service: %v", err)
		}
	}()

	if err := p.Info.PublishService("Node", path); err != nil {
		return fmt.Errorf("node: Could not publish node service: %v", err)
	}
	waitGroup.Wait()
	return nil
}

type nodeService struct {
	Provider *NodeProvider
	Info     *InfoClient
}

func (i nodeService) Request(req Request,
	reply *Response) error {
	nodeType := req.Node.Type
	var f ActionHandler
	switch req.Action {
	case "edit":
		f = i.Provider.types[nodeType].EditAction
	default:
		f = i.Provider.types[nodeType].ViewAction
	}
	f(req, reply, i.Info)
	return nil
}

func (i *nodeService) GetNodeTypes(req int,
	reply *[]string) error {
	*reply = make([]string, 0)
	for key, _ := range i.Provider.types {
		*reply = append(*reply, key)
	}
	return nil
}
<|endoftext|>


<commit_before>package dbx

import (
	"errors"
	"fmt"
	"reflect"
)

type (
	// TableModel is the interface that should be implemented by models which have unconventional table names.
	TableModel interface {
		TableName() string
	}

	// ModelQuery represents a query associated with a struct model.
	ModelQuery struct {
		db        *DB
		builder   Builder
		model     *structValue
		exclude   []string
		lastError error
	}
)

var (
	MissingPKError   = errors.New("missing primary key declaration")
	CompositePKError = errors.New("composite primary key is not supported")
)

func NewModelQuery(model interface{}, fieldMapFunc FieldMapFunc, db *DB, builder Builder) *ModelQuery {
	q := &ModelQuery{
		db:      db,
		builder: builder,
		model:   newStructValue(model, fieldMapFunc),
	}
	if q.model == nil {
		q.lastError = VarTypeError("must be a pointer to a struct representing the model")
	}
	return q
}

// Exclude excludes the specified struct fields from being inserted/updated into the DB table.
func (q *ModelQuery) Exclude(attrs ...string) *ModelQuery {
	q.exclude = attrs
	return q
}

// Insert inserts a row in the table using the struct model associated with this query.
//
// By default, it inserts *all* public fields into the table, including those nil or empty ones.
// You may pass a list of the fields to this method to indicate that only those fields should be inserted.
// You may also call Exclude to exclude some fields from being inserted.
//
// If a model has an empty primary key, it is considered auto-incremental and the corresponding struct
// field will be filled with the generated primary key value after a successful insertion.
func (q *ModelQuery) Insert(attrs ...string) error {
	if q.lastError != nil {
		return q.lastError
	}
	cols := q.model.columns(attrs, q.exclude)
	pkName := ""
	for name, value := range q.model.pk() {
		if isAutoInc(value) {
			delete(cols, name)
			pkName = name
			break
		}
	}

	if pkName == "" {
		_, err := q.builder.Insert(q.model.tableName, Params(cols)).Execute()
		return err
	}

	// handle auto-incremental PK
	query := q.builder.Insert(q.model.tableName, Params(cols))
	pkValue, err := insertAndReturnPK(q.db, query, pkName)
	if err != nil {
		return err
	}
	indirect(q.model.dbNameMap[pkName].getField(q.model.value)).SetInt(pkValue)
	return nil
}

func insertAndReturnPK(db *DB, query *Query, pkName string) (int64, error) {
	if db.DriverName() != "postgres" {
		result, err := query.Execute()
		if err != nil {
			return 0, err
		}
		return result.LastInsertId()
	}

	// specially handle postgres (lib/pq) as it doesn't support LastInsertId
	returning := fmt.Sprintf(" RETURNING %s", db.QuoteColumnName(pkName))
	query.sql += returning
	query.rawSQL += returning
	var pkValue int64
	err := query.Row(&pkValue)
	return pkValue, err
}

func isAutoInc(value interface{}) bool {
	v := reflect.ValueOf(value)
	switch v.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Ptr:
		return v.IsNil() || isAutoInc(v.Elem())
	case reflect.Invalid:
		return true
	}
	return false
}

// Update updates a row in the table using the struct model associated with this query.
// The row being updated has the same primary key as specified by the model.
//
// By default, it updates *all* public fields in the table, including those nil or empty ones.
// You may pass a list of the fields to this method to indicate that only those fields should be updated.
// You may also call Exclude to exclude some fields from being updated.
func (q *ModelQuery) Update(attrs ...string) error {
	if q.lastError != nil {
		return q.lastError
	}
	pk := q.model.pk()
	if len(pk) == 0 {
		return MissingPKError
	}

	cols := q.model.columns(attrs, q.exclude)
	for name := range pk {
		delete(cols, name)
	}
	_, err := q.builder.Update(q.model.tableName, Params(cols), HashExp(pk)).Execute()
	return err
}

// Delete deletes a row in the table using the primary key specified by the struct model associated with this query.
func (q *ModelQuery) Delete() error {
	if q.lastError != nil {
		return q.lastError
	}
	pk := q.model.pk()
	if len(pk) == 0 {
		return MissingPKError
	}
	_, err := q.builder.Delete(q.model.tableName, HashExp(pk)).Execute()
	return err
}
<commit_msg>Support uint primary keys in ModelQuery<commit_after>package dbx

import (
	"errors"
	"fmt"
	"reflect"
)

type (
	// TableModel is the interface that should be implemented by models which have unconventional table names.
	TableModel interface {
		TableName() string
	}

	// ModelQuery represents a query associated with a struct model.
	ModelQuery struct {
		db        *DB
		builder   Builder
		model     *structValue
		exclude   []string
		lastError error
	}
)

var (
	MissingPKError   = errors.New("missing primary key declaration")
	CompositePKError = errors.New("composite primary key is not supported")
)

func NewModelQuery(model interface{}, fieldMapFunc FieldMapFunc, db *DB, builder Builder) *ModelQuery {
	q := &ModelQuery{
		db:      db,
		builder: builder,
		model:   newStructValue(model, fieldMapFunc),
	}
	if q.model == nil {
		q.lastError = VarTypeError("must be a pointer to a struct representing the model")
	}
	return q
}

// Exclude excludes the specified struct fields from being inserted/updated into the DB table.
func (q *ModelQuery) Exclude(attrs ...string) *ModelQuery {
	q.exclude = attrs
	return q
}

// Insert inserts a row in the table using the struct model associated with this query.
//
// By default, it inserts *all* public fields into the table, including those nil or empty ones.
// You may pass a list of the fields to this method to indicate that only those fields should be inserted.
// You may also call Exclude to exclude some fields from being inserted.
//
// If a model has an empty primary key, it is considered auto-incremental and the corresponding struct
// field will be filled with the generated primary key value after a successful insertion.
func (q *ModelQuery) Insert(attrs ...string) error {
	if q.lastError != nil {
		return q.lastError
	}
	cols := q.model.columns(attrs, q.exclude)
	pkName := ""
	for name, value := range q.model.pk() {
		if isAutoInc(value) {
			delete(cols, name)
			pkName = name
			break
		}
	}

	if pkName == "" {
		_, err := q.builder.Insert(q.model.tableName, Params(cols)).Execute()
		return err
	}

	// handle auto-incremental PK
	query := q.builder.Insert(q.model.tableName, Params(cols))
	pkValue, err := insertAndReturnPK(q.db, query, pkName)
	if err != nil {
		return err
	}

	pkField := indirect(q.model.dbNameMap[pkName].getField(q.model.value))
	switch pkField.Kind() {
	case reflect.Uint:
		pkField.SetUint(uint64(pkValue))
	case reflect.Int:
		pkField.SetInt(pkValue)
	}

	return nil
}

func insertAndReturnPK(db *DB, query *Query, pkName string) (int64, error) {
	if db.DriverName() != "postgres" {
		result, err := query.Execute()
		if err != nil {
			return 0, err
		}
		return result.LastInsertId()
	}

	// specially handle postgres (lib/pq) as it doesn't support LastInsertId
	returning := fmt.Sprintf(" RETURNING %s", db.QuoteColumnName(pkName))
	query.sql += returning
	query.rawSQL += returning
	var pkValue int64
	err := query.Row(&pkValue)
	return pkValue, err
}

func isAutoInc(value interface{}) bool {
	v := reflect.ValueOf(value)
	switch v.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Ptr:
		return v.IsNil() || isAutoInc(v.Elem())
	case reflect.Invalid:
		return true
	}
	return false
}

// Update updates a row in the table using the struct model associated with this query.
// The row being updated has the same primary key as specified by the model.
//
// By default, it updates *all* public fields in the table, including those nil or empty ones.
// You may pass a list of the fields to this method to indicate that only those fields should be updated.
// You may also call Exclude to exclude some fields from being updated.
func (q *ModelQuery) Update(attrs ...string) error {
	if q.lastError != nil {
		return q.lastError
	}
	pk := q.model.pk()
	if len(pk) == 0 {
		return MissingPKError
	}

	cols := q.model.columns(attrs, q.exclude)
	for name := range pk {
		delete(cols, name)
	}
	_, err := q.builder.Update(q.model.tableName, Params(cols), HashExp(pk)).Execute()
	return err
}

// Delete deletes a row in the table using the primary key specified by the struct model associated with this query.
func (q *ModelQuery) Delete() error {
	if q.lastError != nil {
		return q.lastError
	}
	pk := q.model.pk()
	if len(pk) == 0 {
		return MissingPKError
	}
	_, err := q.builder.Delete(q.model.tableName, HashExp(pk)).Execute()
	return err
}
<|endoftext|>


<commit_before>package oortcloud

import (
	"bytes"
	"io"
	"net"
	"net/http"
	"sync"
	"time"
)

type HTTPNotifier struct {
	URLs     []string
	BodyType string
	Client   *http.Client

	conMap   *ConnectionMap
	mu       sync.RWMutex
	urlIndex int
}

func NewHTTPNotifier(urls []string) *HTTPNotifier {
	return &HTTPNotifier{
		URLs:     urls,
		BodyType: "application/octet-stream",
		Client: &http.Client{
			Transport: &http.Transport{
				Proxy: http.ProxyFromEnvironment,
				Dial: (&net.Dialer{
					Timeout:   30 * time.Second,
					KeepAlive: 30 * time.Second,
				}).Dial,
				TLSHandshakeTimeout: 10 * time.Second,
			},
		},
		conMap: NewConnectionMap(),
	}
}

func (n *HTTPNotifier) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	id := req.URL.Path
	if len(id) >= 1 && id[0] == '/' {
		id = id[1:len(id)]
	}
	if req.Method != "POST" {
		http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
		return
	}

	con, ok := n.conMap.Get(id)
	if !ok {
		http.NotFound(w, req)
		return
	}
	if con == nil {
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	buf := &bytes.Buffer{}
	io.Copy(buf, req.Body)
	err := con.Send(buf.Bytes())
	if err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
	}

	w.Header().Set("Content-Type", "text/plain")
	w.WriteHeader(http.StatusOK)
}

func (n *HTTPNotifier) Connect(con Connection, request *http.Request) (string, *http.Response, error) {
	id := n.conMap.New(con)
	req, err := http.NewRequest("POST", n.getURL(), nil)
	if err != nil {
		return "", nil, err
	}

	// copy header
	if request != nil {
		for _, h := range hopHeaders {
			request.Header.Del(h)
		}
		for k, vv := range request.Header {
			for _, v := range vv {
				req.Header.Add(k, v)
			}
		}
	}

	// set X-Oortclound headers
	req.Header.Set("Content-Type", n.BodyType)
	req.Header.Set("X-Oortcloud-Connection-Id", id)
	req.Header.Set("x-Oortcloud-Event", Connect.String())

	resp, err := n.Client.Do(req)
	return id, resp, err
}

func (n *HTTPNotifier) Disconnect(id string) error {
	n.conMap.Delete(id)
	return n.send(id, Disconnect, nil)
}

func (n *HTTPNotifier) Notify(id string, data []byte) error {
	return n.send(id, Receive, data)
}

func (n *HTTPNotifier) send(id string, eventType EventType, data []byte) error {
	req, err := http.NewRequest("POST", n.getURL(), bytes.NewBuffer(data))
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", n.BodyType)
	req.Header.Set("X-Oortcloud-Connection-Id", id)
	req.Header.Set("X-Oortcloud-Event", eventType.String())
	resp, err := n.Client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	return err
}

func (n *HTTPNotifier) getURL() string {
	n.mu.Lock()
	defer n.mu.Unlock()

	i := n.urlIndex
	n.urlIndex = (i + 1) % len(n.URLs)
	return n.URLs[i]
}
<commit_msg>fix failing websocket handshaking<commit_after>package oortcloud

import (
	"bytes"
	"io"
	"net"
	"net/http"
	"sync"
	"time"
)

type HTTPNotifier struct {
	URLs     []string
	BodyType string
	Client   *http.Client

	conMap   *ConnectionMap
	mu       sync.RWMutex
	urlIndex int
}

func NewHTTPNotifier(urls []string) *HTTPNotifier {
	return &HTTPNotifier{
		URLs:     urls,
		BodyType: "application/octet-stream",
		Client: &http.Client{
			Transport: &http.Transport{
				Proxy: http.ProxyFromEnvironment,
				Dial: (&net.Dialer{
					Timeout:   30 * time.Second,
					KeepAlive: 30 * time.Second,
				}).Dial,
				TLSHandshakeTimeout: 10 * time.Second,
			},
		},
		conMap: NewConnectionMap(),
	}
}

func (n *HTTPNotifier) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	id := req.URL.Path
	if len(id) >= 1 && id[0] == '/' {
		id = id[1:len(id)]
	}
	if req.Method != "POST" {
		http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
		return
	}

	con, ok := n.conMap.Get(id)
	if !ok {
		http.NotFound(w, req)
		return
	}
	if con == nil {
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	buf := &bytes.Buffer{}
	io.Copy(buf, req.Body)
	err := con.Send(buf.Bytes())
	if err != nil {
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
	}

	w.Header().Set("Content-Type", "text/plain")
	w.WriteHeader(http.StatusOK)
}

func (n *HTTPNotifier) Connect(con Connection, request *http.Request) (string, *http.Response, error) {
	id := n.conMap.New(con)
	req, err := http.NewRequest("POST", n.getURL(), nil)
	if err != nil {
		return "", nil, err
	}

	// copy header
	if request != nil {
		for k, vv := range request.Header {
			for _, v := range vv {
				req.Header.Add(k, v)
			}
		}
		for _, h := range hopHeaders {
			req.Header.Del(h)
		}
	}

	// set X-Oortclound headers
	req.Header.Set("Content-Type", n.BodyType)
	req.Header.Set("X-Oortcloud-Connection-Id", id)
	req.Header.Set("x-Oortcloud-Event", Connect.String())

	resp, err := n.Client.Do(req)
	return id, resp, err
}

func (n *HTTPNotifier) Disconnect(id string) error {
	n.conMap.Delete(id)
	return n.send(id, Disconnect, nil)
}

func (n *HTTPNotifier) Notify(id string, data []byte) error {
	return n.send(id, Receive, data)
}

func (n *HTTPNotifier) send(id string, eventType EventType, data []byte) error {
	req, err := http.NewRequest("POST", n.getURL(), bytes.NewBuffer(data))
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", n.BodyType)
	req.Header.Set("X-Oortcloud-Connection-Id", id)
	req.Header.Set("X-Oortcloud-Event", eventType.String())
	resp, err := n.Client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	return err
}

func (n *HTTPNotifier) getURL() string {
	n.mu.Lock()
	defer n.mu.Unlock()

	i := n.urlIndex
	n.urlIndex = (i + 1) % len(n.URLs)
	return n.URLs[i]
}
<|endoftext|>


<commit_before>package rpc

import (
	"hash/crc32"
	"io"
	"os"
	"testing"

	hdfs "github.com/colinmarc/hdfs/protocol/hadoop_hdfs"
	"github.com/golang/protobuf/proto"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func createBlock(t *testing.T, name string) *BlockWriter {
	namenode := getNamenode(t)
	blockSize := int64(1048576)

	createReq := &hdfs.CreateRequestProto{
		Src:          proto.String(name),
		Masked:       &hdfs.FsPermissionProto{Perm: proto.Uint32(uint32(0644))},
		ClientName:   proto.String(ClientName),
		CreateFlag:   proto.Uint32(1),
		CreateParent: proto.Bool(false),
		Replication:  proto.Uint32(uint32(3)),
		BlockSize:    proto.Uint64(uint64(blockSize)),
	}
	createResp := &hdfs.CreateResponseProto{}

	err := namenode.Execute("create", createReq, createResp)
	require.NoError(t, err)

	addBlockReq := &hdfs.AddBlockRequestProto{
		Src:        proto.String(name),
		ClientName: proto.String(ClientName),
		Previous:   nil,
	}
	addBlockResp := &hdfs.AddBlockResponseProto{}

	err = namenode.Execute("addBlock", addBlockReq, addBlockResp)
	require.NoError(t, err)

	block := addBlockResp.GetBlock()
	return NewBlockWriter(block, namenode, blockSize)
}

func finishBlock(t *testing.T, name string, bw *BlockWriter) {
	namenode := getNamenode(t)

	err := bw.Close()
	require.NoError(t, err)

	completeReq := &hdfs.CompleteRequestProto{
		Src:        proto.String(name),
		ClientName: proto.String(ClientName),
		Last:       bw.block.GetB(),
	}
	completeResp := &hdfs.CompleteResponseProto{}

	err = namenode.Execute("complete", completeReq, completeResp)
	require.NoError(t, err)
}

func baleet(t *testing.T, name string) {
	namenode := getNamenode(t)

	req := &hdfs.DeleteRequestProto{
		Src:       proto.String(name),
		Recursive: proto.Bool(true),
	}
	resp := &hdfs.DeleteResponseProto{}

	err := namenode.Execute("delete", req, resp)
	require.NoError(t, err)
	require.NotNil(t, resp.Result)
}

func TestWriteFailsOver(t *testing.T) {
	name := "/_test/create/6.txt"
	baleet(t, name)

	mobydick, err := os.Open("../test/mobydick.txt")
	require.NoError(t, err)

	bw := createBlock(t, name)

	_, err = io.CopyN(bw, mobydick, 1048576)
	require.NoError(t, err)
	finishBlock(t, name, bw)

	br, _ := getBlockReader(t, name)
	hash := crc32.NewIEEE()
	n, err := io.Copy(hash, br)
	require.NoError(t, err)
	assert.EqualValues(t, 1048576, n)
	assert.EqualValues(t, 0xb35a6a0e, hash.Sum32())
}
<commit_msg>add a failing failover test<commit_after>package rpc

import (
	"hash/crc32"
	"io"
	"os"
	"testing"

	hdfs "github.com/colinmarc/hdfs/protocol/hadoop_hdfs"
	"github.com/golang/protobuf/proto"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func createBlock(t *testing.T, name string) *BlockWriter {
	namenode := getNamenode(t)
	blockSize := int64(1048576)

	createReq := &hdfs.CreateRequestProto{
		Src:          proto.String(name),
		Masked:       &hdfs.FsPermissionProto{Perm: proto.Uint32(uint32(0644))},
		ClientName:   proto.String(ClientName),
		CreateFlag:   proto.Uint32(1),
		CreateParent: proto.Bool(false),
		Replication:  proto.Uint32(uint32(3)),
		BlockSize:    proto.Uint64(uint64(blockSize)),
	}
	createResp := &hdfs.CreateResponseProto{}

	err := namenode.Execute("create", createReq, createResp)
	require.NoError(t, err)

	addBlockReq := &hdfs.AddBlockRequestProto{
		Src:        proto.String(name),
		ClientName: proto.String(ClientName),
		Previous:   nil,
	}
	addBlockResp := &hdfs.AddBlockResponseProto{}

	err = namenode.Execute("addBlock", addBlockReq, addBlockResp)
	require.NoError(t, err)

	block := addBlockResp.GetBlock()
	return NewBlockWriter(block, namenode, blockSize)
}

func finishBlock(t *testing.T, name string, bw *BlockWriter) {
	namenode := getNamenode(t)

	err := bw.Close()
	require.NoError(t, err)

	completeReq := &hdfs.CompleteRequestProto{
		Src:        proto.String(name),
		ClientName: proto.String(ClientName),
		Last:       bw.block.GetB(),
	}
	completeResp := &hdfs.CompleteResponseProto{}

	err = namenode.Execute("complete", completeReq, completeResp)
	require.NoError(t, err)
}

func baleet(t *testing.T, name string) {
	namenode := getNamenode(t)

	req := &hdfs.DeleteRequestProto{
		Src:       proto.String(name),
		Recursive: proto.Bool(true),
	}
	resp := &hdfs.DeleteResponseProto{}

	err := namenode.Execute("delete", req, resp)
	require.NoError(t, err)
	require.NotNil(t, resp.Result)
}

func TestWriteFailsOver(t *testing.T) {
	name := "/_test/create/6.txt"
	baleet(t, name)

	mobydick, err := os.Open("../test/mobydick.txt")
	require.NoError(t, err)

	bw := createBlock(t, name)
	bw.connectNext()
	bw.stream.ackError = ackError{0, 0, hdfs.Status_ERROR}

	_, err = io.CopyN(bw, mobydick, 1048576)
	require.NoError(t, err)
	finishBlock(t, name, bw)

	br, _ := getBlockReader(t, name)
	hash := crc32.NewIEEE()
	n, err := io.Copy(hash, br)
	require.NoError(t, err)
	assert.EqualValues(t, 1048576, n)
	assert.EqualValues(t, 0xb35a6a0e, hash.Sum32())
}
<|endoftext|>


<commit_before>package money

import (
	"fmt"
	"strings"
)

const (
	EUR = "EUR"
	USD = "USD"
)

var Currencies = map[string]float64{
	EUR: 1.0, // default currency is EUR
	USD: 0.902730761,
}

type Money struct {
	AmountInCents int
	Currency      string
}

func (m *Money) Add(other *Money) *Money {
	return &Money{AmountInCents: m.ToEUR().AmountInCents + other.ToEUR().AmountInCents, Currency: EUR}

}

func (m *Money) AmountInEURCents() int {
	factor, ok := Currencies[m.Currency]
	if !ok {
		panic("currency " + m.Currency + " not supported")
	}
	return int(float64(m.AmountInCents) * factor)
}

func (m *Money) PerDays(n int) *Money {
	return &Money{AmountInCents: n * m.AmountInCents, Currency: m.Currency}
}

func (m *Money) ToEUR() *Money {
	return &Money{
		AmountInCents: m.AmountInEURCents(),
		Currency:      EUR,
	}
}

func New(amountInCents int, currency string) *Money {
	return &Money{AmountInCents: amountInCents, Currency: strings.ToUpper(currency)}
}

func NewEUR(amountInCents int) *Money {
	return New(amountInCents, EUR)
}

func (m *Money) String() string {
	return fmt.Sprintf("%.02f EUR", float64(m.ToEUR().AmountInCents)/100.0)
}
<commit_msg>money: add Sub method<commit_after>package money

import (
	"fmt"
	"strings"
)

const (
	EUR = "EUR"
	USD = "USD"
)

var Currencies = map[string]float64{
	EUR: 1.0, // default currency is EUR
	USD: 0.902730761,
}

type Money struct {
	AmountInCents int
	Currency      string
}

func (m *Money) Add(other *Money) *Money {
	return &Money{AmountInCents: m.ToEUR().AmountInCents + other.ToEUR().AmountInCents, Currency: EUR}
}

func (m *Money) Sub(other *Money) *Money {
	return &Money{AmountInCents: m.ToEUR().AmountInCents - other.ToEUR().AmountInCents, Currency: EUR}
}

func (m *Money) AmountInEURCents() int {
	factor, ok := Currencies[m.Currency]
	if !ok {
		panic("currency " + m.Currency + " not supported")
	}
	return int(float64(m.AmountInCents) * factor)
}

func (m *Money) PerDays(n int) *Money {
	return &Money{AmountInCents: n * m.AmountInCents, Currency: m.Currency}
}

func (m *Money) ToEUR() *Money {
	return &Money{
		AmountInCents: m.AmountInEURCents(),
		Currency:      EUR,
	}
}

func New(amountInCents int, currency string) *Money {
	return &Money{AmountInCents: amountInCents, Currency: strings.ToUpper(currency)}
}

func NewEUR(amountInCents int) *Money {
	return New(amountInCents, EUR)
}

func (m *Money) String() string {
	return fmt.Sprintf("%.02f EUR", float64(m.ToEUR().AmountInCents)/100.0)
}
<|endoftext|>


<commit_before>// +build !windows

/*
   Copyright The containerd Authors.

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

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

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

package archive

import (
	"time"

	"golang.org/x/sys/unix"

	"github.com/pkg/errors"
)

func chtimes(path string, atime, mtime time.Time) error {
	var utimes [2]unix.Timespec
	utimes[0] = unix.NsecToTimespec(atime.UnixNano())
	utimes[1] = unix.NsecToTimespec(mtime.UnixNano())

	if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, utimes[0:], unix.AT_SYMLINK_NOFOLLOW); err != nil {
		return errors.Wrap(err, "failed call to UtimesNanoAt")
	}

	return nil
}
<commit_msg>archive: return chtimes error with path information<commit_after>// +build !windows

/*
   Copyright The containerd Authors.

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

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

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

package archive

import (
	"time"

	"golang.org/x/sys/unix"

	"github.com/pkg/errors"
)

func chtimes(path string, atime, mtime time.Time) error {
	var utimes [2]unix.Timespec
	utimes[0] = unix.NsecToTimespec(atime.UnixNano())
	utimes[1] = unix.NsecToTimespec(mtime.UnixNano())

	if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, utimes[0:], unix.AT_SYMLINK_NOFOLLOW); err != nil {
		return errors.Wrapf(err, "failed call to UtimesNanoAt for %s", path)
	}

	return nil
}
<|endoftext|>


<commit_before>package config

import (
	"../step"
	"../util"
	"bufio"
	"fmt"
	"time"
)

func GetOdroidStepList(w *bufio.Writer, c *step.StepConfig) *step.StepList {
	// Initialize steps
	stEnterUboot := &step.Step{
		Trigger: "ModeKey Check...",
		OnTrigger: func() {
			util.MustSendCmd(w, "\n", true)
		},
		Expect:  "Exynos4412 #",
		Msg:     "Enter u-boot console",
		Timeout: 10 * time.Second,
	}

	stStartEthernet := &step.Step{
		OnTrigger: func() {
			// Double \n -> uboot bug
			util.MustSendCmd(w, "usb start\n", true)
		},
		Expect:    "1 Ethernet Device(s) found",
		Msg:       "USB Ethernet start",
		SendProbe: true,
	}

	stSetEnv := &step.Step{
		OnTrigger: func() {
			util.MustSendCmd(w, "setenv ethact sms0;setenv ipaddr "+c.IpAddr, false)
			util.MustSendCmd(w, "setenv netmask 255.255.255.0;setenv serverip "+c.ServerAddr, false)
			util.MustSendCmd(w, "setenv ethaddr "+c.MacAddr+";printenv ipaddr", true)
		},
		Expect:    "ipaddr=" + c.IpAddr,
		Msg:       "Setup environment variables",
		SendProbe: true,
	}

	stLoadKernel := &step.Step{
		OnTrigger: func() {
			util.MustSendCmd(w, "tftp 0x40008000 odroid/zImage; bootm", true)
		},
		Expect:    "Welcome to Odroid",
		Msg:       "Get zImage via tftp",
		SendProbe: true,
		Timeout:   80 * time.Second,
	}

	stLoginRoot := &step.Step{
		OnTrigger: func() {
			util.MustSendCmd(w, "root", true)
		},
		Expect:    "",
		Msg:       "Login as root",
		SendProbe: true,
	}

	stLoadModules := &step.Step{
		OnTrigger: func() {
			util.MustSendCmd(w, "modprobe usbnet; modprobe smsc95xx", true)
		},
		Expect:    "registered new interface driver smsc95xx",
		Msg:       "Load modules",
		SendProbe: true,
	}

	stBringUpEth0 := &step.Step{
		OnTrigger: func() {
			util.MustSendCmd(w, "ifconfig eth0 up", true)
		},
		Expect:    "eth0: link up",
		Msg:       "Bring up eth0",
		SendProbe: true,
	}

	stAssignIP := &step.Step{
		OnTrigger: func() {
			util.MustSendCmd(w, "ip addr add "+c.IpAddr+"/24 dev eth0", false)
			util.MustSendCmd(w, "ip addr show eth0", true)
		},
		Expect:    "inet " + c.IpAddr + "/24",
		Msg:       "Assign IP address",
		SendProbe: true,
	}

	stWriteImage := &step.Step{
		OnTrigger: func() {
			params := "--progress=dot:kilo"
			command := "wget %s http://%s/%s -O -|xzcat -|dd of=%s bs=4M"

			command = fmt.Sprintf(command, params, c.ServerAddr,
				c.ImageFilename, c.Device)
			util.MustSendCmd(w, command, true)
		},
		Expect:    "100%",
		Msg:       "Image rootFS",
		SendProbe: true,
		Timeout:   60 * 3 * time.Second,
	}

	//stUpdateUboot := &step.Step{
	//OnTrigger: func() {
	//params := "--progress=dot:dots"
	//command := "wget %s http://%s/%s -O - | tar -xz && ./update.sh"
	//command = fmt.Sprintf(command, params, c.ServerAddr, c.UbootTar)
	//util.MustSendCmd(w, command, true)
	//},
	//Expect:    "U-boot image is fused successfully",
	//Msg:       "Flash U-boot",
	//SendProbe: true,
	//Timeout:   60 * 2 * time.Second,
	//}

	stFinalReboot := &step.Step{
		OnTrigger: func() {
			util.MustSendCmd(w, "reboot", true)
		},
		Expect:    "Mounting root file system",
		Msg:       "Final reboot",
		SendProbe: true,
	}

	stepList := step.NewList()
	stepList.Append(stEnterUboot)
	stepList.Append(stSetEnv)
	stepList.Append(stStartEthernet)
	stepList.Append(stLoadKernel)
	stepList.Append(stLoginRoot)
	stepList.Append(stLoadModules)
	stepList.Append(stBringUpEth0)
	stepList.Append(stAssignIP)
	stepList.Append(stWriteImage)
	//stepList.Append(stUpdateUboot)
	stepList.Append(stFinalReboot)

	return stepList
}
<commit_msg>Postinstall step added<commit_after>package config

import (
	"../step"
	"../util"
	"bufio"
	"fmt"
	"time"
)

func GetOdroidStepList(w *bufio.Writer, c *step.StepConfig) *step.StepList {
	// Initialize steps
	stEnterUboot := &step.Step{
		Trigger: "ModeKey Check...",
		OnTrigger: func() {
			util.MustSendCmd(w, "\n", true)
		},
		Expect:  "Exynos4412 #",
		Msg:     "Enter u-boot console",
		Timeout: 10 * time.Second,
	}

	stStartEthernet := &step.Step{
		OnTrigger: func() {
			// Double \n -> uboot bug
			util.MustSendCmd(w, "usb start\n", true)
		},
		Expect:    "1 Ethernet Device(s) found",
		Msg:       "USB Ethernet start",
		SendProbe: true,
	}

	stSetEnv := &step.Step{
		OnTrigger: func() {
			util.MustSendCmd(w, "setenv ethact sms0;setenv ipaddr "+c.IpAddr, false)
			util.MustSendCmd(w, "setenv netmask 255.255.255.0;setenv serverip "+c.ServerAddr, false)
			util.MustSendCmd(w, "setenv ethaddr "+c.MacAddr+";printenv ipaddr", true)
		},
		Expect:    "ipaddr=" + c.IpAddr,
		Msg:       "Setup environment variables",
		SendProbe: true,
	}

	stLoadKernel := &step.Step{
		OnTrigger: func() {
			util.MustSendCmd(w, "tftp 0x40008000 odroid/zImage; bootm", true)
		},
		Expect:    "Welcome to Odroid",
		Msg:       "Get zImage via tftp",
		SendProbe: true,
		Timeout:   80 * time.Second,
	}

	stLoginRoot := &step.Step{
		OnTrigger: func() {
			util.MustSendCmd(w, "root", true)
		},
		Expect:    "",
		Msg:       "Login as root",
		SendProbe: true,
	}

	stLoadModules := &step.Step{
		OnTrigger: func() {
			util.MustSendCmd(w, "modprobe usbnet; modprobe smsc95xx", true)
		},
		Expect:    "registered new interface driver smsc95xx",
		Msg:       "Load modules",
		SendProbe: true,
	}

	stBringUpEth0 := &step.Step{
		OnTrigger: func() {
			util.MustSendCmd(w, "ifconfig eth0 up", true)
		},
		Expect:    "eth0: link up",
		Msg:       "Bring up eth0",
		SendProbe: true,
	}

	stAssignIP := &step.Step{
		OnTrigger: func() {
			util.MustSendCmd(w, "ip addr add "+c.IpAddr+"/24 dev eth0", false)
			util.MustSendCmd(w, "ip addr show eth0", true)
		},
		Expect:    "inet " + c.IpAddr + "/24",
		Msg:       "Assign IP address",
		SendProbe: true,
	}

	stWriteImage := &step.Step{
		OnTrigger: func() {
			params := "--progress=dot:kilo"
			command := "wget %s http://%s/%s -O -|xzcat -|dd of=%s bs=4M"

			command = fmt.Sprintf(command, params, c.ServerAddr,
				c.ImageFilename, c.Device)
			util.MustSendCmd(w, command, true)
		},
		Expect:    "100%",
		Msg:       "Image rootFS",
		SendProbe: true,
		Timeout:   60 * 3 * time.Second,
	}

	stRepartition:= &step.Step{
	   OnTrigger: func() {
			util.MustSendCmd(w, "", true)
			command := "wget http://%s/odroid/resizefs.sh && chmod +x *.sh && ./resizefs.sh"
			command = fmt.Sprintf(command, c.ServerAddr)
			util.MustSendCmd(w, command, true)
	   },
	   Expect:    "Information",
	   Msg:       "Repartition",
	   SendProbe: true,
	   Timeout:   80 * time.Second,
        }

	//stUpdateUboot := &step.Step{
	//OnTrigger: func() {
	//params := "--progress=dot:dots"
	//command := "wget %s http://%s/%s -O - | tar -xz && ./update.sh"
	//command = fmt.Sprintf(command, params, c.ServerAddr, c.UbootTar)
	//util.MustSendCmd(w, command, true)
	//},
	//Expect:    "U-boot image is fused successfully",
	//Msg:       "Flash U-boot",
	//SendProbe: true,
	//Timeout:   60 * 2 * time.Second,
	//}

	stReboot := &step.Step{
		OnTrigger: func() {
			util.MustSendCmd(w, "reboot", true)
		},
		Expect:    "Mounting root file system",
		Msg:       "Reboot",
		SendProbe: true,
	   	Timeout:   20 * time.Second,
	}

	stResizeFS := &step.Step{
		OnTrigger: func() {
			util.MustSendCmd(w, "resize2fs /dev/mmcblk0p2 && touch /forcefsck && stat /forcefsck", true)
		},
		Trigger:    "Stopping save kernel messages",
		Expect:    "empty file",
		Msg:       "Resize FS",
		SendProbe: true,
		Timeout:   20 * time.Second,
	}

	stFinalReboot := &step.Step{
		OnTrigger: func() {
			util.MustSendCmd(w, "", true)
			util.MustSendCmd(w, "reboot", true)
		},
		Expect:    "Mounting root file system",
		Msg:       "Final reboot",
		SendProbe: true,
		Timeout:   40 * time.Second,
	}

	stPostinstall := &step.Step{
		OnTrigger: func() {
			util.MustSendCmd(w, "", true)
			util.MustSendCmd(w, "wget http://beagle/postinstall/odroid/install.sh -O i.sh && chmod +x i.sh && ./i.sh >> /tmp/i.log 2>&1", true)
		},
		Trigger:   "Stopping save kernel messages",
		Expect:    "",
		Msg:       "Started postinstall",
		SendProbe: true,
		Timeout:   10 * time.Second,
	}

	stepList := step.NewList()
	stepList.Append(stEnterUboot)
	stepList.Append(stSetEnv)
	stepList.Append(stStartEthernet)
	stepList.Append(stLoadKernel)
	stepList.Append(stLoginRoot)
	stepList.Append(stLoadModules)
	stepList.Append(stBringUpEth0)
	stepList.Append(stAssignIP)
	stepList.Append(stWriteImage)
	stepList.Append(stRepartition)
	//stepList.Append(stUpdateUboot)
	stepList.Append(stReboot)
	stepList.Append(stResizeFS)
	stepList.Append(stFinalReboot)
	stepList.Append(stPostinstall)

	return stepList
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/bwmarrin/discordgo"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

type DiscordLogin struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

func main() {
	loginFile, fileErr := ioutil.ReadFile("./login.json")
	if fileErr != nil {
		fmt.Println(fileErr.Error())
		os.Exit(1)
	}

	var login DiscordLogin
	jsonErr := json.Unmarshal(loginFile, &login)

	if jsonErr != nil {
		fmt.Println(jsonErr.Error())
		os.Exit(1)
	}

	dg, err := discordgo.New(login.Username, login.Password)

	if err != nil {
		fmt.Println("Error creating session: ", err)
		os.Exit(1)
	} else {
		fmt.Println("Successfully logged in as " + login.Username)
	}

	dg.AddHandler(messageCreate)

	err = dg.Open()
	if err != nil {
		fmt.Println("Error opening connection: ", err)
		os.Exit(1)
	}

	http.HandleFunc("/chat", func(w http.ResponseWriter, r *http.Request) {
		id := r.URL.Query().Get("id")
		msg := r.URL.Query().Get("msg")
		if id != "" && msg != "" {
			dg.ChannelMessageSend(id, "Message from HTTP chat endpoint: \n`"+msg+"`")
			fmt.Fprintf(w, "You are sending: \n"+msg+"\nto channel ID: \n"+id)
		}
	})

	fmt.Println("Bot is now running.  Press CTRL-C to exit.")
	// Simple way to keep program running until CTRL-C is pressed.
	log.Fatal(http.ListenAndServe(":8080", nil))
	<-make(chan struct{})
	return
}

func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	msg := strings.Split(m.Content, " ")

	switch msg[0] {
	case "nazoupdate":
		s.ChannelMessageDelete(m.ChannelID, m.ID)
		s.ChannelMessageSend(m.ChannelID, "This is your daily reminder that <@!165846085020024832> is adorable.")
		break
	case "deltaspeak":
		s.ChannelMessageDelete(m.ChannelID, m.ID)
		s.ChannelMessageSend(m.ChannelID, "`ds:` "+m.Content[11:len(m.Content)])
		break
	}

}
<commit_msg>Added cleverbot integration<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/bwmarrin/discordgo"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
	"github.com/CleverbotIO/go-cleverbot.io"
)

// DiscordLogin is a simple struct which contains a username and password for a Discord login
type DiscordLogin struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

var cb *cleverbot.Session
var botErr error

func main() {
	loginFile, fileErr := ioutil.ReadFile("./login.json")
	if fileErr != nil {
		fmt.Println(fileErr.Error())
		os.Exit(1)
	}

	var login DiscordLogin
	jsonErr := json.Unmarshal(loginFile, &login)

	if jsonErr != nil {
		fmt.Println(jsonErr.Error())
		os.Exit(1)
	}

	dg, err := discordgo.New(login.Username, login.Password)

	if err != nil {
		fmt.Println("Error creating session: ", err)
		os.Exit(1)
	} else {
		fmt.Println("Successfully logged in as " + login.Username)
	}

	dg.AddHandler(messageCreate)

	err = dg.Open()
	if err != nil {
		fmt.Println("Error opening connection: ", err)
		os.Exit(1)
	}

	cb, botErr = cleverbot.New("JHowZe3ddT6Da0JU","8NSK1vZVH1lRNMIcTbu4hU6kGEyIDxsW","")
	if botErr != nil {
		log.Fatal(botErr)
	}

	http.HandleFunc("/chat", func(w http.ResponseWriter, r *http.Request) {
		id := r.URL.Query().Get("id")
		msg := r.URL.Query().Get("msg")
		if id != "" && msg != "" {
			dg.ChannelMessageSend(id, "Message from HTTP chat endpoint: \n`"+msg+"`")
			fmt.Fprintf(w, "You are sending: \n"+msg+"\nto channel ID: \n"+id)
		}
	})

	fmt.Println("Bot is now running.  Press CTRL-C to exit.")
	// Simple way to keep program running until CTRL-C is pressed.
	log.Fatal(http.ListenAndServe(":8080", nil))
	<-make(chan struct{})
	return
}

// messageCreate is the handler function for all incoming Discord messages
func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	msg := strings.Split(m.Content, " ")

	switch msg[0] {
	case "nazoupdate": // Reminds everyone that Nazo is adorable
		s.ChannelMessageDelete(m.ChannelID, m.ID)
		s.ChannelMessageSend(m.ChannelID, "This is your daily reminder that <@!165846085020024832> is adorable.")
		break
	case "deltaspeak": // Echoes the given text from my own user account
		s.ChannelMessageDelete(m.ChannelID, m.ID)
		s.ChannelMessageSend(m.ChannelID, "`ds:` "+m.Content[11:len(m.Content)])
		break
	case "cb": // Communicates with Cleverbot.
		response, botErr2 := cb.Ask(m.Content[2:len(m.Content)])
		if botErr2 != nil {
			log.Fatal(botErr2)
		}

		s.ChannelMessageSend(m.ChannelID, "Cleverbot says: " + response)

		break
	}
}
<|endoftext|>


<commit_before>package net

import (
	"net"
	"strconv"
)

const (
	AddrTypeIP     = byte(0x01)
	AddrTypeDomain = byte(0x03)
)

type Address struct {
	Type   byte
	IP     net.IP
	Domain string
	Port   uint16
}

func IPAddress(ip []byte, port uint16) Address {
	ipCopy := make([]byte, 4)
	copy(ipCopy, ip)
	// TODO: check IP length
	return Address{
		Type:   AddrTypeIP,
		IP:     net.IP(ipCopy),
		Domain: "",
		Port:   port,
	}
}

func DomainAddress(domain string, port uint16) Address {
	return Address{
		Type:   AddrTypeDomain,
		IP:     nil,
		Domain: domain,
		Port:   port,
	}
}

func (addr Address) IsIPv4() bool {
	return addr.Type == AddrTypeIP && len(addr.IP) == net.IPv4len
}

func (addr Address) IsIPv6() bool {
	return addr.Type == AddrTypeIP && len(addr.IP) == net.IPv6len
}

func (addr Address) IsDomain() bool {
	return addr.Type == AddrTypeDomain
}

func (addr Address) String() string {
	var host string
	switch addr.Type {
	case AddrTypeIP:
		host = addr.IP.String()
		if len(addr.IP) == net.IPv6len {
			host = "[" + host + "]"
		}

	case AddrTypeDomain:
		host = addr.Domain
	default:
		panic("Unknown Address Type " + strconv.Itoa(int(addr.Type)))
	}
	return host + ":" + strconv.Itoa(int(addr.Port))
}
<commit_msg>fix test break<commit_after>package net

import (
	"net"
	"strconv"
)

const (
	AddrTypeIP     = byte(0x01)
	AddrTypeDomain = byte(0x03)
)

type Address struct {
	Type   byte
	IP     net.IP
	Domain string
	Port   uint16
}

func IPAddress(ip []byte, port uint16) Address {
	// TODO: check IP length
	return Address{
		Type:   AddrTypeIP,
		IP:     net.IP(ip),
		Domain: "",
		Port:   port,
	}
}

func DomainAddress(domain string, port uint16) Address {
	return Address{
		Type:   AddrTypeDomain,
		IP:     nil,
		Domain: domain,
		Port:   port,
	}
}

func (addr Address) IsIPv4() bool {
	return addr.Type == AddrTypeIP && len(addr.IP) == net.IPv4len
}

func (addr Address) IsIPv6() bool {
	return addr.Type == AddrTypeIP && len(addr.IP) == net.IPv6len
}

func (addr Address) IsDomain() bool {
	return addr.Type == AddrTypeDomain
}

func (addr Address) String() string {
	var host string
	switch addr.Type {
	case AddrTypeIP:
		host = addr.IP.String()
		if len(addr.IP) == net.IPv6len {
			host = "[" + host + "]"
		}

	case AddrTypeDomain:
		host = addr.Domain
	default:
		panic("Unknown Address Type " + strconv.Itoa(int(addr.Type)))
	}
	return host + ":" + strconv.Itoa(int(addr.Port))
}
<|endoftext|>


<commit_before>//go:build linux && go1.10
// +build linux,go1.10

package netns

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"

	"golang.org/x/sys/unix"
)

// Deprecated: use syscall pkg instead (go >= 1.5 needed).
const (
	CLONE_NEWUTS  = 0x04000000   /* New utsname group? */
	CLONE_NEWIPC  = 0x08000000   /* New ipcs */
	CLONE_NEWUSER = 0x10000000   /* New user namespace */
	CLONE_NEWPID  = 0x20000000   /* New pid namespace */
	CLONE_NEWNET  = 0x40000000   /* New network namespace */
	CLONE_IO      = 0x80000000   /* Get io context */
	bindMountPath = "/run/netns" /* Bind mount path for named netns */
)

// Setns sets namespace using syscall. Note that this should be a method
// in syscall but it has not been added.
func Setns(ns NsHandle, nstype int) (err error) {
	return unix.Setns(int(ns), nstype)
}

// Set sets the current network namespace to the namespace represented
// by NsHandle.
func Set(ns NsHandle) (err error) {
	return Setns(ns, CLONE_NEWNET)
}

// New creates a new network namespace, sets it as current and returns
// a handle to it.
func New() (ns NsHandle, err error) {
	if err := unix.Unshare(CLONE_NEWNET); err != nil {
		return -1, err
	}
	return Get()
}

// NewNamed creates a new named network namespace and returns a handle to it
func NewNamed(name string) (NsHandle, error) {
	if _, err := os.Stat(bindMountPath); os.IsNotExist(err) {
		err = os.MkdirAll(bindMountPath, 0755)
		if err != nil {
			return None(), err
		}
	}

	newNs, err := New()
	if err != nil {
		return None(), err
	}

	namedPath := path.Join(bindMountPath, name)

	f, err := os.OpenFile(namedPath, os.O_CREATE|os.O_EXCL, 0444)
	if err != nil {
		return None(), err
	}
	f.Close()

	nsPath := fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), syscall.Gettid())
	err = syscall.Mount(nsPath, namedPath, "bind", syscall.MS_BIND, "")
	if err != nil {
		return None(), err
	}

	return newNs, nil
}

// DeleteNamed deletes a named network namespace
func DeleteNamed(name string) error {
	namedPath := path.Join(bindMountPath, name)

	err := syscall.Unmount(namedPath, syscall.MNT_DETACH)
	if err != nil {
		return err
	}

	return os.Remove(namedPath)
}

// Get gets a handle to the current threads network namespace.
func Get() (NsHandle, error) {
	return GetFromThread(os.Getpid(), unix.Gettid())
}

// GetFromPath gets a handle to a network namespace
// identified by the path
func GetFromPath(path string) (NsHandle, error) {
	fd, err := unix.Open(path, unix.O_RDONLY|unix.O_CLOEXEC, 0)
	if err != nil {
		return -1, err
	}
	return NsHandle(fd), nil
}

// GetFromName gets a handle to a named network namespace such as one
// created by `ip netns add`.
func GetFromName(name string) (NsHandle, error) {
	return GetFromPath(fmt.Sprintf("/var/run/netns/%s", name))
}

// GetFromPid gets a handle to the network namespace of a given pid.
func GetFromPid(pid int) (NsHandle, error) {
	return GetFromPath(fmt.Sprintf("/proc/%d/ns/net", pid))
}

// GetFromThread gets a handle to the network namespace of a given pid and tid.
func GetFromThread(pid, tid int) (NsHandle, error) {
	return GetFromPath(fmt.Sprintf("/proc/%d/task/%d/ns/net", pid, tid))
}

// GetFromDocker gets a handle to the network namespace of a docker container.
// Id is prefixed matched against the running docker containers, so a short
// identifier can be used as long as it isn't ambiguous.
func GetFromDocker(id string) (NsHandle, error) {
	pid, err := getPidForContainer(id)
	if err != nil {
		return -1, err
	}
	return GetFromPid(pid)
}

// borrowed from docker/utils/utils.go
func findCgroupMountpoint(cgroupType string) (int, string, error) {
	output, err := ioutil.ReadFile("/proc/mounts")
	if err != nil {
		return -1, "", err
	}

	// /proc/mounts has 6 fields per line, one mount per line, e.g.
	// cgroup /sys/fs/cgroup/devices cgroup rw,relatime,devices 0 0
	for _, line := range strings.Split(string(output), "\n") {
		parts := strings.Split(line, " ")
		if len(parts) == 6 {
			switch parts[2] {
			case "cgroup2":
				return 2, parts[1], nil
			case "cgroup":
				for _, opt := range strings.Split(parts[3], ",") {
					if opt == cgroupType {
						return 1, parts[1], nil
					}
				}
			}
		}
	}

	return -1, "", fmt.Errorf("cgroup mountpoint not found for %s", cgroupType)
}

// Returns the relative path to the cgroup docker is running in.
// borrowed from docker/utils/utils.go
// modified to get the docker pid instead of using /proc/self
func getDockerCgroup(cgroupVer int, cgroupType string) (string, error) {
	dockerpid, err := ioutil.ReadFile("/var/run/docker.pid")
	if err != nil {
		return "", err
	}
	result := strings.Split(string(dockerpid), "\n")
	if len(result) == 0 || len(result[0]) == 0 {
		return "", fmt.Errorf("docker pid not found in /var/run/docker.pid")
	}
	pid, err := strconv.Atoi(result[0])
	if err != nil {
		return "", err
	}
	output, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cgroup", pid))
	if err != nil {
		return "", err
	}
	for _, line := range strings.Split(string(output), "\n") {
		parts := strings.Split(line, ":")
		// any type used by docker should work
		if (cgroupVer == 1 && parts[1] == cgroupType) ||
			(cgroupVer == 2 && parts[1] == "") {
			return parts[2], nil
		}
	}
	return "", fmt.Errorf("cgroup '%s' not found in /proc/%d/cgroup", cgroupType, pid)
}

// Returns the first pid in a container.
// borrowed from docker/utils/utils.go
// modified to only return the first pid
// modified to glob with id
// modified to search for newer docker containers
// modified to look for cgroups v2
func getPidForContainer(id string) (int, error) {
	pid := 0

	// memory is chosen randomly, any cgroup used by docker works
	cgroupType := "memory"

	cgroupVer, cgroupRoot, err := findCgroupMountpoint(cgroupType)
	if err != nil {
		return pid, err
	}

	cgroupDocker, err := getDockerCgroup(cgroupVer, cgroupType)
	if err != nil {
		return pid, err
	}

	id += "*"

	var pidFile string
	if cgroupVer == 1 {
		pidFile = "tasks"
	} else if cgroupVer == 2 {
		pidFile = "cgroup.procs"
	} else {
		return -1, fmt.Errorf("Invalid cgroup version '%d'", cgroupVer)
	}

	attempts := []string{
		filepath.Join(cgroupRoot, cgroupDocker, id, pidFile),
		// With more recent lxc versions use, cgroup will be in lxc/
		filepath.Join(cgroupRoot, cgroupDocker, "lxc", id, pidFile),
		// With more recent docker, cgroup will be in docker/
		filepath.Join(cgroupRoot, cgroupDocker, "docker", id, pidFile),
		// Even more recent docker versions under systemd use docker-<id>.scope/
		filepath.Join(cgroupRoot, "system.slice", "docker-"+id+".scope", pidFile),
		// Even more recent docker versions under cgroup/systemd/docker/<id>/
		filepath.Join(cgroupRoot, "..", "systemd", "docker", id, pidFile),
		// Kubernetes with docker and CNI is even more different. Works for BestEffort and Burstable QoS
		filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "*", "pod*", id, pidFile),
		// Same as above but for Guaranteed QoS
		filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "pod*", id, pidFile),
		// Another flavor of containers location in recent kubernetes 1.11+. Works for BestEffort and Burstable QoS
		filepath.Join(cgroupRoot, cgroupDocker, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", pidFile),
		// Same as above but for Guaranteed QoS
		filepath.Join(cgroupRoot, cgroupDocker, "kubepods.slice", "*", "docker-"+id+".scope", pidFile),
		// When runs inside of a container with recent kubernetes 1.11+. Works for BestEffort and Burstable QoS
		filepath.Join(cgroupRoot, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", pidFile),
		// Same as above but for Guaranteed QoS
		filepath.Join(cgroupRoot, "kubepods.slice", "*", "docker-"+id+".scope", pidFile),
	}

	var filename string
	for _, attempt := range attempts {
		filenames, _ := filepath.Glob(attempt)
		if len(filenames) > 1 {
			return pid, fmt.Errorf("Ambiguous id supplied: %v", filenames)
		} else if len(filenames) == 1 {
			filename = filenames[0]
			break
		}
	}

	if filename == "" {
		return pid, fmt.Errorf("Unable to find container: %v", id[:len(id)-1])
	}

	output, err := ioutil.ReadFile(filename)
	if err != nil {
		return pid, err
	}

	result := strings.Split(string(output), "\n")
	if len(result) == 0 || len(result[0]) == 0 {
		return pid, fmt.Errorf("No pid found for container")
	}

	pid, err = strconv.Atoi(result[0])
	if err != nil {
		return pid, fmt.Errorf("Invalid pid '%s': %s", result[0], err)
	}

	return pid, nil
}
<commit_msg>Migrate `syscall` --> `golang.org/x/sys/unix`, redux<commit_after>//go:build linux && go1.10
// +build linux,go1.10

package netns

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"

	"golang.org/x/sys/unix"
)

// Deprecated: use golang.org/x/sys/unix pkg instead.
const (
	CLONE_NEWUTS  = 0x04000000   /* New utsname group? */
	CLONE_NEWIPC  = 0x08000000   /* New ipcs */
	CLONE_NEWUSER = 0x10000000   /* New user namespace */
	CLONE_NEWPID  = 0x20000000   /* New pid namespace */
	CLONE_NEWNET  = 0x40000000   /* New network namespace */
	CLONE_IO      = 0x80000000   /* Get io context */
	bindMountPath = "/run/netns" /* Bind mount path for named netns */
)

// Setns sets namespace using golang.org/x/sys/unix.Setns.
//
// Deprecated: Use golang.org/x/sys/unix.Setns instead.
func Setns(ns NsHandle, nstype int) (err error) {
	return unix.Setns(int(ns), nstype)
}

// Set sets the current network namespace to the namespace represented
// by NsHandle.
func Set(ns NsHandle) (err error) {
	return Setns(ns, CLONE_NEWNET)
}

// New creates a new network namespace, sets it as current and returns
// a handle to it.
func New() (ns NsHandle, err error) {
	if err := unix.Unshare(CLONE_NEWNET); err != nil {
		return -1, err
	}
	return Get()
}

// NewNamed creates a new named network namespace and returns a handle to it
func NewNamed(name string) (NsHandle, error) {
	if _, err := os.Stat(bindMountPath); os.IsNotExist(err) {
		err = os.MkdirAll(bindMountPath, 0755)
		if err != nil {
			return None(), err
		}
	}

	newNs, err := New()
	if err != nil {
		return None(), err
	}

	namedPath := path.Join(bindMountPath, name)

	f, err := os.OpenFile(namedPath, os.O_CREATE|os.O_EXCL, 0444)
	if err != nil {
		return None(), err
	}
	f.Close()

	nsPath := fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), unix.Gettid())
	err = unix.Mount(nsPath, namedPath, "bind", unix.MS_BIND, "")
	if err != nil {
		return None(), err
	}

	return newNs, nil
}

// DeleteNamed deletes a named network namespace
func DeleteNamed(name string) error {
	namedPath := path.Join(bindMountPath, name)

	err := unix.Unmount(namedPath, unix.MNT_DETACH)
	if err != nil {
		return err
	}

	return os.Remove(namedPath)
}

// Get gets a handle to the current threads network namespace.
func Get() (NsHandle, error) {
	return GetFromThread(os.Getpid(), unix.Gettid())
}

// GetFromPath gets a handle to a network namespace
// identified by the path
func GetFromPath(path string) (NsHandle, error) {
	fd, err := unix.Open(path, unix.O_RDONLY|unix.O_CLOEXEC, 0)
	if err != nil {
		return -1, err
	}
	return NsHandle(fd), nil
}

// GetFromName gets a handle to a named network namespace such as one
// created by `ip netns add`.
func GetFromName(name string) (NsHandle, error) {
	return GetFromPath(fmt.Sprintf("/var/run/netns/%s", name))
}

// GetFromPid gets a handle to the network namespace of a given pid.
func GetFromPid(pid int) (NsHandle, error) {
	return GetFromPath(fmt.Sprintf("/proc/%d/ns/net", pid))
}

// GetFromThread gets a handle to the network namespace of a given pid and tid.
func GetFromThread(pid, tid int) (NsHandle, error) {
	return GetFromPath(fmt.Sprintf("/proc/%d/task/%d/ns/net", pid, tid))
}

// GetFromDocker gets a handle to the network namespace of a docker container.
// Id is prefixed matched against the running docker containers, so a short
// identifier can be used as long as it isn't ambiguous.
func GetFromDocker(id string) (NsHandle, error) {
	pid, err := getPidForContainer(id)
	if err != nil {
		return -1, err
	}
	return GetFromPid(pid)
}

// borrowed from docker/utils/utils.go
func findCgroupMountpoint(cgroupType string) (int, string, error) {
	output, err := ioutil.ReadFile("/proc/mounts")
	if err != nil {
		return -1, "", err
	}

	// /proc/mounts has 6 fields per line, one mount per line, e.g.
	// cgroup /sys/fs/cgroup/devices cgroup rw,relatime,devices 0 0
	for _, line := range strings.Split(string(output), "\n") {
		parts := strings.Split(line, " ")
		if len(parts) == 6 {
			switch parts[2] {
			case "cgroup2":
				return 2, parts[1], nil
			case "cgroup":
				for _, opt := range strings.Split(parts[3], ",") {
					if opt == cgroupType {
						return 1, parts[1], nil
					}
				}
			}
		}
	}

	return -1, "", fmt.Errorf("cgroup mountpoint not found for %s", cgroupType)
}

// Returns the relative path to the cgroup docker is running in.
// borrowed from docker/utils/utils.go
// modified to get the docker pid instead of using /proc/self
func getDockerCgroup(cgroupVer int, cgroupType string) (string, error) {
	dockerpid, err := ioutil.ReadFile("/var/run/docker.pid")
	if err != nil {
		return "", err
	}
	result := strings.Split(string(dockerpid), "\n")
	if len(result) == 0 || len(result[0]) == 0 {
		return "", fmt.Errorf("docker pid not found in /var/run/docker.pid")
	}
	pid, err := strconv.Atoi(result[0])
	if err != nil {
		return "", err
	}
	output, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cgroup", pid))
	if err != nil {
		return "", err
	}
	for _, line := range strings.Split(string(output), "\n") {
		parts := strings.Split(line, ":")
		// any type used by docker should work
		if (cgroupVer == 1 && parts[1] == cgroupType) ||
			(cgroupVer == 2 && parts[1] == "") {
			return parts[2], nil
		}
	}
	return "", fmt.Errorf("cgroup '%s' not found in /proc/%d/cgroup", cgroupType, pid)
}

// Returns the first pid in a container.
// borrowed from docker/utils/utils.go
// modified to only return the first pid
// modified to glob with id
// modified to search for newer docker containers
// modified to look for cgroups v2
func getPidForContainer(id string) (int, error) {
	pid := 0

	// memory is chosen randomly, any cgroup used by docker works
	cgroupType := "memory"

	cgroupVer, cgroupRoot, err := findCgroupMountpoint(cgroupType)
	if err != nil {
		return pid, err
	}

	cgroupDocker, err := getDockerCgroup(cgroupVer, cgroupType)
	if err != nil {
		return pid, err
	}

	id += "*"

	var pidFile string
	if cgroupVer == 1 {
		pidFile = "tasks"
	} else if cgroupVer == 2 {
		pidFile = "cgroup.procs"
	} else {
		return -1, fmt.Errorf("Invalid cgroup version '%d'", cgroupVer)
	}

	attempts := []string{
		filepath.Join(cgroupRoot, cgroupDocker, id, pidFile),
		// With more recent lxc versions use, cgroup will be in lxc/
		filepath.Join(cgroupRoot, cgroupDocker, "lxc", id, pidFile),
		// With more recent docker, cgroup will be in docker/
		filepath.Join(cgroupRoot, cgroupDocker, "docker", id, pidFile),
		// Even more recent docker versions under systemd use docker-<id>.scope/
		filepath.Join(cgroupRoot, "system.slice", "docker-"+id+".scope", pidFile),
		// Even more recent docker versions under cgroup/systemd/docker/<id>/
		filepath.Join(cgroupRoot, "..", "systemd", "docker", id, pidFile),
		// Kubernetes with docker and CNI is even more different. Works for BestEffort and Burstable QoS
		filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "*", "pod*", id, pidFile),
		// Same as above but for Guaranteed QoS
		filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "pod*", id, pidFile),
		// Another flavor of containers location in recent kubernetes 1.11+. Works for BestEffort and Burstable QoS
		filepath.Join(cgroupRoot, cgroupDocker, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", pidFile),
		// Same as above but for Guaranteed QoS
		filepath.Join(cgroupRoot, cgroupDocker, "kubepods.slice", "*", "docker-"+id+".scope", pidFile),
		// When runs inside of a container with recent kubernetes 1.11+. Works for BestEffort and Burstable QoS
		filepath.Join(cgroupRoot, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", pidFile),
		// Same as above but for Guaranteed QoS
		filepath.Join(cgroupRoot, "kubepods.slice", "*", "docker-"+id+".scope", pidFile),
	}

	var filename string
	for _, attempt := range attempts {
		filenames, _ := filepath.Glob(attempt)
		if len(filenames) > 1 {
			return pid, fmt.Errorf("Ambiguous id supplied: %v", filenames)
		} else if len(filenames) == 1 {
			filename = filenames[0]
			break
		}
	}

	if filename == "" {
		return pid, fmt.Errorf("Unable to find container: %v", id[:len(id)-1])
	}

	output, err := ioutil.ReadFile(filename)
	if err != nil {
		return pid, err
	}

	result := strings.Split(string(output), "\n")
	if len(result) == 0 || len(result[0]) == 0 {
		return pid, fmt.Errorf("No pid found for container")
	}

	pid, err = strconv.Atoi(result[0])
	if err != nil {
		return pid, fmt.Errorf("Invalid pid '%s': %s", result[0], err)
	}

	return pid, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"strings"
)

func main() {

	http.HandleFunc("/", rootHandle)

	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal("Listen and serve:", err)
	}
}

func rootHandle(w http.ResponseWriter, r *http.Request) {
	// parse language and user-agent
	header := r.Header
	addr := r.RemoteAddr

	// get os
	h := fmt.Sprintf("%v", header)
	os := parseOs(h)
	fmt.Println(os)

	// get language
	l := parseLang(h)
	fmt.Println(l)

	// get ip
	ip := parseIP(addr)
	fmt.Println(ip)

	fmt.Fprintf(w, "%s\n", header)
	fmt.Fprintf(w, "%v\n", addr)
}

// parse ip from remote address
func parseIP(addr string) string {
	ip := strings.Split(addr, ":")[0]
	return ip
}

// parse language from header
func parseLang(h string) string {
	tag := strings.Index(h, "Accept-Language:")
	start := strings.Index(h[tag:], "[")
	start += tag + 1

	end := strings.Index(h[start:], "]")
	end += start

	l := h[start:end]

	return strings.Split(l, ";")[0]
}

// parse of from header string
func parseOs(h string) string {
	tag := strings.Index(h, "User-Agent")
	start := strings.Index(h[tag:], "(")
	start += tag + 1 // +1 to remove the first bracket

	end := strings.Index(h[start:], ")")
	end += start

	return h[start:end]
}
<commit_msg>Added comments<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strings"
)

func main() {
	http.HandleFunc("/", mainHandle)
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal("Listen and serve:", err)
	}
}

// reply struct for marshalling output data into json
type reply struct {
	Language string `json:"language"`
	Os       string `json:"software"`
	IP       string `json:"ipaddress"`
}

// mainHandle function
func mainHandle(w http.ResponseWriter, r *http.Request) {
	// parse language and user-agent
	header := r.Header
	h := fmt.Sprintf("%v", header)
	addr := r.RemoteAddr

	// get os
	os := parseOs(h)
	// get language
	l := parseLang(h)
	// get ip
	ip := parseIP(addr)

	reply := reply{Language: l, Os: os, IP: ip}

	out, err := json.MarshalIndent(reply, "", "    ")
	if err != nil {
		fmt.Println("Cannot produce json", err)
		return
	}

	// output json
	fmt.Fprintf(w, "%s\n", out)
}

//
// HELPER FUNCTIONS
//

// parse ip from remote address
func parseIP(addr string) string {
	ip := strings.Split(addr, ":")[0]
	return ip
}

// parse language from header
func parseLang(h string) string {
	tag := strings.Index(h, "Accept-Language:")
	start := strings.Index(h[tag:], "[")
	start += tag + 1

	end := strings.Index(h[start:], "]")
	end += start

	l := h[start:end]

	return strings.Split(l, ";")[0]
}

// parse of from header string
func parseOs(h string) string {
	tag := strings.Index(h, "User-Agent")
	start := strings.Index(h[tag:], "(")
	start += tag + 1 // +1 to remove the first bracket

	end := strings.Index(h[start:], ")")
	end += start

	return h[start:end]
}
<|endoftext|>


<commit_before>package main

import (
  _ "os"
  "fmt"
  "log"
  "flag"
  "net/http"

  "github.com/gorilla/mux"

  "github.com/r4start/web-tracer/tracerdb"
)

func getServeAddress() (string, string, string) {
  var host string
  var port string
  var db_name string

  flag.StringVar(&host, "host", "localhost", "IP address for listening")
  flag.StringVar(&port, "port", "4000", "Port number")
  flag.StringVar(&db_name, "dbname", "tracer.db", "Database name or path")

  flag.Parse()

  return host, port, db_name
}

func main() {
  host, port, db_name := getServeAddress()

  router := mux.NewRouter()
  router.HandleFunc("/", mainPage)
  router.NotFoundHandler = http.HandlerFunc(notFoundPage)

  writeHandler, err := tracerdb.CreateDbLogHandler(db_name)
  if err != nil {
    log.Fatal(err)
  } else {
    router.Handle("/terminal/{id:[0-9]+}", writeHandler)
  }

  http.Handle("/", router)

  bind := fmt.Sprintf("%s:%s", host, port)

  fmt.Printf("Listening on %s. Use database %s", bind, db_name)

  err = http.ListenAndServe(bind, nil)

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

func mainPage(res http.ResponseWriter, req *http.Request) {
  fmt.Fprintf(res, "Web tracer main page.")
}

func notFoundPage(res http.ResponseWriter, req *http.Request) {
  header := res.Header()
  header.Add("Location", "http://localhost")
  res.WriteHeader(302)
}
<commit_msg>Added correct redirection.<commit_after>package main

import (
  "fmt"
  "log"
  "flag"
  "net/http"

  "github.com/gorilla/mux"

  "github.com/r4start/web-tracer/tracerdb"
)

func getServeAddress() (string, string, string) {
  var host string
  var port string
  var db_name string

  flag.StringVar(&host, "host", "localhost", "IP address for listening")
  flag.StringVar(&port, "port", "4000", "Port number")
  flag.StringVar(&db_name, "dbname", "tracer.db", "Database name or path")

  flag.Parse()

  return host, port, db_name
}

func main() {
  host, port, db_name := getServeAddress()

  router := mux.NewRouter()
  router.HandleFunc("/", mainPage)
  router.NotFoundHandler = http.HandlerFunc(notFoundPage)

  writeHandler, err := tracerdb.CreateDbLogHandler(db_name)
  if err != nil {
    log.Fatal(err)
  } else {
    router.Handle("/terminal/{id:[0-9]+}", writeHandler)
  }

  http.Handle("/", router)

  bind := fmt.Sprintf("%s:%s", host, port)

  fmt.Printf("Listening on %s. Use database %s", bind, db_name)

  err = http.ListenAndServe(bind, nil)

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

func mainPage(res http.ResponseWriter, req *http.Request) {
  fmt.Fprintf(res, "Web tracer main page.")
}

func notFoundPage(res http.ResponseWriter, req *http.Request) {
  res.Header().Add("Location", "http://" + req.Host)
  res.WriteHeader(302)
}
<|endoftext|>


<commit_before>package main

import _ "github.com/joho/godotenv/autoload"
import (
	"encoding/json"
	"fmt"
	"github.com/MariaTerzieva/gotumblr"
	"os"
)

func main() {
	posts := getPosts()
	fmt.Println(len(posts))
	fmt.Println(posts[0].Title)
	fmt.Println(posts[0].Body)
	fmt.Println(posts[0].Post_url)
}

func getPosts() []gotumblr.TextPost {
	client := gotumblr.NewTumblrRestClient(
		os.Getenv("CONSUMER_KEY"),
		os.Getenv("CONSUMER_SECRET"),
		os.Getenv("TOKEN"),
		os.Getenv("TOKEN_SECRET"),
		"https://www.albertyw.com/",
		"http://api.tumblr.com",
	)
	blogname := "devopsreactions.tumblr.com"
	blogtypes := "text"
	options := map[string]string{}
	postsResponse := client.Posts(blogname, blogtypes, options)
	posts := parsePosts(postsResponse)
	return posts
}

func parsePosts(postsResponse gotumblr.PostsResponse) []gotumblr.TextPost {
	var posts []gotumblr.TextPost
	var post gotumblr.TextPost
	for _, element := range postsResponse.Posts {
		err := json.Unmarshal(element, &post)
		if err != nil {
			fmt.Println(err)
		} else {
			posts = append(posts, post)
		}
	}
	return posts
}
<commit_msg>Add ability to set offset and limit<commit_after>package main

import _ "github.com/joho/godotenv/autoload"
import (
	"encoding/json"
	"fmt"
	"github.com/MariaTerzieva/gotumblr"
	"os"
)

func main() {
	posts := getPosts()
	fmt.Println(len(posts))
	fmt.Println(posts[0].Title)
	fmt.Println(posts[0].Body)
	fmt.Println(posts[0].Post_url)
}

func getPosts() []gotumblr.TextPost {
	client := gotumblr.NewTumblrRestClient(
		os.Getenv("CONSUMER_KEY"),
		os.Getenv("CONSUMER_SECRET"),
		os.Getenv("TOKEN"),
		os.Getenv("TOKEN_SECRET"),
		"https://www.albertyw.com/",
		"http://api.tumblr.com",
	)
	blogname := "devopsreactions.tumblr.com"
	blogtypes := "text"
	options := map[string]string{}
	options["offset"] = "1"
	options["limit"] = "5"
	postsResponse := client.Posts(blogname, blogtypes, options)
	posts := parsePosts(postsResponse)
	return posts
}

func parsePosts(postsResponse gotumblr.PostsResponse) []gotumblr.TextPost {
	var posts []gotumblr.TextPost
	var post gotumblr.TextPost
	for _, element := range postsResponse.Posts {
		err := json.Unmarshal(element, &post)
		if err != nil {
			fmt.Println(err)
		} else {
			posts = append(posts, post)
		}
	}
	return posts
}
<|endoftext|>


<commit_before>package main

import (
	"../nsq"
	"../util/notify"
	"log"
	"net"
	"os"
	"strconv"
	"time"
)

var notifyChannelChan = make(chan interface{})
var notifyTopicChan = make(chan interface{})
var syncTopicChan = make(chan *LookupPeerWrapper)
var lookupPeers = make([]*LookupPeerWrapper, 0)

var (
	LookupPeerStateDisconnected int32 = 0
	LookupPeerStateConnected    int32 = 1
	LookupPeerStateSyncing      int32 = 2
)

type LookupPeerWrapper struct {
	state int32
	peer  *nsq.LookupPeer
}

func (w *LookupPeerWrapper) Command(cmd *nsq.ProtocolCommand) ([]byte, error) {
	peer := w.peer
	initialState := w.state
	if !peer.IsConnected() {
		err := peer.Connect()
		if err != nil {
			log.Printf("LOOKUP: failed to connect to %s", peer.String())
			return nil, err
		}
		w.state = LookupPeerStateConnected
		peer.Version(nsq.LookupProtocolV1Magic)
		if initialState == LookupPeerStateDisconnected {
			go func() {
				syncTopicChan <- w
			}()
		}
	}
	err := peer.WriteCommand(cmd)
	if err != nil {
		peer.Close()
		w.state = 0
		return nil, err
	}
	resp, err := peer.ReadResponse()
	if err != nil {
		peer.Close()
		w.state = 0
		return nil, err
	}
	return resp, nil
}

// TODO: this needs a clean shutdown
func LookupRouter(lookupHosts []string) {
	if len(lookupHosts) == 0 {
		return
	}

	tcpAddr, _ := net.ResolveTCPAddr("tcp", *tcpAddress)
	hostname, err := os.Hostname()
	if err != nil {
		log.Printf("ERROR: failed to get hostname - %s", err.Error())
		return
	}

	for _, host := range lookupHosts {
		tcpAddr, err := net.ResolveTCPAddr("tcp", host)
		if err != nil {
			log.Fatal("LOOKUP: could not resolve TCP address for %s", host)
		}
		log.Printf("LOOKUP: adding peer %s", tcpAddr.String())
		lookupPeer := nsq.NewLookupPeer(tcpAddr)
		lookupPeerWrapper := &LookupPeerWrapper{
			peer: lookupPeer,
		}
		lookupPeers = append(lookupPeers, lookupPeerWrapper)
	}

	notify.Observe("new_channel", notifyChannelChan)
	notify.Observe("new_topic", notifyTopicChan)

	for {
		// so that we can stop the timer and not leak
		// see: https://groups.google.com/d/topic/golang-nuts/A597Btr_0P8/discussion
		timer := time.NewTimer(10 * time.Second)
		select {
		case <-timer.C:
			// send a heartbeat and read a response (read detects closed conns)
			for _, lookupPeer := range lookupPeers {
				log.Printf("LOOKUP: sending heartbeat to %s", lookupPeer.peer.String())
				lookupPeer.Command(lookupPeer.peer.Ping())
			}
		case newChannel := <-notifyChannelChan:
			channel := newChannel.(*Channel)
			log.Printf("LOOKUP: new channel %s", channel.name)
			// TODO: notify all nsds that a new channel exists
		case newTopic := <-notifyTopicChan:
			// notify all nsds that a new topic exists
			topic := newTopic.(*Topic)
			log.Printf("LOOKUP: new topic %s", topic.name)
			for _, lookupPeer := range lookupPeers {
				lookupPeer.Command(lookupPeer.peer.Announce(topic.name, hostname, strconv.Itoa(tcpAddr.Port)))
			}
		case lookupPeer := <-syncTopicChan:
			topicMutex.RLock()
			lookupPeer.state = LookupPeerStateSyncing
			for _, topic := range topicMap {
				lookupPeer.Command(lookupPeer.peer.Announce(topic.name, hostname, strconv.Itoa(tcpAddr.Port)))
			}
			topicMutex.RUnlock()
		}
		timer.Stop()
	}
}
<commit_msg>use ticker instead of timer, no need to clean up<commit_after>package main

import (
	"../nsq"
	"../util/notify"
	"log"
	"net"
	"os"
	"strconv"
	"time"
)

var notifyChannelChan = make(chan interface{})
var notifyTopicChan = make(chan interface{})
var syncTopicChan = make(chan *LookupPeerWrapper)
var lookupPeers = make([]*LookupPeerWrapper, 0)

var (
	LookupPeerStateDisconnected int32 = 0
	LookupPeerStateConnected    int32 = 1
	LookupPeerStateSyncing      int32 = 2
)

type LookupPeerWrapper struct {
	state int32
	peer  *nsq.LookupPeer
}

func (w *LookupPeerWrapper) Command(cmd *nsq.ProtocolCommand) ([]byte, error) {
	peer := w.peer
	initialState := w.state
	if !peer.IsConnected() {
		err := peer.Connect()
		if err != nil {
			log.Printf("LOOKUP: failed to connect to %s", peer.String())
			return nil, err
		}
		w.state = LookupPeerStateConnected
		peer.Version(nsq.LookupProtocolV1Magic)
		if initialState == LookupPeerStateDisconnected {
			go func() {
				syncTopicChan <- w
			}()
		}
	}
	err := peer.WriteCommand(cmd)
	if err != nil {
		peer.Close()
		w.state = 0
		return nil, err
	}
	resp, err := peer.ReadResponse()
	if err != nil {
		peer.Close()
		w.state = 0
		return nil, err
	}
	return resp, nil
}

// TODO: this needs a clean shutdown
func LookupRouter(lookupHosts []string) {
	if len(lookupHosts) == 0 {
		return
	}

	tcpAddr, _ := net.ResolveTCPAddr("tcp", *tcpAddress)
	hostname, err := os.Hostname()
	if err != nil {
		log.Printf("ERROR: failed to get hostname - %s", err.Error())
		return
	}

	for _, host := range lookupHosts {
		tcpAddr, err := net.ResolveTCPAddr("tcp", host)
		if err != nil {
			log.Fatal("LOOKUP: could not resolve TCP address for %s", host)
		}
		log.Printf("LOOKUP: adding peer %s", tcpAddr.String())
		lookupPeer := nsq.NewLookupPeer(tcpAddr)
		lookupPeerWrapper := &LookupPeerWrapper{
			peer: lookupPeer,
		}
		lookupPeers = append(lookupPeers, lookupPeerWrapper)
	}

	notify.Observe("new_channel", notifyChannelChan)
	notify.Observe("new_topic", notifyTopicChan)

	ticker := time.Tick(15 * time.Second)
	for {
		select {
		case <-ticker:
			// send a heartbeat and read a response (read detects closed conns)
			for _, lookupPeer := range lookupPeers {
				log.Printf("LOOKUP: sending heartbeat to %s", lookupPeer.peer.String())
				lookupPeer.Command(lookupPeer.peer.Ping())
			}
		case newChannel := <-notifyChannelChan:
			channel := newChannel.(*Channel)
			log.Printf("LOOKUP: new channel %s", channel.name)
			// TODO: notify all nsds that a new channel exists
		case newTopic := <-notifyTopicChan:
			// notify all nsds that a new topic exists
			topic := newTopic.(*Topic)
			log.Printf("LOOKUP: new topic %s", topic.name)
			for _, lookupPeer := range lookupPeers {
				lookupPeer.Command(lookupPeer.peer.Announce(topic.name, hostname, strconv.Itoa(tcpAddr.Port)))
			}
		case lookupPeer := <-syncTopicChan:
			topicMutex.RLock()
			lookupPeer.state = LookupPeerStateSyncing
			for _, topic := range topicMap {
				lookupPeer.Command(lookupPeer.peer.Announce(topic.name, hostname, strconv.Itoa(tcpAddr.Port)))
			}
			topicMutex.RUnlock()
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"go/build"
	"internal/testenv"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"sync"
	"testing"
)

func TestMain(m *testing.M) {
	flag.Parse()
	for _, c := range contexts {
		c.Compiler = build.Default.Compiler
	}
	build.Default.GOROOT = testenv.GOROOT(nil)

	// Warm up the import cache in parallel.
	var wg sync.WaitGroup
	for _, context := range contexts {
		context := context
		wg.Add(1)
		go func() {
			defer wg.Done()
			_ = NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
		}()
	}
	wg.Wait()

	os.Exit(m.Run())
}

var (
	updateGolden = flag.Bool("updategolden", false, "update golden files")
)

func TestGolden(t *testing.T) {
	td, err := os.Open("testdata/src/pkg")
	if err != nil {
		t.Fatal(err)
	}
	fis, err := td.Readdir(0)
	if err != nil {
		t.Fatal(err)
	}
	for _, fi := range fis {
		if !fi.IsDir() {
			continue
		}

		// TODO(gri) remove extra pkg directory eventually
		goldenFile := filepath.Join("testdata", "src", "pkg", fi.Name(), "golden.txt")
		w := NewWalker(nil, "testdata/src/pkg")
		pkg, _ := w.Import(fi.Name())
		w.export(pkg)

		if *updateGolden {
			os.Remove(goldenFile)
			f, err := os.Create(goldenFile)
			if err != nil {
				t.Fatal(err)
			}
			for _, feat := range w.Features() {
				fmt.Fprintf(f, "%s\n", feat)
			}
			f.Close()
		}

		bs, err := os.ReadFile(goldenFile)
		if err != nil {
			t.Fatalf("opening golden.txt for package %q: %v", fi.Name(), err)
		}
		wanted := strings.Split(string(bs), "\n")
		sort.Strings(wanted)
		for _, feature := range wanted {
			if feature == "" {
				continue
			}
			_, ok := w.features[feature]
			if !ok {
				t.Errorf("package %s: missing feature %q", fi.Name(), feature)
			}
			delete(w.features, feature)
		}

		for _, feature := range w.Features() {
			t.Errorf("package %s: extra feature not in golden file: %q", fi.Name(), feature)
		}
	}
}

func TestCompareAPI(t *testing.T) {
	tests := []struct {
		name                                    string
		features, required, optional, exception []string
		ok                                      bool   // want
		out                                     string // want
	}{
		{
			name:     "feature added",
			features: []string{"A", "B", "C", "D", "E", "F"},
			required: []string{"B", "D"},
			ok:       true,
			out:      "+A\n+C\n+E\n+F\n",
		},
		{
			name:     "feature removed",
			features: []string{"C", "A"},
			required: []string{"A", "B", "C"},
			ok:       false,
			out:      "-B\n",
		},
		{
			name:     "feature added then removed",
			features: []string{"A", "C"},
			optional: []string{"B"},
			required: []string{"A", "C"},
			ok:       true,
			out:      "±B\n",
		},
		{
			name:      "exception removal",
			required:  []string{"A", "B", "C"},
			features:  []string{"A", "C"},
			exception: []string{"B"},
			ok:        true,
			out:       "",
		},
		{
			// https://golang.org/issue/4303
			name: "contexts reconverging",
			required: []string{
				"A",
				"pkg syscall (darwin-amd64), type RawSockaddrInet6 struct",
			},
			features: []string{
				"A",
				"pkg syscall, type RawSockaddrInet6 struct",
			},
			ok:  true,
			out: "+pkg syscall, type RawSockaddrInet6 struct\n",
		},
	}
	for _, tt := range tests {
		buf := new(strings.Builder)
		gotok := compareAPI(buf, tt.features, tt.required, tt.optional, tt.exception, true)
		if gotok != tt.ok {
			t.Errorf("%s: ok = %v; want %v", tt.name, gotok, tt.ok)
		}
		if got := buf.String(); got != tt.out {
			t.Errorf("%s: output differs\nGOT:\n%s\nWANT:\n%s", tt.name, got, tt.out)
		}
	}
}

func TestSkipInternal(t *testing.T) {
	tests := []struct {
		pkg  string
		want bool
	}{
		{"net/http", true},
		{"net/http/internal-foo", true},
		{"net/http/internal", false},
		{"net/http/internal/bar", false},
		{"internal/foo", false},
		{"internal", false},
	}
	for _, tt := range tests {
		got := !internalPkg.MatchString(tt.pkg)
		if got != tt.want {
			t.Errorf("%s is internal = %v; want %v", tt.pkg, got, tt.want)
		}
	}
}

func BenchmarkAll(b *testing.B) {
	for i := 0; i < b.N; i++ {
		for _, context := range contexts {
			w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
			for _, name := range w.stdPackages {
				pkg, _ := w.Import(name)
				w.export(pkg)
			}
			w.Features()
		}
	}
}

func TestIssue21181(t *testing.T) {
	for _, context := range contexts {
		w := NewWalker(context, "testdata/src/issue21181")
		pkg, err := w.Import("p")
		if err != nil {
			t.Fatalf("%s: (%s-%s) %s %v", err, context.GOOS, context.GOARCH,
				pkg.Name(), w.imported)
		}
		w.export(pkg)
	}
}

func TestIssue29837(t *testing.T) {
	for _, context := range contexts {
		w := NewWalker(context, "testdata/src/issue29837")
		_, err := w.Import("p")
		if _, nogo := err.(*build.NoGoError); !nogo {
			t.Errorf("expected *build.NoGoError, got %T", err)
		}
	}
}

func TestIssue41358(t *testing.T) {
	context := new(build.Context)
	*context = build.Default
	context.Dir = filepath.Join(context.GOROOT, "src")

	w := NewWalker(context, context.Dir)
	for _, pkg := range w.stdPackages {
		if strings.HasPrefix(pkg, "vendor/") || strings.HasPrefix(pkg, "golang.org/x/") {
			t.Fatalf("stdPackages contains unexpected package %s", pkg)
		}
	}
}
<commit_msg>cmd/api: skip tests on platforms that cannot exec<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"go/build"
	"internal/testenv"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"sync"
	"testing"
)

func TestMain(m *testing.M) {
	if !testenv.HasExec() {
		os.Stdout.WriteString("skipping test: platform cannot exec")
		os.Exit(0)
	}

	flag.Parse()
	for _, c := range contexts {
		c.Compiler = build.Default.Compiler
	}
	build.Default.GOROOT = testenv.GOROOT(nil)

	// Warm up the import cache in parallel.
	var wg sync.WaitGroup
	for _, context := range contexts {
		context := context
		wg.Add(1)
		go func() {
			defer wg.Done()
			_ = NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
		}()
	}
	wg.Wait()

	os.Exit(m.Run())
}

var (
	updateGolden = flag.Bool("updategolden", false, "update golden files")
)

func TestGolden(t *testing.T) {
	td, err := os.Open("testdata/src/pkg")
	if err != nil {
		t.Fatal(err)
	}
	fis, err := td.Readdir(0)
	if err != nil {
		t.Fatal(err)
	}
	for _, fi := range fis {
		if !fi.IsDir() {
			continue
		}

		// TODO(gri) remove extra pkg directory eventually
		goldenFile := filepath.Join("testdata", "src", "pkg", fi.Name(), "golden.txt")
		w := NewWalker(nil, "testdata/src/pkg")
		pkg, _ := w.Import(fi.Name())
		w.export(pkg)

		if *updateGolden {
			os.Remove(goldenFile)
			f, err := os.Create(goldenFile)
			if err != nil {
				t.Fatal(err)
			}
			for _, feat := range w.Features() {
				fmt.Fprintf(f, "%s\n", feat)
			}
			f.Close()
		}

		bs, err := os.ReadFile(goldenFile)
		if err != nil {
			t.Fatalf("opening golden.txt for package %q: %v", fi.Name(), err)
		}
		wanted := strings.Split(string(bs), "\n")
		sort.Strings(wanted)
		for _, feature := range wanted {
			if feature == "" {
				continue
			}
			_, ok := w.features[feature]
			if !ok {
				t.Errorf("package %s: missing feature %q", fi.Name(), feature)
			}
			delete(w.features, feature)
		}

		for _, feature := range w.Features() {
			t.Errorf("package %s: extra feature not in golden file: %q", fi.Name(), feature)
		}
	}
}

func TestCompareAPI(t *testing.T) {
	tests := []struct {
		name                                    string
		features, required, optional, exception []string
		ok                                      bool   // want
		out                                     string // want
	}{
		{
			name:     "feature added",
			features: []string{"A", "B", "C", "D", "E", "F"},
			required: []string{"B", "D"},
			ok:       true,
			out:      "+A\n+C\n+E\n+F\n",
		},
		{
			name:     "feature removed",
			features: []string{"C", "A"},
			required: []string{"A", "B", "C"},
			ok:       false,
			out:      "-B\n",
		},
		{
			name:     "feature added then removed",
			features: []string{"A", "C"},
			optional: []string{"B"},
			required: []string{"A", "C"},
			ok:       true,
			out:      "±B\n",
		},
		{
			name:      "exception removal",
			required:  []string{"A", "B", "C"},
			features:  []string{"A", "C"},
			exception: []string{"B"},
			ok:        true,
			out:       "",
		},
		{
			// https://golang.org/issue/4303
			name: "contexts reconverging",
			required: []string{
				"A",
				"pkg syscall (darwin-amd64), type RawSockaddrInet6 struct",
			},
			features: []string{
				"A",
				"pkg syscall, type RawSockaddrInet6 struct",
			},
			ok:  true,
			out: "+pkg syscall, type RawSockaddrInet6 struct\n",
		},
	}
	for _, tt := range tests {
		buf := new(strings.Builder)
		gotok := compareAPI(buf, tt.features, tt.required, tt.optional, tt.exception, true)
		if gotok != tt.ok {
			t.Errorf("%s: ok = %v; want %v", tt.name, gotok, tt.ok)
		}
		if got := buf.String(); got != tt.out {
			t.Errorf("%s: output differs\nGOT:\n%s\nWANT:\n%s", tt.name, got, tt.out)
		}
	}
}

func TestSkipInternal(t *testing.T) {
	tests := []struct {
		pkg  string
		want bool
	}{
		{"net/http", true},
		{"net/http/internal-foo", true},
		{"net/http/internal", false},
		{"net/http/internal/bar", false},
		{"internal/foo", false},
		{"internal", false},
	}
	for _, tt := range tests {
		got := !internalPkg.MatchString(tt.pkg)
		if got != tt.want {
			t.Errorf("%s is internal = %v; want %v", tt.pkg, got, tt.want)
		}
	}
}

func BenchmarkAll(b *testing.B) {
	for i := 0; i < b.N; i++ {
		for _, context := range contexts {
			w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
			for _, name := range w.stdPackages {
				pkg, _ := w.Import(name)
				w.export(pkg)
			}
			w.Features()
		}
	}
}

func TestIssue21181(t *testing.T) {
	for _, context := range contexts {
		w := NewWalker(context, "testdata/src/issue21181")
		pkg, err := w.Import("p")
		if err != nil {
			t.Fatalf("%s: (%s-%s) %s %v", err, context.GOOS, context.GOARCH,
				pkg.Name(), w.imported)
		}
		w.export(pkg)
	}
}

func TestIssue29837(t *testing.T) {
	for _, context := range contexts {
		w := NewWalker(context, "testdata/src/issue29837")
		_, err := w.Import("p")
		if _, nogo := err.(*build.NoGoError); !nogo {
			t.Errorf("expected *build.NoGoError, got %T", err)
		}
	}
}

func TestIssue41358(t *testing.T) {
	context := new(build.Context)
	*context = build.Default
	context.Dir = filepath.Join(context.GOROOT, "src")

	w := NewWalker(context, context.Dir)
	for _, pkg := range w.stdPackages {
		if strings.HasPrefix(pkg, "vendor/") || strings.HasPrefix(pkg, "golang.org/x/") {
			t.Fatalf("stdPackages contains unexpected package %s", pkg)
		}
	}
}
<|endoftext|>