<commit_before>package cloudformation

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"

	"golang.org/x/net/context"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/client"
	"github.com/aws/aws-sdk-go/service/ecs"
	"github.com/aws/aws-sdk-go/service/sqs"
	"github.com/remind101/empire"
	"github.com/remind101/empire/scheduler/ecs/lb"
	"github.com/remind101/pkg/logger"
	"github.com/remind101/pkg/reporter"
)

// Provisioner is something that can provision custom resources.
type Provisioner interface {
	// Provision should do the appropriate provisioning, then return:
	//
	// 1. The physical id that was created, if any.
	// 2. The data to return.
	Provision(Request) (string, interface{}, error)
}

// Possible request types.
const (
	Create = "Create"
	Update = "Update"
	Delete = "Delete"
)

// Request represents a Custom Resource request.
//
// See http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref-requests.html
type Request struct {
	// The request type is set by the AWS CloudFormation stack operation
	// (create-stack, update-stack, or delete-stack) that was initiated by
	// the template developer for the stack that contains the custom
	// resource.
	//
	// Must be one of: Create, Update, or Delete.
	RequestType string `json:"RequestType"`

	// The response URL identifies a pre-signed Amazon S3 bucket that
	// receives responses from the custom resource provider to AWS
	// CloudFormation.
	ResponseURL string `json:"ResponseURL"`

	// The Amazon Resource Name (ARN) that identifies the stack containing
	// the custom resource.
	//
	// Combining the StackId with the RequestId forms a value that can be
	// used to uniquely identify a request on a particular custom resource.
	StackId string `json:"StackId"`

	// A unique ID for the request.
	//
	// Combining the StackId with the RequestId forms a value that can be
	// used to uniquely identify a request on a particular custom resource.
	RequestId string `json:"RequestId"`

	// The template developer-chosen resource type of the custom resource in
	// the AWS CloudFormation template. Custom resource type names can be up
	// to 60 characters long and can include alphanumeric and the following
	// characters: _@-.
	ResourceType string `json:"ResourceType"`

	// The template developer-chosen name (logical ID) of the custom
	// resource in the AWS CloudFormation template. This is provided to
	// facilitate communication between the custom resource provider and the
	// template developer.
	LogicalResourceId string `json:"LogicalResourceId"`

	// A required custom resource provider-defined physical ID that is
	// unique for that provider.
	//
	// Always sent with Update and Delete requests; never sent with Create.
	PhysicalResourceId string `json:"PhysicalResourceId"`

	// This field contains the contents of the Properties object sent by the
	// template developer. Its contents are defined by the custom resource
	// provider.
	ResourceProperties map[string]interface{} `json:"ResourceProperties"`

	// Used only for Update requests. Contains the resource properties that
	// were declared previous to the update request.
	OldResourceProperties map[string]interface{} `json:"OldResourceProperties"`
}

// Possible response statuses.
const (
	StatusSuccess = "SUCCESS"
	StatusFailed  = "FAILED"
)

// Response represents the response body we send back to CloudFormation when
// provisioning is complete.
//
// See http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref-responses.html
type Response struct {
	// The status value sent by the custom resource provider in response to
	// an AWS CloudFormation-generated request.
	//
	// Must be either SUCCESS or FAILED.
	Status string `json:"Status"`

	// Describes the reason for a failure response.
	//
	// Required if Status is FAILED; optional otherwise.
	Reason string `json:"Reason"`

	// This value should be an identifier unique to the custom resource
	// vendor, and can be up to 1Kb in size. The value must be a non-empty
	// string.
	PhysicalResourceId string `json:"PhysicalResourceId"`

	// The Amazon Resource Name (ARN) that identifies the stack containing
	// the custom resource. This response value should be copied verbatim
	// from the request.
	StackId string `json:"StackId"`

	// A unique ID for the request. This response value should be copied
	// verbatim from the request.
	RequestId string `json:"RequestId"`

	// The template developer-chosen name (logical ID) of the custom
	// resource in the AWS CloudFormation template. This response value
	// should be copied verbatim from the request.
	LogicalResourceId string `json:"LogicalResourceId"`

	// Optional, custom resource provider-defined name-value pairs to send
	// with the response. The values provided here can be accessed by name
	// in the template with Fn::GetAtt.
	Data interface{} `json:"Data"`
}

// Represents the body of the SQS message, which would have been received from
// SNS.
type Message struct {
	Message string `json:"Message"`
}

// NewResponseFromRequest initializes a new Response from a Request, filling in
// the required verbatim fields.
func NewResponseFromRequest(req Request) Response {
	return Response{
		StackId:           req.StackId,
		RequestId:         req.RequestId,
		LogicalResourceId: req.LogicalResourceId,
	}
}

// NewUser returns an empire.User that should be used by sources when making
// requests to empire.
func NewUser() *empire.User {
	return &empire.User{Name: "cloudformation"}
}

// sqsClient duck types the sqs.SQS interface.
type sqsClient interface {
	ReceiveMessage(*sqs.ReceiveMessageInput) (*sqs.ReceiveMessageOutput, error)
	DeleteMessage(*sqs.DeleteMessageInput) (*sqs.DeleteMessageOutput, error)
}

// CustomResourceProvisioner polls for CloudFormation Custom Resource requests
// from an sqs queue, provisions them, then responds back.
type CustomResourceProvisioner struct {
	// Logger to use to perform logging.
	Logger logger.Logger

	// The SQS queue url to listen for CloudFormation Custom Resource
	// requests.
	QueueURL string

	// Provisioners routes a custom resource to the thing that should do the
	// provisioning.
	Provisioners map[string]Provisioner

	// Reporter is called when an error occurs during provisioning.
	Reporter reporter.Reporter

	client interface {
		Do(*http.Request) (*http.Response, error)
	}
	sqs sqsClient
}

// NewCustomResourceProvisioner returns a new CustomResourceProvisioner with an
// sqs client configured from config.
func NewCustomResourceProvisioner(empire *empire.Empire, config client.ConfigProvider) *CustomResourceProvisioner {
	return &CustomResourceProvisioner{
		Provisioners: map[string]Provisioner{
			"Custom::InstancePort": &InstancePortsProvisioner{
				ports: lb.NewDBPortAllocator(empire.DB.DB.DB()),
			},
			"Custom::EmpireApp": &AppResource{
				empire: empire,
			},
			"Custom:EmpireAppEnvironment": &EnvironmentResource{
				empire: empire,
			},
			"Custom::ECSService": &ECSServiceResource{
				ecs:     ecs.New(config),
				postfix: postfix,
			},
		},
		client: http.DefaultClient,
		sqs:    sqs.New(config),
	}
}

// Start starts pulling requests from the queue and provisioning them.
func (c *CustomResourceProvisioner) Start() {
	t := time.Tick(10 * time.Second)

	for range t {
		ctx := context.Background()

		resp, err := c.sqs.ReceiveMessage(&sqs.ReceiveMessageInput{
			QueueUrl: aws.String(c.QueueURL),
		})
		if err != nil {
			c.Reporter.Report(ctx, err)
			continue
		}

		for _, m := range resp.Messages {
			if err := c.handle(m); err != nil {
				c.Reporter.Report(ctx, err)
				continue
			}
		}
	}
}

func (c *CustomResourceProvisioner) handle(message *sqs.Message) error {
	err := c.Handle(message)
	if err == nil {
		_, err = c.sqs.DeleteMessage(&sqs.DeleteMessageInput{
			QueueUrl:      aws.String(c.QueueURL),
			ReceiptHandle: message.ReceiptHandle,
		})
	}

	return err
}

// Handle handles a single sqs.Message to perform the provisioning.
func (c *CustomResourceProvisioner) Handle(message *sqs.Message) error {
	var m Message
	err := json.Unmarshal([]byte(*message.Body), &m)
	if err != nil {
		return fmt.Errorf("error unmarshalling sqs message body: %v", err)
	}

	var req Request
	err = json.Unmarshal([]byte(m.Message), &req)
	if err != nil {
		return fmt.Errorf("error unmarshalling to cloudformation request: %v", err)
	}

	p, ok := c.Provisioners[req.ResourceType]
	if !ok {
		return fmt.Errorf("no provisioner for %v", req.ResourceType)
	}

	// If the provisioner defines a type for the properties, let's unmarhsal
	// into that Go type.
	if p, ok := p.(interface {
		Properties() interface{}
	}); ok {
		req.ResourceProperties = p.Properties()
		req.OldResourceProperties = p.Properties()
		err = json.Unmarshal([]byte(m.Message), &req)
		if err != nil {
			return fmt.Errorf("error unmarshalling to cloudformation request: %v", err)
		}
	}

	resp := NewResponseFromRequest(req)
	resp.PhysicalResourceId, resp.Data, err = p.Provision(req)
	switch err {
	case nil:
		resp.Status = StatusSuccess
		c.Logger.Info("cloudformation.provision",
			"request", req,
			"response", resp,
		)
	default:
		resp.Status = StatusFailed
		resp.Reason = err.Error()
		c.Logger.Error("cloudformation.provision.error",
			"request", req,
			"response", resp,
			"err", err.Error(),
		)
	}

	raw, err := json.Marshal(resp)
	if err != nil {
		return err
	}

	r, err := http.NewRequest("PUT", req.ResponseURL, bytes.NewReader(raw))
	if err != nil {
		return err
	}

	httpResp, err := c.client.Do(r)
	if err != nil {
		return err
	}
	defer httpResp.Body.Close()
	body, _ := ioutil.ReadAll(httpResp.Body)

	if code := httpResp.StatusCode; code/100 != 2 {
		return fmt.Errorf("unexpected response from pre-signed url: %v: %v", code, string(body))
	}

	return nil
}

// IntValue defines an int64 type that can parse integers as strings from json.
// It's common to use `Ref`'s inside templates, which means the value of some
// properties could be a string or an integer.
type IntValue int64

func intValue(v int64) *IntValue {
	i := IntValue(v)
	return &i
}

func (i *IntValue) UnmarshalJSON(b []byte) error {
	var si int64
	if err := json.Unmarshal(b, &si); err == nil {
		*i = IntValue(si)
		return nil
	}

	v, err := strconv.Atoi(string(b[1 : len(b)-1]))
	if err != nil {
		return fmt.Errorf("error parsing int from string: %v", err)
	}

	*i = IntValue(v)
	return nil
}

func (i *IntValue) Value() *int64 {
	if i == nil {
		return nil
	}
	p := int64(*i)
	return &p
}
<commit_msg>Use interface{} so we can cast to specific types<commit_after>package cloudformation

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"

	"golang.org/x/net/context"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/client"
	"github.com/aws/aws-sdk-go/service/ecs"
	"github.com/aws/aws-sdk-go/service/sqs"
	"github.com/remind101/empire"
	"github.com/remind101/empire/scheduler/ecs/lb"
	"github.com/remind101/pkg/logger"
	"github.com/remind101/pkg/reporter"
)

