<commit_before>// Copyright 2012 Gary Burd
//
// 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 redis_test

import (
	"bufio"
	"bytes"
	"errors"
	"math"
	"net"
	"reflect"
	"strings"
	"testing"
	"time"

	"github.com/garyburd/redigo/redis"
)

var writeTests = []struct {
	args     []interface{}
	expected string
}{
	{
		[]interface{}{"SET", "foo", "bar"},
		"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",
	},
	{
		[]interface{}{"SET", "foo", "bar"},
		"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",
	},
	{
		[]interface{}{"SET", "foo", byte(100)},
		"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\n100\r\n",
	},
	{
		[]interface{}{"SET", "foo", 100},
		"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\n100\r\n",
	},
	{
		[]interface{}{"SET", "foo", int64(math.MinInt64)},
		"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$20\r\n-9223372036854775808\r\n",
	},
	{
		[]interface{}{"SET", "foo", float64(1349673917.939762)},
		"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$21\r\n1.349673917939762e+09\r\n",
	},
	{
		[]interface{}{"SET", "", []byte("foo")},
		"*3\r\n$3\r\nSET\r\n$0\r\n\r\n$3\r\nfoo\r\n",
	},
	{
		[]interface{}{"SET", nil, []byte("foo")},
		"*3\r\n$3\r\nSET\r\n$0\r\n\r\n$3\r\nfoo\r\n",
	},
}

func TestWrite(t *testing.T) {
	for _, tt := range writeTests {
		var buf bytes.Buffer
		rw := bufio.ReadWriter{Writer: bufio.NewWriter(&buf)}
		c := redis.NewConnBufio(rw)
		err := c.Send(tt.args[0].(string), tt.args[1:]...)
		if err != nil {
			t.Errorf("Send(%v) returned error %v", tt.args, err)
			continue
		}
		rw.Flush()
		actual := buf.String()
		if actual != tt.expected {
			t.Errorf("Send(%v) = %q, want %q", tt.args, actual, tt.expected)
		}
	}
}

var errorSentinel = &struct{}{}

var readTests = []struct {
	reply    string
	expected interface{}
}{
	{
		"+OK\r\n",
		"OK",
	},
	{
		"+PONG\r\n",
		"PONG",
	},
	{
		"@OK\r\n",
		errorSentinel,
	},
	{
		"$6\r\nfoobar\r\n",
		[]byte("foobar"),
	},
	{
		"$-1\r\n",
		nil,
	},
	{
		":1\r\n",
		int64(1),
	},
	{
		":-2\r\n",
		int64(-2),
	},
	{
		"*0\r\n",
		[]interface{}{},
	},
	{
		"*-1\r\n",
		nil,
	},
	{
		"*4\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$5\r\nHello\r\n$5\r\nWorld\r\n",
		[]interface{}{[]byte("foo"), []byte("bar"), []byte("Hello"), []byte("World")},
	},
	{
		"*3\r\n$3\r\nfoo\r\n$-1\r\n$3\r\nbar\r\n",
		[]interface{}{[]byte("foo"), nil, []byte("bar")},
	},
}

func TestRead(t *testing.T) {
	for _, tt := range readTests {
		rw := bufio.ReadWriter{
			Reader: bufio.NewReader(strings.NewReader(tt.reply)),
			Writer: bufio.NewWriter(nil), // writer need to support Flush
		}
		c := redis.NewConnBufio(rw)
		actual, err := c.Receive()
		if tt.expected == errorSentinel {
			if err == nil {
				t.Errorf("Receive(%q) did not return expected error", tt.reply)
			}
		} else {
			if err != nil {
				t.Errorf("Receive(%q) returned error %v", tt.reply, err)
				continue
			}
			if !reflect.DeepEqual(actual, tt.expected) {
				t.Errorf("Receive(%q) = %v, want %v", tt.reply, actual, tt.expected)
			}
		}
	}
}

type testConn struct {
	redis.Conn
}

func (t testConn) Close() error {
	_, err := t.Conn.Do("SELECT", "9")
	if err != nil {
		return nil
	}
	_, err = t.Conn.Do("FLUSHDB")
	if err != nil {
		return err
	}
	return t.Conn.Close()
}

func dial() (redis.Conn, error) {
	c, err := redis.DialTimeout("tcp", ":6379", 0, 1*time.Second, 1*time.Second)
	if err != nil {
		return nil, err
	}

	_, err = c.Do("SELECT", "9")
	if err != nil {
		return nil, err
	}

	n, err := redis.Int(c.Do("DBSIZE"))
	if err != nil {
		return nil, err
	}

	if n != 0 {
		return nil, errors.New("Database #9 is not empty, test can not continue")
	}

	return testConn{c}, nil
}

func dialt(t *testing.T) redis.Conn {
	c, err := dial()
	if err != nil {
		t.Fatalf("error connection to database, %v", err)
	}
	return c
}

var testCommands = []struct {
	args     []interface{}
	expected interface{}
}{
	{
		[]interface{}{"PING"},
		"PONG",
	},
	{
		[]interface{}{"SET", "foo", "bar"},
		"OK",
	},
	{
		[]interface{}{"GET", "foo"},
		[]byte("bar"),
	},
	{
		[]interface{}{"GET", "nokey"},
		nil,
	},
	{
		[]interface{}{"MGET", "nokey", "foo"},
		[]interface{}{nil, []byte("bar")},
	},
	{
		[]interface{}{"INCR", "mycounter"},
		int64(1),
	},
	{
		[]interface{}{"LPUSH", "mylist", "foo"},
		int64(1),
	},
	{
		[]interface{}{"LPUSH", "mylist", "bar"},
		int64(2),
	},
	{
		[]interface{}{"LRANGE", "mylist", 0, -1},
		[]interface{}{[]byte("bar"), []byte("foo")},
	},
	{
		[]interface{}{"MULTI"},
		"OK",
	},
	{
		[]interface{}{"LRANGE", "mylist", 0, -1},
		"QUEUED",
	},
	{
		[]interface{}{"PING"},
		"QUEUED",
	},
	{
		[]interface{}{"EXEC"},
		[]interface{}{
			[]interface{}{[]byte("bar"), []byte("foo")},
			"PONG",
		},
	},
}

func TestDoCommands(t *testing.T) {
	c := dialt(t)
	defer c.Close()

	for _, cmd := range testCommands {
		actual, err := c.Do(cmd.args[0].(string), cmd.args[1:]...)
		if err != nil {
			t.Errorf("Do(%v) returned error %v", cmd.args, err)
			continue
		}
		if !reflect.DeepEqual(actual, cmd.expected) {
			t.Errorf("Do(%v) = %v, want %v", cmd.args, actual, cmd.expected)
		}
	}
}

func TestPipelineCommands(t *testing.T) {
	c := dialt(t)
	defer c.Close()

	for _, cmd := range testCommands {
		if err := c.Send(cmd.args[0].(string), cmd.args[1:]...); err != nil {
			t.Fatalf("Send(%v) returned error %v", cmd.args, err)
		}
	}
	if err := c.Flush(); err != nil {
		t.Errorf("Flush() returned error %v", err)
	}
	for _, cmd := range testCommands {
		actual, err := c.Receive()
		if err != nil {
			t.Fatalf("Receive(%v) returned error %v", cmd.args, err)
		}
		if !reflect.DeepEqual(actual, cmd.expected) {
			t.Errorf("Receive(%v) = %v, want %v", cmd.args, actual, cmd.expected)
		}
	}
}

func TestBlankCommmand(t *testing.T) {
	c := dialt(t)
	defer c.Close()

	for _, cmd := range testCommands {
		if err := c.Send(cmd.args[0].(string), cmd.args[1:]...); err != nil {
			t.Fatalf("Send(%v) returned error %v", cmd.args, err)
		}
	}
	reply, err := redis.Values(c.Do(""))
	if err != nil {
		t.Fatalf("Do() returned error %v", err)
	}
	if len(reply) != len(testCommands) {
		t.Fatalf("len(reply)=%d, want %d", len(reply), len(testCommands))
	}
	for i, cmd := range testCommands {
		actual := reply[i]
		if !reflect.DeepEqual(actual, cmd.expected) {
			t.Errorf("Receive(%v) = %v, want %v", cmd.args, actual, cmd.expected)
		}
	}
}

func TestError(t *testing.T) {
	c := dialt(t)
	defer c.Close()

	c.Do("SET", "key", "val")
	_, err := c.Do("HSET", "key", "fld", "val")
	if err == nil {
		t.Errorf("Expected err for HSET on string key.")
	}
	if c.Err() != nil {
		t.Errorf("Conn has Err()=%v, expect nil", c.Err())
	}
	_, err = c.Do("SET", "key", "val")
	if err != nil {
		t.Errorf("Do(SET, key, val) returned error %v, expected nil.", err)
	}
}

func TestReadDeadline(t *testing.T) {
	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("net.Listen returned %v", err)
	}
	defer l.Close()

	go func() {
		for {
			c, err := l.Accept()
			if err != nil {
				return
			}
			go func() {
				time.Sleep(time.Second)
				c.Write([]byte("+OK\r\n"))
				c.Close()
			}()
		}
	}()

	c1, err := redis.DialTimeout(l.Addr().Network(), l.Addr().String(), 0, time.Millisecond, 0)
	if err != nil {
		t.Fatalf("redis.Dial returned %v", err)
	}
	defer c1.Close()

	_, err = c1.Do("PING")
	if err == nil {
		t.Fatalf("Do did not return error.")
	}

	c2, err := redis.DialTimeout(l.Addr().Network(), l.Addr().String(), 0, time.Millisecond, 0)
	if err != nil {
		t.Fatalf("redis.Dial returned %v", err)
	}
	defer c2.Close()

	c2.Send("PING")
	c2.Flush()
	_, err = c2.Receive()
	if err == nil {
		t.Fatalf("Receive did not return error.")
	}
}

// Connect to local instance of Redis running on the default port.
func ExampleDial(x int) {
	c, err := redis.Dial("tcp", ":6379")
	if err != nil {
		// handle error
	}
	defer c.Close()
}
<commit_msg>Add server close test.<commit_after>// Copyright 2012 Gary Burd
//
// 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 redis_test

import (
	"bufio"
	"bytes"
	"errors"
	"math"
	"net"
	"reflect"
	"strings"
	"testing"
	"time"

	"github.com/garyburd/redigo/redis"
)

var writeTests = []struct {
	args     []interface{}
	expected string
}{
	{
		[]interface{}{"SET", "foo", "bar"},
		"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",
	},
	{
		[]interface{}{"SET", "foo", "bar"},
		"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",
	},
	{
		[]interface{}{"SET", "foo", byte(100)},
		"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\n100\r\n",
	},
	{
		[]interface{}{"SET", "foo", 100},
		"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\n100\r\n",
	},
	{
		[]interface{}{"SET", "foo", int64(math.MinInt64)},
		"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$20\r\n-9223372036854775808\r\n",
	},
	{
		[]interface{}{"SET", "foo", float64(1349673917.939762)},
		"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$21\r\n1.349673917939762e+09\r\n",
	},
	{
		[]interface{}{"SET", "", []byte("foo")},
		"*3\r\n$3\r\nSET\r\n$0\r\n\r\n$3\r\nfoo\r\n",
	},
	{
		[]interface{}{"SET", nil, []byte("foo")},
		"*3\r\n$3\r\nSET\r\n$0\r\n\r\n$3\r\nfoo\r\n",
	},
}

func TestWrite(t *testing.T) {
	for _, tt := range writeTests {
		var buf bytes.Buffer
		rw := bufio.ReadWriter{Writer: bufio.NewWriter(&buf)}
		c := redis.NewConnBufio(rw)
		err := c.Send(tt.args[0].(string), tt.args[1:]...)
		if err != nil {
			t.Errorf("Send(%v) returned error %v", tt.args, err)
			continue
		}
		rw.Flush()
		actual := buf.String()
		if actual != tt.expected {
			t.Errorf("Send(%v) = %q, want %q", tt.args, actual, tt.expected)
		}
	}
}

var errorSentinel = &struct{}{}

var readTests = []struct {
	reply    string
	expected interface{}
}{
	{
		"+OK\r\n",
		"OK",
	},
	{
		"+PONG\r\n",
		"PONG",
	},
	{
		"@OK\r\n",
		errorSentinel,
	},
	{
		"$6\r\nfoobar\r\n",
		[]byte("foobar"),
	},
	{
		"$-1\r\n",
		nil,
	},
	{
		":1\r\n",
		int64(1),
	},
	{
		":-2\r\n",
		int64(-2),
	},
	{
		"*0\r\n",
		[]interface{}{},
	},
	{
		"*-1\r\n",
		nil,
	},
	{
		"*4\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$5\r\nHello\r\n$5\r\nWorld\r\n",
		[]interface{}{[]byte("foo"), []byte("bar"), []byte("Hello"), []byte("World")},
	},
	{
		"*3\r\n$3\r\nfoo\r\n$-1\r\n$3\r\nbar\r\n",
		[]interface{}{[]byte("foo"), nil, []byte("bar")},
	},
}