// Provisioner is something that can provision custom resources.
type Provisioner interface {
	// Provision should do the appropriate provisioning, then return:
	//
	// 1. The physical id that was created, if any.
	// 2. The data to return.
	Provision(Request) (string, interface{}, error)
}

// Possible request types.
const (
	Create = "Create"
	Update = "Update"
	Delete = "Delete"
)

// Request represents a Custom Resource request.
//
// See http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref-requests.html
type Request struct {
	// The request type is set by the AWS CloudFormation stack operation
	// (create-stack, update-stack, or delete-stack) that was initiated by
	// the template developer for the stack that contains the custom
	// resource.
	//
	// Must be one of: Create, Update, or Delete.
	RequestType string `json:"RequestType"`

	// The response URL identifies a pre-signed Amazon S3 bucket that
	// receives responses from the custom resource provider to AWS
	// CloudFormation.
	ResponseURL string `json:"ResponseURL"`

	// The Amazon Resource Name (ARN) that identifies the stack containing
	// the custom resource.
	//
	// Combining the StackId with the RequestId forms a value that can be
	// used to uniquely identify a request on a particular custom resource.
	StackId string `json:"StackId"`

	// A unique ID for the request.
	//
	// Combining the StackId with the RequestId forms a value that can be
	// used to uniquely identify a request on a particular custom resource.
	RequestId string `json:"RequestId"`

	// The template developer-chosen resource type of the custom resource in
	// the AWS CloudFormation template. Custom resource type names can be up
	// to 60 characters long and can include alphanumeric and the following
	// characters: _@-.
	ResourceType string `json:"ResourceType"`

	// The template developer-chosen name (logical ID) of the custom
	// resource in the AWS CloudFormation template. This is provided to
	// facilitate communication between the custom resource provider and the
	// template developer.
	LogicalResourceId string `json:"LogicalResourceId"`

	// A required custom resource provider-defined physical ID that is
	// unique for that provider.
	//
	// Always sent with Update and Delete requests; never sent with Create.
	PhysicalResourceId string `json:"PhysicalResourceId"`

	// This field contains the contents of the Properties object sent by the
	// template developer. Its contents are defined by the custom resource
	// provider.
	ResourceProperties interface{} `json:"ResourceProperties"`

	// Used only for Update requests. Contains the resource properties that
	// were declared previous to the update request.
	OldResourceProperties interface{} `json:"OldResourceProperties"`
}

// Possible response statuses.
const (
	StatusSuccess = "SUCCESS"
	StatusFailed  = "FAILED"
)

// Response represents the response body we send back to CloudFormation when
// provisioning is complete.
//
// See http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref-responses.html
type Response struct {
	// The status value sent by the custom resource provider in response to
	// an AWS CloudFormation-generated request.
	//
	// Must be either SUCCESS or FAILED.
	Status string `json:"Status"`

	// Describes the reason for a failure response.
	//
	// Required if Status is FAILED; optional otherwise.
	Reason string `json:"Reason"`

	// This value should be an identifier unique to the custom resource
	// vendor, and can be up to 1Kb in size. The value must be a non-empty
	// string.
	PhysicalResourceId string `json:"PhysicalResourceId"`

	// The Amazon Resource Name (ARN) that identifies the stack containing
	// the custom resource. This response value should be copied verbatim
	// from the request.
	StackId string `json:"StackId"`

	// A unique ID for the request. This response value should be copied
	// verbatim from the request.
	RequestId string `json:"RequestId"`

	// The template developer-chosen name (logical ID) of the custom
	// resource in the AWS CloudFormation template. This response value
	// should be copied verbatim from the request.
	LogicalResourceId string `json:"LogicalResourceId"`

	// Optional, custom resource provider-defined name-value pairs to send
	// with the response. The values provided here can be accessed by name
	// in the template with Fn::GetAtt.
	Data interface{} `json:"Data"`
}

// Represents the body of the SQS message, which would have been received from
// SNS.
type Message struct {
	Message string `json:"Message"`
}

// NewResponseFromRequest initializes a new Response from a Request, filling in
// the required verbatim fields.
func NewResponseFromRequest(req Request) Response {
	return Response{
		StackId:           req.StackId,
		RequestId:         req.RequestId,
		LogicalResourceId: req.LogicalResourceId,
	}
}

// NewUser returns an empire.User that should be used by sources when making
// requests to empire.
func NewUser() *empire.User {
	return &empire.User{Name: "cloudformation"}
}

// sqsClient duck types the sqs.SQS interface.
type sqsClient interface {
	ReceiveMessage(*sqs.ReceiveMessageInput) (*sqs.ReceiveMessageOutput, error)
	DeleteMessage(*sqs.DeleteMessageInput) (*sqs.DeleteMessageOutput, error)
}

// CustomResourceProvisioner polls for CloudFormation Custom Resource requests
// from an sqs queue, provisions them, then responds back.
type CustomResourceProvisioner struct {
	// Logger to use to perform logging.
	Logger logger.Logger

	// The SQS queue url to listen for CloudFormation Custom Resource
	// requests.
	QueueURL string

	// Provisioners routes a custom resource to the thing that should do the
	// provisioning.
	Provisioners map[string]Provisioner

	// Reporter is called when an error occurs during provisioning.
	Reporter reporter.Reporter

	client interface {
		Do(*http.Request) (*http.Response, error)
	}
	sqs sqsClient
}

// NewCustomResourceProvisioner returns a new CustomResourceProvisioner with an
// sqs client configured from config.
func NewCustomResourceProvisioner(empire *empire.Empire, config client.ConfigProvider) *CustomResourceProvisioner {
	return &CustomResourceProvisioner{
		Provisioners: map[string]Provisioner{
			"Custom::InstancePort": &InstancePortsProvisioner{
				ports: lb.NewDBPortAllocator(empire.DB.DB.DB()),
			},
			"Custom::EmpireApp": &AppResource{
				empire: empire,
			},
			"Custom:EmpireAppEnvironment": &EnvironmentResource{
				empire: empire,
			},
			"Custom::ECSService": &ECSServiceResource{
				ecs:     ecs.New(config),
				postfix: postfix,
			},
		},
		client: http.DefaultClient,
		sqs:    sqs.New(config),
	}
}

// Start starts pulling requests from the queue and provisioning them.
func (c *CustomResourceProvisioner) Start() {
	t := time.Tick(10 * time.Second)

	for range t {
		ctx := context.Background()

		resp, err := c.sqs.ReceiveMessage(&sqs.ReceiveMessageInput{
			QueueUrl: aws.String(c.QueueURL),
		})
		if err != nil {
			c.Reporter.Report(ctx, err)
			continue
		}

		for _, m := range resp.Messages {
			if err := c.handle(m); err != nil {
				c.Reporter.Report(ctx, err)
				continue
			}
		}
	}
}

func (c *CustomResourceProvisioner) handle(message *sqs.Message) error {
	err := c.Handle(message)
	if err == nil {
		_, err = c.sqs.DeleteMessage(&sqs.DeleteMessageInput{
			QueueUrl:      aws.String(c.QueueURL),
			ReceiptHandle: message.ReceiptHandle,
		})
	}

	return err
}

// Handle handles a single sqs.Message to perform the provisioning.
func (c *CustomResourceProvisioner) Handle(message *sqs.Message) error {
	var m Message
	err := json.Unmarshal([]byte(*message.Body), &m)
	if err != nil {
		return fmt.Errorf("error unmarshalling sqs message body: %v", err)
	}

	var req Request
	err = json.Unmarshal([]byte(m.Message), &req)
	if err != nil {
		return fmt.Errorf("error unmarshalling to cloudformation request: %v", err)
	}

	p, ok := c.Provisioners[req.ResourceType]
	if !ok {
		return fmt.Errorf("no provisioner for %v", req.ResourceType)
	}

	// If the provisioner defines a type for the properties, let's unmarhsal
	// into that Go type.
	if p, ok := p.(interface {
		Properties() interface{}
	}); ok {
		req.ResourceProperties = p.Properties()
		req.OldResourceProperties = p.Properties()
		err = json.Unmarshal([]byte(m.Message), &req)
		if err != nil {
			return fmt.Errorf("error unmarshalling to cloudformation request: %v", err)
		}
	}

	resp := NewResponseFromRequest(req)
	resp.PhysicalResourceId, resp.Data, err = p.Provision(req)
	switch err {
	case nil:
		resp.Status = StatusSuccess
		c.Logger.Info("cloudformation.provision",
			"request", req,
			"response", resp,
		)
	default:
		resp.Status = StatusFailed
		resp.Reason = err.Error()
		c.Logger.Error("cloudformation.provision.error",
			"request", req,
			"response", resp,
			"err", err.Error(),
		)
	}

	raw, err := json.Marshal(resp)
	if err != nil {
		return err
	}

	r, err := http.NewRequest("PUT", req.ResponseURL, bytes.NewReader(raw))
	if err != nil {
		return err
	}

	httpResp, err := c.client.Do(r)
	if err != nil {
		return err
	}
	defer httpResp.Body.Close()
	body, _ := ioutil.ReadAll(httpResp.Body)

	if code := httpResp.StatusCode; code/100 != 2 {
		return fmt.Errorf("unexpected response from pre-signed url: %v: %v", code, string(body))
	}

	return nil
}

// IntValue defines an int64 type that can parse integers as strings from json.
// It's common to use `Ref`'s inside templates, which means the value of some
// properties could be a string or an integer.
type IntValue int64

func intValue(v int64) *IntValue {
	i := IntValue(v)
	return &i
}

func (i *IntValue) UnmarshalJSON(b []byte) error {
	var si int64
	if err := json.Unmarshal(b, &si); err == nil {
		*i = IntValue(si)
		return nil
	}

	v, err := strconv.Atoi(string(b[1 : len(b)-1]))
	if err != nil {
		return fmt.Errorf("error parsing int from string: %v", err)
	}

	*i = IntValue(v)
	return nil
}

func (i *IntValue) Value() *int64 {
	if i == nil {
		return nil
	}
	p := int64(*i)
	return &p
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2019 VMware, Inc. All Rights Reserved.

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 object_test

import (
	"context"
	"fmt"
	"log"

	"github.com/vmware/govmomi/find"
	"github.com/vmware/govmomi/object"
	"github.com/vmware/govmomi/property"
	"github.com/vmware/govmomi/simulator"
	"github.com/vmware/govmomi/view"
	"github.com/vmware/govmomi/vim25"
	"github.com/vmware/govmomi/vim25/mo"
	"github.com/vmware/govmomi/vim25/types"
)

func ExampleResourcePool_Owner() {
	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
		finder := find.NewFinder(c)

		for _, name := range []string{"DC0_H0_VM0", "DC0_C0_RP0_VM0"} {
			vm, err := finder.VirtualMachine(ctx, name)
			if err != nil {
				return err
			}

			pool, err := vm.ResourcePool(ctx)
			if err != nil {
				return err
			}

			owner, err := pool.Owner(ctx)
			if err != nil {
				return err
			}

			fmt.Printf("%s owner is a %T\n", name, owner)
		}

		return nil
	})
	// Output:
	// DC0_H0_VM0 owner is a *object.ComputeResource
	// DC0_C0_RP0_VM0 owner is a *object.ClusterComputeResource
}

func ExampleVirtualMachine_CreateSnapshot() {
	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
		vm, err := find.NewFinder(c).VirtualMachine(ctx, "DC0_H0_VM0")
		if err != nil {
			return err
		}

		task, err := vm.CreateSnapshot(ctx, "backup", "Backup", false, false)
		if err != nil {
			return err
		}
		if err = task.Wait(ctx); err != nil {
			return err
		}

		id, err := vm.FindSnapshot(ctx, "backup")
		if err != nil {
			return err
		}

		var snapshot mo.VirtualMachineSnapshot
		err = vm.Properties(ctx, *id, []string{"config.hardware.device"}, &snapshot)
		if err != nil {
			return err
		}

		fmt.Printf("%d devices", len(snapshot.Config.Hardware.Device))

		return nil
	})
	// Output: 13 devices
}

func ExampleVirtualMachine_HostSystem() {
	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
		vm, err := find.NewFinder(c).VirtualMachine(ctx, "DC0_H0_VM0")
		if err != nil {
			return err
		}

		host, err := vm.HostSystem(ctx)
		if err != nil {
			return err
		}

		name, err := host.ObjectName(ctx)
		if err != nil {
			return err
		}

		fmt.Println(name)

		return nil
	})
	// Output: DC0_H0
}

func ExampleVirtualMachine_Clone() {
	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
		finder := find.NewFinder(c)
		dc, err := finder.Datacenter(ctx, "DC0")
		if err != nil {
			return err
		}

		finder.SetDatacenter(dc)

		vm, err := finder.VirtualMachine(ctx, "DC0_H0_VM0")
		if err != nil {
			return err
		}

		folders, err := dc.Folders(ctx)
		if err != nil {
			return err
		}

		spec := types.VirtualMachineCloneSpec{
			PowerOn: false,
		}

		task, err := vm.Clone(ctx, folders.VmFolder, "example-clone", spec)
		if err != nil {
			return err
		}

		info, err := task.WaitForResult(ctx)
		if err != nil {
			return err
		}

		clone := object.NewVirtualMachine(c, info.Result.(types.ManagedObjectReference))
		name, err := clone.ObjectName(ctx)
		if err != nil {
			return err
		}

		fmt.Println(name)

		return nil
	})
	// Output: example-clone
}

func ExampleVirtualMachine_Reconfigure() {
	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
		vm, err := find.NewFinder(c).VirtualMachine(ctx, "DC0_H0_VM0")
		if err != nil {
			return err
		}

		spec := types.VirtualMachineConfigSpec{Annotation: "example reconfig"}

		task, err := vm.Reconfigure(ctx, spec)
		if err != nil {
			return err
		}

		err = task.Wait(ctx)
		if err != nil {
			return err
		}

		var obj mo.VirtualMachine
		err = vm.Properties(ctx, vm.Reference(), []string{"config.annotation"}, &obj)
		if err != nil {
			return err
		}

		fmt.Println(obj.Config.Annotation)

		return nil
	})
	// Output: example reconfig
}

func ExampleCommon_Destroy() {
	model := simulator.VPX()
	model.Datastore = 2

	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
		// Change to "LocalDS_0" will cause ResourceInUse error,
		// as simulator VMs created by the VPX model use "LocalDS_0".
		ds, err := find.NewFinder(c).Datastore(ctx, "LocalDS_1")
		if err != nil {
			return err
		}

		task, err := ds.Destroy(ctx)
		if err != nil {
			return err
		}

		if err = task.Wait(ctx); err != nil {
			return err
		}

		fmt.Println("destroyed", ds.InventoryPath)
		return nil
	}, model)
	// Output: destroyed /DC0/datastore/LocalDS_1
}

func ExampleCustomFieldsManager_Set() {
	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
		m, err := object.GetCustomFieldsManager(c)
		if err != nil {
			return err
		}

		any := []string{"ManagedEntity"}
		field, err := m.Add(ctx, "backup", any[0], nil, nil) // adds the custom field "backup" to all types
		if err != nil {
			return err
		}

		v, err := view.NewManager(c).CreateContainerView(ctx, c.ServiceContent.RootFolder, any, true)
		if err != nil {
			log.Fatal(err)
		}

		all, err := v.Find(ctx, any, nil) // gives us the count of all objects in the inventory
		if err != nil {
			return err
		}

		refs, err := v.Find(ctx, []string{"VirtualMachine", "Datastore"}, nil)
		if err != nil {
			return err
		}

		for _, ref := range refs {
			err = m.Set(ctx, ref, field.Key, "true") // sets the custom value "backup=true" on specific types
			if err != nil {
				return err
			}
		}

		// filter used to find objects with "backup=true"
		filter := property.Filter{"customValue": &types.CustomFieldStringValue{
			CustomFieldValue: types.CustomFieldValue{Key: field.Key},
			Value:            "true",
		}}

		var objs []mo.ManagedEntity
		err = v.RetrieveWithFilter(ctx, any, []string{"name", "customValue"}, &objs, filter)
		if err != nil {
			return err
		}

		fmt.Printf("backup %d of %d objects", len(objs), len(all))
		return v.Destroy(ctx)
	})
	// Output: backup 5 of 22 objects
}