func TestRead(t *testing.T) {
	for _, tt := range readTests {
		rw := bufio.ReadWriter{
			Reader: bufio.NewReader(strings.NewReader(tt.reply)),
			Writer: bufio.NewWriter(nil), // writer need to support Flush
		}
		c := redis.NewConnBufio(rw)
		actual, err := c.Receive()
		if tt.expected == errorSentinel {
			if err == nil {
				t.Errorf("Receive(%q) did not return expected error", tt.reply)
			}
		} else {
			if err != nil {
				t.Errorf("Receive(%q) returned error %v", tt.reply, err)
				continue
			}
			if !reflect.DeepEqual(actual, tt.expected) {
				t.Errorf("Receive(%q) = %v, want %v", tt.reply, actual, tt.expected)
			}
		}
	}
}

type testConn struct {
	redis.Conn
}

func (t testConn) Close() error {
	_, err := t.Conn.Do("SELECT", "9")
	if err != nil {
		return nil
	}
	_, err = t.Conn.Do("FLUSHDB")
	if err != nil {
		return err
	}
	return t.Conn.Close()
}

func dial() (redis.Conn, error) {
	c, err := redis.DialTimeout("tcp", ":6379", 0, 1*time.Second, 1*time.Second)
	if err != nil {
		return nil, err
	}

	_, err = c.Do("SELECT", "9")
	if err != nil {
		return nil, err
	}

	n, err := redis.Int(c.Do("DBSIZE"))
	if err != nil {
		return nil, err
	}

	if n != 0 {
		return nil, errors.New("Database #9 is not empty, test can not continue")
	}

	return testConn{c}, nil
}

func dialt(t *testing.T) redis.Conn {
	c, err := dial()
	if err != nil {
		t.Fatalf("error connection to database, %v", err)
	}
	return c
}

var testCommands = []struct {
	args     []interface{}
	expected interface{}
}{
	{
		[]interface{}{"PING"},
		"PONG",
	},
	{
		[]interface{}{"SET", "foo", "bar"},
		"OK",
	},
	{
		[]interface{}{"GET", "foo"},
		[]byte("bar"),
	},
	{
		[]interface{}{"GET", "nokey"},
		nil,
	},
	{
		[]interface{}{"MGET", "nokey", "foo"},
		[]interface{}{nil, []byte("bar")},
	},
	{
		[]interface{}{"INCR", "mycounter"},
		int64(1),
	},
	{
		[]interface{}{"LPUSH", "mylist", "foo"},
		int64(1),
	},
	{
		[]interface{}{"LPUSH", "mylist", "bar"},
		int64(2),
	},
	{
		[]interface{}{"LRANGE", "mylist", 0, -1},
		[]interface{}{[]byte("bar"), []byte("foo")},
	},
	{
		[]interface{}{"MULTI"},
		"OK",
	},
	{
		[]interface{}{"LRANGE", "mylist", 0, -1},
		"QUEUED",
	},
	{
		[]interface{}{"PING"},
		"QUEUED",
	},
	{
		[]interface{}{"EXEC"},
		[]interface{}{
			[]interface{}{[]byte("bar"), []byte("foo")},
			"PONG",
		},
	},
}

func TestDoCommands(t *testing.T) {
	c := dialt(t)
	defer c.Close()

	for _, cmd := range testCommands {
		actual, err := c.Do(cmd.args[0].(string), cmd.args[1:]...)
		if err != nil {
			t.Errorf("Do(%v) returned error %v", cmd.args, err)
			continue
		}
		if !reflect.DeepEqual(actual, cmd.expected) {
			t.Errorf("Do(%v) = %v, want %v", cmd.args, actual, cmd.expected)
		}
	}
}

func TestPipelineCommands(t *testing.T) {
	c := dialt(t)
	defer c.Close()

	for _, cmd := range testCommands {
		if err := c.Send(cmd.args[0].(string), cmd.args[1:]...); err != nil {
			t.Fatalf("Send(%v) returned error %v", cmd.args, err)
		}
	}
	if err := c.Flush(); err != nil {
		t.Errorf("Flush() returned error %v", err)
	}
	for _, cmd := range testCommands {
		actual, err := c.Receive()
		if err != nil {
			t.Fatalf("Receive(%v) returned error %v", cmd.args, err)
		}
		if !reflect.DeepEqual(actual, cmd.expected) {
			t.Errorf("Receive(%v) = %v, want %v", cmd.args, actual, cmd.expected)
		}
	}
}

func TestBlankCommmand(t *testing.T) {
	c := dialt(t)
	defer c.Close()

	for _, cmd := range testCommands {
		if err := c.Send(cmd.args[0].(string), cmd.args[1:]...); err != nil {
			t.Fatalf("Send(%v) returned error %v", cmd.args, err)
		}
	}
	reply, err := redis.Values(c.Do(""))
	if err != nil {
		t.Fatalf("Do() returned error %v", err)
	}
	if len(reply) != len(testCommands) {
		t.Fatalf("len(reply)=%d, want %d", len(reply), len(testCommands))
	}
	for i, cmd := range testCommands {
		actual := reply[i]
		if !reflect.DeepEqual(actual, cmd.expected) {
			t.Errorf("Receive(%v) = %v, want %v", cmd.args, actual, cmd.expected)
		}
	}
}

func TestError(t *testing.T) {
	c := dialt(t)
	defer c.Close()

	c.Do("SET", "key", "val")
	_, err := c.Do("HSET", "key", "fld", "val")
	if err == nil {
		t.Errorf("Expected err for HSET on string key.")
	}
	if c.Err() != nil {
		t.Errorf("Conn has Err()=%v, expect nil", c.Err())
	}
	_, err = c.Do("SET", "key", "val")
	if err != nil {
		t.Errorf("Do(SET, key, val) returned error %v, expected nil.", err)
	}
}

func TestReadDeadline(t *testing.T) {
	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("net.Listen returned %v", err)
	}
	defer l.Close()

	go func() {
		for {
			c, err := l.Accept()
			if err != nil {
				return
			}
			go func() {
				time.Sleep(time.Second)
				c.Write([]byte("+OK\r\n"))
				c.Close()
			}()
		}
	}()

	c1, err := redis.DialTimeout(l.Addr().Network(), l.Addr().String(), 0, time.Millisecond, 0)
	if err != nil {
		t.Fatalf("redis.Dial returned %v", err)
	}
	defer c1.Close()

	_, err = c1.Do("PING")
	if err == nil {
		t.Fatalf("c1.Do() returned nil, expect error")
	}
	if c1.Err() == nil {
		t.Fatalf("c1.Err() = nil, expect error")
	}

	c2, err := redis.DialTimeout(l.Addr().Network(), l.Addr().String(), 0, time.Millisecond, 0)
	if err != nil {
		t.Fatalf("redis.Dial returned %v", err)
	}
	defer c2.Close()

	c2.Send("PING")
	c2.Flush()
	_, err = c2.Receive()
	if err == nil {
		t.Fatalf("c2.Receive() returned nil, expect error")
	}
	if c2.Err() == nil {
		t.Fatalf("c2.Err() = nil, expect error")
	}
}

func TestCloseHandling(t *testing.T) {
	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("net.Listen returned %v", err)
	}
	defer l.Close()

	go func() {
		for {
			c, err := l.Accept()
			if err != nil {
				return
			}
			c.Close()
		}
	}()

	c1, err := redis.DialTimeout(l.Addr().Network(), l.Addr().String(), 0, time.Millisecond, 0)
	if err != nil {
		t.Fatalf("redis.Dial returned %v", err)
	}
	defer c1.Close()

	_, err = c1.Do("PING")
	if err == nil {
		t.Fatalf("c1.Do() returned nil, expect error")
	}
	if c1.Err() == nil {
		t.Fatalf("c1.Err() = nil, expect error")
	}

	c2, err := redis.DialTimeout(l.Addr().Network(), l.Addr().String(), 0, time.Millisecond, 0)
	if err != nil {
		t.Fatalf("redis.Dial returned %v", err)
	}
	defer c2.Close()

	c2.Send("PING")
	c2.Flush()
	_, err = c2.Receive()
	if err == nil {
		t.Fatalf("c2.Receive() returned nil, expect error")
	}
	if c2.Err() == nil {
		t.Fatalf("c2.Err() = nil, expect error")
	}
}

// Connect to local instance of Redis running on the default port.
func ExampleDial(x int) {
	c, err := redis.Dial("tcp", ":6379")
	if err != nil {
		// handle error
	}
	defer c.Close()
}
<|endoftext|>


<commit_before>package host