func ExampleCustomizationSpecManager_Info() {
	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
		m := object.NewCustomizationSpecManager(c)
		info, err := m.Info(ctx)
		if err != nil {
			return err
		}

		for i := range info {
			item, err := m.GetCustomizationSpec(ctx, info[i].Name)
			if err != nil {
				return err
			}
			fmt.Printf("%s=%T\n", item.Info.Name, item.Spec.Identity)
		}
		return nil
	})
	// Output:
	// vcsim-linux=*types.CustomizationLinuxPrep
	// vcsim-linux-static=*types.CustomizationLinuxPrep
	// vcsim-windows-static=*types.CustomizationSysprep
	// vcsim-windows-domain=*types.CustomizationSysprep
}
<commit_msg>examples: add VirtualMachine.Customize<commit_after>/*
Copyright (c) 2019 VMware, Inc. All Rights Reserved.

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 object_test

import (
	"context"
	"fmt"
	"log"

	"github.com/vmware/govmomi/find"
	"github.com/vmware/govmomi/object"
	"github.com/vmware/govmomi/property"
	"github.com/vmware/govmomi/simulator"
	"github.com/vmware/govmomi/view"
	"github.com/vmware/govmomi/vim25"
	"github.com/vmware/govmomi/vim25/mo"
	"github.com/vmware/govmomi/vim25/types"
)

func ExampleResourcePool_Owner() {
	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
		finder := find.NewFinder(c)

		for _, name := range []string{"DC0_H0_VM0", "DC0_C0_RP0_VM0"} {
			vm, err := finder.VirtualMachine(ctx, name)
			if err != nil {
				return err
			}

			pool, err := vm.ResourcePool(ctx)
			if err != nil {
				return err
			}

			owner, err := pool.Owner(ctx)
			if err != nil {
				return err
			}

			fmt.Printf("%s owner is a %T\n", name, owner)
		}

		return nil
	})
	// Output:
	// DC0_H0_VM0 owner is a *object.ComputeResource
	// DC0_C0_RP0_VM0 owner is a *object.ClusterComputeResource
}

func ExampleVirtualMachine_CreateSnapshot() {
	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
		vm, err := find.NewFinder(c).VirtualMachine(ctx, "DC0_H0_VM0")
		if err != nil {
			return err
		}

		task, err := vm.CreateSnapshot(ctx, "backup", "Backup", false, false)
		if err != nil {
			return err
		}
		if err = task.Wait(ctx); err != nil {
			return err
		}

		id, err := vm.FindSnapshot(ctx, "backup")
		if err != nil {
			return err
		}

		var snapshot mo.VirtualMachineSnapshot
		err = vm.Properties(ctx, *id, []string{"config.hardware.device"}, &snapshot)
		if err != nil {
			return err
		}

		fmt.Printf("%d devices", len(snapshot.Config.Hardware.Device))

		return nil
	})
	// Output: 13 devices
}

func ExampleVirtualMachine_Customize() {
	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
		vm, err := find.NewFinder(c).VirtualMachine(ctx, "DC0_H0_VM0")
		if err != nil {
			return err
		}
		task, err := vm.PowerOff(ctx)
		if err != nil {
			return err
		}
		if err = task.Wait(ctx); err != nil {
			return err
		}

		spec := types.CustomizationSpec{
			NicSettingMap: []types.CustomizationAdapterMapping{
				types.CustomizationAdapterMapping{
					Adapter: types.CustomizationIPSettings{
						Ip: &types.CustomizationFixedIp{
							IpAddress: "192.168.1.100",
						},
						SubnetMask:    "255.255.255.0",
						Gateway:       []string{"192.168.1.1"},
						DnsServerList: []string{"192.168.1.1"},
						DnsDomain:     "ad.domain",
					},
				},
			},
			Identity: &types.CustomizationLinuxPrep{
				HostName: &types.CustomizationFixedName{
					Name: "hostname",
				},
				Domain:     "ad.domain",
				TimeZone:   "Etc/UTC",
				HwClockUTC: types.NewBool(true),
			},
			GlobalIPSettings: types.CustomizationGlobalIPSettings{
				DnsSuffixList: []string{"ad.domain"},
				DnsServerList: []string{"192.168.1.1"},
			},
		}

		task, err = vm.Customize(ctx, spec)
		if err != nil {
			return err
		}
		if err = task.Wait(ctx); err != nil {
			return err
		}

		task, err = vm.PowerOn(ctx)
		if err != nil {
			return err
		}
		if err = task.Wait(ctx); err != nil {
			return err
		}

		ip, err := vm.WaitForIP(ctx)
		if err != nil {
			return err
		}

		fmt.Println(ip)

		return nil
	})
	// Output: 192.168.1.100
}

func ExampleVirtualMachine_HostSystem() {
	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
		vm, err := find.NewFinder(c).VirtualMachine(ctx, "DC0_H0_VM0")
		if err != nil {
			return err
		}

		host, err := vm.HostSystem(ctx)
		if err != nil {
			return err
		}

		name, err := host.ObjectName(ctx)
		if err != nil {
			return err
		}

		fmt.Println(name)

		return nil
	})
	// Output: DC0_H0
}

func ExampleVirtualMachine_Clone() {
	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
		finder := find.NewFinder(c)
		dc, err := finder.Datacenter(ctx, "DC0")
		if err != nil {
			return err
		}

		finder.SetDatacenter(dc)

		vm, err := finder.VirtualMachine(ctx, "DC0_H0_VM0")
		if err != nil {
			return err
		}

		folders, err := dc.Folders(ctx)
		if err != nil {
			return err
		}

		spec := types.VirtualMachineCloneSpec{
			PowerOn: false,
		}

		task, err := vm.Clone(ctx, folders.VmFolder, "example-clone", spec)
		if err != nil {
			return err
		}

		info, err := task.WaitForResult(ctx)
		if err != nil {
			return err
		}

		clone := object.NewVirtualMachine(c, info.Result.(types.ManagedObjectReference))
		name, err := clone.ObjectName(ctx)
		if err != nil {
			return err
		}

		fmt.Println(name)

		return nil
	})
	// Output: example-clone
}

func ExampleVirtualMachine_Reconfigure() {
	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
		vm, err := find.NewFinder(c).VirtualMachine(ctx, "DC0_H0_VM0")
		if err != nil {
			return err
		}

		spec := types.VirtualMachineConfigSpec{Annotation: "example reconfig"}

		task, err := vm.Reconfigure(ctx, spec)
		if err != nil {
			return err
		}

		err = task.Wait(ctx)
		if err != nil {
			return err
		}

		var obj mo.VirtualMachine
		err = vm.Properties(ctx, vm.Reference(), []string{"config.annotation"}, &obj)
		if err != nil {
			return err
		}

		fmt.Println(obj.Config.Annotation)

		return nil
	})
	// Output: example reconfig
}

func ExampleCommon_Destroy() {
	model := simulator.VPX()
	model.Datastore = 2

	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
		// Change to "LocalDS_0" will cause ResourceInUse error,
		// as simulator VMs created by the VPX model use "LocalDS_0".
		ds, err := find.NewFinder(c).Datastore(ctx, "LocalDS_1")
		if err != nil {
			return err
		}

		task, err := ds.Destroy(ctx)
		if err != nil {
			return err
		}

		if err = task.Wait(ctx); err != nil {
			return err
		}

		fmt.Println("destroyed", ds.InventoryPath)
		return nil
	}, model)
	// Output: destroyed /DC0/datastore/LocalDS_1
}

func ExampleCustomFieldsManager_Set() {
	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
		m, err := object.GetCustomFieldsManager(c)
		if err != nil {
			return err
		}

		any := []string{"ManagedEntity"}
		field, err := m.Add(ctx, "backup", any[0], nil, nil) // adds the custom field "backup" to all types
		if err != nil {
			return err
		}

		v, err := view.NewManager(c).CreateContainerView(ctx, c.ServiceContent.RootFolder, any, true)
		if err != nil {
			log.Fatal(err)
		}

		all, err := v.Find(ctx, any, nil) // gives us the count of all objects in the inventory
		if err != nil {
			return err
		}

		refs, err := v.Find(ctx, []string{"VirtualMachine", "Datastore"}, nil)
		if err != nil {
			return err
		}

		for _, ref := range refs {
			err = m.Set(ctx, ref, field.Key, "true") // sets the custom value "backup=true" on specific types
			if err != nil {
				return err
			}
		}

		// filter used to find objects with "backup=true"
		filter := property.Filter{"customValue": &types.CustomFieldStringValue{
			CustomFieldValue: types.CustomFieldValue{Key: field.Key},
			Value:            "true",
		}}

		var objs []mo.ManagedEntity
		err = v.RetrieveWithFilter(ctx, any, []string{"name", "customValue"}, &objs, filter)
		if err != nil {
			return err
		}

		fmt.Printf("backup %d of %d objects", len(objs), len(all))
		return v.Destroy(ctx)
	})
	// Output: backup 5 of 22 objects
}

func ExampleCustomizationSpecManager_Info() {
	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
		m := object.NewCustomizationSpecManager(c)
		info, err := m.Info(ctx)
		if err != nil {
			return err
		}

		for i := range info {
			item, err := m.GetCustomizationSpec(ctx, info[i].Name)
			if err != nil {
				return err
			}
			fmt.Printf("%s=%T\n", item.Info.Name, item.Spec.Identity)
		}
		return nil
	})
	// Output:
	// vcsim-linux=*types.CustomizationLinuxPrep
	// vcsim-linux-static=*types.CustomizationLinuxPrep
	// vcsim-windows-static=*types.CustomizationSysprep
	// vcsim-windows-domain=*types.CustomizationSysprep
}
<|endoftext|>


<commit_before>package controllers

import (
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
	"github.com/juanfgs/blog/models"
	"github.com/astaxie/beego/utils/pagination"
	"time"
	"log"
)

type AdminController struct {
	MainController
}

func (this *AdminController) Index() {
	this.Layout = "admin/index.tpl"

	var posts []models.Post
	o := orm.NewOrm()
	postsPerPage := 10
	countPosts, err := o.QueryTable("posts").Count()
	if err != nil {
		log.Println(err)
	}
	paginator := pagination.SetPaginator(this.Ctx, postsPerPage, countPosts)
	o.QueryTable("posts").Limit(postsPerPage, paginator.Offset()).All(&posts)

	this.Data["posts"] = posts

	this.TplNames = "admin/dashboard.tpl"
}

func (this *AdminController) CategoryIndex() {
	this.Layout = "admin/index.tpl"
	this.Data["Title"] = "Category List"
	var categories []models.Category
	o := orm.NewOrm()
	categoriesPerPage := 10
	countCategories, err := o.QueryTable("categories").Count()
	if err != nil {
		log.Println(err)
	}
	paginator := pagination.SetPaginator(this.Ctx, categoriesPerPage, countCategories)
	o.QueryTable("categories").Limit(categoriesPerPage, paginator.Offset()).All(&categories)

	this.Data["Categories"] = categories

	this.TplNames = "admin/categories.tpl"
}

func (this *AdminController) NewCategory(){
	this.Layout = "admin/index.tpl"
	this.Data["Title"] = "Create new category"
	this.TplNames = "admin/newcategory.tpl"
}

func (this *AdminController) EditCategory(){
	this.Layout = "admin/index.tpl"
	categoryId, err:= this.GetInt(":id")

	if err != nil {
		this.Abort("400")
	}
	o := orm.NewOrm()

	category := new(models.Category)

	o.QueryTable("categories").Filter("id", categoryId).One(category)
	this.Data["Title"] = "Editing Category '"+ category.Title +"'"
	this.Data["Category"] = category
	this.TplNames = "admin/editcategory.tpl"
}

func (this *AdminController) NewCategoryWrite(){
	flash := beego.NewFlash()
	o := orm.NewOrm()

	category := new(models.Category)
	category.Title = this.GetString("Title")
	category.Description = this.GetString("Description")

	_, err := o.Insert(category)
	if err != nil {
		log.Println(err)
		flash.Error("Error creating category")
		flash.Store(&this.Controller)
		this.Abort("500")
		return
	}
	flash.Notice("Category Created")
	flash.Store(&this.Controller)
	this.Redirect("/admin/categories/", 302)
}

func (this *AdminController) EditCategoryWrite(){
	categoryId, err:= this.GetInt(":id")
	flash := beego.NewFlash()
	if err != nil {
		this.Abort("400")
	}

	category := new(models.Category)

	o := orm.NewOrm()

	o.QueryTable("categories").Filter("id", categoryId).One(category)
	if val := this.GetString("Title"); val != category.Title {
		category.Title = val
	}

	if val := this.GetString("Description"); val != category.Description {
		category.Description = val
	}

	if _, err := o.Update(category); err == nil {
		flash.Notice("Category Saved")
		flash.Store(&this.Controller)
		this.Redirect("/admin/categories/", 302)
		return
	} else {

		this.Abort("500")
	}

}
func (this *AdminController) DeletePost(){

	postId, err:= this.GetInt(":id")
	flash := beego.NewFlash()
	if err != nil {
		this.Abort("400")
	}
	o := orm.NewOrm()

	post := new(models.Post)
	o.QueryTable("posts").Filter("id", postId).One(post)
	if _, err = o.Delete(post); err == nil {
		flash.Notice("Post erased")
		flash.Store(&this.Controller)
	} else {
		flash.Notice("Cannot delete post")
		log.Println(err)
		flash.Store(&this.Controller)
	}
	this.Redirect("/admin/", 302)
	return
}

func (this *AdminController) DeleteCategory(){

	categoryId, err:= this.GetInt(":id")
	flash := beego.NewFlash()
	if err != nil {
		this.Abort("400")
	}
	o := orm.NewOrm()

	category := new(models.Category)
	o.QueryTable("posts").Filter("id", categoryId).One(category)
	if _, err = o.Delete(category); err == nil {
		flash.Notice("Category erased")
		flash.Store(&this.Controller)
	} else {
		flash.Notice("Cannot delete category, check log for details")
		log.Println(err)
		flash.Store(&this.Controller)
	}
	this.Redirect("/admin/", 302)
	return
}

func (this *AdminController) EditPost(){
	this.Layout = "admin/index.tpl"
	postId, err:= this.GetInt(":id")

	if err != nil {
		this.Abort("400")
	}
	o := orm.NewOrm()

	post := new(models.Post)

	var categories []models.Category
	o.QueryTable("categories").All(&categories)
	this.Data["Categories"] = categories

	o.QueryTable("posts").Filter("id", postId).One(post)
	this.Data["Title"] = "Editing Post '"+ post.Title +"'"
	this.Data["Post"] = post

	this.TplNames = "admin/editpost.tpl"
}

func (this *AdminController) EditPostWrite(){
	postId, err:= this.GetInt(":id")
	flash := beego.NewFlash()
	if err != nil {
		this.Abort("400")
	}

	post := new(models.Post)

	o := orm.NewOrm()

	o.QueryTable("posts").Filter("id", postId).One(post)
	if val := this.GetString("Title"); val != post.Title {
		post.Title = val
	}
	if val := this.GetString("Tagline"); val != post.Tagline {
		post.Tagline = val
	}
	if val := this.GetString("Content"); val != post.Content {
		post.Content = val
	}

	if val := this.GetString("Keywords"); val != post.Keywords {
		post.Keywords = val
	}
	if val := this.GetString("Description"); val != post.Description {
		post.Description = val
	}

	if val, err := this.GetInt("CategoryId"); err == nil {
			var category models.Category
			o.QueryTable("categories").Filter("id", val).One(&category)
			post.Category = &category

	}
	published, errbool := this.GetBool("Published")
	if errbool == nil {
		post.Published = published
	} else {
		post.Published = false
	}
	if _, err := o.Update(post); err == nil {
		flash.Notice("Post Saved")
		flash.Store(&this.Controller)
		this.Redirect("/admin/", 302)
		return
	} else {

		this.Abort("500")
	}

}

func (this *AdminController) NewPost(){
	this.Layout = "admin/index.tpl"
	this.Data["Title"] = "Create new post"
	o := orm.NewOrm()
	var categories []models.Category
	o.QueryTable("categories").All(&categories)
	this.Data["Categories"] = categories
	this.TplNames = "admin/newpost.tpl"
}

func (this *AdminController) NewPostWrite(){
	flash := beego.NewFlash()
	o := orm.NewOrm()

	post := new(models.Post)
	post.Title = this.GetString("Title")
	post.Tagline = this.GetString("Tagline")
	post.Content = this.GetString("Content")

	post.Description = this.GetString("Description")
	post.Keywords = this.GetString("Keywords")
	published, errbool := this.GetBool("Published")
	if errbool == nil {
		post.Published = published
	} else {
		post.Published = false
	}

	if val, err := this.GetInt("CategoryId"); err == nil {
			var category models.Category
			o.QueryTable("categories").Filter("id", val).One(&category)
			post.Category = &category
	}
	post.CreatedAt = time.Now()
	post.UpdatedAt = time.Now()
	if user, ok := this.Data["User"].(models.User); ok {
		post.Author = &user
	}

	_, err := o.Insert(post)
	if err != nil {
		log.Println(err)
		flash.Error("Error creating post")
		flash.Store(&this.Controller)
		this.Abort("500")
		return
	}
	flash.Notice("Post Created")
	flash.Store(&this.Controller)
	this.Redirect("/admin/", 302)
}

func (this *AdminController) URLMapping() {
	this.Mapping("Index", this.Index)
	this.Mapping("NewPost", this.NewPost)
	this.Mapping("NewPostWrite", this.NewPostWrite)

}

<commit_msg>added appropiate order to admin<commit_after>package controllers

import (
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
	"github.com/juanfgs/blog/models"
	"github.com/astaxie/beego/utils/pagination"
	"time"
	"log"
)

type AdminController struct {
	MainController
}

func (this *AdminController) Index() {
	this.Layout = "admin/index.tpl"

	var posts []models.Post
	o := orm.NewOrm()
	postsPerPage := 10
	countPosts, err := o.QueryTable("posts").Count()
	if err != nil {
		log.Println(err)
	}
	paginator := pagination.SetPaginator(this.Ctx, postsPerPage, countPosts)
	o.QueryTable("posts").Limit(postsPerPage, paginator.Offset()).OrderBy("-created_at").All(&posts)

	this.Data["posts"] = posts

	this.TplNames = "admin/dashboard.tpl"
}

func (this *AdminController) CategoryIndex() {
	this.Layout = "admin/index.tpl"
	this.Data["Title"] = "Category List"
	var categories []models.Category
	o := orm.NewOrm()
	categoriesPerPage := 10
	countCategories, err := o.QueryTable("categories").Count()
	if err != nil {
		log.Println(err)
	}
	paginator := pagination.SetPaginator(this.Ctx, categoriesPerPage, countCategories)
	o.QueryTable("categories").Limit(categoriesPerPage, paginator.Offset()).All(&categories)

	this.Data["Categories"] = categories

	this.TplNames = "admin/categories.tpl"
}

func (this *AdminController) NewCategory(){
	this.Layout = "admin/index.tpl"
	this.Data["Title"] = "Create new category"
	this.TplNames = "admin/newcategory.tpl"
}

func (this *AdminController) EditCategory(){
	this.Layout = "admin/index.tpl"
	categoryId, err:= this.GetInt(":id")

	if err != nil {
		this.Abort("400")
	}
	o := orm.NewOrm()

	category := new(models.Category)

	o.QueryTable("categories").Filter("id", categoryId).One(category)
	this.Data["Title"] = "Editing Category '"+ category.Title +"'"
	this.Data["Category"] = category
	this.TplNames = "admin/editcategory.tpl"
}

func (this *AdminController) NewCategoryWrite(){
	flash := beego.NewFlash()
	o := orm.NewOrm()

	category := new(models.Category)
	category.Title = this.GetString("Title")
	category.Description = this.GetString("Description")

	_, err := o.Insert(category)
	if err != nil {
		log.Println(err)
		flash.Error("Error creating category")
		flash.Store(&this.Controller)
		this.Abort("500")
		return
	}
	flash.Notice("Category Created")
	flash.Store(&this.Controller)
	this.Redirect("/admin/categories/", 302)
}

func (this *AdminController) EditCategoryWrite(){
	categoryId, err:= this.GetInt(":id")
	flash := beego.NewFlash()
	if err != nil {
		this.Abort("400")
	}

	category := new(models.Category)

	o := orm.NewOrm()

	o.QueryTable("categories").Filter("id", categoryId).One(category)
	if val := this.GetString("Title"); val != category.Title {
		category.Title = val
	}

	if val := this.GetString("Description"); val != category.Description {
		category.Description = val
	}

	if _, err := o.Update(category); err == nil {
		flash.Notice("Category Saved")
		flash.Store(&this.Controller)
		this.Redirect("/admin/categories/", 302)
		return
	} else {

		this.Abort("500")
	}

}
func (this *AdminController) DeletePost(){

	postId, err:= this.GetInt(":id")
	flash := beego.NewFlash()
	if err != nil {
		this.Abort("400")
	}
	o := orm.NewOrm()

	post := new(models.Post)
	o.QueryTable("posts").Filter("id", postId).One(post)
	if _, err = o.Delete(post); err == nil {
		flash.Notice("Post erased")
		flash.Store(&this.Controller)
	} else {
		flash.Notice("Cannot delete post")
		log.Println(err)
		flash.Store(&this.Controller)
	}
	this.Redirect("/admin/", 302)
	return
}

func (this *AdminController) DeleteCategory(){

	categoryId, err:= this.GetInt(":id")
	flash := beego.NewFlash()
	if err != nil {
		this.Abort("400")
	}
	o := orm.NewOrm()

	category := new(models.Category)
	o.QueryTable("posts").Filter("id", categoryId).One(category)
	if _, err = o.Delete(category); err == nil {
		flash.Notice("Category erased")
		flash.Store(&this.Controller)
	} else {
		flash.Notice("Cannot delete category, check log for details")
		log.Println(err)
		flash.Store(&this.Controller)
	}
	this.Redirect("/admin/", 302)
	return
}

func (this *AdminController) EditPost(){
	this.Layout = "admin/index.tpl"
	postId, err:= this.GetInt(":id")

	if err != nil {
		this.Abort("400")
	}
	o := orm.NewOrm()

	post := new(models.Post)

	var categories []models.Category
	o.QueryTable("categories").All(&categories)
	this.Data["Categories"] = categories

	o.QueryTable("posts").Filter("id", postId).One(post)
	this.Data["Title"] = "Editing Post '"+ post.Title +"'"
	this.Data["Post"] = post

	this.TplNames = "admin/editpost.tpl"
}

func (this *AdminController) EditPostWrite(){
	postId, err:= this.GetInt(":id")
	flash := beego.NewFlash()
	if err != nil {
		this.Abort("400")
	}

	post := new(models.Post)

	o := orm.NewOrm()

	o.QueryTable("posts").Filter("id", postId).One(post)
	if val := this.GetString("Title"); val != post.Title {
		post.Title = val
	}
	if val := this.GetString("Tagline"); val != post.Tagline {
		post.Tagline = val
	}
	if val := this.GetString("Content"); val != post.Content {
		post.Content = val
	}

	if val := this.GetString("Keywords"); val != post.Keywords {
		post.Keywords = val
	}
	if val := this.GetString("Description"); val != post.Description {
		post.Description = val
	}

	if val, err := this.GetInt("CategoryId"); err == nil {
			var category models.Category
			o.QueryTable("categories").Filter("id", val).One(&category)
			post.Category = &category

	}
	published, errbool := this.GetBool("Published")
	if errbool == nil {
		post.Published = published
	} else {
		post.Published = false
	}
	if _, err := o.Update(post); err == nil {
		flash.Notice("Post Saved")
		flash.Store(&this.Controller)
		this.Redirect("/admin/", 302)
		return
	} else {

		this.Abort("500")
	}

}

func (this *AdminController) NewPost(){
	this.Layout = "admin/index.tpl"
	this.Data["Title"] = "Create new post"
	o := orm.NewOrm()
	var categories []models.Category
	o.QueryTable("categories").All(&categories)
	this.Data["Categories"] = categories
	this.TplNames = "admin/newpost.tpl"
}

func (this *AdminController) NewPostWrite(){
	flash := beego.NewFlash()
	o := orm.NewOrm()

	post := new(models.Post)
	post.Title = this.GetString("Title")
	post.Tagline = this.GetString("Tagline")
	post.Content = this.GetString("Content")

	post.Description = this.GetString("Description")
	post.Keywords = this.GetString("Keywords")
	published, errbool := this.GetBool("Published")
	if errbool == nil {
		post.Published = published
	} else {
		post.Published = false
	}

	if val, err := this.GetInt("CategoryId"); err == nil {
			var category models.Category
			o.QueryTable("categories").Filter("id", val).One(&category)
			post.Category = &category
	}
	post.CreatedAt = time.Now()
	post.UpdatedAt = time.Now()
	if user, ok := this.Data["User"].(models.User); ok {
		post.Author = &user
	}

	_, err := o.Insert(post)
	if err != nil {
		log.Println(err)
		flash.Error("Error creating post")
		flash.Store(&this.Controller)
		this.Abort("500")
		return
	}
	flash.Notice("Post Created")
	flash.Store(&this.Controller)
	this.Redirect("/admin/", 302)
}

func (this *AdminController) URLMapping() {
	this.Mapping("Index", this.Index)
	this.Mapping("NewPost", this.NewPost)
	this.Mapping("NewPostWrite", this.NewPostWrite)

}

<|endoftext|>


<commit_before>package snake

import (
	"errors"
	"fmt"
	"math"
	"sync"
	"time"

	"github.com/pquerna/ffjson/ffjson"
	"github.com/satori/go.uuid"
	"github.com/sirupsen/logrus"

	"github.com/ivan1993spb/snake-server/engine"
	"github.com/ivan1993spb/snake-server/objects"
	"github.com/ivan1993spb/snake-server/world"
)

const (
	snakeTypeLabel = "snake"

	snakeStartSpeed  = time.Millisecond * 500
	snakeSpeedFactor = 1

	snakeStartLength = 3
	snakeStartMargin = 1

	snakeMaxInteractionRetries = 5

	snakeForceBaby  = 1
	snakeForceAdult = 2
)

type Command string

const (
	CommandToNorth Command = "north"
	CommandToEast  Command = "east"
	CommandToSouth Command = "south"
	CommandToWest  Command = "west"
)

var snakeCommands = map[Command]engine.Direction{
	CommandToNorth: engine.DirectionNorth,
	CommandToEast:  engine.DirectionEast,
	CommandToSouth: engine.DirectionSouth,
	CommandToWest:  engine.DirectionWest,
}

// Snake object
// ffjson: skip
type Snake struct {
	uuid string

	world *world.World

	location engine.Location
	length   uint16

	direction engine.Direction

	mux *sync.RWMutex

	stopper *sync.Once
	stop    chan struct{}
}

// NewSnake creates new snake
func NewSnake(world *world.World) (*Snake, error) {
	snake := &Snake{
		uuid:      uuid.Must(uuid.NewV4()).String(),
		world:     world,
		location:  make(engine.Location, snakeStartLength),
		length:    snakeStartLength,
		direction: engine.RandomDirection(),
		mux:       &sync.RWMutex{},
		stopper:   &sync.Once{},
		stop:      make(chan struct{}),
	}

	if err := snake.initLocate(); err != nil {
		return nil, fmt.Errorf("cannot create snake: %s", err)
	}

	return snake, nil
}

type errSnakeInitLocate string

func (e errSnakeInitLocate) Error() string {
	return "snake initial locate error: " + string(e)
}

func (s *Snake) initLocate() error {
	s.mux.Lock()
	defer s.mux.Unlock()

	var err error
	var location engine.Location

	switch s.direction {
	case engine.DirectionNorth, engine.DirectionSouth:
		location, err = s.world.CreateObjectRandomRectMargin(s, 1, snakeStartLength, snakeStartMargin)
	case engine.DirectionEast, engine.DirectionWest:
		location, err = s.world.CreateObjectRandomRectMargin(s, snakeStartLength, 1, snakeStartMargin)
	default:
		return errSnakeInitLocate("invalid initial direction")
	}

	if err != nil {
		return errSnakeInitLocate(err.Error())
	}

	if s.direction == engine.DirectionSouth || s.direction == engine.DirectionEast {
		location = location.Reverse()
	}

	s.location = location

	return nil
}

func (s *Snake) GetUUID() string {
	s.mux.RLock()
	defer s.mux.RUnlock()
	return s.uuid
}

func (s *Snake) String() string {
	s.mux.RLock()
	defer s.mux.RUnlock()
	return fmt.Sprintf("snake %s", s.location)
}

func (s *Snake) die() error {
	s.mux.RLock()
	defer s.mux.RUnlock()

	if err := s.world.DeleteObject(s, s.location); err != nil {
		return fmt.Errorf("die snake error: %s", err)
	}

	// Do not empty location to pass it for corpse creation.

	return nil
}

func (s *Snake) feed(f uint16) {
	if f > 0 {
		s.mux.Lock()
		s.length += f
		s.mux.Unlock()
	}
}

type errSnakeHit string

func (e errSnakeHit) Error() string {
	return "snake hit error: " + string(e)
}

func (s *Snake) Hit(dot engine.Dot, force float32) (success bool, err error) {
	s.mux.Lock()
	defer s.mux.Unlock()

	if s.location.Contains(dot) {
		if force > s.unsafeGetForce() {
			newLocation := s.location.Delete(dot)
			if err := s.world.UpdateObject(s, s.location, newLocation); err != nil {
				return false, errSnakeHit(err.Error())
			}

			s.location = newLocation

			s.stopper.Do(func() {
				close(s.stop)
			})

			return true, nil
		}

		return false, nil
	}

	return false, errSnakeHit("snake does not contain dot")
}

func (s *Snake) unsafeGetForce() float32 {
	if s.length > snakeStartLength {
		return snakeForceAdult
	}
	return snakeForceBaby
}

func (s *Snake) getForce() float32 {
	s.mux.RLock()
	defer s.mux.RUnlock()
	return s.unsafeGetForce()
}

func (s *Snake) Run(stop <-chan struct{}, logger logrus.FieldLogger) <-chan struct{} {
	snakeStop := make(chan struct{})
	logger = logger.WithField("uuid", s.uuid)

	go func() {
		var ticker = time.NewTicker(s.calculateDelay())
		defer ticker.Stop()
		defer close(snakeStop)
		defer func() {
			if err := s.die(); err != nil {
				logger.WithError(err).Error("die snake error")
			}
		}()
		defer s.stopper.Do(func() {
			close(s.stop)
		})

		for {
			select {
			case <-ticker.C:
				if err := s.move(); err != nil {
					if err != errUnsuccessfulInteraction {
						logger.WithError(err).Error("snake move error")
					}
					return
				}
			case <-stop:
				// Global stop
				return
			case <-s.stop:
				// Local snake stop
				return
			}
		}
	}()

	return snakeStop
}

type errSnakeMove string

func (e errSnakeMove) Error() string {
	return "move snake error: " + string(e)
}

var errUnsuccessfulInteraction = errSnakeMove("unsuccessful interaction")

func (s *Snake) move() error {
	// Calculate next position
	dot, err := s.getNextHeadDot()
	if err != nil {
		return errSnakeMove(err.Error())
	}

	retries := 0

	for {
		if object := s.world.GetObjectByDot(dot); object != nil {
			if success, err := s.interactObject(object, dot); err != nil {
				return errSnakeMove(err.Error())
			} else if !success {
				return errUnsuccessfulInteraction
			}
		} else {
			break
		}

		if retries >= snakeMaxInteractionRetries {
			return errSnakeMove("interaction retries limit reached")
		}

		retries++
	}

	s.mux.Lock()
	defer s.mux.Unlock()

	tmpLocation := make(engine.Location, len(s.location)+1)
	copy(tmpLocation[1:], s.location)
	tmpLocation[0] = dot

	if s.length < uint16(len(tmpLocation)) {
		tmpLocation = tmpLocation[:len(tmpLocation)-1]
	}

	if err := s.world.UpdateObject(s, s.location, tmpLocation); err != nil {
		return fmt.Errorf("update snake error: %s", err)
	}

	s.location = tmpLocation

	return nil
}

type errInteractObject string

func (e errInteractObject) Error() string {
	return "object interaction error: " + string(e)
}

var errInteractObjectUnexpectedType = errInteractObject("unexpected object type")

func (s *Snake) interactObject(object interface{}, dot engine.Dot) (success bool, err error) {
	if food, ok := object.(objects.Food); ok {
		nv, success, err := food.Bite(dot)
		if err != nil {
			return false, errInteractObject(err.Error())
		}
		if success {
			s.feed(nv)
		}
		return success, nil
	}

	if alive, ok := object.(objects.Alive); ok {
		success, err := alive.Hit(dot, s.getForce())
		if err != nil {
			return false, errInteractObject(err.Error())
		}
		return success, nil
	}

	if object, ok := object.(objects.Object); ok {
		success, err := object.Break(dot, s.getForce())
		if err != nil {
			return false, errInteractObject(err.Error())
		}
		return success, nil
	}

	return false, errInteractObjectUnexpectedType
}

func (s *Snake) calculateDelay() time.Duration {
	s.mux.RLock()
	defer s.mux.RUnlock()
	return time.Duration(math.Pow(snakeSpeedFactor, float64(s.length)) * float64(snakeStartSpeed))
}

// getNextHeadDot calculates new position of snake's head by its direction and current head position
func (s *Snake) getNextHeadDot() (engine.Dot, error) {
	s.mux.RLock()
	defer s.mux.RUnlock()

	if len(s.location) > 0 {
		return s.world.Navigate(s.location[0], s.direction, 1)
	}

	return engine.Dot{}, errors.New("cannot get next head dots: empty location")
}

func (s *Snake) Command(cmd Command) error {
	if direction, ok := snakeCommands[cmd]; ok {
		if err := s.setMovementDirection(direction); err != nil {
			return fmt.Errorf("cannot execute command: %s", err)
		}
		return nil
	}

	return errors.New("cannot execute command: unknown command")
}

type errSetMovementDirection string

func (e errSetMovementDirection) Error() string {
	return "set movement direction error: " + string(e)
}

func (s *Snake) setMovementDirection(nextDir engine.Direction) error {
	if engine.ValidDirection(nextDir) {
		s.mux.Lock()
		defer s.mux.Unlock()

		if len(s.location) < 2 {
			return errSetMovementDirection("cannot calculate current movement direction")
		}

		currentDir := engine.CalculateDirection(s.location[1], s.location[0])
		// If the dots are not nearby, reverse the direction
		if s.location[1].DistanceTo(s.location[0]) > 1 {
			if dir, err := currentDir.Reverse(); err != nil {
				return errSetMovementDirection("cannot calculate current movement direction")
			} else {
				currentDir = dir
			}
		}

		rNextDir, err := nextDir.Reverse()
		if err != nil {
			return errSetMovementDirection(err.Error())
		}

		// Next direction cannot be opposite to current direction
		if rNextDir == currentDir {
			return errSetMovementDirection("next direction cannot be opposite to current direction")
		}

		s.direction = nextDir

		return nil
	}

	return errors.New("invalid direction")
}

func (s *Snake) GetLocation() engine.Location {
	s.mux.RLock()
	defer s.mux.RUnlock()
	return engine.Location(s.location).Copy()
}

func (s *Snake) MarshalJSON() ([]byte, error) {
	s.mux.RLock()
	defer s.mux.RUnlock()
	return ffjson.Marshal(&snake{
		UUID: s.uuid,
		Dots: s.location,
		Type: snakeTypeLabel,
	})
}

//go:generate ffjson $GOFILE

// ffjson: nodecoder
type snake struct {
	UUID string       `json:"uuid"`
	Dots []engine.Dot `json:"dots,omitempty"`
	Type string       `json:"type"`
}
<commit_msg>Create on snake hit award food<commit_after>package snake

import (
	"errors"
	"fmt"
	"math"
	"sync"
	"time"

	"github.com/pquerna/ffjson/ffjson"
	"github.com/satori/go.uuid"
	"github.com/sirupsen/logrus"

	"github.com/ivan1993spb/snake-server/engine"
	"github.com/ivan1993spb/snake-server/objects"
	"github.com/ivan1993spb/snake-server/world"
)

const (
	snakeTypeLabel = "snake"

	snakeStartSpeed  = time.Millisecond * 500
	snakeSpeedFactor = 1

	snakeStartLength = 3
	snakeStartMargin = 1

	snakeMaxInteractionRetries = 5

	snakeForceBaby  = 1
	snakeForceAdult = 2

	snakeHitAward = 3
)

type Command string

const (
	CommandToNorth Command = "north"
	CommandToEast  Command = "east"
	CommandToSouth Command = "south"
	CommandToWest  Command = "west"
)

var snakeCommands = map[Command]engine.Direction{
	CommandToNorth: engine.DirectionNorth,
	CommandToEast:  engine.DirectionEast,
	CommandToSouth: engine.DirectionSouth,
	CommandToWest:  engine.DirectionWest,
}

// Snake object
// ffjson: skip
type Snake struct {
	uuid string

	world *world.World

	location engine.Location
	length   uint16

	direction engine.Direction

	mux *sync.RWMutex

	stopper *sync.Once
	stop    chan struct{}
}

// NewSnake creates new snake
func NewSnake(world *world.World) (*Snake, error) {
	snake := &Snake{
		uuid:      uuid.Must(uuid.NewV4()).String(),
		world:     world,
		location:  make(engine.Location, snakeStartLength),
		length:    snakeStartLength,
		direction: engine.RandomDirection(),
		mux:       &sync.RWMutex{},
		stopper:   &sync.Once{},
		stop:      make(chan struct{}),
	}

	if err := snake.initLocate(); err != nil {
		return nil, fmt.Errorf("cannot create snake: %s", err)
	}

	return snake, nil
}

type errSnakeInitLocate string

func (e errSnakeInitLocate) Error() string {
	return "snake initial locate error: " + string(e)
}

func (s *Snake) initLocate() error {
	s.mux.Lock()
	defer s.mux.Unlock()

	var err error
	var location engine.Location

	switch s.direction {
	case engine.DirectionNorth, engine.DirectionSouth:
		location, err = s.world.CreateObjectRandomRectMargin(s, 1, snakeStartLength, snakeStartMargin)
	case engine.DirectionEast, engine.DirectionWest:
		location, err = s.world.CreateObjectRandomRectMargin(s, snakeStartLength, 1, snakeStartMargin)
	default:
		return errSnakeInitLocate("invalid initial direction")
	}

	if err != nil {
		return errSnakeInitLocate(err.Error())
	}

	if s.direction == engine.DirectionSouth || s.direction == engine.DirectionEast {
		location = location.Reverse()
	}

	s.location = location

	return nil
}

func (s *Snake) GetUUID() string {
	s.mux.RLock()
	defer s.mux.RUnlock()
	return s.uuid
}

func (s *Snake) String() string {
	s.mux.RLock()
	defer s.mux.RUnlock()
	return fmt.Sprintf("snake %s", s.location)
}

func (s *Snake) die() error {
	s.mux.RLock()
	defer s.mux.RUnlock()

	if err := s.world.DeleteObject(s, s.location); err != nil {
		return fmt.Errorf("die snake error: %s", err)
	}

	// Do not empty location to pass it for corpse creation.

	return nil
}

func (s *Snake) feed(f uint16) {
	if f > 0 {
		s.mux.Lock()
		s.length += f
		s.mux.Unlock()
	}
}

type errSnakeHit string

func (e errSnakeHit) Error() string {
	return "snake hit error: " + string(e)
}

func (s *Snake) Hit(dot engine.Dot, force float32) (success bool, err error) {
	s.mux.Lock()
	defer s.mux.Unlock()

	if s.location.Contains(dot) {
		if force > s.unsafeGetForce() {
			newLocation := s.location.Delete(dot)
			if err := s.world.UpdateObject(s, s.location, newLocation); err != nil {
				return false, errSnakeHit(err.Error())
			}

			s.location = newLocation

			s.stopper.Do(func() {
				close(s.stop)
			})

			return true, nil
		}

		return false, nil
	}

	return false, errSnakeHit("snake does not contain dot")
}

func (s *Snake) unsafeGetForce() float32 {
	if s.length > snakeStartLength {
		return snakeForceAdult
	}
	return snakeForceBaby
}

func (s *Snake) getForce() float32 {
	s.mux.RLock()
	defer s.mux.RUnlock()
	return s.unsafeGetForce()
}

func (s *Snake) Run(stop <-chan struct{}, logger logrus.FieldLogger) <-chan struct{} {
	snakeStop := make(chan struct{})
	logger = logger.WithField("uuid", s.uuid)

	go func() {
		var ticker = time.NewTicker(s.calculateDelay())
		defer ticker.Stop()
		defer close(snakeStop)
		defer func() {
			if err := s.die(); err != nil {
				logger.WithError(err).Error("die snake error")
			}
		}()
		defer s.stopper.Do(func() {
			close(s.stop)
		})

		for {
			select {
			case <-ticker.C:
				if err := s.move(); err != nil {
					if err != errUnsuccessfulInteraction {
						logger.WithError(err).Error("snake move error")
					}
					return
				}
			case <-stop:
				// Global stop
				return
			case <-s.stop:
				// Local snake stop
				return
			}
		}
	}()

	return snakeStop
}

type errSnakeMove string

func (e errSnakeMove) Error() string {
	return "move snake error: " + string(e)
}

var errUnsuccessfulInteraction = errSnakeMove("unsuccessful interaction")

func (s *Snake) move() error {
	// Calculate next position
	dot, err := s.getNextHeadDot()
	if err != nil {
		return errSnakeMove(err.Error())
	}

	retries := 0

	for {
		if object := s.world.GetObjectByDot(dot); object != nil {
			if success, err := s.interactObject(object, dot); err != nil {
				return errSnakeMove(err.Error())
			} else if !success {
				return errUnsuccessfulInteraction
			}
		} else {
			break
		}

		if retries >= snakeMaxInteractionRetries {
			return errSnakeMove("interaction retries limit reached")
		}

		retries++
	}

	s.mux.Lock()
	defer s.mux.Unlock()

	tmpLocation := make(engine.Location, len(s.location)+1)
	copy(tmpLocation[1:], s.location)
	tmpLocation[0] = dot

	if s.length < uint16(len(tmpLocation)) {
		tmpLocation = tmpLocation[:len(tmpLocation)-1]
	}

	if err := s.world.UpdateObject(s, s.location, tmpLocation); err != nil {
		return fmt.Errorf("update snake error: %s", err)
	}

	s.location = tmpLocation

	return nil
}

type errInteractObject string

func (e errInteractObject) Error() string {
	return "object interaction error: " + string(e)
}

var errInteractObjectUnexpectedType = errInteractObject("unexpected object type")

func (s *Snake) interactObject(object interface{}, dot engine.Dot) (success bool, err error) {
	if food, ok := object.(objects.Food); ok {
		nv, success, err := food.Bite(dot)
		if err != nil {
			return false, errInteractObject(err.Error())
		}
		if success {
			s.feed(nv)
		}
		return success, nil
	}

	if alive, ok := object.(objects.Alive); ok {
		success, err := alive.Hit(dot, s.getForce())
		if err != nil {
			return false, errInteractObject(err.Error())
		}
		if success {
			s.feed(snakeHitAward)
		}
		return success, nil
	}

	if object, ok := object.(objects.Object); ok {
		success, err := object.Break(dot, s.getForce())
		if err != nil {
			return false, errInteractObject(err.Error())
		}
		return success, nil
	}

	return false, errInteractObjectUnexpectedType
}

func (s *Snake) calculateDelay() time.Duration {
	s.mux.RLock()
	defer s.mux.RUnlock()
	return time.Duration(math.Pow(snakeSpeedFactor, float64(s.length)) * float64(snakeStartSpeed))
}

// getNextHeadDot calculates new position of snake's head by its direction and current head position
func (s *Snake) getNextHeadDot() (engine.Dot, error) {
	s.mux.RLock()
	defer s.mux.RUnlock()

	if len(s.location) > 0 {
		return s.world.Navigate(s.location[0], s.direction, 1)
	}

	return engine.Dot{}, errors.New("cannot get next head dots: empty location")
}

func (s *Snake) Command(cmd Command) error {
	if direction, ok := snakeCommands[cmd]; ok {
		if err := s.setMovementDirection(direction); err != nil {
			return fmt.Errorf("cannot execute command: %s", err)
		}
		return nil
	}

	return errors.New("cannot execute command: unknown command")
}

type errSetMovementDirection string

func (e errSetMovementDirection) Error() string {
	return "set movement direction error: " + string(e)
}

func (s *Snake) setMovementDirection(nextDir engine.Direction) error {
	if engine.ValidDirection(nextDir) {
		s.mux.Lock()
		defer s.mux.Unlock()

		if len(s.location) < 2 {
			return errSetMovementDirection("cannot calculate current movement direction")
		}

		currentDir := engine.CalculateDirection(s.location[1], s.location[0])
		// If the dots are not nearby, reverse the direction
		if s.location[1].DistanceTo(s.location[0]) > 1 {
			if dir, err := currentDir.Reverse(); err != nil {
				return errSetMovementDirection("cannot calculate current movement direction")
			} else {
				currentDir = dir
			}
		}

		rNextDir, err := nextDir.Reverse()
		if err != nil {
			return errSetMovementDirection(err.Error())
		}

		// Next direction cannot be opposite to current direction
		if rNextDir == currentDir {
			return errSetMovementDirection("next direction cannot be opposite to current direction")
		}

		s.direction = nextDir

		return nil
	}

	return errors.New("invalid direction")
}

func (s *Snake) GetLocation() engine.Location {
	s.mux.RLock()
	defer s.mux.RUnlock()
	return engine.Location(s.location).Copy()
}

func (s *Snake) MarshalJSON() ([]byte, error) {
	s.mux.RLock()
	defer s.mux.RUnlock()
	return ffjson.Marshal(&snake{
		UUID: s.uuid,
		Dots: s.location,
		Type: snakeTypeLabel,
	})
}

//go:generate ffjson $GOFILE

// ffjson: nodecoder
type snake struct {
	UUID string       `json:"uuid"`
	Dots []engine.Dot `json:"dots,omitempty"`
	Type string       `json:"type"`
}
<|endoftext|>


<commit_before>package controllers

import (
	"github.com/UniversityRadioYork/2016-site/models"
	"github.com/cbroglie/mustache"
	"log"
	"net/http"
	"github.com/UniversityRadioYork/myradio-go"
	"github.com/UniversityRadioYork/2016-site/structs"
)

type IndexController struct {
	Controller
}

func NewIndexController(s *myradio.Session, o *structs.Options) *IndexController {
	return &IndexController{Controller{session:s, options:o}}
}

type TemplateData struct {
	Globals structs.Globals
	Local  myradio.CurrentAndNext
}

func (ic *IndexController) Get(w http.ResponseWriter, r *http.Request) {

	// This is where any form params would be parsed

	model := models.NewIndexModel(ic.session)

	data, err := model.Get()

	if err != nil {
		log.Println(err)
		return
	}

	td := TemplateData{Local: data, Globals: ic.options.Globals}

	output, err := mustache.RenderFile("views/index.mustache", td)

	if err != nil {
		log.Println(err)
		return
	}

	w.Write([]byte(output))

}
<commit_msg>Remove typed struct for index model, use anonymous struct instead<commit_after>package controllers

import (
	"github.com/UniversityRadioYork/2016-site/models"
	"github.com/cbroglie/mustache"
	"log"
	"net/http"
	"github.com/UniversityRadioYork/myradio-go"
	"github.com/UniversityRadioYork/2016-site/structs"
)

type IndexController struct {
	Controller
}

func NewIndexController(s *myradio.Session, o *structs.Options) *IndexController {
	return &IndexController{Controller{session:s, options:o}}
}

func (ic *IndexController) Get(w http.ResponseWriter, r *http.Request) {

	// This is where any form params would be parsed

	model := models.NewIndexModel(ic.session)

	data, err := model.Get()

	if err != nil {
		log.Println(err)
		return
	}

	td := struct {
		Globals structs.Globals
		Local   myradio.CurrentAndNext
	}{
		Local: data,
		Globals: ic.options.Globals,
	}

	output, err := mustache.RenderFile("views/index.mustache", td)

	if err != nil {
		log.Println(err)
		return
	}

	w.Write([]byte(output))

}
<|endoftext|>


<commit_before>package controllers

import (
	"fmt"
	"net/http"

	"github.com/julienschmidt/httprouter"
	"github.com/liam-lai/ptt-alertor/hello"
)

func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	// t, err := template.ParseFiles("public/index.html")
	// if err != nil {
	// 	panic(err)
	// }
	// t.Execute(w, nil)
	fmt.Fprintf(w, hello.HelloWorld())
}
<commit_msg>enable index.html route<commit_after>package controllers

import (
	"html/template"
	"net/http"

	"github.com/julienschmidt/httprouter"
)

func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	t, err := template.ParseFiles("public/index.html")
	if err != nil {
		panic(err)
	}
	t.Execute(w, nil)
}
<|endoftext|>


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

/*
Package template (html/template) implements data-driven templates for
generating HTML output safe against code injection. It provides the
same interface as package text/template and should be used instead of
text/template whenever the output is HTML.

The documentation here focuses on the security features of the package.
For information about how to program the templates themselves, see the
documentation for text/template.

Introduction

This package wraps package text/template so you can share its template API
to parse and execute HTML templates safely.

  tmpl, err := template.New("name").Parse(...)
  // Error checking elided
  err = tmpl.Execute(out, data)

If successful, tmpl will now be injection-safe. Otherwise, err is an error
defined in the docs for ErrorCode.

HTML templates treat data values as plain text which should be encoded so they
can be safely embedded in an HTML document. The escaping is contextual, so
actions can appear within JavaScript, CSS, and URI contexts.

The security model used by this package assumes that template authors are
trusted, while text/template Execute's data parameter is not. More details are
provided below.

Example

  import "text/template"
  ...
  t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
  err = t.ExecuteTemplate(out, "T", "")

produces

  Hello, !

but the contextual autoescaping in html/template

  import "html/template"
  ...
  t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
  err = t.ExecuteTemplate(out, "T", "")

produces safe, escaped HTML output

  Hello, <script>alert('you have been pwned')</script>!

Contexts

This package understands HTML, CSS, JavaScript, and URIs. It adds sanitizing
functions to each simple action pipeline, so given the excerpt

  {{.}}

At parse time each {{.}} is overwritten to add escaping functions as necessary.
In this case it becomes

  {{. | html}}

Errors

See the documentation of ErrorCode for details.

A fuller picture

The rest of this package comment may be skipped on first reading; it includes
details necessary to understand escaping contexts and error messages. Most users
will not need to understand these details.

Contexts

Assuming {{.}} is `O'Reilly: How are <i>you</i>?`, the table below shows
how {{.}} appears when used in the context to the left.

  Context                          {{.}} After
  {{.}}                            O'Reilly: How are <i>you</i>?
                  O'Reilly: How are you?
                  O'Reilly: How are %3ci%3eyou%3c/i%3e?
                O'Reilly%3a%20How%20are%3ci%3e...%3f
               O\x27Reilly: How are \x3ci\x3eyou...?
                 "O\x27Reilly: How are \x3ci\x3eyou...?"
       O\x27Reilly: How are \x3ci\x3eyou...\x3f

If used in an unsafe context, then the value might be filtered out:

  Context                          {{.}} After
                   #ZgotmplZ

since "O'Reilly:" is not an allowed protocol like "http:".

If {{.}} is the innocuous word, `left`, then it can appear more widely,

  Context                              {{.}} After
  {{.}}                                left
                      left
                       left
                      left
                  left
          left
               left
         left
    left
     left

Non-string values can be used in JavaScript contexts.
If {{.}} is

  []struct{A,B string}{ "foo", "bar" }

in the escaped template

then the template output is

See package json to understand how non-string content is marshalled for
embedding in JavaScript contexts.

Typed Strings

By default, this package assumes that all pipelines produce a plain text string.
It adds escaping pipeline stages necessary to correctly and safely embed that
plain text string in the appropriate context.

When a data value is not plain text, you can make sure it is not over-escaped
by marking it with its type.

Types HTML, JS, URL, and others from content.go can carry safe content that is
exempted from escaping.

The template

  Hello, {{.}}!

can be invoked with

  tmpl.Execute(out, HTML(`<b>World</b>`))

to produce

  Hello, World!

instead of the

  Hello, <b>World<b>!

that would have been produced if {{.}} was a regular string.

Security Model

http://js-quasis-libraries-and-repl.googlecode.com/svn/trunk/safetemplate.html#problem_definition defines "safe" as used by this package.

This package assumes that template authors are trusted, that Execute's data
parameter is not, and seeks to preserve the properties below in the face
of untrusted data:

Structure Preservation Property:
"... when a template author writes an HTML tag in a safe templating language,
the browser will interpret the corresponding portion of the output as a tag
regardless of the values of untrusted data, and similarly for other structures
such as attribute boundaries and JS and CSS string boundaries."

Code Effect Property:
"... only code specified by the template author should run as a result of
injecting the template output into a page and all code specified by the
template author should run as a result of the same."

Least Surprise Property:
"A developer (or code reviewer) familiar with HTML, CSS, and JavaScript, who
knows that contextual autoescaping happens should be able to look at a {{.}}
and correctly infer what sanitization happens."
*/
package template
<commit_msg>html/template: doc nit<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package template (html/template) implements data-driven templates for
generating HTML output safe against code injection. It provides the
same interface as package text/template and should be used instead of
text/template whenever the output is HTML.

The documentation here focuses on the security features of the package.
For information about how to program the templates themselves, see the
documentation for text/template.

Introduction

This package wraps package text/template so you can share its template API
to parse and execute HTML templates safely.

  tmpl, err := template.New("name").Parse(...)
  // Error checking elided
  err = tmpl.Execute(out, data)

If successful, tmpl will now be injection-safe. Otherwise, err is an error
defined in the docs for ErrorCode.

HTML templates treat data values as plain text which should be encoded so they
can be safely embedded in an HTML document. The escaping is contextual, so
actions can appear within JavaScript, CSS, and URI contexts.

The security model used by this package assumes that template authors are
trusted, while Execute's data parameter is not. More details are
provided below.

Example

  import "text/template"
  ...
  t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
  err = t.ExecuteTemplate(out, "T", "")

produces

  Hello, !

but the contextual autoescaping in html/template

  import "html/template"
  ...
  t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
  err = t.ExecuteTemplate(out, "T", "")

produces safe, escaped HTML output

  Hello, <script>alert('you have been pwned')</script>!

Contexts

This package understands HTML, CSS, JavaScript, and URIs. It adds sanitizing
functions to each simple action pipeline, so given the excerpt

  {{.}}

At parse time each {{.}} is overwritten to add escaping functions as necessary.
In this case it becomes

  {{. | html}}