import (
	"bytes"
	"errors"
	"io"
	"net"
	"os"
	"path/filepath"
	"strconv"

	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/encoding"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)

var (
	HostCapacityErr = errors.New("host is at capacity and cannot take more files")
)

// deallocate deletes a file and restores its allocated space.
func (h *Host) deallocate(path string) error {
	fullpath := filepath.Join(h.saveDir, path)
	stat, err := os.Stat(fullpath)
	if err != nil {
		return err
	}
	h.spaceRemaining += stat.Size()
	return os.Remove(fullpath)
}

// considerContract checks that the provided transaction matches the host's
// terms, and doesn't contain any flagrant errors.
func (h *Host) considerContract(txn types.Transaction, renterKey types.SiaPublicKey) error {
	// Check that there is only one file contract.
	// TODO: check that the txn is empty except for the contract?
	if len(txn.FileContracts) != 1 {
		return errors.New("transaction should have only one file contract")
	}
	// convenience variables
	fc := txn.FileContracts[0]
	duration := fc.WindowStart - h.blockHeight
	voidAddress := types.UnlockHash{}

	// check contract fields for sanity and acceptability
	switch {
	case fc.FileSize != 0:
		return errors.New("initial file size must be 0")

	case fc.WindowStart <= h.blockHeight:
		return errors.New("window start cannot be in the past")

	case duration < h.MinDuration || duration > h.MaxDuration:
		return errors.New("duration is out of bounds")

	case fc.WindowEnd <= fc.WindowStart:
		return errors.New("window cannot end before it starts")

	case fc.WindowEnd-fc.WindowStart < h.WindowSize:
		return errors.New("challenge window is not large enough")

	case fc.FileMerkleRoot != crypto.Hash{}:
		return errors.New("bad file contract Merkle root")

	case fc.Payout.IsZero():
		return errors.New("bad file contract payout")

	case len(fc.ValidProofOutputs) != 2:
		return errors.New("bad file contract valid proof outputs")

	case len(fc.MissedProofOutputs) != 2:
		return errors.New("bad file contract missed proof outputs")

	case !fc.ValidProofOutputs[1].Value.IsZero(), !fc.MissedProofOutputs[1].Value.IsZero():
		return errors.New("file contract collateral is not zero")

	case fc.ValidProofOutputs[1].UnlockHash != h.UnlockHash:
		return errors.New("file contract valid proof output not sent to host")
	case fc.MissedProofOutputs[1].UnlockHash != voidAddress:
		return errors.New("file contract missed proof output not sent to void")
	}

	// check unlock hash
	uc := types.UnlockConditions{
		PublicKeys:         []types.SiaPublicKey{renterKey, h.publicKey},
		SignaturesRequired: 2,
	}
	if fc.UnlockHash != uc.UnlockHash() {
		return errors.New("bad file contract unlock hash")
	}

	return nil
}

// considerRevision checks that the provided file contract revision is still
// acceptable to the host.
// TODO: should take a txn and check that is only contains the single revision
func (h *Host) considerRevision(txn types.Transaction, obligation contractObligation) error {
	// Check that there is only one revision.
	// TODO: check that the txn is empty except for the revision?
	if len(txn.FileContractRevisions) != 1 {
		return errors.New("transaction should have only one revision")
	}

	// calculate minimum expected output value
	rev := txn.FileContractRevisions[0]
	fc := obligation.FileContract
	duration := types.NewCurrency64(uint64(fc.WindowStart - h.blockHeight))
	minHostPrice := types.NewCurrency64(rev.NewFileSize).Mul(duration).Mul(h.Price)
	expectedPayout := fc.Payout.Sub(fc.Tax())

	switch {
	// these fields should never change
	case rev.ParentID != obligation.ID:
		return errors.New("bad revision parent ID")
	case rev.NewWindowStart != fc.WindowStart:
		return errors.New("bad revision window start")
	case rev.NewWindowEnd != fc.WindowEnd:
		return errors.New("bad revision window end")
	case rev.NewUnlockHash != fc.UnlockHash:
		return errors.New("bad revision unlock hash")
	case rev.UnlockConditions.UnlockHash() != fc.UnlockHash:
		return errors.New("bad revision unlock conditions")
	case len(rev.NewValidProofOutputs) != 2:
		return errors.New("bad revision valid proof outputs")
	case len(rev.NewMissedProofOutputs) != 2:
		return errors.New("bad revision missed proof outputs")
	case rev.NewValidProofOutputs[1].UnlockHash != fc.ValidProofOutputs[1].UnlockHash,
		rev.NewMissedProofOutputs[1].UnlockHash != fc.MissedProofOutputs[1].UnlockHash:
		return errors.New("bad revision proof outputs")

	case rev.NewRevisionNumber <= fc.RevisionNumber:
		return errors.New("revision must have higher revision number")

	case rev.NewFileSize > uint64(h.spaceRemaining) || rev.NewFileSize > h.MaxFilesize:
		return errors.New("revision file size is too large")

	// valid and missing outputs should still sum to payout
	case rev.NewValidProofOutputs[0].Value.Add(rev.NewValidProofOutputs[1].Value).Cmp(expectedPayout) != 0,
		rev.NewMissedProofOutputs[0].Value.Add(rev.NewMissedProofOutputs[1].Value).Cmp(expectedPayout) != 0:
		return errors.New("revision outputs do not sum to original payout")

	// outputs should have been adjusted proportional to the new filesize
	case rev.NewValidProofOutputs[1].Value.Cmp(minHostPrice) <= 0:
		return errors.New("revision price is too small")
	case rev.NewMissedProofOutputs[0].Value.Cmp(rev.NewValidProofOutputs[0].Value) != 0:
		return errors.New("revision missed renter payout does not match valid payout")
	}

	return nil
}

// rpcUpload is an RPC that negotiates a file contract. Under the new scheme,
// file contracts should not initially hold any data.
func (h *Host) rpcUpload(conn net.Conn) error {
	// perform key exchange
	if err := encoding.WriteObject(conn, h.publicKey); err != nil {
		return err
	}
	var renterKey types.SiaPublicKey
	if err := encoding.ReadObject(conn, &renterKey, 256); err != nil {
		return err
	}

	// read initial transaction set
	var unsignedTxnSet []types.Transaction
	if err := encoding.ReadObject(conn, &unsignedTxnSet, maxContractLen); err != nil {
		return err
	}

	// check the contract transaction, which should be the last txn in the set.
	contractTxn := unsignedTxnSet[len(unsignedTxnSet)-1]
	lockID := h.mu.RLock()
	err := h.considerContract(contractTxn, renterKey)
	h.mu.RUnlock(lockID)
	if err != nil {
		encoding.WriteObject(conn, err.Error())
		return err
	}

	// send acceptance
	if err := encoding.WriteObject(conn, modules.AcceptResponse); err != nil {
		return err
	}

	// add collateral to txn and send. For now, we never add collateral, so no
	// changes are made.
	if err := encoding.WriteObject(conn, unsignedTxnSet); err != nil {
		return err
	}

	// read signed transaction set
	var signedTxnSet []types.Transaction
	if err := encoding.ReadObject(conn, &signedTxnSet, maxContractLen); err != nil {
		return err
	}

	// check that transaction set was not modified
	if len(signedTxnSet) != len(unsignedTxnSet) {
		return errors.New("renter sent bad signed transaction set")
	}
	for i := range signedTxnSet {
		if signedTxnSet[i].ID() != unsignedTxnSet[i].ID() {
			return errors.New("renter sent bad signed transaction set")
		}
	}

	// sign and submit to blockchain
	signedTxn, parents := signedTxnSet[len(signedTxnSet)-1], signedTxnSet[:len(signedTxnSet)-1]
	txnBuilder := h.wallet.RegisterTransaction(signedTxn, parents)
	signedTxnSet, err = txnBuilder.Sign(true)
	if err != nil {
		return err
	}
	err = h.tpool.AcceptTransactionSet(signedTxnSet)
	if err == modules.ErrDuplicateTransactionSet {
		// this can happen if the host is uploading to itself
		err = nil
	}
	if err != nil {
		return err
	}

	// send doubly-signed transaction set
	if err := encoding.WriteObject(conn, signedTxnSet); err != nil {
		return err
	}

	// Add this contract to the host's list of obligations.
	// TODO: is there a race condition here?
	lockID = h.mu.Lock()
	h.fileCounter++
	co := contractObligation{
		ID:           contractTxn.FileContractID(0),
		FileContract: contractTxn.FileContracts[0],
		Path:         filepath.Join(h.saveDir, strconv.Itoa(h.fileCounter)),
	}
	proofHeight := co.FileContract.WindowStart + StorageProofReorgDepth
	h.obligationsByHeight[proofHeight] = append(h.obligationsByHeight[proofHeight], co)
	h.obligationsByID[co.ID] = co
	h.save()
	h.mu.Unlock(lockID)

	return nil
}

// rpcRevise is an RPC that allows a renter to revise a file contract. It will
// read new revisions in a loop until the renter sends a termination signal.
func (h *Host) rpcRevise(conn net.Conn) error {
	// read ID of contract to be revised
	var fcid types.FileContractID
	if err := encoding.ReadObject(conn, &fcid, crypto.HashSize); err != nil {
		return err
	}
	lockID := h.mu.RLock()
	obligation, exists := h.obligationsByID[fcid]
	h.mu.RUnlock(lockID)
	if !exists {
		return errors.New("no record of that contract")
	}

	// need to protect against two simultaneous revisions to the same
	// contract; this can cause inconsistency and data loss, making storage
	// proofs impossible
	obligation.mu.Lock()
	defer obligation.mu.Unlock()

	// open the file in append mode
	file, err := os.OpenFile(obligation.Path, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0660)
	if err != nil {
		return err
	}
	defer func() {
		// if a newly-created file was not updated, remove it
		if stat, _ := file.Stat(); stat.Size() == 0 {
			os.Remove(obligation.Path)
		}
		file.Close()
	}()

	// rebuild current Merkle tree
	tree := crypto.NewTree()
	buf := make([]byte, crypto.SegmentSize)
	for {
		_, err := io.ReadFull(file, buf)
		if err == io.EOF {
			break
		} else if err != nil && err != io.ErrUnexpectedEOF {
			return err
		}
		tree.Push(buf)
	}

	// accept new revisions in a loop
	emptyID := types.Transaction{}.ID()
	for {
		// read proposed revision
		var revTxn types.Transaction
		if err := encoding.ReadObject(conn, &revTxn, types.BlockSizeLimit); err != nil {
			return err
		}
		// an empty transaction indicates completion
		if revTxn.ID() == emptyID {
			break
		}

		// check revision against original file contract
		lockID = h.mu.RLock()
		err := h.considerRevision(revTxn, obligation)
		h.mu.RUnlock(lockID)
		if err != nil {
			encoding.WriteObject(conn, err.Error())
			continue // don't terminate loop; subsequent revisions may be okay
		}

		// indicate acceptance
		if err := encoding.WriteObject(conn, modules.AcceptResponse); err != nil {
			return err
		}

		// read piece
		// TODO: simultaneously read into tree?
		rev := revTxn.FileContractRevisions[0]
		piece := make([]byte, rev.NewFileSize-obligation.FileContract.FileSize)
		_, err = io.ReadFull(conn, piece)
		if err != nil {
			return err
		}

		// verify Merkle root
		r := bytes.NewReader(piece)
		for {
			_, err := io.ReadFull(r, buf)
			if err == io.EOF {
				break
			} else if err != nil && err != io.ErrUnexpectedEOF {
				return err
			}
			tree.Push(buf)
		}
		if tree.Root() != rev.NewFileMerkleRoot {
			return errors.New("revision has bad Merkle root")
		}

		// manually sign the transaction
		revTxn.TransactionSignatures = append(revTxn.TransactionSignatures, types.TransactionSignature{
			ParentID:       crypto.Hash(fcid),
			CoveredFields:  types.CoveredFields{FileContractRevisions: []uint64{0}},
			PublicKeyIndex: 1, // host key is always second
		})
		encodedSig, err := crypto.SignHash(revTxn.SigHash(1), h.secretKey)
		if err != nil {
			return err
		}
		revTxn.TransactionSignatures[1].Signature = encodedSig[:]

		// send the signed transaction
		if err := encoding.WriteObject(conn, revTxn); err != nil {
			return err
		}

		// append piece to file
		if _, err := file.Write(piece); err != nil {
			return err
		}

		// save updated obligation to disk
		lockID = h.mu.Lock()
		h.spaceRemaining -= int64(len(piece))
		obligation.FileContract.RevisionNumber = rev.NewRevisionNumber
		obligation.FileContract.FileSize = rev.NewFileSize
		h.obligationsByID[obligation.ID] = obligation
		heightObligations := h.obligationsByHeight[obligation.FileContract.WindowStart+StorageProofReorgDepth]
		for i := range heightObligations {
			if heightObligations[i].ID == obligation.ID {
				heightObligations[i] = obligation
			}
		}
		h.save()
		h.mu.Unlock(lockID)
	}

	return nil
}
<commit_msg>fix deallocate path<commit_after>package host

import (
	"bytes"
	"errors"
	"io"
	"net"
	"os"
	"path/filepath"
	"strconv"

	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/encoding"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)

var (
	HostCapacityErr = errors.New("host is at capacity and cannot take more files")
)

// deallocate deletes a file and restores its allocated space.
func (h *Host) deallocate(path string) error {
	stat, err := os.Stat(path)
	if err != nil {
		return err
	}
	h.spaceRemaining += stat.Size()
	return os.Remove(path)
}

// considerContract checks that the provided transaction matches the host's
// terms, and doesn't contain any flagrant errors.
func (h *Host) considerContract(txn types.Transaction, renterKey types.SiaPublicKey) error {
	// Check that there is only one file contract.
	// TODO: check that the txn is empty except for the contract?
	if len(txn.FileContracts) != 1 {
		return errors.New("transaction should have only one file contract")
	}
	// convenience variables
	fc := txn.FileContracts[0]
	duration := fc.WindowStart - h.blockHeight
	voidAddress := types.UnlockHash{}

	// check contract fields for sanity and acceptability
	switch {
	case fc.FileSize != 0:
		return errors.New("initial file size must be 0")

	case fc.WindowStart <= h.blockHeight:
		return errors.New("window start cannot be in the past")

	case duration < h.MinDuration || duration > h.MaxDuration:
		return errors.New("duration is out of bounds")

	case fc.WindowEnd <= fc.WindowStart:
		return errors.New("window cannot end before it starts")

	case fc.WindowEnd-fc.WindowStart < h.WindowSize:
		return errors.New("challenge window is not large enough")

	case fc.FileMerkleRoot != crypto.Hash{}:
		return errors.New("bad file contract Merkle root")

	case fc.Payout.IsZero():
		return errors.New("bad file contract payout")

	case len(fc.ValidProofOutputs) != 2:
		return errors.New("bad file contract valid proof outputs")

	case len(fc.MissedProofOutputs) != 2:
		return errors.New("bad file contract missed proof outputs")

	case !fc.ValidProofOutputs[1].Value.IsZero(), !fc.MissedProofOutputs[1].Value.IsZero():
		return errors.New("file contract collateral is not zero")

	case fc.ValidProofOutputs[1].UnlockHash != h.UnlockHash:
		return errors.New("file contract valid proof output not sent to host")
	case fc.MissedProofOutputs[1].UnlockHash != voidAddress:
		return errors.New("file contract missed proof output not sent to void")
	}

	// check unlock hash
	uc := types.UnlockConditions{
		PublicKeys:         []types.SiaPublicKey{renterKey, h.publicKey},
		SignaturesRequired: 2,
	}
	if fc.UnlockHash != uc.UnlockHash() {
		return errors.New("bad file contract unlock hash")
	}

	return nil
}

// considerRevision checks that the provided file contract revision is still
// acceptable to the host.
// TODO: should take a txn and check that is only contains the single revision
func (h *Host) considerRevision(txn types.Transaction, obligation contractObligation) error {
	// Check that there is only one revision.
	// TODO: check that the txn is empty except for the revision?
	if len(txn.FileContractRevisions) != 1 {
		return errors.New("transaction should have only one revision")
	}

	// calculate minimum expected output value
	rev := txn.FileContractRevisions[0]
	fc := obligation.FileContract
	duration := types.NewCurrency64(uint64(fc.WindowStart - h.blockHeight))
	minHostPrice := types.NewCurrency64(rev.NewFileSize).Mul(duration).Mul(h.Price)
	expectedPayout := fc.Payout.Sub(fc.Tax())

	switch {
	// these fields should never change
	case rev.ParentID != obligation.ID:
		return errors.New("bad revision parent ID")
	case rev.NewWindowStart != fc.WindowStart:
		return errors.New("bad revision window start")
	case rev.NewWindowEnd != fc.WindowEnd:
		return errors.New("bad revision window end")
	case rev.NewUnlockHash != fc.UnlockHash:
		return errors.New("bad revision unlock hash")
	case rev.UnlockConditions.UnlockHash() != fc.UnlockHash:
		return errors.New("bad revision unlock conditions")
	case len(rev.NewValidProofOutputs) != 2:
		return errors.New("bad revision valid proof outputs")
	case len(rev.NewMissedProofOutputs) != 2:
		return errors.New("bad revision missed proof outputs")
	case rev.NewValidProofOutputs[1].UnlockHash != fc.ValidProofOutputs[1].UnlockHash,
		rev.NewMissedProofOutputs[1].UnlockHash != fc.MissedProofOutputs[1].UnlockHash:
		return errors.New("bad revision proof outputs")

	case rev.NewRevisionNumber <= fc.RevisionNumber:
		return errors.New("revision must have higher revision number")

	case rev.NewFileSize > uint64(h.spaceRemaining) || rev.NewFileSize > h.MaxFilesize:
		return errors.New("revision file size is too large")

	// valid and missing outputs should still sum to payout
	case rev.NewValidProofOutputs[0].Value.Add(rev.NewValidProofOutputs[1].Value).Cmp(expectedPayout) != 0,
		rev.NewMissedProofOutputs[0].Value.Add(rev.NewMissedProofOutputs[1].Value).Cmp(expectedPayout) != 0:
		return errors.New("revision outputs do not sum to original payout")

	// outputs should have been adjusted proportional to the new filesize
	case rev.NewValidProofOutputs[1].Value.Cmp(minHostPrice) <= 0:
		return errors.New("revision price is too small")
	case rev.NewMissedProofOutputs[0].Value.Cmp(rev.NewValidProofOutputs[0].Value) != 0:
		return errors.New("revision missed renter payout does not match valid payout")
	}

	return nil
}

// rpcUpload is an RPC that negotiates a file contract. Under the new scheme,
// file contracts should not initially hold any data.
func (h *Host) rpcUpload(conn net.Conn) error {
	// perform key exchange
	if err := encoding.WriteObject(conn, h.publicKey); err != nil {
		return err
	}
	var renterKey types.SiaPublicKey
	if err := encoding.ReadObject(conn, &renterKey, 256); err != nil {
		return err
	}

	// read initial transaction set
	var unsignedTxnSet []types.Transaction
	if err := encoding.ReadObject(conn, &unsignedTxnSet, maxContractLen); err != nil {
		return err
	}

	// check the contract transaction, which should be the last txn in the set.
	contractTxn := unsignedTxnSet[len(unsignedTxnSet)-1]
	lockID := h.mu.RLock()
	err := h.considerContract(contractTxn, renterKey)
	h.mu.RUnlock(lockID)
	if err != nil {
		encoding.WriteObject(conn, err.Error())
		return err
	}

	// send acceptance
	if err := encoding.WriteObject(conn, modules.AcceptResponse); err != nil {
		return err
	}

	// add collateral to txn and send. For now, we never add collateral, so no
	// changes are made.
	if err := encoding.WriteObject(conn, unsignedTxnSet); err != nil {
		return err
	}

	// read signed transaction set
	var signedTxnSet []types.Transaction
	if err := encoding.ReadObject(conn, &signedTxnSet, maxContractLen); err != nil {
		return err
	}

	// check that transaction set was not modified
	if len(signedTxnSet) != len(unsignedTxnSet) {
		return errors.New("renter sent bad signed transaction set")
	}
	for i := range signedTxnSet {
		if signedTxnSet[i].ID() != unsignedTxnSet[i].ID() {
			return errors.New("renter sent bad signed transaction set")
		}
	}

	// sign and submit to blockchain
	signedTxn, parents := signedTxnSet[len(signedTxnSet)-1], signedTxnSet[:len(signedTxnSet)-1]
	txnBuilder := h.wallet.RegisterTransaction(signedTxn, parents)
	signedTxnSet, err = txnBuilder.Sign(true)
	if err != nil {
		return err
	}
	err = h.tpool.AcceptTransactionSet(signedTxnSet)
	if err == modules.ErrDuplicateTransactionSet {
		// this can happen if the host is uploading to itself
		err = nil
	}
	if err != nil {
		return err
	}

	// send doubly-signed transaction set
	if err := encoding.WriteObject(conn, signedTxnSet); err != nil {
		return err
	}

	// Add this contract to the host's list of obligations.
	// TODO: is there a race condition here?
	lockID = h.mu.Lock()
	h.fileCounter++
	co := contractObligation{
		ID:           contractTxn.FileContractID(0),
		FileContract: contractTxn.FileContracts[0],
		Path:         filepath.Join(h.saveDir, strconv.Itoa(h.fileCounter)),
	}
	proofHeight := co.FileContract.WindowStart + StorageProofReorgDepth
	h.obligationsByHeight[proofHeight] = append(h.obligationsByHeight[proofHeight], co)
	h.obligationsByID[co.ID] = co
	h.save()
	h.mu.Unlock(lockID)

	return nil
}

// rpcRevise is an RPC that allows a renter to revise a file contract. It will
// read new revisions in a loop until the renter sends a termination signal.
func (h *Host) rpcRevise(conn net.Conn) error {
	// read ID of contract to be revised
	var fcid types.FileContractID
	if err := encoding.ReadObject(conn, &fcid, crypto.HashSize); err != nil {
		return err
	}
	lockID := h.mu.RLock()
	obligation, exists := h.obligationsByID[fcid]
	h.mu.RUnlock(lockID)
	if !exists {
		return errors.New("no record of that contract")
	}

	// need to protect against two simultaneous revisions to the same
	// contract; this can cause inconsistency and data loss, making storage
	// proofs impossible
	obligation.mu.Lock()
	defer obligation.mu.Unlock()

	// open the file in append mode
	file, err := os.OpenFile(obligation.Path, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0660)
	if err != nil {
		return err
	}
	defer func() {
		// if a newly-created file was not updated, remove it
		if stat, _ := file.Stat(); stat.Size() == 0 {
			os.Remove(obligation.Path)
		}
		file.Close()
	}()

	// rebuild current Merkle tree
	tree := crypto.NewTree()
	buf := make([]byte, crypto.SegmentSize)
	for {
		_, err := io.ReadFull(file, buf)
		if err == io.EOF {
			break
		} else if err != nil && err != io.ErrUnexpectedEOF {
			return err
		}
		tree.Push(buf)
	}

	// accept new revisions in a loop
	emptyID := types.Transaction{}.ID()
	for {
		// read proposed revision
		var revTxn types.Transaction
		if err := encoding.ReadObject(conn, &revTxn, types.BlockSizeLimit); err != nil {
			return err
		}
		// an empty transaction indicates completion
		if revTxn.ID() == emptyID {
			break
		}

		// check revision against original file contract
		lockID = h.mu.RLock()
		err := h.considerRevision(revTxn, obligation)
		h.mu.RUnlock(lockID)
		if err != nil {
			encoding.WriteObject(conn, err.Error())
			continue // don't terminate loop; subsequent revisions may be okay
		}

		// indicate acceptance
		if err := encoding.WriteObject(conn, modules.AcceptResponse); err != nil {
			return err
		}

		// read piece
		// TODO: simultaneously read into tree?
		rev := revTxn.FileContractRevisions[0]
		piece := make([]byte, rev.NewFileSize-obligation.FileContract.FileSize)
		_, err = io.ReadFull(conn, piece)
		if err != nil {
			return err
		}

		// verify Merkle root
		r := bytes.NewReader(piece)
		for {
			_, err := io.ReadFull(r, buf)
			if err == io.EOF {
				break
			} else if err != nil && err != io.ErrUnexpectedEOF {
				return err
			}
			tree.Push(buf)
		}
		if tree.Root() != rev.NewFileMerkleRoot {
			return errors.New("revision has bad Merkle root")
		}

		// manually sign the transaction
		revTxn.TransactionSignatures = append(revTxn.TransactionSignatures, types.TransactionSignature{
			ParentID:       crypto.Hash(fcid),
			CoveredFields:  types.CoveredFields{FileContractRevisions: []uint64{0}},
			PublicKeyIndex: 1, // host key is always second
		})
		encodedSig, err := crypto.SignHash(revTxn.SigHash(1), h.secretKey)
		if err != nil {
			return err
		}
		revTxn.TransactionSignatures[1].Signature = encodedSig[:]

		// send the signed transaction
		if err := encoding.WriteObject(conn, revTxn); err != nil {
			return err
		}

		// append piece to file
		if _, err := file.Write(piece); err != nil {
			return err
		}

		// save updated obligation to disk
		lockID = h.mu.Lock()
		h.spaceRemaining -= int64(len(piece))
		obligation.FileContract.RevisionNumber = rev.NewRevisionNumber
		obligation.FileContract.FileSize = rev.NewFileSize
		h.obligationsByID[obligation.ID] = obligation
		heightObligations := h.obligationsByHeight[obligation.FileContract.WindowStart+StorageProofReorgDepth]
		for i := range heightObligations {
			if heightObligations[i].ID == obligation.ID {
				heightObligations[i] = obligation
			}
		}
		h.save()
		h.mu.Unlock(lockID)
	}

	return nil
}
<|endoftext|>


<commit_before>package onedrive

import (
	"fmt"
	"net/http"
	"time"
)

// ItemService manages the communication with Item related API endpoints
type ItemService struct {
	*OneDrive
}

// The Thumbnail resource type represents a thumbnail for an image, video,
// document, or any file or folder on OneDrive that has a graphical representation.
// See: http://onedrive.github.io/resources/thumbnail.htm
type Thumbnail struct {
	Width  int    `json:"width"`
	Height int    `json:"height"`
	URL    string `json:"url"`
	// Relationships
	Content []byte `json:"content"`
}

// The ThumbnailSet type is a keyed collection of Thumbnail objects. It is used
// to represent a set of thumbnails associated with a single file on OneDrive.
// See: http://onedrive.github.io/resources/thumbnailSet.htm
type ThumbnailSet struct {
	ID     string     `json:"id"`
	Small  *Thumbnail `json:"small"`
	Medium *Thumbnail `json:"medium"`
	Large  *Thumbnail `json:"large"`
}

// Items represents a collection of Items
type Items struct {
	Collection []*Item `json:"value"`
}

// The ItemReference type groups data needed to reference a OneDrive item across
// the service into a single structure.
// See: http://onedrive.github.io/resources/itemReference.htm
type ItemReference struct {
	DriveID string `json:"driveId"`
	ID      string `json:"id"`
	Path    string `json:"path"`
}

// The Item resource type represents metadata for an item in OneDrive. All
// top-level filesystem objects in OneDrive are Item resources. If an item is
// a Folder or File facet, the Item resource will contain a value for either
// the folder or file property, respectively.
// See: http://onedrive.github.io/resources/item.htm
type Item struct {
	ID                   string         `json:"id"`
	Name                 string         `json:"name"`
	ETag                 string         `json:"eTag"`
	CTag                 string         `json:"cTag"`
	CreatedBy            *IdentitySet   `json:"createdBy"`
	LastModifiedBy       *IdentitySet   `json:"lastModifiedBy"`
	CreatedDateTime      time.Time      `json:"createdDateTime"`
	LastModifiedDateTime time.Time      `json:"lastModifiedDateTime"`
	Size                 int64          `json:"size"`
	ParentReference      *ItemReference `json:"parentReference"`
	WebURL               string         `json:"webUrl"`
	File                 *FileFacet     `json:"file"`
	Folder               *FolderFacet   `json:"folder"`
	Image                *ImageFacet    `json:"image"`
	Photo                *PhotoFacet    `json:"photo"`
	Audio                *AudioFacet    `json:"audio"`
	Video                *VideoFacet    `json:"video"`
	Location             *LocationFacet `json:"location"`
	Deleted              *DeletedFacet  `json:"deleted"`
	// Instance attributes
	ConflictBehaviour string `json:"@name.conflictBehavior"`
	DownloadURL       string `json:"@content.downloadUrl"`
	SourceURL         string `json:"@content.sourceUrl"`
	// Relationships
	Content    []byte        `json:"content"`
	Children   []*Item       `json:"children"`
	Thumbnails *ThumbnailSet `json:"thumbnails"`
}

// driveURIFromID returns a valid request URI based on the ID of the drive.
// Mostly exists to simplify special cases such as the default and root drives.
func itemURIFromID(itemID string) string {
	switch itemID {
	case "", "root":
		return "/drive/root"
	default:
		return fmt.Sprintf("/drive/items/%s", itemID)
	}
}

// Get returns an item with the specified ID.
func (is *ItemService) Get(itemID string) (*Item, *http.Response, error) {
	req, err := is.newRequest("GET", itemURIFromID(itemID), nil, nil)
	if err != nil {
		return nil, nil, err
	}

	item := new(Item)
	resp, err := is.do(req, item)
	if err != nil {
		return nil, resp, err
	}

	return item, resp, nil
}

// GetDefaultDriveRootFolder is a convenience function to return the root folder
// of the users default Drive
func (is *ItemService) GetDefaultDriveRootFolder() (*Item, *http.Response, error) {
	return is.Get("root")
}

// ListChildren returns a collection of all the Items under an Item
func (is *ItemService) ListChildren(itemID string) (*Items, *http.Response, error) {
	reqURI := fmt.Sprintf("/drive/items/%s/children", itemID)
	req, err := is.newRequest("GET", reqURI, nil, nil)
	if err != nil {
		return nil, nil, err
	}

	items := new(Items)
	resp, err := is.do(req, items)
	if err != nil {
		return nil, resp, err
	}

	return items, resp, nil
}

type newFolder struct {
	Name   string       `json:"name"`
	Folder *FolderFacet `json:"folder"`
}

// CreateFolder creates a new folder within the parent.
func (is *ItemService) CreateFolder(parentID, folderName string) (*Item, *http.Response, error) {
	folder := newFolder{
		Name:   folderName,
		Folder: new(FolderFacet),
	}

	path := fmt.Sprintf("/drive/items/%s/children/%s", parentID, folderName)
	req, err := is.newRequest("PUT", path, nil, folder)
	if err != nil {
		return nil, nil, err
	}

	item := new(Item)
	resp, err := is.do(req, item)
	if err != nil {
		return nil, resp, err
	}

	return item, resp, nil
}

type newWebUpload struct {
	SourceURL string     `json:"@content.sourceUrl"`
	Name      string     `json:"name"`
	File      *FileFacet `json:"file"`
}

// UploadFromURL allows your app to upload an item to OneDrive by providing a URL.
// OneDrive will download the file directly from a remote server so your app
// doesn't have to upload the file's bytes.
// See: http://onedrive.github.io/items/upload_url.htm
func (is *ItemService) UploadFromURL(parentID, name, webURL string) (*Item, *http.Response, error) {
	requestHeaders := map[string]string{
		"Prefer": "respond-async",
	}

	newFile := newWebUpload{
		webURL, name, new(FileFacet),
	}

	path := fmt.Sprintf("/drive/items/%s/children", parentID)
	req, err := is.newRequest("POST", path, requestHeaders, newFile)
	if err != nil {
		return nil, nil, err
	}

	item := new(Item)
	resp, err := is.do(req, item)
	if err != nil {
		return nil, resp, err
	}

	return item, resp, nil
}

// Delete removed a OneDrive item by using its ID. Note that deleting items
// using this method will move the items to the Recycle Bin, instead of
// permanently deleting them.
// See: http://onedrive.github.io/items/delete.htm
func (is *ItemService) Delete(itemID, eTag string) (bool, *http.Response, error) {
	requestHeaders := make(map[string]string)
	if eTag != "" {
		requestHeaders["if-match"] = eTag
	}

	path := fmt.Sprintf("/drive/items/%s", itemID)
	req, err := is.newRequest("DELETE", path, requestHeaders, nil)
	if err != nil {
		return false, nil, err
	}

	resp, err := is.do(req, nil)
	if err != nil {
		return false, resp, err
	}

	return (resp.StatusCode == statusNoContent), resp, err
}
<commit_msg>Add methods to Copy/Move and Update item.<commit_after>package onedrive

import (
	"fmt"
	"net/http"
	"time"
)

// ItemService manages the communication with Item related API endpoints
type ItemService struct {
	*OneDrive
}

// The Thumbnail resource type represents a thumbnail for an image, video,
// document, or any file or folder on OneDrive that has a graphical representation.
// See: http://onedrive.github.io/resources/thumbnail.htm
type Thumbnail struct {
	Width  int    `json:"width"`
	Height int    `json:"height"`
	URL    string `json:"url"`
	// Relationships
	Content []byte `json:"content"`
}

// The ThumbnailSet type is a keyed collection of Thumbnail objects. It is used
// to represent a set of thumbnails associated with a single file on OneDrive.
// See: http://onedrive.github.io/resources/thumbnailSet.htm
type ThumbnailSet struct {
	ID     string     `json:"id"`
	Small  *Thumbnail `json:"small"`
	Medium *Thumbnail `json:"medium"`
	Large  *Thumbnail `json:"large"`
}

// Items represents a collection of Items
type Items struct {
	Collection []*Item `json:"value"`
}

// The ItemReference type groups data needed to reference a OneDrive item across
// the service into a single structure.
// See: http://onedrive.github.io/resources/itemReference.htm
type ItemReference struct {
	DriveID string `json:"driveId"`
	ID      string `json:"id"`
	Path    string `json:"path"`
}

// The Item resource type represents metadata for an item in OneDrive. All
// top-level filesystem objects in OneDrive are Item resources. If an item is
// a Folder or File facet, the Item resource will contain a value for either
// the folder or file property, respectively.
// See: http://onedrive.github.io/resources/item.htm
type Item struct {
	ID                   string         `json:"id"`
	Name                 string         `json:"name"`
	ETag                 string         `json:"eTag"`
	CTag                 string         `json:"cTag"`
	CreatedBy            *IdentitySet   `json:"createdBy"`
	LastModifiedBy       *IdentitySet   `json:"lastModifiedBy"`
	CreatedDateTime      time.Time      `json:"createdDateTime"`
	LastModifiedDateTime time.Time      `json:"lastModifiedDateTime"`
	Size                 int64          `json:"size"`
	ParentReference      *ItemReference `json:"parentReference"`
	WebURL               string         `json:"webUrl"`
	File                 *FileFacet     `json:"file"`
	Folder               *FolderFacet   `json:"folder"`
	Image                *ImageFacet    `json:"image"`
	Photo                *PhotoFacet    `json:"photo"`
	Audio                *AudioFacet    `json:"audio"`
	Video                *VideoFacet    `json:"video"`
	Location             *LocationFacet `json:"location"`
	Deleted              *DeletedFacet  `json:"deleted"`
	// Instance attributes
	ConflictBehaviour string `json:"@name.conflictBehavior"`
	DownloadURL       string `json:"@content.downloadUrl"`
	SourceURL         string `json:"@content.sourceUrl"`
	// Relationships
	Content    []byte        `json:"content"`
	Children   []*Item       `json:"children"`
	Thumbnails *ThumbnailSet `json:"thumbnails"`
}

// driveURIFromID returns a valid request URI based on the ID of the drive.
// Mostly exists to simplify special cases such as the default and root drives.
func itemURIFromID(itemID string) string {
	switch itemID {
	case "", "root":
		return "/drive/root"
	default:
		return fmt.Sprintf("/drive/items/%s", itemID)
	}
}

// Get returns an item with the specified ID.
func (is *ItemService) Get(itemID string) (*Item, *http.Response, error) {
	req, err := is.newRequest("GET", itemURIFromID(itemID), nil, nil)
	if err != nil {
		return nil, nil, err
	}

	item := new(Item)
	resp, err := is.do(req, item)
	if err != nil {
		return nil, resp, err
	}

	return item, resp, nil
}

// GetDefaultDriveRootFolder is a convenience function to return the root folder
// of the users default Drive
func (is *ItemService) GetDefaultDriveRootFolder() (*Item, *http.Response, error) {
	return is.Get("root")
}

// ListChildren returns a collection of all the Items under an Item
func (is *ItemService) ListChildren(itemID string) (*Items, *http.Response, error) {
	reqURI := fmt.Sprintf("/drive/items/%s/children", itemID)
	req, err := is.newRequest("GET", reqURI, nil, nil)
	if err != nil {
		return nil, nil, err
	}

	items := new(Items)
	resp, err := is.do(req, items)
	if err != nil {
		return nil, resp, err
	}

	return items, resp, nil
}

type newFolder struct {
	Name   string       `json:"name"`
	Folder *FolderFacet `json:"folder"`
}

// CreateFolder creates a new folder within the parent.
func (is *ItemService) CreateFolder(parentID, folderName string) (*Item, *http.Response, error) {
	folder := newFolder{
		Name:   folderName,
		Folder: new(FolderFacet),
	}

	path := fmt.Sprintf("/drive/items/%s/children/%s", parentID, folderName)
	req, err := is.newRequest("PUT", path, nil, folder)
	if err != nil {
		return nil, nil, err
	}

	item := new(Item)
	resp, err := is.do(req, item)
	if err != nil {
		return nil, resp, err
	}

	return item, resp, nil
}

type newWebUpload struct {
	SourceURL string     `json:"@content.sourceUrl"`
	Name      string     `json:"name"`
	File      *FileFacet `json:"file"`
}

// UploadFromURL allows your app to upload an item to OneDrive by providing a URL.
// OneDrive will download the file directly from a remote server so your app
// doesn't have to upload the file's bytes.
// See: http://onedrive.github.io/items/upload_url.htm
func (is *ItemService) UploadFromURL(parentID, name, webURL string) (*Item, *http.Response, error) {
	requestHeaders := map[string]string{
		"Prefer": "respond-async",
	}

	newFile := newWebUpload{
		webURL, name, new(FileFacet),
	}

	path := fmt.Sprintf("/drive/items/%s/children", parentID)
	req, err := is.newRequest("POST", path, requestHeaders, newFile)
	if err != nil {
		return nil, nil, err
	}

	item := new(Item)
	resp, err := is.do(req, item)
	if err != nil {
		return nil, resp, err
	}

	return item, resp, nil
}

// Move changes the parent folder for a OneDrive Item resource.
// See: http://onedrive.github.io/items/move.htm
func (is ItemService) Update(item *Item, ifMatch bool) (*Item, *http.Response, error) {
	requestHeaders := make(map[string]string)
	if ifMatch {
		requestHeaders["if-match"] = item.ETag
	}

	path := fmt.Sprintf("/drive/items/%s", item.ID)
	req, err := is.newRequest("PATCH", path, requestHeaders, item)
	if err != nil {
		return nil, nil, err
	}

	resp, err := is.do(req, item)
	if err != nil {
		return nil, resp, err
	}

	return item, resp, nil
}

// Delete removed a OneDrive item by using its ID. Note that deleting items
// using this method will move the items to the Recycle Bin, instead of
// permanently deleting them.
// See: http://onedrive.github.io/items/delete.htm
func (is *ItemService) Delete(itemID, eTag string) (bool, *http.Response, error) {
	requestHeaders := make(map[string]string)
	if eTag != "" {
		requestHeaders["if-match"] = eTag
	}

	path := fmt.Sprintf("/drive/items/%s", itemID)
	req, err := is.newRequest("DELETE", path, requestHeaders, nil)
	if err != nil {
		return false, nil, err
	}

	resp, err := is.do(req, nil)
	if err != nil {
		return false, resp, err
	}

	return (resp.StatusCode == statusNoContent), resp, err
}

// Move changes the parent folder for a OneDrive Item resource.
// See: http://onedrive.github.io/items/move.htm
func (is ItemService) Move(itemID, parentReference ItemReference) (*Item, *http.Response, error) {
	path := fmt.Sprintf("/drive/items/%s", itemID)
	req, err := is.newRequest("PATCH", path, nil, parentReference)
	if err != nil {
		return nil, nil, err
	}

	item := new(Item)
	resp, err := is.do(req, item)
	if err != nil {
		return nil, resp, err
	}

	return item, resp, nil
}

// Move changes the parent folder for a OneDrive Item resource.
// See: http://onedrive.github.io/items/move.htm
func (is ItemService) Copy(itemID, name string, parentReference ItemReference) (*Item, *http.Response, error) {
	copyAction := struct {
		ParentReference *ItemReference `json:"parentReference"`
		Name            string         `json:"name,omitempty"`
	}{&parentReference, name}

	path := fmt.Sprintf("/drive/items/%s/action.copy", itemID)
	req, err := is.newRequest("POST", path, nil, copyAction)
	if err != nil {
		return nil, nil, err
	}

	item := new(Item)
	resp, err := is.do(req, item)
	if err != nil {
		return nil, resp, err
	}

	return item, resp, nil
}
<|endoftext|>


<commit_before>/**
 *  Copyright 2014 Paul Querna
 *
 *  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 storage

import (
	"github.com/pquerna/distsync/common"
	"github.com/pquerna/distsync/crypto"
	"github.com/rackspace/gophercloud"
	osObjects "github.com/rackspace/gophercloud/openstack/objectstorage/v1/objects"
	"github.com/rackspace/gophercloud/pagination"
	"github.com/rackspace/gophercloud/rackspace"
	"github.com/rackspace/gophercloud/rackspace/objectstorage/v1/objects"

	"errors"
	"io"
	"time"
)

const (
	// This is basically time.RFC3339Nano, but missing the timezone.
	// Swift docs say its always in UTC though. So. Here. We. Go.
	swiftTimelayout = "2006-01-02T15:04:05.999999999"
)

type CloudFilesStorage struct {
	bucket string
	creds  *common.RackspaceCreds
}

func NewCloudFiles(creds *common.RackspaceCreds, bucket string) (*CloudFilesStorage, error) {
	if creds == nil {
		return nil, errors.New("CloudFiles: No Rackspace credentials provided.")
	}

	if bucket == "" {
		return nil, errors.New("CloudFiles: empty StorageBucket")
	}

	return &CloudFilesStorage{
		bucket: bucket,
		creds:  creds,
	}, nil
}

func (cf *CloudFilesStorage) client() (*gophercloud.ServiceClient, error) {
	auth := gophercloud.AuthOptions{
		Username: cf.creds.Username,
		APIKey:   cf.creds.ApiKey,
	}

	ac, err := rackspace.AuthenticatedClient(auth)
	if err != nil {
		return nil, err
	}

	// TOOD: auto-detect serviceNet?
	return rackspace.NewObjectStorageV1(ac, gophercloud.EndpointOpts{
		Region: cf.creds.Region,
	})
}

func (cf *CloudFilesStorage) Download(filename string, writer io.Writer) error {
	client, err := cf.client()
	if err != nil {
		return err
	}

	resp := objects.Download(client, cf.bucket, filename, &osObjects.DownloadOpts{})
	if resp.Err != nil {
		return resp.Err
	}
	defer resp.Body.Close()

	_, err = io.Copy(writer, resp.Body)
	if err != nil {
		return err
	}

	return nil
}

func (cf *CloudFilesStorage) List(dc crypto.Decryptor) ([]*FileInfo, error) {
	client, err := cf.client()
	if err != nil {
		return nil, err
	}

	rv := make([]*FileInfo, 0)
	err = objects.List(client, cf.bucket, osObjects.ListOpts{Full: true}).EachPage(func(p pagination.Page) (bool, error) {
		objs, err := objects.ExtractInfo(p)
		if err != nil {
			return false, err
		}
		for _, obj := range objs {
			if obj.Name == ".distsync" {
				continue
			}

			lm, err := time.Parse(swiftTimelayout, obj.LastModified)
			if err != nil {
				return false, err
			}
			name := ""
			if dc != nil {
				name, err = dc.DecryptName(obj.Name)
				if err != nil {
					return false, err
				}
			}

			rv = append(rv, &FileInfo{
				EncryptedName: obj.Name,
				Name:          name,
				LastModified:  lm,
				Length:        int64(obj.Bytes),
			})
		}
		return true, nil
	})

	return rv, nil
}

func (cf *CloudFilesStorage) Upload(filename string, reader io.ReadSeeker) error {
	return errors.New("not done")
}

func (cf *CloudFilesStorage) Start() error {
	return nil
}

func (cf *CloudFilesStorage) Stop() error {
	return nil
}
<commit_msg>Add CloudFiles.Upload<commit_after>/**
 *  Copyright 2014 Paul Querna
 *
 *  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 storage

import (
	"github.com/pquerna/distsync/common"
	"github.com/pquerna/distsync/crypto"
	"github.com/rackspace/gophercloud"
	osObjects "github.com/rackspace/gophercloud/openstack/objectstorage/v1/objects"
	"github.com/rackspace/gophercloud/pagination"
	"github.com/rackspace/gophercloud/rackspace"
	"github.com/rackspace/gophercloud/rackspace/objectstorage/v1/objects"

	"errors"
	"io"
	"strings"
	"time"
)

const (
	// This is basically time.RFC3339Nano, but missing the timezone.
	// Swift docs say its always in UTC though. So. Here. We. Go.
	swiftTimelayout = "2006-01-02T15:04:05.999999999"
)

type CloudFilesStorage struct {
	bucket string
	creds  *common.RackspaceCreds
}

func NewCloudFiles(creds *common.RackspaceCreds, bucket string) (*CloudFilesStorage, error) {
	if creds == nil {
		return nil, errors.New("CloudFiles: No Rackspace credentials provided.")
	}

	if bucket == "" {
		return nil, errors.New("CloudFiles: empty StorageBucket")
	}

	return &CloudFilesStorage{
		bucket: bucket,
		creds:  creds,
	}, nil
}

func (cf *CloudFilesStorage) client() (*gophercloud.ServiceClient, error) {
	auth := gophercloud.AuthOptions{
		Username: cf.creds.Username,
		APIKey:   cf.creds.ApiKey,
	}

	ac, err := rackspace.AuthenticatedClient(auth)
	if err != nil {
		return nil, err
	}

	// TOOD: auto-detect serviceNet?
	return rackspace.NewObjectStorageV1(ac, gophercloud.EndpointOpts{
		Region: cf.creds.Region,
	})
}

func (cf *CloudFilesStorage) Download(filename string, writer io.Writer) error {
	client, err := cf.client()
	if err != nil {
		return err
	}

	resp := objects.Download(client, cf.bucket, filename, &osObjects.DownloadOpts{})
	if resp.Err != nil {
		return resp.Err
	}
	defer resp.Body.Close()

	_, err = io.Copy(writer, resp.Body)
	if err != nil {
		return err
	}

	return nil
}

func (cf *CloudFilesStorage) List(dc crypto.Decryptor) ([]*FileInfo, error) {
	client, err := cf.client()
	if err != nil {
		return nil, err
	}

	rv := make([]*FileInfo, 0)
	err = objects.List(client, cf.bucket, osObjects.ListOpts{Full: true}).EachPage(func(p pagination.Page) (bool, error) {
		objs, err := objects.ExtractInfo(p)
		if err != nil {
			return false, err
		}
		for _, obj := range objs {
			if obj.Name == ".distsync" {
				continue
			}

			lm, err := time.Parse(swiftTimelayout, obj.LastModified)
			if err != nil {
				return false, err
			}
			name := ""
			if dc != nil {
				name, err = dc.DecryptName(obj.Name)
				if err != nil {
					return false, err
				}
			}

			rv = append(rv, &FileInfo{
				EncryptedName: obj.Name,
				Name:          name,
				LastModified:  lm,
				Length:        int64(obj.Bytes),
			})
		}
		return true, nil
	})

	return rv, nil
}

func (cf *CloudFilesStorage) Upload(filename string, reader io.ReadSeeker) error {
	// just a random string taht will change the etag of .distsync,
	// so that `notify.S3Poller` look for new files.
	tsec, err := crypto.RandomSecret()
	if err != nil {
		return err
	}

	l, err := reader.Seek(0, 2)

	if err != nil {
		return err
	}

	_, err = reader.Seek(0, 0)

	if err != nil {
		return err
	}

	client, err := cf.client()
	if err != nil {
		return err
	}

	_, err = objects.Create(client, cf.bucket, filename, reader, &osObjects.CreateOpts{
		// gophercloud API issue: https://github.com/rackspace/gophercloud/issues/308
		ContentLength: int(l),
		ContentType:   "application/octet-stream",
	}).ExtractHeader()
	if err != nil {
		return err
	}

	sr := strings.NewReader(tsec)
	_, err = objects.Create(client, cf.bucket, ".distsync", sr, &osObjects.CreateOpts{
		ContentLength: sr.Len(),
		ContentType:   "text/plain",
	}).ExtractHeader()
	if err != nil {
		return err
	}

	return nil
}

func (cf *CloudFilesStorage) Start() error {
	return nil
}

func (cf *CloudFilesStorage) Stop() error {
	return nil
}
<|endoftext|>


<commit_before>package blackjack

import (
	"fmt"
	"github.com/jkomoros/boardgame"
	"strings"
)

type mainState struct {
	Game    *gameState
	Players []*playerState
}

type gameState struct {
	DiscardStack  *boardgame.GrowableStack
	DrawStack     *boardgame.GrowableStack
	UnusedCards   *boardgame.GrowableStack
	CurrentPlayer int
}

type playerState struct {
	playerIndex int
	Hand        *boardgame.GrowableStack
	Busted      bool
	Stood       bool
}

func (g *gameState) Props() []string {
	return boardgame.PropertyReaderPropsImpl(g)
}

func (g *gameState) Prop(name string) interface{} {
	return boardgame.PropertyReaderPropImpl(g, name)
}

func (g *gameState) Copy() boardgame.GameState {
	var result gameState
	result = *g
	return &result
}

func (p *playerState) Props() []string {
	return boardgame.PropertyReaderPropsImpl(p)
}

func (p *playerState) Prop(name string) interface{} {
	return boardgame.PropertyReaderPropImpl(p, name)
}

func (p *playerState) Copy() boardgame.PlayerState {
	var result playerState
	result = *p
	return &result
}

func (p *playerState) PlayerIndex() int {
	return p.playerIndex
}

//HandValue returns the value of the player's hand.
func (p *playerState) HandValue() int {

	var numUnconvertedAces int
	var currentValue int

	for _, card := range cards(p.Hand.ComponentValues()) {
		switch card.Rank {
		case RankAce:
			numUnconvertedAces++
			//We count the ace as 1 now. Later we'll check to see if we can
			//expand any aces.
			currentValue += 1
		case RankJack, RankQueen, RankKing:
			currentValue += 10
		default:
			currentValue += int(card.Rank)
		}
	}

	for numUnconvertedAces > 0 {

		if currentValue >= (targetScore - 10) {
			break
		}

		numUnconvertedAces--
		currentValue += 10
	}

	return currentValue

}

func (m *mainState) Diagram() string {
	var result []string

	result = append(result, fmt.Sprintf("Cards left in deck: %d", m.Game.DrawStack.NumComponents()))

	for i, player := range m.Players {
		result = append(result, fmt.Sprintf("Player %d", i))

		statusLine := fmt.Sprintf("\tValue: %d", player.HandValue())

		if player.Busted {
			statusLine += " BUSTED"
		}

		if player.Stood {
			statusLine += " STOOD"
		}

		result = append(result, statusLine)

		result = append(result, "\tCards:")

		for _, card := range cards(player.Hand.ComponentValues()) {
			result = append(result, "\t\t"+card.String())
		}

		result = append(result, "")
	}

	return strings.Join(result, "\n")
}

func (s *mainState) GameState() boardgame.GameState {
	return s.Game
}

func (s *mainState) PlayerStates() []boardgame.PlayerState {
	array := make([]boardgame.PlayerState, len(s.Players))

	for i := 0; i < len(s.Players); i++ {
		array[i] = s.Players[i]
	}

	return array
}

func (s *mainState) Copy() boardgame.State {
	array := make([]*playerState, len(s.Players))

	for i := 0; i < len(s.Players); i++ {
		array[i] = s.Players[i].Copy().(*playerState)
	}

	return &mainState{
		Game:    s.Game.Copy().(*gameState),
		Players: array,
	}
}
<commit_msg>In blackjack diagram, mark which player is the current player. part of #16.<commit_after>package blackjack

import (
	"fmt"
	"github.com/jkomoros/boardgame"
	"strings"
)

type mainState struct {
	Game    *gameState
	Players []*playerState
}

type gameState struct {
	DiscardStack  *boardgame.GrowableStack
	DrawStack     *boardgame.GrowableStack
	UnusedCards   *boardgame.GrowableStack
	CurrentPlayer int
}

type playerState struct {
	playerIndex int
	Hand        *boardgame.GrowableStack
	Busted      bool
	Stood       bool
}

func (g *gameState) Props() []string {
	return boardgame.PropertyReaderPropsImpl(g)
}

func (g *gameState) Prop(name string) interface{} {
	return boardgame.PropertyReaderPropImpl(g, name)
}

func (g *gameState) Copy() boardgame.GameState {
	var result gameState
	result = *g
	return &result
}

func (p *playerState) Props() []string {
	return boardgame.PropertyReaderPropsImpl(p)
}

func (p *playerState) Prop(name string) interface{} {
	return boardgame.PropertyReaderPropImpl(p, name)
}

func (p *playerState) Copy() boardgame.PlayerState {
	var result playerState
	result = *p
	return &result
}

func (p *playerState) PlayerIndex() int {
	return p.playerIndex
}

//HandValue returns the value of the player's hand.
func (p *playerState) HandValue() int {

	var numUnconvertedAces int
	var currentValue int

	for _, card := range cards(p.Hand.ComponentValues()) {
		switch card.Rank {
		case RankAce:
			numUnconvertedAces++
			//We count the ace as 1 now. Later we'll check to see if we can
			//expand any aces.
			currentValue += 1
		case RankJack, RankQueen, RankKing:
			currentValue += 10
		default:
			currentValue += int(card.Rank)
		}
	}

	for numUnconvertedAces > 0 {

		if currentValue >= (targetScore - 10) {
			break
		}

		numUnconvertedAces--
		currentValue += 10
	}

	return currentValue

}

func (m *mainState) Diagram() string {
	var result []string

	result = append(result, fmt.Sprintf("Cards left in deck: %d", m.Game.DrawStack.NumComponents()))

	for i, player := range m.Players {

		playerLine := fmt.Sprintf("Player %d", i)

		if i == m.Game.CurrentPlayer {
			playerLine += "  *CURRENT*"
		}

		result = append(result, playerLine)

		statusLine := fmt.Sprintf("\tValue: %d", player.HandValue())

		if player.Busted {
			statusLine += " BUSTED"
		}

		if player.Stood {
			statusLine += " STOOD"
		}

		result = append(result, statusLine)

		result = append(result, "\tCards:")

		for _, card := range cards(player.Hand.ComponentValues()) {
			result = append(result, "\t\t"+card.String())
		}

		result = append(result, "")
	}

	return strings.Join(result, "\n")
}

func (s *mainState) GameState() boardgame.GameState {
	return s.Game
}

func (s *mainState) PlayerStates() []boardgame.PlayerState {
	array := make([]boardgame.PlayerState, len(s.Players))

	for i := 0; i < len(s.Players); i++ {
		array[i] = s.Players[i]
	}

	return array
}

func (s *mainState) Copy() boardgame.State {
	array := make([]*playerState, len(s.Players))

	for i := 0; i < len(s.Players); i++ {
		array[i] = s.Players[i].Copy().(*playerState)
	}

	return &mainState{
		Game:    s.Game.Copy().(*gameState),
		Players: array,
	}
}
<|endoftext|>


<commit_before>// Package tests provides the generic support all tests require.
package tests

import (
	"bytes"
	"io"
	"net/http"
	"net/url"
	"os"
	"testing"

	"github.com/ardanlabs/kit/cfg"
	"github.com/ardanlabs/kit/db"
	"github.com/ardanlabs/kit/db/mongo"
	"github.com/ardanlabs/kit/log"
)

// Context provides a base context for tests.
var Context = "Test"

// TestSession is the name used to register the MongoDB session.
var TestSession = "test"

// Success and failure markers.
var (
	Success = "\u2713"
	Failed  = "\u2717"
)

// logdash is the central buffer where all logs are stored.
var logdash bytes.Buffer

//==============================================================================

// ResetLog resets the contents of logdash.
func ResetLog() {
	logdash.Reset()
}

// DisplayLog writes the logdash data to standand out, if testing in verbose mode
// was turned on.
func DisplayLog() {
	if !testing.Verbose() {
		return
	}

	logdash.WriteTo(os.Stdout)
}

// Init initializes the log package.
func Init(cfgKey string) {
	cfg.Init(cfg.EnvProvider{Namespace: cfgKey})

	logLevel := func() int {
		ll, err := cfg.Int("LOGGING_LEVEL")
		if err != nil {
			return log.USER
		}
		return ll
	}
	log.Init(&logdash, logLevel, log.Ldefault)
}

// InitMongo initializes the mongodb connections for testing.
func InitMongo(cfg mongo.Config) {
	if err := db.RegMasterSession("Test", TestSession, cfg); err != nil {
		log.Error("Test", "Init", err, "Completed")
		logdash.WriteTo(os.Stdout)
		os.Exit(1)
	}
}

// NewRequest used to setup a request for mocking API calls with httptreemux.
func NewRequest(method, path string, body io.Reader) *http.Request {
	r, _ := http.NewRequest(method, path, body)
	u, _ := url.Parse(path)
	r.URL = u
	r.RequestURI = path

	return r
}
<commit_msg>Added json indentation function<commit_after>// Package tests provides the generic support all tests require.
package tests

import (
	"bytes"
	"encoding/json"
	"io"
	"net/http"
	"net/url"
	"os"
	"testing"

	"github.com/ardanlabs/kit/cfg"
	"github.com/ardanlabs/kit/db"
	"github.com/ardanlabs/kit/db/mongo"
	"github.com/ardanlabs/kit/log"
)

// Context provides a base context for tests.
var Context = "Test"

// TestSession is the name used to register the MongoDB session.
var TestSession = "test"

// Success and failure markers.
var (
	Success = "\u2713"
	Failed  = "\u2717"
)

// logdash is the central buffer where all logs are stored.
var logdash bytes.Buffer

//==============================================================================

// ResetLog resets the contents of logdash.
func ResetLog() {
	logdash.Reset()
}

// DisplayLog writes the logdash data to standand out, if testing in verbose mode
// was turned on.
func DisplayLog() {
	if !testing.Verbose() {
		return
	}

	logdash.WriteTo(os.Stdout)
}

// Init initializes the log package.
func Init(cfgKey string) {
	cfg.Init(cfg.EnvProvider{Namespace: cfgKey})

	logLevel := func() int {
		ll, err := cfg.Int("LOGGING_LEVEL")
		if err != nil {
			return log.USER
		}
		return ll
	}
	log.Init(&logdash, logLevel, log.Ldefault)
}

// InitMongo initializes the mongodb connections for testing.
func InitMongo(cfg mongo.Config) {
	if err := db.RegMasterSession("Test", TestSession, cfg); err != nil {
		log.Error("Test", "Init", err, "Completed")
		logdash.WriteTo(os.Stdout)
		os.Exit(1)
	}
}

// NewRequest used to setup a request for mocking API calls with httptreemux.
func NewRequest(method, path string, body io.Reader) *http.Request {
	r, _ := http.NewRequest(method, path, body)
	u, _ := url.Parse(path)
	r.URL = u
	r.RequestURI = path

	return r
}

// IndentJSON takes a JSON payload as a string and re-indents it to make
// comparing expected strings to tests strings during testing.
func IndentJSON(j string) string {
	var indented interface{}
	if err := json.Unmarshal([]byte(j), &indented); err != nil {
		return ""
	}

	data, err := json.MarshalIndent(indented, "", "  ")
	if err != nil {
		return ""
	}

	return string(data)
}
<|endoftext|>


<commit_before>package text

import (
	"image"
	"image/color"
	"image/draw"
	"os"
	"time"
)

// Buffer represents a text buffer which, if you send it keystrokes and mouse events,
// will maintain a graphical representation of itself accessible by the Img method.
type Buffer struct {
	img    *image.RGBA
	bgCol  *image.Uniform
	selCol *image.Uniform
	cursor *image.RGBA // the cursor to draw when nothing is selected
	font   *ttf
	lines  []*line         // the text data
	dot    Selection       // the current selection
	clear  image.Rectangle // to be cleared next redraw
	dirty  bool            // indicates the client should redraw

	// mouse related state
	dClicking    bool        // the user is potentially double clicking
	dClickTimer  *time.Timer // times out when it is too late to complete a double click
	mButtons     int         // the buttons of the most recent mouse event
	mPos         image.Point // the position of the most recent mouse event
	mSweepOrigin Address     // keeps track of the origin of a sweep
}

// NewBuffer returns a new buffer of size r, using the TTF font at fontpath.
func NewBuffer(r image.Rectangle, fontpath string) (*Buffer, error) {
	f, err := os.Open(fontpath)
	if err != nil {
		return nil, err
	}
	font, err := newTTF(f)
	if err != nil {
		return nil, err
	}

	bgCol := image.NewUniform(color.RGBA{R: 0xFF, G: 0xFF, B: 0xEA, A: 0xFF})
	selCol := image.NewUniform(color.RGBA{R: 0xEE, G: 0xEE, B: 0x9E, A: 0xFF})

	// draw the default cursor
	cursor := image.NewRGBA(image.Rect(0, 0, 3, font.height))
	draw.Draw(cursor, cursor.Rect, image.Black, image.ZP, draw.Src)
	h := font.height - 3 // TODO magic 3
	draw.Draw(cursor, image.Rect(0, 3, 1, h), bgCol, image.ZP, draw.Src)
	draw.Draw(cursor, image.Rect(2, 3, 3, h), bgCol, image.ZP, draw.Src)

	b := &Buffer{
		img:    image.NewRGBA(r),
		bgCol:  bgCol,
		selCol: selCol,
		cursor: cursor,
		font:   font,
		lines:  []*line{&line{}},
		clear:  r,
	}

	return b, nil
}

// Resize resizes the Buffer. Subsequent calls to Img will return an image of size r.
func (b *Buffer) Resize(r image.Rectangle) {
	b.img = image.NewRGBA(r)
	b.clear = r
	for _, line := range b.lines {
		line.dirty = true
	}
}

// Dirty returns true if the Buffer has changed visibly since the last call to
// Img.
func (b *Buffer) Dirty() bool {
	return b.dirty
}

// Img returns an image representing the current state of the Buffer.
func (b *Buffer) Img() *image.RGBA {
	b.redraw()
	b.dirty = false
	return b.img
}

// Select sets the current selection of the Buffer.
func (b *Buffer) Select(head, tail Address) {
	b.dot = Selection{head, tail}
}

// LoadString replaces the currently selected text with s, and returns the new Selection.
func (b *Buffer) LoadString(s string) Selection {
	b.load(s)
	return b.dot
}

// SendKey sends a keystroke to be interpreted by the Buffer.
func (b *Buffer) SendKey(r rune) {
	b.handleKey(r)
}

// SendMouseEvent sends a mouse event to be interpreted by the Buffer.
func (b *Buffer) SendMouseEvent(pos image.Point, buttons int) {
	b.handleMouseEvent(pos, buttons)
}
<commit_msg>text: mark buffer as dirty after resize<commit_after>package text

import (
	"image"
	"image/color"
	"image/draw"
	"os"
	"time"
)

// Buffer represents a text buffer which, if you send it keystrokes and mouse events,
// will maintain a graphical representation of itself accessible by the Img method.
type Buffer struct {
	img    *image.RGBA
	bgCol  *image.Uniform
	selCol *image.Uniform
	cursor *image.RGBA // the cursor to draw when nothing is selected
	font   *ttf
	lines  []*line         // the text data
	dot    Selection       // the current selection
	clear  image.Rectangle // to be cleared next redraw
	dirty  bool            // indicates the client should redraw

	// mouse related state
	dClicking    bool        // the user is potentially double clicking
	dClickTimer  *time.Timer // times out when it is too late to complete a double click
	mButtons     int         // the buttons of the most recent mouse event
	mPos         image.Point // the position of the most recent mouse event
	mSweepOrigin Address     // keeps track of the origin of a sweep
}

// NewBuffer returns a new buffer of size r, using the TTF font at fontpath.
func NewBuffer(r image.Rectangle, fontpath string) (*Buffer, error) {
	f, err := os.Open(fontpath)
	if err != nil {
		return nil, err
	}
	font, err := newTTF(f)
	if err != nil {
		return nil, err
	}

	bgCol := image.NewUniform(color.RGBA{R: 0xFF, G: 0xFF, B: 0xEA, A: 0xFF})
	selCol := image.NewUniform(color.RGBA{R: 0xEE, G: 0xEE, B: 0x9E, A: 0xFF})

	// draw the default cursor
	cursor := image.NewRGBA(image.Rect(0, 0, 3, font.height))
	draw.Draw(cursor, cursor.Rect, image.Black, image.ZP, draw.Src)
	h := font.height - 3 // TODO magic 3
	draw.Draw(cursor, image.Rect(0, 3, 1, h), bgCol, image.ZP, draw.Src)
	draw.Draw(cursor, image.Rect(2, 3, 3, h), bgCol, image.ZP, draw.Src)

	b := &Buffer{
		img:    image.NewRGBA(r),
		bgCol:  bgCol,
		selCol: selCol,
		cursor: cursor,
		font:   font,
		lines:  []*line{&line{}},
		clear:  r,
	}

	return b, nil
}

// Resize resizes the Buffer. Subsequent calls to Img will return an image of size r.
func (b *Buffer) Resize(r image.Rectangle) {
	b.img = image.NewRGBA(r)
	b.clear = r
	for _, line := range b.lines {
		line.dirty = true
	}
	b.dirty = true
}

// Dirty returns true if the Buffer has changed visibly since the last call to
// Img.
func (b *Buffer) Dirty() bool {
	return b.dirty
}

// Img returns an image representing the current state of the Buffer.
func (b *Buffer) Img() *image.RGBA {
	b.redraw()
	b.dirty = false
	return b.img
}

// Select sets the current selection of the Buffer.
func (b *Buffer) Select(head, tail Address) {
	b.dot = Selection{head, tail}
}

// LoadString replaces the currently selected text with s, and returns the new Selection.
func (b *Buffer) LoadString(s string) Selection {
	b.load(s)
	return b.dot
}

// SendKey sends a keystroke to be interpreted by the Buffer.
func (b *Buffer) SendKey(r rune) {
	b.handleKey(r)
}

// SendMouseEvent sends a mouse event to be interpreted by the Buffer.
func (b *Buffer) SendMouseEvent(pos image.Point, buttons int) {
	b.handleMouseEvent(pos, buttons)
}
<|endoftext|>


<commit_before>package text

import (
	"github.com/opsidian/parsley/ast"
	"github.com/opsidian/parsley/data"
	"github.com/opsidian/parsley/parser"
	"github.com/opsidian/parsley/parsley"
)

// LeftTrim skips the whitespaces before it tries to match the given parser
func LeftTrim(p parsley.Parser, wsMode WsMode) *parser.NamedFunc {
	return parser.Func(func(h parsley.History, leftRecCtx data.IntMap, r parsley.Reader, pos parsley.Pos) (parsley.Node, parsley.Error, data.IntSet) {
		return p.Parse(h, leftRecCtx, r, r.(*Reader).SkipWhitespaces(pos, wsMode))
	}).WithName(p.Name)
}

// RightTrim reads and skips the whitespaces after any parser matches and updates the reader position
func RightTrim(p parsley.Parser, wsMode WsMode) *parser.NamedFunc {
	return parser.Func(func(h parsley.History, leftRecCtx data.IntMap, r parsley.Reader, pos parsley.Pos) (parsley.Node, parsley.Error, data.IntSet) {
		tr := r.(*Reader)
		res, err, cp := p.Parse(h, leftRecCtx, r, pos)
		if res != nil {
			res = ast.SetReaderPos(res, func(pos parsley.Pos) parsley.Pos { return tr.SkipWhitespaces(pos, wsMode) })
		}
		return res, err, cp
	}).WithName(p.Name)
}

// Trim removes all whitespaces before and after the result token
func Trim(p parsley.Parser) *parser.NamedFunc {
	return RightTrim(LeftTrim(p, WsSpacesNl), WsSpacesNl)
}
<commit_msg>In text.RightTrim also amend the position of an error<commit_after>package text

import (
	"github.com/opsidian/parsley/ast"
	"github.com/opsidian/parsley/data"
	"github.com/opsidian/parsley/parser"
	"github.com/opsidian/parsley/parsley"
)

// LeftTrim skips the whitespaces before it tries to match the given parser
func LeftTrim(p parsley.Parser, wsMode WsMode) *parser.NamedFunc {
	return parser.Func(func(h parsley.History, leftRecCtx data.IntMap, r parsley.Reader, pos parsley.Pos) (parsley.Node, parsley.Error, data.IntSet) {
		return p.Parse(h, leftRecCtx, r, r.(*Reader).SkipWhitespaces(pos, wsMode))
	}).WithName(p.Name)
}

// RightTrim reads and skips the whitespaces after any parser matches and updates the reader position
func RightTrim(p parsley.Parser, wsMode WsMode) *parser.NamedFunc {
	return parser.Func(func(h parsley.History, leftRecCtx data.IntMap, r parsley.Reader, pos parsley.Pos) (parsley.Node, parsley.Error, data.IntSet) {
		tr := r.(*Reader)
		res, err, cp := p.Parse(h, leftRecCtx, r, pos)
		if res != nil {
			res = ast.SetReaderPos(res, func(pos parsley.Pos) parsley.Pos { return tr.SkipWhitespaces(pos, wsMode) })
		}
		if err != nil {
			errPos := tr.SkipWhitespaces(err.Pos(), wsMode)
			if errPos > err.Pos() {
				err = parsley.NewError(errPos, err.Error())
			}
		}
		return res, err, cp
	}).WithName(p.Name)
}

// Trim removes all whitespaces before and after the result token
func Trim(p parsley.Parser) *parser.NamedFunc {
	return RightTrim(LeftTrim(p, WsSpacesNl), WsSpacesNl)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/HewlettPackard/oneview-golang/ov"
	"os"
)

func main() {
	var (
		ClientOV *ov.OVClient
	)
	ovc := ClientOV.NewOVClient(
		os.Getenv("ONEVIEW_OV_USER"),
		os.Getenv("ONEVIEW_OV_PASSWORD"),
		os.Getenv("ONEVIEW_OV_DOMAIN"),
		os.Getenv("ONEVIEW_OV_ENDPOINT"),
		false,
		800)

	println("Get server hardware list by name")
	serverName, _ := ovc.GetServerHardwareByName("0000A66101, bay 4")

	fmt.Println("******************")
	fmt.Println(serverName.Model)
	fmt.Println(serverName.URI)
	fmt.Println(serverName.UUID)

	fmt.Println("Get server hardware list by url")

	fmt.Println("******************")

	ServerId, _ := ovc.GetServerHardware("/rest/server-hardware/30373737-3237-4D32-3230-313530314752")
	fmt.Println(ServerId.URI)

	fmt.Println("Get server-hardware list statistics specifying parameters")
	fmt.Println("******************")

	filters := []string{"name matches '0000A66101, bay 3'"}
	ServerList, _ := ovc.GetServerHardwareList(filters, "name:ascending")
	fmt.Println("Total server list :", ServerList.Total)

	print("Get server-hardware whoes profiles are unassigned ")
	fmt.Println("******************")
	serverHarware, _ := ovc.GetAvailableHardware("/rest/server-hardware-types/9F529AA5-2021-4A10-93ED-DDC5BD80E949", "/rest/enclosure-groups/293e8efe-c6b1-4783-bf88-2d35a8e49071")
	fmt.Println(serverHarware.Type)

	print("Get power status of a server ")
	fmt.Println("******************")
	powerState, _ := serverName.GetPowerState()
	fmt.Println("Power state of the machine is ", powerState)

	print("Get ilo ipaddress of a server ")
	fmt.Println("******************")
	iloIpaddress := serverName.GetIloIPAddress()
	fmt.Println("ilo ip address of an server is =", iloIpaddress)

}
<commit_msg>fixed formatting<commit_after>package main

import (
	"fmt"
	"github.com/HewlettPackard/oneview-golang/ov"
	"os"
)

func main() {
	var (
		ClientOV *ov.OVClient
	)
	ovc := ClientOV.NewOVClient(
		os.Getenv("ONEVIEW_OV_USER"),
		os.Getenv("ONEVIEW_OV_PASSWORD"),
		os.Getenv("ONEVIEW_OV_DOMAIN"),
		os.Getenv("ONEVIEW_OV_ENDPOINT"),
		false,
		800)

	fmt.Println("Get server hardware list by name")
	serverName, _ := ovc.GetServerHardwareByName("0000A66101, bay 4")

	fmt.Println("******************")
	fmt.Println(serverName.Model)
	fmt.Println(serverName.URI)
	fmt.Println(serverName.UUID)

	fmt.Println("Get server hardware list by url")

	fmt.Println("******************")

	ServerId, _ := ovc.GetServerHardware("/rest/server-hardware/30373737-3237-4D32-3230-313530314752")
	fmt.Println(ServerId.URI)

	fmt.Println("Get server-hardware list statistics specifying parameters")
	fmt.Println("******************")

	filters := []string{"name matches '0000A66101, bay 3'"}
	ServerList, _ := ovc.GetServerHardwareList(filters, "name:ascending")
	fmt.Println("Total server list :", ServerList.Total)

	fmt.Println("Get server-hardware whoes profiles are unassigned ")
	fmt.Println("******************")
	serverHarware, _ := ovc.GetAvailableHardware("/rest/server-hardware-types/9F529AA5-2021-4A10-93ED-DDC5BD80E949", "/rest/enclosure-groups/293e8efe-c6b1-4783-bf88-2d35a8e49071")
	fmt.Println(serverHarware.Type)

	fmt.Println("Get power status of a server ")
	fmt.Println("******************")
	powerState, _ := serverName.GetPowerState()
	fmt.Println("Power state of the machine is ", powerState)

	fmt.Println("Get ilo ipaddress of a server ")
	fmt.Println("******************")
	iloIpaddress := serverName.GetIloIPAddress()
	fmt.Println("ilo ip address of an server is =", iloIpaddress)

}
<|endoftext|>


<commit_before>package tictactoe

import (
	"errors"
	"github.com/jkomoros/boardgame"
)

//TODO: test this!!

//+autoreader readsetter
type MovePlaceToken struct {
	//Which token to place the token
	Slot int
	//Which player we THINK is making the move.
	TargetPlayerIndex boardgame.PlayerIndex
}

func MovePlaceTokenFactory(state boardgame.State) boardgame.Move {
	result := &MovePlaceToken{}

	if state != nil {
		game, _ := concreteStates(state)

		result.TargetPlayerIndex = game.CurrentPlayer

		//Default to setting a slot that's empty.
		for i, token := range game.Slots.ComponentValues() {
			if token == nil {
				result.Slot = i
				break
			}
		}
	}

	return result
}

func (m *MovePlaceToken) Legal(state boardgame.State, proposer boardgame.PlayerIndex) error {
	game, players := concreteStates(state)

	if game.CurrentPlayer != m.TargetPlayerIndex {
		return errors.New("The specified player is not the current player.")
	}

	if !m.TargetPlayerIndex.Equivalent(proposer) {
		return errors.New("The proposing player is not the target player.")
	}

	if players[m.TargetPlayerIndex].UnusedTokens.Len() < 1 {
		return errors.New("There aren't any remaining tokens for the current player to place.")
	}

	if m.Slot < 0 || m.Slot >= game.Slots.Len() {
		return errors.New("The specified slot is not legal.")
	}

	if game.Slots.ComponentAt(m.Slot) != nil {
		return errors.New("The specified slot is already taken.")
	}

	return nil

}

func (m *MovePlaceToken) Apply(state boardgame.MutableState) error {

	game, players := concreteStates(state)

	u := players[m.TargetPlayerIndex]

	if err := u.UnusedTokens.MoveComponent(boardgame.FirstComponentIndex, game.Slots, m.Slot); err != nil {
		return err
	}

	u.TokensToPlaceThisTurn--

	return nil
}

func (m *MovePlaceToken) Name() string {
	return "Place Token"
}

func (m *MovePlaceToken) HelpText() string {
	return "Place a player's token in a specific space."
}

func (t *MovePlaceToken) ImmediateFixUp(state boardgame.State) boardgame.Move {
	return nil
}

//+autoreader readsetter
type MoveAdvancePlayer struct{}

func MoveAdvancePlayerFactory(state boardgame.State) boardgame.Move {
	return &MoveAdvancePlayer{}
}

func (m *MoveAdvancePlayer) Legal(state boardgame.State, proposer boardgame.PlayerIndex) error {

	game, players := concreteStates(state)

	user := players[game.CurrentPlayer]

	if user.TokensToPlaceThisTurn > 0 {
		return errors.New("The current player still has tokens left to place this turn.")
	}

	return nil
}

func (m *MoveAdvancePlayer) Apply(state boardgame.MutableState) error {

	game, players := concreteStates(state)

	game.CurrentPlayer = game.CurrentPlayer.Next(state)

	newUser := players[game.CurrentPlayer]

	newUser.TokensToPlaceThisTurn = 1

	return nil

}

func (m *MoveAdvancePlayer) Name() string {
	//TODO: these should be package constants
	return "Advance Player"
}

func (m *MoveAdvancePlayer) HelpText() string {
	return "After the current player has made all of their moves, this fix-up move advances to the next player."
}

func (t *MoveAdvancePlayer) ImmediateFixUp(state boardgame.State) boardgame.Move {
	return nil
}
<commit_msg>tictactoe uses defaultmove. Part of #309.<commit_after>package tictactoe

import (
	"errors"
	"github.com/jkomoros/boardgame"
)

//TODO: test this!!

//+autoreader readsetter
type MovePlaceToken struct {
	boardgame.DefaultMove
	//Which token to place the token
	Slot int
	//Which player we THINK is making the move.
	TargetPlayerIndex boardgame.PlayerIndex
}

func MovePlaceTokenFactory(state boardgame.State) boardgame.Move {
	result := &MovePlaceToken{
		boardgame.DefaultMove{
			"Place Token",
			"Place a player's token in a specific space.",
		},
		0,
		0,
	}

	if state != nil {
		game, _ := concreteStates(state)

		result.TargetPlayerIndex = game.CurrentPlayer

		//Default to setting a slot that's empty.
		for i, token := range game.Slots.ComponentValues() {
			if token == nil {
				result.Slot = i
				break
			}
		}
	}

	return result
}

func (m *MovePlaceToken) Legal(state boardgame.State, proposer boardgame.PlayerIndex) error {
	game, players := concreteStates(state)

	if game.CurrentPlayer != m.TargetPlayerIndex {
		return errors.New("The specified player is not the current player.")
	}

	if !m.TargetPlayerIndex.Equivalent(proposer) {
		return errors.New("The proposing player is not the target player.")
	}

	if players[m.TargetPlayerIndex].UnusedTokens.Len() < 1 {
		return errors.New("There aren't any remaining tokens for the current player to place.")
	}

	if m.Slot < 0 || m.Slot >= game.Slots.Len() {
		return errors.New("The specified slot is not legal.")
	}

	if game.Slots.ComponentAt(m.Slot) != nil {
		return errors.New("The specified slot is already taken.")
	}

	return nil

}

func (m *MovePlaceToken) Apply(state boardgame.MutableState) error {

	game, players := concreteStates(state)

	u := players[m.TargetPlayerIndex]

	if err := u.UnusedTokens.MoveComponent(boardgame.FirstComponentIndex, game.Slots, m.Slot); err != nil {
		return err
	}

	u.TokensToPlaceThisTurn--

	return nil
}

//+autoreader readsetter
type MoveAdvancePlayer struct {
	boardgame.DefaultMove
}

func MoveAdvancePlayerFactory(state boardgame.State) boardgame.Move {
	return &MoveAdvancePlayer{
		boardgame.DefaultMove{
			"Advance Player",
			"After the current player has made all of their moves, this fix-up move advances to the next player.",
		},
	}
}

func (m *MoveAdvancePlayer) Legal(state boardgame.State, proposer boardgame.PlayerIndex) error {

	game, players := concreteStates(state)

	user := players[game.CurrentPlayer]

	if user.TokensToPlaceThisTurn > 0 {
		return errors.New("The current player still has tokens left to place this turn.")
	}

	return nil
}

func (m *MoveAdvancePlayer) Apply(state boardgame.MutableState) error {

	game, players := concreteStates(state)

	game.CurrentPlayer = game.CurrentPlayer.Next(state)

	newUser := players[game.CurrentPlayer]

	newUser.TokensToPlaceThisTurn = 1

	return nil

}
<|endoftext|>


<commit_before>package typed

import (
	"testing"

	"github.com/elpinal/coco3/extra/types"
)

func TestSignature(t *testing.T) {
	cmd := Command{Params: []types.Type{types.Int, types.String}}
	got := string(cmd.Signature())
	want := "Int -> String"
	if got != want {
		t.Errorf("got %q, want %q", got, want)
	}
}
<commit_msg>Update test for Command.Signature<commit_after>package typed

import (
	"testing"

	"github.com/elpinal/coco3/extra/types"
)

func TestSignature(t *testing.T) {
	tests := []struct {
		ts   []types.Type
		want string
	}{
		{
			ts:   []types.Type{},
			want: "",
		},
		{
			ts:   []types.Type{types.Int},
			want: "Int",
		},
		{
			ts:   []types.Type{types.Int, types.String},
			want: "Int -> String",
		},
		{
			ts:   []types.Type{types.Int, types.String, types.StringList},
			want: "Int -> String -> List String",
		},
	}
	for i, test := range tests {
		cmd := Command{Params: test.ts}
		got := string(cmd.Signature())
		if got != test.want {
			t.Errorf("Signature/%d: got %q, want %q", i, got, test.want)
		}
	}
}
<|endoftext|>