Errors

See the documentation of ErrorCode for details.

A fuller picture

The rest of this package comment may be skipped on first reading; it includes
details necessary to understand escaping contexts and error messages. Most users
will not need to understand these details.

Contexts

Assuming {{.}} is `O'Reilly: How are <i>you</i>?`, the table below shows
how {{.}} appears when used in the context to the left.

  Context                          {{.}} After
  {{.}}                            O'Reilly: How are <i>you</i>?
                  O'Reilly: How are you?
                  O'Reilly: How are %3ci%3eyou%3c/i%3e?
                O'Reilly%3a%20How%20are%3ci%3e...%3f
               O\x27Reilly: How are \x3ci\x3eyou...?
                 "O\x27Reilly: How are \x3ci\x3eyou...?"
       O\x27Reilly: How are \x3ci\x3eyou...\x3f

If used in an unsafe context, then the value might be filtered out:

  Context                          {{.}} After
                   #ZgotmplZ

since "O'Reilly:" is not an allowed protocol like "http:".

If {{.}} is the innocuous word, `left`, then it can appear more widely,

  Context                              {{.}} After
  {{.}}                                left
                      left
                       left
                      left
                  left
          left
               left
         left
    left
     left

Non-string values can be used in JavaScript contexts.
If {{.}} is

  []struct{A,B string}{ "foo", "bar" }

in the escaped template

then the template output is

See package json to understand how non-string content is marshalled for
embedding in JavaScript contexts.

Typed Strings

By default, this package assumes that all pipelines produce a plain text string.
It adds escaping pipeline stages necessary to correctly and safely embed that
plain text string in the appropriate context.

When a data value is not plain text, you can make sure it is not over-escaped
by marking it with its type.

Types HTML, JS, URL, and others from content.go can carry safe content that is
exempted from escaping.

The template

  Hello, {{.}}!

can be invoked with

  tmpl.Execute(out, HTML(`<b>World</b>`))

to produce

  Hello, World!

instead of the

  Hello, <b>World<b>!

that would have been produced if {{.}} was a regular string.

Security Model

http://js-quasis-libraries-and-repl.googlecode.com/svn/trunk/safetemplate.html#problem_definition defines "safe" as used by this package.

This package assumes that template authors are trusted, that Execute's data
parameter is not, and seeks to preserve the properties below in the face
of untrusted data:

Structure Preservation Property:
"... when a template author writes an HTML tag in a safe templating language,
the browser will interpret the corresponding portion of the output as a tag
regardless of the values of untrusted data, and similarly for other structures
such as attribute boundaries and JS and CSS string boundaries."

Code Effect Property:
"... only code specified by the template author should run as a result of
injecting the template output into a page and all code specified by the
template author should run as a result of the same."

Least Surprise Property:
"A developer (or code reviewer) familiar with HTML, CSS, and JavaScript, who
knows that contextual autoescaping happens should be able to look at a {{.}}
and correctly infer what sanitization happens."
*/
package template
<|endoftext|>