<commit_before>/*
Copyright (c) 2014 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 govmomi

import (
	"errors"
	"fmt"
	"reflect"
	"regexp"
	"strings"

	"github.com/vmware/govmomi/vim25/types"
)

// Type values for use in BootOrder
const (
	DeviceTypeCdrom    = "cdrom"
	DeviceTypeDisk     = "disk"
	DeviceTypeEthernet = "ethernet"
	DeviceTypeFloppy   = "floppy"
)

// VirtualDeviceList provides helper methods for working with a list of virtual devices.
type VirtualDeviceList []types.BaseVirtualDevice

// Select returns a new list containing all elements of the list for which the given func returns true.
func (l VirtualDeviceList) Select(f func(device types.BaseVirtualDevice) bool) VirtualDeviceList {
	var found VirtualDeviceList

	for _, device := range l {
		if f(device) {
			found = append(found, device)
		}
	}

	return found
}

// SelectByType returns a new list with devices that are equal to or extend the given type.
func (l VirtualDeviceList) SelectByType(deviceType types.BaseVirtualDevice) VirtualDeviceList {
	dtype := reflect.TypeOf(deviceType)
	dname := dtype.Elem().Name()

	return l.Select(func(device types.BaseVirtualDevice) bool {
		t := reflect.TypeOf(device)

		if t == dtype {
			return true
		}

		_, ok := t.Elem().FieldByName(dname)

		return ok
	})
}

// Find returns the device matching the given name.
func (l VirtualDeviceList) Find(name string) types.BaseVirtualDevice {
	for _, device := range l {
		if l.Name(device) == name {
			return device
		}
	}
	return nil
}

// FindByKey returns the device matching the given key.
func (l VirtualDeviceList) FindByKey(key int) types.BaseVirtualDevice {
	for _, device := range l {
		if device.GetVirtualDevice().Key == key {
			return device
		}
	}
	return nil
}

// FindIDEController will find the named IDE controller if given, otherwise will pick an available controller.
// An error is returned if the named controller is not found or not an IDE controller.  Or, if name is not
// given and no available controller can be found.
func (l VirtualDeviceList) FindIDEController(name string) (*types.VirtualIDEController, error) {
	if name != "" {
		d := l.Find(name)
		if d == nil {
			return nil, fmt.Errorf("device '%s' not found", name)
		}
		if c, ok := d.(*types.VirtualIDEController); ok {
			return c, nil
		}
		return nil, fmt.Errorf("%s is not an IDE controller", name)
	}

	c := l.PickController((*types.VirtualIDEController)(nil))
	if c == nil {
		return nil, errors.New("no available IDE controller")
	}

	return c.(*types.VirtualIDEController), nil
}

// PickController returns a controller of the given type(s).
// If no controllers are found or have no available slots, then nil is returned.
func (l VirtualDeviceList) PickController(kind types.BaseVirtualController) types.BaseVirtualController {
	l = l.SelectByType(kind.(types.BaseVirtualDevice)).Select(func(device types.BaseVirtualDevice) bool {
		num := len(device.(types.BaseVirtualController).GetVirtualController().Device)

		switch device.(type) {
		case types.BaseVirtualSCSIController:
			return num < 15
		default:
			return num < 2
		}
	})

	if len(l) == 0 {
		return nil
	}

	return l[0].(types.BaseVirtualController)
}

// newUnitNumber returns the unit number to use for attaching a new device to the given controller.
func (l VirtualDeviceList) newUnitNumber(c types.BaseVirtualController) int {
	key := c.GetVirtualController().Key
	max := -1

	for _, device := range l {
		d := device.GetVirtualDevice()

		if d.ControllerKey == key {
			if d.UnitNumber > max {
				max = d.UnitNumber
			}
		}
	}

	return max + 1
}

// AssignController assigns a device to a controller.
func (l VirtualDeviceList) AssignController(device types.BaseVirtualDevice, c types.BaseVirtualController) {
	d := device.GetVirtualDevice()
	d.ControllerKey = c.GetVirtualController().Key
	d.UnitNumber = l.newUnitNumber(c)
	d.Key = -1
}

func (l VirtualDeviceList) connectivity(device types.BaseVirtualDevice, v bool) error {
	c := device.GetVirtualDevice().Connectable
	if c == nil {
		return fmt.Errorf("%s is not connectable", l.Name(device))
	}

	c.Connected = v
	c.StartConnected = v

	return nil
}

// Connect changes the device to connected, returns an error if the device is not connectable.
func (l VirtualDeviceList) Connect(device types.BaseVirtualDevice) error {
	return l.connectivity(device, true)
}

// Disconnect changes the device to disconnected, returns an error if the device is not connectable.
func (l VirtualDeviceList) Disconnect(device types.BaseVirtualDevice) error {
	return l.connectivity(device, false)
}

// FindCdrom finds a cdrom device with the given name, defaulting to the first cdrom device if any.
func (l VirtualDeviceList) FindCdrom(name string) (*types.VirtualCdrom, error) {
	if name != "" {
		d := l.Find(name)
		if d == nil {
			return nil, fmt.Errorf("device '%s' not found", name)
		}
		if c, ok := d.(*types.VirtualCdrom); ok {
			return c, nil
		}
		return nil, fmt.Errorf("%s is not a cdrom device", name)
	}

	c := l.SelectByType((*types.VirtualCdrom)(nil))
	if len(c) == 0 {
		return nil, errors.New("no cdrom device found")
	}

	return c[0].(*types.VirtualCdrom), nil
}

// CreateCdrom creates a new VirtualCdrom device which can be added to a VM.
func (l VirtualDeviceList) CreateCdrom(c *types.VirtualIDEController) (*types.VirtualCdrom, error) {
	device := &types.VirtualCdrom{}

	l.AssignController(device, c)

	l.setDefaultCdromBacking(device)

	device.Connectable = &types.VirtualDeviceConnectInfo{
		AllowGuestControl: true,
		Connected:         true,
		StartConnected:    true,
	}

	return device, nil
}

// InsertIso changes the cdrom device backing to use the given iso file.
func (l VirtualDeviceList) InsertIso(device *types.VirtualCdrom, iso string) *types.VirtualCdrom {
	device.Backing = &types.VirtualCdromIsoBackingInfo{
		VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{
			FileName: iso,
		},
	}

	return device
}

// EjectIso removes the iso file based backing and replaces with the default cdrom backing.
func (l VirtualDeviceList) EjectIso(device *types.VirtualCdrom) *types.VirtualCdrom {
	l.setDefaultCdromBacking(device)
	return device
}

func (l VirtualDeviceList) setDefaultCdromBacking(device *types.VirtualCdrom) {
	device.Backing = &types.VirtualCdromAtapiBackingInfo{
		VirtualDeviceDeviceBackingInfo: types.VirtualDeviceDeviceBackingInfo{
			DeviceName:    fmt.Sprintf("%s-%d-%d", DeviceTypeCdrom, device.ControllerKey, device.UnitNumber),
			UseAutoDetect: false,
		},
	}
}

// PrimaryMacAddress returns the MacAddress field of the primary VirtualEthernetCard
func (l VirtualDeviceList) PrimaryMacAddress() string {
	eth0 := l.Find("ethernet-0")

	if eth0 == nil {
		return ""
	}

	return eth0.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard().MacAddress
}

// convert a BaseVirtualDevice to a BaseVirtualMachineBootOptionsBootableDevice
var bootableDevices = map[string]func(device types.BaseVirtualDevice) types.BaseVirtualMachineBootOptionsBootableDevice{
	DeviceTypeCdrom: func(types.BaseVirtualDevice) types.BaseVirtualMachineBootOptionsBootableDevice {
		return &types.VirtualMachineBootOptionsBootableCdromDevice{}
	},
	DeviceTypeDisk: func(d types.BaseVirtualDevice) types.BaseVirtualMachineBootOptionsBootableDevice {
		return &types.VirtualMachineBootOptionsBootableDiskDevice{
			DeviceKey: d.GetVirtualDevice().Key,
		}
	},
	DeviceTypeEthernet: func(d types.BaseVirtualDevice) types.BaseVirtualMachineBootOptionsBootableDevice {
		return &types.VirtualMachineBootOptionsBootableEthernetDevice{
			DeviceKey: d.GetVirtualDevice().Key,
		}
	},
	DeviceTypeFloppy: func(types.BaseVirtualDevice) types.BaseVirtualMachineBootOptionsBootableDevice {
		return &types.VirtualMachineBootOptionsBootableFloppyDevice{}
	},
}

// BootOrder returns a list of devices which can be used to set boot order via VirtualMachine.SetBootOptions.
// The order can any of "ethernet", "cdrom", "floppy" or "disk" or by specific device name.
func (l VirtualDeviceList) BootOrder(order []string) []types.BaseVirtualMachineBootOptionsBootableDevice {
	var devices []types.BaseVirtualMachineBootOptionsBootableDevice

	for _, name := range order {
		if kind, ok := bootableDevices[name]; ok {
			for _, device := range l {
				if l.Type(device) == name {
					devices = append(devices, kind(device))
				}

			}
			continue
		}

		if d := l.Find(name); d != nil {
			if kind, ok := bootableDevices[l.Type(d)]; ok {
				devices = append(devices, kind(d))
			}
		}
	}

	return devices
}

// SelectBootOrder returns an ordered list of devices matching the given bootable device order
func (l VirtualDeviceList) SelectBootOrder(order []types.BaseVirtualMachineBootOptionsBootableDevice) VirtualDeviceList {
	var devices VirtualDeviceList

	for _, bd := range order {
		for _, device := range l {
			if kind, ok := bootableDevices[l.Type(device)]; ok {
				if reflect.DeepEqual(kind(device), bd) {
					devices = append(devices, device)
				}
			}
		}
	}

	return devices
}

// TypeName returns the vmodl type name of the device
func (l VirtualDeviceList) TypeName(device types.BaseVirtualDevice) string {
	return reflect.TypeOf(device).Elem().Name()
}

var deviceNameRegexp = regexp.MustCompile(`(?:Virtual)?(?:Machine)?(\w+?)(?:Card|Device|Controller)?$`)

// Type returns a human-readable name for the given device
func (l VirtualDeviceList) Type(device types.BaseVirtualDevice) string {
	switch device.(type) {
	case types.BaseVirtualEthernetCard:
		return DeviceTypeEthernet
	case *types.ParaVirtualSCSIController:
		return "pvscsi"
	default:
		name := "device"
		typeName := l.TypeName(device)
		m := deviceNameRegexp.FindStringSubmatch(typeName)
		if len(m) == 2 {
			name = strings.ToLower(m[1])
		}
		return name
	}
}

// Name returns a stable, human-readable name for the given device
func (l VirtualDeviceList) Name(device types.BaseVirtualDevice) string {
	var key string
	d := device.GetVirtualDevice()
	dtype := l.Type(device)

	switch dtype {
	case DeviceTypeEthernet:
		key = fmt.Sprintf("%d", d.UnitNumber-7)
	case DeviceTypeDisk:
		key = fmt.Sprintf("%d-%d", d.ControllerKey, d.UnitNumber)
	default:
		key = fmt.Sprintf("%d", d.Key)
	}

	return fmt.Sprintf("%s-%s", dtype, key)
}
<commit_msg>Add floppy device related helpers<commit_after>/*
Copyright (c) 2014 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 govmomi

import (
	"errors"
	"fmt"
	"reflect"
	"regexp"
	"strings"

	"github.com/vmware/govmomi/vim25/types"
)

// Type values for use in BootOrder
const (
	DeviceTypeCdrom    = "cdrom"
	DeviceTypeDisk     = "disk"
	DeviceTypeEthernet = "ethernet"
	DeviceTypeFloppy   = "floppy"
)

// VirtualDeviceList provides helper methods for working with a list of virtual devices.
type VirtualDeviceList []types.BaseVirtualDevice

// Select returns a new list containing all elements of the list for which the given func returns true.
func (l VirtualDeviceList) Select(f func(device types.BaseVirtualDevice) bool) VirtualDeviceList {
	var found VirtualDeviceList

	for _, device := range l {
		if f(device) {
			found = append(found, device)
		}
	}

	return found
}

// SelectByType returns a new list with devices that are equal to or extend the given type.
func (l VirtualDeviceList) SelectByType(deviceType types.BaseVirtualDevice) VirtualDeviceList {
	dtype := reflect.TypeOf(deviceType)
	dname := dtype.Elem().Name()

	return l.Select(func(device types.BaseVirtualDevice) bool {
		t := reflect.TypeOf(device)

		if t == dtype {
			return true
		}

		_, ok := t.Elem().FieldByName(dname)

		return ok
	})
}

// Find returns the device matching the given name.
func (l VirtualDeviceList) Find(name string) types.BaseVirtualDevice {
	for _, device := range l {
		if l.Name(device) == name {
			return device
		}
	}
	return nil
}

// FindByKey returns the device matching the given key.
func (l VirtualDeviceList) FindByKey(key int) types.BaseVirtualDevice {
	for _, device := range l {
		if device.GetVirtualDevice().Key == key {
			return device
		}
	}
	return nil
}

// FindIDEController will find the named IDE controller if given, otherwise will pick an available controller.
// An error is returned if the named controller is not found or not an IDE controller.  Or, if name is not
// given and no available controller can be found.
func (l VirtualDeviceList) FindIDEController(name string) (*types.VirtualIDEController, error) {
	if name != "" {
		d := l.Find(name)
		if d == nil {
			return nil, fmt.Errorf("device '%s' not found", name)
		}
		if c, ok := d.(*types.VirtualIDEController); ok {
			return c, nil
		}
		return nil, fmt.Errorf("%s is not an IDE controller", name)
	}

	c := l.PickController((*types.VirtualIDEController)(nil))
	if c == nil {
		return nil, errors.New("no available IDE controller")
	}

	return c.(*types.VirtualIDEController), nil
}

// PickController returns a controller of the given type(s).
// If no controllers are found or have no available slots, then nil is returned.
func (l VirtualDeviceList) PickController(kind types.BaseVirtualController) types.BaseVirtualController {
	l = l.SelectByType(kind.(types.BaseVirtualDevice)).Select(func(device types.BaseVirtualDevice) bool {
		num := len(device.(types.BaseVirtualController).GetVirtualController().Device)

		switch device.(type) {
		case types.BaseVirtualSCSIController:
			return num < 15
		case *types.VirtualIDEController:
			return num < 2
		default:
			return true
		}
	})

	if len(l) == 0 {
		return nil
	}

	return l[0].(types.BaseVirtualController)
}

// newUnitNumber returns the unit number to use for attaching a new device to the given controller.
func (l VirtualDeviceList) newUnitNumber(c types.BaseVirtualController) int {
	key := c.GetVirtualController().Key
	max := -1

	for _, device := range l {
		d := device.GetVirtualDevice()

		if d.ControllerKey == key {
			if d.UnitNumber > max {
				max = d.UnitNumber
			}
		}
	}

	return max + 1
}

// AssignController assigns a device to a controller.
func (l VirtualDeviceList) AssignController(device types.BaseVirtualDevice, c types.BaseVirtualController) {
	d := device.GetVirtualDevice()
	d.ControllerKey = c.GetVirtualController().Key
	d.UnitNumber = l.newUnitNumber(c)
	d.Key = -1
}

func (l VirtualDeviceList) connectivity(device types.BaseVirtualDevice, v bool) error {
	c := device.GetVirtualDevice().Connectable
	if c == nil {
		return fmt.Errorf("%s is not connectable", l.Name(device))
	}

	c.Connected = v
	c.StartConnected = v

	return nil
}

// Connect changes the device to connected, returns an error if the device is not connectable.
func (l VirtualDeviceList) Connect(device types.BaseVirtualDevice) error {
	return l.connectivity(device, true)
}

// Disconnect changes the device to disconnected, returns an error if the device is not connectable.
func (l VirtualDeviceList) Disconnect(device types.BaseVirtualDevice) error {
	return l.connectivity(device, false)
}

// FindCdrom finds a cdrom device with the given name, defaulting to the first cdrom device if any.
func (l VirtualDeviceList) FindCdrom(name string) (*types.VirtualCdrom, error) {
	if name != "" {
		d := l.Find(name)
		if d == nil {
			return nil, fmt.Errorf("device '%s' not found", name)
		}
		if c, ok := d.(*types.VirtualCdrom); ok {
			return c, nil
		}
		return nil, fmt.Errorf("%s is not a cdrom device", name)
	}

	c := l.SelectByType((*types.VirtualCdrom)(nil))
	if len(c) == 0 {
		return nil, errors.New("no cdrom device found")
	}

	return c[0].(*types.VirtualCdrom), nil
}

// CreateCdrom creates a new VirtualCdrom device which can be added to a VM.
func (l VirtualDeviceList) CreateCdrom(c *types.VirtualIDEController) (*types.VirtualCdrom, error) {
	device := &types.VirtualCdrom{}

	l.AssignController(device, c)

	l.setDefaultCdromBacking(device)

	device.Connectable = &types.VirtualDeviceConnectInfo{
		AllowGuestControl: true,
		Connected:         true,
		StartConnected:    true,
	}

	return device, nil
}

// InsertIso changes the cdrom device backing to use the given iso file.
func (l VirtualDeviceList) InsertIso(device *types.VirtualCdrom, iso string) *types.VirtualCdrom {
	device.Backing = &types.VirtualCdromIsoBackingInfo{
		VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{
			FileName: iso,
		},
	}

	return device
}

// EjectIso removes the iso file based backing and replaces with the default cdrom backing.
func (l VirtualDeviceList) EjectIso(device *types.VirtualCdrom) *types.VirtualCdrom {
	l.setDefaultCdromBacking(device)
	return device
}

func (l VirtualDeviceList) setDefaultCdromBacking(device *types.VirtualCdrom) {
	device.Backing = &types.VirtualCdromAtapiBackingInfo{
		VirtualDeviceDeviceBackingInfo: types.VirtualDeviceDeviceBackingInfo{
			DeviceName:    fmt.Sprintf("%s-%d-%d", DeviceTypeCdrom, device.ControllerKey, device.UnitNumber),
			UseAutoDetect: false,
		},
	}
}

// FindFloppy finds a floppy device with the given name, defaulting to the first floppy device if any.
func (l VirtualDeviceList) FindFloppy(name string) (*types.VirtualFloppy, error) {
	if name != "" {
		d := l.Find(name)
		if d == nil {
			return nil, fmt.Errorf("device '%s' not found", name)
		}
		if c, ok := d.(*types.VirtualFloppy); ok {
			return c, nil
		}
		return nil, fmt.Errorf("%s is not a floppy device", name)
	}

	c := l.SelectByType((*types.VirtualFloppy)(nil))
	if len(c) == 0 {
		return nil, errors.New("no floppy device found")
	}

	return c[0].(*types.VirtualFloppy), nil
}

// CreateFloppy creates a new VirtualFloppy device which can be added to a VM.
func (l VirtualDeviceList) CreateFloppy() (*types.VirtualFloppy, error) {
	device := &types.VirtualFloppy{}

	c := l.PickController((*types.VirtualSIOController)(nil))
	if c == nil {
		return nil, errors.New("no available SIO controller")
	}

	l.AssignController(device, c)

	l.setDefaultFloppyBacking(device)

	device.Connectable = &types.VirtualDeviceConnectInfo{
		AllowGuestControl: true,
		Connected:         true,
		StartConnected:    true,
	}

	return device, nil
}

// InsertImg changes the floppy device backing to use the given img file.
func (l VirtualDeviceList) InsertImg(device *types.VirtualFloppy, img string) *types.VirtualFloppy {
	device.Backing = &types.VirtualFloppyImageBackingInfo{
		VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{
			FileName: img,
		},
	}

	return device
}

// EjectImg removes the img file based backing and replaces with the default floppy backing.
func (l VirtualDeviceList) EjectImg(device *types.VirtualFloppy) *types.VirtualFloppy {
	l.setDefaultFloppyBacking(device)
	return device
}

func (l VirtualDeviceList) setDefaultFloppyBacking(device *types.VirtualFloppy) {
	device.Backing = &types.VirtualFloppyDeviceBackingInfo{
		VirtualDeviceDeviceBackingInfo: types.VirtualDeviceDeviceBackingInfo{
			DeviceName:    fmt.Sprintf("%s-%d", DeviceTypeFloppy, device.UnitNumber),
			UseAutoDetect: false,
		},
	}
}

// PrimaryMacAddress returns the MacAddress field of the primary VirtualEthernetCard
func (l VirtualDeviceList) PrimaryMacAddress() string {
	eth0 := l.Find("ethernet-0")

	if eth0 == nil {
		return ""
	}

	return eth0.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard().MacAddress
}

// convert a BaseVirtualDevice to a BaseVirtualMachineBootOptionsBootableDevice
var bootableDevices = map[string]func(device types.BaseVirtualDevice) types.BaseVirtualMachineBootOptionsBootableDevice{
	DeviceTypeCdrom: func(types.BaseVirtualDevice) types.BaseVirtualMachineBootOptionsBootableDevice {
		return &types.VirtualMachineBootOptionsBootableCdromDevice{}
	},
	DeviceTypeDisk: func(d types.BaseVirtualDevice) types.BaseVirtualMachineBootOptionsBootableDevice {
		return &types.VirtualMachineBootOptionsBootableDiskDevice{
			DeviceKey: d.GetVirtualDevice().Key,
		}
	},
	DeviceTypeEthernet: func(d types.BaseVirtualDevice) types.BaseVirtualMachineBootOptionsBootableDevice {
		return &types.VirtualMachineBootOptionsBootableEthernetDevice{
			DeviceKey: d.GetVirtualDevice().Key,
		}
	},
	DeviceTypeFloppy: func(types.BaseVirtualDevice) types.BaseVirtualMachineBootOptionsBootableDevice {
		return &types.VirtualMachineBootOptionsBootableFloppyDevice{}
	},
}

// BootOrder returns a list of devices which can be used to set boot order via VirtualMachine.SetBootOptions.
// The order can any of "ethernet", "cdrom", "floppy" or "disk" or by specific device name.
func (l VirtualDeviceList) BootOrder(order []string) []types.BaseVirtualMachineBootOptionsBootableDevice {
	var devices []types.BaseVirtualMachineBootOptionsBootableDevice

	for _, name := range order {
		if kind, ok := bootableDevices[name]; ok {
			for _, device := range l {
				if l.Type(device) == name {
					devices = append(devices, kind(device))
				}

			}
			continue
		}

		if d := l.Find(name); d != nil {
			if kind, ok := bootableDevices[l.Type(d)]; ok {
				devices = append(devices, kind(d))
			}
		}
	}

	return devices
}

// SelectBootOrder returns an ordered list of devices matching the given bootable device order
func (l VirtualDeviceList) SelectBootOrder(order []types.BaseVirtualMachineBootOptionsBootableDevice) VirtualDeviceList {
	var devices VirtualDeviceList

	for _, bd := range order {
		for _, device := range l {
			if kind, ok := bootableDevices[l.Type(device)]; ok {
				if reflect.DeepEqual(kind(device), bd) {
					devices = append(devices, device)
				}
			}
		}
	}

	return devices
}

// TypeName returns the vmodl type name of the device
func (l VirtualDeviceList) TypeName(device types.BaseVirtualDevice) string {
	return reflect.TypeOf(device).Elem().Name()
}

var deviceNameRegexp = regexp.MustCompile(`(?:Virtual)?(?:Machine)?(\w+?)(?:Card|Device|Controller)?$`)

// Type returns a human-readable name for the given device
func (l VirtualDeviceList) Type(device types.BaseVirtualDevice) string {
	switch device.(type) {
	case types.BaseVirtualEthernetCard:
		return DeviceTypeEthernet
	case *types.ParaVirtualSCSIController:
		return "pvscsi"
	default:
		name := "device"
		typeName := l.TypeName(device)
		m := deviceNameRegexp.FindStringSubmatch(typeName)
		if len(m) == 2 {
			name = strings.ToLower(m[1])
		}
		return name
	}
}

// Name returns a stable, human-readable name for the given device
func (l VirtualDeviceList) Name(device types.BaseVirtualDevice) string {
	var key string
	d := device.GetVirtualDevice()
	dtype := l.Type(device)

	switch dtype {
	case DeviceTypeEthernet:
		key = fmt.Sprintf("%d", d.UnitNumber-7)
	case DeviceTypeDisk:
		key = fmt.Sprintf("%d-%d", d.ControllerKey, d.UnitNumber)
	default:
		key = fmt.Sprintf("%d", d.Key)
	}

	return fmt.Sprintf("%s-%s", dtype, key)
}
<|endoftext|>


<commit_before>package requestparsing

import (
	"bytes"
	"context"
	"net/http"
	"testing"

	"github.com/google/go-cmp/cmp"
)

const (
	statusOK = "HTTP/1.1 200 OK\r\n"
)

func TestCase(t *testing.T) {
	request := []byte("GET / HTTP/1.1\r\n" +
		"Host: localhost:8080\r\n" +
		"A: B\r\n" +
		"\r\n")
	response, err := makeRequest(context.Background(), request, func(r *http.Request) {
		want := map[string][]string{"A": []string{"B"}}
		if diff := cmp.Diff(want, map[string][]string(r.Header)); diff != "" {
			t.Errorf("r.Header mismatch (-want +got):\n%s", diff)
		}
	})
	if err != nil {
		t.Errorf("makeRequest() got err %v want nil", err)
	}

	if !bytes.HasPrefix(response, []byte(statusOK)) {
		got := string(response[:bytes.IndexByte(response, '\n')+1])
		t.Errorf("status code got: %q want: %q", got, statusOK)
	}
}
<commit_msg>Removed sample tests<commit_after><|endoftext|>


<commit_before>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package main

import (
	"encoding/json"
	"fmt"
	"strconv"
	"time"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
)

// This chaincode implements a simple map that is stored in the state.
// The following operations are available.

// Invoke operations
// put - requires two arguments, a key and value
// remove - requires a key
// get - requires one argument, a key, and returns a value
// keys - requires no arguments, returns all keys

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

type PageResponse struct {
	Bookmark string   `json:"bookmark"`
	Keys     []string `json:"keys"`
}

// Init is a no-op
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
	return shim.Success(nil)
}

// Invoke has two functions
// put - takes two arguments, a key and value, and stores them in the state
// remove - takes one argument, a key, and removes if from the state
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
	function, args := stub.GetFunctionAndParameters()
	switch function {

	case "putPrivate":
		if len(args) < 3 {
			return shim.Error("put operation on private data must include three arguments: [collection, key, value]")
		}
		collection := args[0]
		key := args[1]
		value := args[2]

		if err := stub.PutPrivateData(collection, key, []byte(value)); err != nil {
			fmt.Printf("Error putting private data%s", err)
			return shim.Error(fmt.Sprintf("put operation failed. Error updating state: %s", err))
		}

		return shim.Success(nil)

	case "removePrivate":
		if len(args) < 2 {
			return shim.Error("remove operation on private data must include two arguments: [collection, key]")
		}
		collection := args[0]
		key := args[1]

		err := stub.DelPrivateData(collection, key)
		if err != nil {
			return shim.Error(fmt.Sprintf("remove operation on private data failed. Error updating state: %s", err))
		}
		return shim.Success(nil)

	case "getPrivate":
		if len(args) < 2 {
			return shim.Error("get operation on private data must include two arguments: [collection, key]")
		}
		collection := args[0]
		key := args[1]
		value, err := stub.GetPrivateData(collection, key)
		if err != nil {
			return shim.Error(fmt.Sprintf("get operation on private data failed. Error accessing state: %s", err))
		}
		jsonVal, err := json.Marshal(string(value))
		return shim.Success(jsonVal)

	case "keysPrivate":
		if len(args) < 3 {
			return shim.Error("range query operation on private data must include three arguments, a collection, key and value")
		}
		collection := args[0]
		startKey := args[1]
		endKey := args[2]

		//sleep needed to test peer's timeout behavior when using iterators
		stime := 0
		if len(args) > 3 {
			stime, _ = strconv.Atoi(args[3])
		}

		keysIter, err := stub.GetPrivateDataByRange(collection, startKey, endKey)
		if err != nil {
			return shim.Error(fmt.Sprintf("keys operation failed on private data. Error accessing state: %s", err))
		}
		defer keysIter.Close()

		var keys []string
		for keysIter.HasNext() {
			//if sleeptime is specied, take a nap
			if stime > 0 {
				time.Sleep(time.Duration(stime) * time.Millisecond)
			}

			response, iterErr := keysIter.Next()
			if iterErr != nil {
				return shim.Error(fmt.Sprintf("keys operation on private data failed. Error accessing state: %s", err))
			}
			keys = append(keys, response.Key)
		}

		for key, value := range keys {
			fmt.Printf("key %d contains %s\n", key, value)
		}

		jsonKeys, err := json.Marshal(keys)
		if err != nil {
			return shim.Error(fmt.Sprintf("keys operation on private data failed. Error marshaling JSON: %s", err))
		}

		return shim.Success(jsonKeys)

	case "queryPrivate":
		collection := args[0]
		query := args[1]
		keysIter, err := stub.GetPrivateDataQueryResult(collection, query)
		if err != nil {
			return shim.Error(fmt.Sprintf("query operation on private data failed. Error accessing state: %s", err))
		}
		defer keysIter.Close()

		var keys []string
		for keysIter.HasNext() {
			response, iterErr := keysIter.Next()
			if iterErr != nil {
				return shim.Error(fmt.Sprintf("query operation on private data failed. Error accessing state: %s", err))
			}
			keys = append(keys, response.Key)
		}

		jsonKeys, err := json.Marshal(keys)
		if err != nil {
			return shim.Error(fmt.Sprintf("query operation on private data failed. Error marshaling JSON: %s", err))
		}

		return shim.Success(jsonKeys)

	case "put":
		if len(args) < 2 {
			return shim.Error("put operation must include two arguments: [key, value]")
		}
		key := args[0]
		value := args[1]

		if err := stub.PutState(key, []byte(value)); err != nil {
			fmt.Printf("Error putting state %s", err)
			return shim.Error(fmt.Sprintf("put operation failed. Error updating state: %s", err))
		}

		indexName := "compositeKeyTest"
		compositeKeyTestIndex, err := stub.CreateCompositeKey(indexName, []string{key})
		if err != nil {
			return shim.Error(err.Error())
		}

		valueByte := []byte{0x00}
		if err := stub.PutState(compositeKeyTestIndex, valueByte); err != nil {
			fmt.Printf("Error putting state with compositeKey %s", err)
			return shim.Error(fmt.Sprintf("put operation failed. Error updating state with compositeKey: %s", err))
		}

		return shim.Success(nil)

	case "remove":
		if len(args) < 1 {
			return shim.Error("remove operation must include one argument: [key]")
		}
		key := args[0]

		err := stub.DelState(key)
		if err != nil {
			return shim.Error(fmt.Sprintf("remove operation failed. Error updating state: %s", err))
		}
		return shim.Success(nil)

	case "get":
		if len(args) < 1 {
			return shim.Error("get operation must include one argument, a key")
		}
		key := args[0]
		value, err := stub.GetState(key)
		if err != nil {
			return shim.Error(fmt.Sprintf("get operation failed. Error accessing state: %s", err))
		}
		jsonVal, err := json.Marshal(string(value))
		return shim.Success(jsonVal)

	case "keys":
		if len(args) < 2 {
			return shim.Error("keys operation must include two arguments, a key and value")
		}
		startKey := args[0]
		endKey := args[1]

		//sleep needed to test peer's timeout behavior when using iterators
		stime := 0
		if len(args) > 2 {
			stime, _ = strconv.Atoi(args[2])
		}

		keysIter, err := stub.GetStateByRange(startKey, endKey)
		if err != nil {
			return shim.Error(fmt.Sprintf("keys operation failed. Error accessing state: %s", err))
		}
		defer keysIter.Close()

		var keys []string
		for keysIter.HasNext() {
			//if sleeptime is specied, take a nap
			if stime > 0 {
				time.Sleep(time.Duration(stime) * time.Millisecond)
			}

			response, iterErr := keysIter.Next()
			if iterErr != nil {
				return shim.Error(fmt.Sprintf("keys operation failed. Error accessing state: %s", err))
			}
			keys = append(keys, response.Key)
		}

		for key, value := range keys {
			fmt.Printf("key %d contains %s\n", key, value)
		}

		jsonKeys, err := json.Marshal(keys)
		if err != nil {
			return shim.Error(fmt.Sprintf("keys operation failed. Error marshaling JSON: %s", err))
		}

		return shim.Success(jsonKeys)

	case "keysByPage":
		if len(args) < 4 {
			return shim.Error("paginated range query operation must include four arguments, a key, value, pageSize and a bookmark")
		}
		startKey := args[0]
		endKey := args[1]
		pageSize, parserr := strconv.ParseInt(args[2], 10, 32)
		if parserr != nil {
			return shim.Error(fmt.Sprintf("error parsing range pagesize: %s", parserr))
		}
		bookmark := args[3]

		//sleep needed to test peer's timeout behavior when using iterators
		stime := 0
		if len(args) > 4 {
			stime, _ = strconv.Atoi(args[4])
		}

		keysIter, resp, err := stub.GetStateByRangeWithPagination(startKey, endKey, int32(pageSize), bookmark)
		if err != nil {
			return shim.Error(fmt.Sprintf("keysByPage operation failed. Error accessing state: %s", err))
		}
		defer keysIter.Close()

		var keys []string
		for keysIter.HasNext() {
			//if sleeptime is specied, take a nap
			if stime > 0 {
				time.Sleep(time.Duration(stime) * time.Millisecond)
			}

			response, iterErr := keysIter.Next()
			if iterErr != nil {
				return shim.Error(fmt.Sprintf("keysByPage operation failed. Error accessing state: %s", err))
			}
			keys = append(keys, response.Key)
		}

		for index, value := range keys {
			fmt.Printf("key %d contains %s\n", index, value)
		}

		jsonResp := PageResponse{
			Bookmark: resp.Bookmark,
			Keys:     keys,
		}

		queryResp, err := json.Marshal(jsonResp)
		if err != nil {
			return shim.Error(fmt.Sprintf("keysByPage operation failed. Error marshaling JSON: %s", err))
		}

		return shim.Success(queryResp)

	case "query":
		query := args[0]
		keysIter, err := stub.GetQueryResult(query)
		if err != nil {
			return shim.Error(fmt.Sprintf("query operation failed. Error accessing state: %s", err))
		}
		defer keysIter.Close()

		var keys []string
		for keysIter.HasNext() {
			response, iterErr := keysIter.Next()
			if iterErr != nil {
				return shim.Error(fmt.Sprintf("query operation failed. Error accessing state: %s", err))
			}
			keys = append(keys, response.Key)
		}

		jsonKeys, err := json.Marshal(keys)
		if err != nil {
			return shim.Error(fmt.Sprintf("query operation failed. Error marshaling JSON: %s", err))
		}

		return shim.Success(jsonKeys)

	case "queryByPage":
		query := args[0]
		pageSize, parserr := strconv.ParseInt(args[1], 10, 32)
		if parserr != nil {
			return shim.Error(fmt.Sprintf("error parsing query pagesize: %s", parserr))
		}
		bookmark := args[2]

		keysIter, resp, err := stub.GetQueryResultWithPagination(query, int32(pageSize), bookmark)
		if err != nil {
			return shim.Error(fmt.Sprintf("queryByPage operation failed. Error accessing state: %s", err))
		}
		defer keysIter.Close()

		var keys []string
		for keysIter.HasNext() {
			response, iterErr := keysIter.Next()
			if iterErr != nil {
				return shim.Error(fmt.Sprintf("queryByPage operation failed. Error accessing state: %s", err))
			}
			keys = append(keys, response.Key)
		}

		for key, value := range keys {
			fmt.Printf("key %d contains %s\n", key, value)
		}

		jsonResp := PageResponse{
			Bookmark: resp.Bookmark,
			Keys:     keys,
		}

		queryResp, err := json.Marshal(jsonResp)
		if err != nil {
			return shim.Error(fmt.Sprintf("queryByPage operation failed. Error marshaling JSON: %s", err))
		}

		return shim.Success(queryResp)

	case "history":
		key := args[0]
		keysIter, err := stub.GetHistoryForKey(key)
		if err != nil {
			return shim.Error(fmt.Sprintf("get history operation failed. Error accessing state: %s", err))
		}
		defer keysIter.Close()

		var keys []string
		for keysIter.HasNext() {
			response, iterErr := keysIter.Next()
			if iterErr != nil {
				return shim.Error(fmt.Sprintf("get history operation failed. Error accessing state: %s", err))
			}
			keys = append(keys, response.TxId)
		}

		for key, txID := range keys {
			fmt.Printf("key %d contains %s\n", key, txID)
		}

		jsonKeys, err := json.Marshal(keys)
		if err != nil {
			return shim.Error(fmt.Sprintf("get history operation failed. Error marshaling JSON: %s", err))
		}

		return shim.Success(jsonKeys)

	default:
		return shim.Success([]byte("Unsupported operation"))
	}
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting chaincode: %s", err)
	}
}
<commit_msg>[FAB-12995] Add new functions to the example cc<commit_after>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package main

import (
	"encoding/json"
	"fmt"
	"strconv"
	"time"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
)

// This chaincode implements a simple map that is stored in the state.
// The following operations are available.

// Invoke operations
// put - requires two arguments, a key and value
// remove - requires a key
// get - requires one argument, a key, and returns a value
// keys - requires no arguments, returns all keys

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

type PageResponse struct {
	Bookmark string   `json:"bookmark"`
	Keys     []string `json:"keys"`
}

// Init is a no-op
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
	return shim.Success(nil)
}

// Invoke has two functions
// put - takes two arguments, a key and value, and stores them in the state
// remove - takes one argument, a key, and removes if from the state
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
	function, args := stub.GetFunctionAndParameters()
	switch function {

	case "putPrivate":
		return t.putPrivate(stub, args)

	case "removePrivate":
		return t.removePrivate(stub, args)

	case "getPrivate":
		return t.getPrivate(stub, args)

	case "keysPrivate":
		return t.keysPrivate(stub, args)

	case "queryPrivate":
		return t.queryPrivate(stub, args)

	case "put":
		return t.put(stub, args)

	case "remove":
		return t.remove(stub, args)

	case "get":
		return t.get(stub, args)

	case "keys":
		return t.keys(stub, args)

	case "keysByPage":
		return t.keysByPage(stub, args)

	case "query":
		return t.query(stub, args)

	case "queryByPage":
		return t.queryByPage(stub, args)

	case "history":
		return t.history(stub, args)

	case "getPut":
		return t.getPut(stub, args)

	case "getPutPrivate":
		return t.getPutPrivate(stub, args)

	default:
		return shim.Error("Unsupported operation")
	}
}

func (t *SimpleChaincode) putPrivate(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) < 3 {
		return shim.Error("put operation on private data must include three arguments: [collection, key, value]")
	}
	collection := args[0]
	key := args[1]
	value := args[2]

	if err := stub.PutPrivateData(collection, key, []byte(value)); err != nil {
		fmt.Printf("Error putting private data%s", err)
		return shim.Error(fmt.Sprintf("put operation failed. Error updating state: %s", err))
	}

	return shim.Success(nil)
}
func (t *SimpleChaincode) removePrivate(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) < 2 {
		return shim.Error("remove operation on private data must include two arguments: [collection, key]")
	}
	collection := args[0]
	key := args[1]

	err := stub.DelPrivateData(collection, key)
	if err != nil {
		return shim.Error(fmt.Sprintf("remove operation on private data failed. Error updating state: %s", err))
	}
	return shim.Success(nil)
}
func (t *SimpleChaincode) getPrivate(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) < 2 {
		return shim.Error("get operation on private data must include two arguments: [collection, key]")
	}
	collection := args[0]
	key := args[1]
	value, err := stub.GetPrivateData(collection, key)
	if err != nil {
		return shim.Error(fmt.Sprintf("get operation on private data failed. Error accessing state: %s", err))
	}
	jsonVal, err := json.Marshal(string(value))
	return shim.Success(jsonVal)

}
func (t *SimpleChaincode) keysPrivate(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) < 3 {
		return shim.Error("range query operation on private data must include three arguments, a collection, key and value")
	}
	collection := args[0]
	startKey := args[1]
	endKey := args[2]

	//sleep needed to test peer's timeout behavior when using iterators
	stime := 0
	if len(args) > 3 {
		stime, _ = strconv.Atoi(args[3])
	}

	keysIter, err := stub.GetPrivateDataByRange(collection, startKey, endKey)
	if err != nil {
		return shim.Error(fmt.Sprintf("keys operation failed on private data. Error accessing state: %s", err))
	}
	defer keysIter.Close()

	var keys []string
	for keysIter.HasNext() {
		//if sleeptime is specied, take a nap
		if stime > 0 {
			time.Sleep(time.Duration(stime) * time.Millisecond)
		}

		response, iterErr := keysIter.Next()
		if iterErr != nil {
			return shim.Error(fmt.Sprintf("keys operation on private data failed. Error accessing state: %s", err))
		}
		keys = append(keys, response.Key)
	}

	for key, value := range keys {
		fmt.Printf("key %d contains %s\n", key, value)
	}

	jsonKeys, err := json.Marshal(keys)
	if err != nil {
		return shim.Error(fmt.Sprintf("keys operation on private data failed. Error marshaling JSON: %s", err))
	}

	return shim.Success(jsonKeys)
}

func (t *SimpleChaincode) queryPrivate(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	collection := args[0]
	query := args[1]
	keysIter, err := stub.GetPrivateDataQueryResult(collection, query)
	if err != nil {
		return shim.Error(fmt.Sprintf("query operation on private data failed. Error accessing state: %s", err))
	}
	defer keysIter.Close()

	var keys []string
	for keysIter.HasNext() {
		response, iterErr := keysIter.Next()
		if iterErr != nil {
			return shim.Error(fmt.Sprintf("query operation on private data failed. Error accessing state: %s", err))
		}
		keys = append(keys, response.Key)
	}

	jsonKeys, err := json.Marshal(keys)
	if err != nil {
		return shim.Error(fmt.Sprintf("query operation on private data failed. Error marshaling JSON: %s", err))
	}

	return shim.Success(jsonKeys)
}
func (t *SimpleChaincode) put(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) < 2 {
		return shim.Error("put operation must include two arguments: [key, value]")
	}
	key := args[0]
	value := args[1]

	if err := stub.PutState(key, []byte(value)); err != nil {
		fmt.Printf("Error putting state %s", err)
		return shim.Error(fmt.Sprintf("put operation failed. Error updating state: %s", err))
	}

	indexName := "compositeKeyTest"
	compositeKeyTestIndex, err := stub.CreateCompositeKey(indexName, []string{key})
	if err != nil {
		return shim.Error(err.Error())
	}

	valueByte := []byte{0x00}
	if err := stub.PutState(compositeKeyTestIndex, valueByte); err != nil {
		fmt.Printf("Error putting state with compositeKey %s", err)
		return shim.Error(fmt.Sprintf("put operation failed. Error updating state with compositeKey: %s", err))
	}

	return shim.Success(nil)
}
func (t *SimpleChaincode) remove(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) < 1 {
		return shim.Error("remove operation must include one argument: [key]")
	}
	key := args[0]

	err := stub.DelState(key)
	if err != nil {
		return shim.Error(fmt.Sprintf("remove operation failed. Error updating state: %s", err))
	}
	return shim.Success(nil)
}
func (t *SimpleChaincode) get(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) < 1 {
		return shim.Error("get operation must include one argument, a key")
	}
	key := args[0]
	value, err := stub.GetState(key)
	if err != nil {
		return shim.Error(fmt.Sprintf("get operation failed. Error accessing state: %s", err))
	}
	jsonVal, err := json.Marshal(string(value))
	return shim.Success(jsonVal)
}
func (t *SimpleChaincode) keys(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) < 2 {
		return shim.Error("keys operation must include two arguments, a key and value")
	}
	startKey := args[0]
	endKey := args[1]

	//sleep needed to test peer's timeout behavior when using iterators
	stime := 0
	if len(args) > 2 {
		stime, _ = strconv.Atoi(args[2])
	}

	keysIter, err := stub.GetStateByRange(startKey, endKey)
	if err != nil {
		return shim.Error(fmt.Sprintf("keys operation failed. Error accessing state: %s", err))
	}
	defer keysIter.Close()

	var keys []string
	for keysIter.HasNext() {
		//if sleeptime is specied, take a nap
		if stime > 0 {
			time.Sleep(time.Duration(stime) * time.Millisecond)
		}

		response, iterErr := keysIter.Next()
		if iterErr != nil {
			return shim.Error(fmt.Sprintf("keys operation failed. Error accessing state: %s", err))
		}
		keys = append(keys, response.Key)
	}

	for key, value := range keys {
		fmt.Printf("key %d contains %s\n", key, value)
	}

	jsonKeys, err := json.Marshal(keys)
	if err != nil {
		return shim.Error(fmt.Sprintf("keys operation failed. Error marshaling JSON: %s", err))
	}

	return shim.Success(jsonKeys)
}

func (t *SimpleChaincode) keysByPage(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) < 4 {
		return shim.Error("paginated range query operation must include four arguments, a key, value, pageSize and a bookmark")
	}
	startKey := args[0]
	endKey := args[1]
	pageSize, parserr := strconv.ParseInt(args[2], 10, 32)
	if parserr != nil {
		return shim.Error(fmt.Sprintf("error parsing range pagesize: %s", parserr))
	}
	bookmark := args[3]

	//sleep needed to test peer's timeout behavior when using iterators
	stime := 0
	if len(args) > 4 {
		stime, _ = strconv.Atoi(args[4])
	}

	keysIter, resp, err := stub.GetStateByRangeWithPagination(startKey, endKey, int32(pageSize), bookmark)
	if err != nil {
		return shim.Error(fmt.Sprintf("keysByPage operation failed. Error accessing state: %s", err))
	}
	defer keysIter.Close()

	var keys []string
	for keysIter.HasNext() {
		//if sleeptime is specied, take a nap
		if stime > 0 {
			time.Sleep(time.Duration(stime) * time.Millisecond)
		}

		response, iterErr := keysIter.Next()
		if iterErr != nil {
			return shim.Error(fmt.Sprintf("keysByPage operation failed. Error accessing state: %s", err))
		}
		keys = append(keys, response.Key)
	}

	for index, value := range keys {
		fmt.Printf("key %d contains %s\n", index, value)
	}

	jsonResp := PageResponse{
		Bookmark: resp.Bookmark,
		Keys:     keys,
	}

	queryResp, err := json.Marshal(jsonResp)
	if err != nil {
		return shim.Error(fmt.Sprintf("keysByPage operation failed. Error marshaling JSON: %s", err))
	}

	return shim.Success(queryResp)
}
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	query := args[0]
	keysIter, err := stub.GetQueryResult(query)
	if err != nil {
		return shim.Error(fmt.Sprintf("query operation failed. Error accessing state: %s", err))
	}
	defer keysIter.Close()

	var keys []string
	for keysIter.HasNext() {
		response, iterErr := keysIter.Next()
		if iterErr != nil {
			return shim.Error(fmt.Sprintf("query operation failed. Error accessing state: %s", err))
		}
		keys = append(keys, response.Key)
	}

	jsonKeys, err := json.Marshal(keys)
	if err != nil {
		return shim.Error(fmt.Sprintf("query operation failed. Error marshaling JSON: %s", err))
	}

	return shim.Success(jsonKeys)
}
func (t *SimpleChaincode) queryByPage(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	query := args[0]
	pageSize, parserr := strconv.ParseInt(args[1], 10, 32)
	if parserr != nil {
		return shim.Error(fmt.Sprintf("error parsing query pagesize: %s", parserr))
	}
	bookmark := args[2]

	keysIter, resp, err := stub.GetQueryResultWithPagination(query, int32(pageSize), bookmark)
	if err != nil {
		return shim.Error(fmt.Sprintf("queryByPage operation failed. Error accessing state: %s", err))
	}
	defer keysIter.Close()

	var keys []string
	for keysIter.HasNext() {
		response, iterErr := keysIter.Next()
		if iterErr != nil {
			return shim.Error(fmt.Sprintf("queryByPage operation failed. Error accessing state: %s", err))
		}
		keys = append(keys, response.Key)
	}

	for key, value := range keys {
		fmt.Printf("key %d contains %s\n", key, value)
	}

	jsonResp := PageResponse{
		Bookmark: resp.Bookmark,
		Keys:     keys,
	}

	queryResp, err := json.Marshal(jsonResp)
	if err != nil {
		return shim.Error(fmt.Sprintf("queryByPage operation failed. Error marshaling JSON: %s", err))
	}

	return shim.Success(queryResp)
}
func (t *SimpleChaincode) history(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	key := args[0]
	keysIter, err := stub.GetHistoryForKey(key)
	if err != nil {
		return shim.Error(fmt.Sprintf("get history operation failed. Error accessing state: %s", err))
	}
	defer keysIter.Close()

	var keys []string
	for keysIter.HasNext() {
		response, iterErr := keysIter.Next()
		if iterErr != nil {
			return shim.Error(fmt.Sprintf("get history operation failed. Error accessing state: %s", err))
		}
		keys = append(keys, response.TxId)
	}

	for key, txID := range keys {
		fmt.Printf("key %d contains %s\n", key, txID)
	}

	jsonKeys, err := json.Marshal(keys)
	if err != nil {
		return shim.Error(fmt.Sprintf("get history operation failed. Error marshaling JSON: %s", err))
	}

	return shim.Success(jsonKeys)
}
func (t *SimpleChaincode) getPut(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	_ = t.get(stub, args)
	return t.put(stub, args)
}
func (t *SimpleChaincode) getPutPrivate(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	_ = t.getPrivate(stub, args)
	return t.putPrivate(stub, args)
}
func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting chaincode: %s", err)
	}
}
<|endoftext|>


<commit_before>package securepass

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
)

const (
	// DefaultRemote is the default Content-Type header used in HTTP requests
	DefaultRemote = "https://beta.secure-pass.net"
	// ContentType is the default Content-Type header used in HTTP requests
	ContentType = "application/json"
	// UserAgent contains the default User-Agent value used in HTTP requests
	UserAgent = "SecurePass CLI"
)

// SecurePass main object type
type SecurePass struct {
	AppID     string `ini:"APP_ID"`
	AppSecret string `ini:"APP_SECRET"`
	Endpoint  string
}

// NewSecurePass makes and initialize a new SecurePass instance
func NewSecurePass(appid, appsecret, remote string) (*SecurePass, error) {
	u, err := url.Parse(remote)
	if err != nil {
		return nil, err
	}
	if !u.IsAbs() {
		return nil, fmt.Errorf("'%s' is not an absolute URL", remote)
	}
	if u.Scheme != "https" {
		return nil, fmt.Errorf("scheme of '%s' isn't 'https'", remote)
	}

	return &SecurePass{
		AppID:     appid,
		AppSecret: appsecret,
		Endpoint:  remote}, nil
}

func (s *SecurePass) setupRequestFieds(req *http.Request) {
	req.Header.Set("Accept", ContentType)
	req.Header.Set("Content-Type", ContentType)
	req.Header.Set("User-Agent", UserAgent)
	req.Header.Set("X-SecurePass-App-ID", s.AppID)
	req.Header.Set("X-SecurePass-App-Secret", s.AppSecret)
}

func (s *SecurePass) makeRequestURL(path string) (string, error) {
	baseURL, _ := url.Parse(s.Endpoint)
	URL, err := url.Parse(path)
	if err != nil {
		return "", err
	}
	return baseURL.ResolveReference(URL).String(), nil
}

// NewRequest initializes and issues an HTTP request to the SecurePass endpoint
func (s *SecurePass) NewRequest(method, path string, buf *bytes.Buffer) (*http.Request, error) {
	var err error
	var req *http.Request

	URL, err := s.makeRequestURL(path)
	if err != nil {
		return nil, err
	}
	if buf != nil {
		req, err = http.NewRequest(method, URL, buf)
	} else {
		req, err = http.NewRequest(method, URL, nil)
	}
	if err != nil {
		return nil, err
	}
	s.setupRequestFieds(req)
	return req, nil
}

// DoRequest issues an HTTP request
func (s *SecurePass) DoRequest(req *http.Request, obj APIResponse, expstatus int) error {
	client := NewClient(nil)
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	if resp.StatusCode != expstatus {
		return fmt.Errorf("%s", resp.Status)
	}
	defer resp.Body.Close()

	err = json.NewDecoder(resp.Body).Decode(obj)
	if err != nil {
		return err
	}
	if obj.ErrorCode() != 0 {
		return fmt.Errorf("%d: %s", obj.ErrorCode(), obj.ErrorMessage())
	}
	return nil
}

// NewClient initialize http.Client with a certain http.Transport
func NewClient(tr *http.Transport) *http.Client {
	// Skip SSL certificate verification
	if tr == nil {
		tr = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
	}
	return &http.Client{Transport: tr}
}

// AppInfo retrieves information on a SecurePass application
func (s *SecurePass) AppInfo(app string) (*AppInfoResponse, error) {
	var obj AppInfoResponse

	data := url.Values{}
	if app != "" {
		data.Set("APP_ID", app)
	}

	req, err := s.NewRequest("POST", "/api/v1/apps/info", bytes.NewBufferString(data.Encode()))
	if err != nil {
		return nil, err
	}
	err = s.DoRequest(req, &obj, 200)
	return &obj, err
}

// AppAdd represents /api/v1/apps/add
func (s *SecurePass) AppAdd(app *ApplicationDescriptor) (*AppAddResponse, error) {
	var obj AppAddResponse

	data := url.Values{}
	data.Set("LABEL", app.Label)
	data.Set("WRITE", fmt.Sprintf("%v", app.Write))
	data.Set("PRIVACY", fmt.Sprintf("%v", app.Privacy))
	if app.AllowNetworkIPv4 != "" {
		data.Set("ALLOW_NETWORK_IPv4", app.AllowNetworkIPv4)
	}
	if app.AllowNetworkIPv6 != "" {
		data.Set("ALLOW_NETWORK_IPv6", app.AllowNetworkIPv6)
	}
	if app.Group != "" {
		data.Set("GROUP", app.Group)
	}
	if app.Realm != "" {
		data.Set("REALM", app.Realm)
	}

	req, err := s.NewRequest("POST", "/api/v1/apps/add", bytes.NewBufferString(data.Encode()))
	if err != nil {
		return nil, err
	}
	err = s.DoRequest(req, &obj, 200)
	return &obj, err
}

// AppDel deletes an application from SecurePass
func (s *SecurePass) AppDel(app string) (*Response, error) {
	var obj Response

	data := url.Values{}
	if app != "" {
		data.Set("APP_ID", app)
	}

	req, err := s.NewRequest("POST", "/api/v1/apps/delete", bytes.NewBufferString(data.Encode()))
	if err != nil {
		return nil, err
	}
	err = s.DoRequest(req, &obj, 200)
	return &obj, err
}

// AppMod represents /api/v1/apps/modify
func (s *SecurePass) AppMod(app_id string, app *ApplicationDescriptor) (*AppInfoResponse, error) {
	var obj AppInfoResponse

	data := url.Values{}
	data.Set("APP_ID", app_id)
	data.Set("WRITE", fmt.Sprintf("%v", app.Write))
	data.Set("PRIVACY", fmt.Sprintf("%v", app.Privacy))
	if app.Label != "" {
		data.Set("LABEL", app.Label)
	}
	if app.AllowNetworkIPv4 != "" {
		data.Set("ALLOW_NETWORK_IPv4", app.AllowNetworkIPv4)
	}
	if app.AllowNetworkIPv6 != "" {
		data.Set("ALLOW_NETWORK_IPv6", app.AllowNetworkIPv6)
	}
	if app.Group != "" {
		data.Set("GROUP", app.Group)
	}

	fmt.Println(data)

	req, err := s.NewRequest("POST", "/api/v1/apps/modify", bytes.NewBufferString(data.Encode()))
	if err != nil {
		return nil, err
	}
	err = s.DoRequest(req, &obj, 200)
	return &obj, err
}

// AppList retrieves the list of applications available in SecurePass
func (s *SecurePass) AppList(app *ApplicationDescriptor) (*AppListResponse, error) {
	var obj AppListResponse

	data := url.Values{}
	if app.Realm != "" {
		data.Set("REALM", app.Realm)
	}

	req, err := s.NewRequest("POST", "/api/v1/apps/list", bytes.NewBufferString(data.Encode()))
	if err != nil {
		return nil, err
	}
	err = s.DoRequest(req, &obj, 200)
	return &obj, err
}

// Ping reprenets the /api/v1/ping API call
func (s *SecurePass) Ping() (*PingResponse, error) {
	var obj PingResponse

	req, err := s.NewRequest("GET", "/api/v1/ping", nil)
	if err != nil {
		return nil, err
	}
	err = s.DoRequest(req, &obj, 200)
	return &obj, err
}
<commit_msg>Fix golint's "don't use underscores" warning<commit_after>package securepass

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
)

const (
	// DefaultRemote is the default Content-Type header used in HTTP requests
	DefaultRemote = "https://beta.secure-pass.net"
	// ContentType is the default Content-Type header used in HTTP requests
	ContentType = "application/json"
	// UserAgent contains the default User-Agent value used in HTTP requests
	UserAgent = "SecurePass CLI"
)

// SecurePass main object type
type SecurePass struct {
	AppID     string `ini:"APP_ID"`
	AppSecret string `ini:"APP_SECRET"`
	Endpoint  string
}

// NewSecurePass makes and initialize a new SecurePass instance
func NewSecurePass(appid, appsecret, remote string) (*SecurePass, error) {
	u, err := url.Parse(remote)
	if err != nil {
		return nil, err
	}
	if !u.IsAbs() {
		return nil, fmt.Errorf("'%s' is not an absolute URL", remote)
	}
	if u.Scheme != "https" {
		return nil, fmt.Errorf("scheme of '%s' isn't 'https'", remote)
	}

	return &SecurePass{
		AppID:     appid,
		AppSecret: appsecret,
		Endpoint:  remote}, nil
}

func (s *SecurePass) setupRequestFieds(req *http.Request) {
	req.Header.Set("Accept", ContentType)
	req.Header.Set("Content-Type", ContentType)
	req.Header.Set("User-Agent", UserAgent)
	req.Header.Set("X-SecurePass-App-ID", s.AppID)
	req.Header.Set("X-SecurePass-App-Secret", s.AppSecret)
}

func (s *SecurePass) makeRequestURL(path string) (string, error) {
	baseURL, _ := url.Parse(s.Endpoint)
	URL, err := url.Parse(path)
	if err != nil {
		return "", err
	}
	return baseURL.ResolveReference(URL).String(), nil
}

// NewRequest initializes and issues an HTTP request to the SecurePass endpoint
func (s *SecurePass) NewRequest(method, path string, buf *bytes.Buffer) (*http.Request, error) {
	var err error
	var req *http.Request

	URL, err := s.makeRequestURL(path)
	if err != nil {
		return nil, err
	}
	if buf != nil {
		req, err = http.NewRequest(method, URL, buf)
	} else {
		req, err = http.NewRequest(method, URL, nil)
	}
	if err != nil {
		return nil, err
	}
	s.setupRequestFieds(req)
	return req, nil
}

// DoRequest issues an HTTP request
func (s *SecurePass) DoRequest(req *http.Request, obj APIResponse, expstatus int) error {
	client := NewClient(nil)
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	if resp.StatusCode != expstatus {
		return fmt.Errorf("%s", resp.Status)
	}
	defer resp.Body.Close()

	err = json.NewDecoder(resp.Body).Decode(obj)
	if err != nil {
		return err
	}
	if obj.ErrorCode() != 0 {
		return fmt.Errorf("%d: %s", obj.ErrorCode(), obj.ErrorMessage())
	}
	return nil
}

// NewClient initialize http.Client with a certain http.Transport
func NewClient(tr *http.Transport) *http.Client {
	// Skip SSL certificate verification
	if tr == nil {
		tr = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
	}
	return &http.Client{Transport: tr}
}

// AppInfo retrieves information on a SecurePass application
func (s *SecurePass) AppInfo(app string) (*AppInfoResponse, error) {
	var obj AppInfoResponse

	data := url.Values{}
	if app != "" {
		data.Set("APP_ID", app)
	}

	req, err := s.NewRequest("POST", "/api/v1/apps/info", bytes.NewBufferString(data.Encode()))
	if err != nil {
		return nil, err
	}
	err = s.DoRequest(req, &obj, 200)
	return &obj, err
}

// AppAdd represents /api/v1/apps/add
func (s *SecurePass) AppAdd(app *ApplicationDescriptor) (*AppAddResponse, error) {
	var obj AppAddResponse

	data := url.Values{}
	data.Set("LABEL", app.Label)
	data.Set("WRITE", fmt.Sprintf("%v", app.Write))
	data.Set("PRIVACY", fmt.Sprintf("%v", app.Privacy))
	if app.AllowNetworkIPv4 != "" {
		data.Set("ALLOW_NETWORK_IPv4", app.AllowNetworkIPv4)
	}
	if app.AllowNetworkIPv6 != "" {
		data.Set("ALLOW_NETWORK_IPv6", app.AllowNetworkIPv6)
	}
	if app.Group != "" {
		data.Set("GROUP", app.Group)
	}
	if app.Realm != "" {
		data.Set("REALM", app.Realm)
	}

	req, err := s.NewRequest("POST", "/api/v1/apps/add", bytes.NewBufferString(data.Encode()))
	if err != nil {
		return nil, err
	}
	err = s.DoRequest(req, &obj, 200)
	return &obj, err
}

// AppDel deletes an application from SecurePass
func (s *SecurePass) AppDel(app string) (*Response, error) {
	var obj Response

	data := url.Values{}
	if app != "" {
		data.Set("APP_ID", app)
	}

	req, err := s.NewRequest("POST", "/api/v1/apps/delete", bytes.NewBufferString(data.Encode()))
	if err != nil {
		return nil, err
	}
	err = s.DoRequest(req, &obj, 200)
	return &obj, err
}

// AppMod represents /api/v1/apps/modify
func (s *SecurePass) AppMod(appID string, app *ApplicationDescriptor) (*AppInfoResponse, error) {
	var obj AppInfoResponse

	data := url.Values{}
	data.Set("APP_ID", appID)
	data.Set("WRITE", fmt.Sprintf("%v", app.Write))
	data.Set("PRIVACY", fmt.Sprintf("%v", app.Privacy))
	if app.Label != "" {
		data.Set("LABEL", app.Label)
	}
	if app.AllowNetworkIPv4 != "" {
		data.Set("ALLOW_NETWORK_IPv4", app.AllowNetworkIPv4)
	}
	if app.AllowNetworkIPv6 != "" {
		data.Set("ALLOW_NETWORK_IPv6", app.AllowNetworkIPv6)
	}
	if app.Group != "" {
		data.Set("GROUP", app.Group)
	}

	fmt.Println(data)

	req, err := s.NewRequest("POST", "/api/v1/apps/modify", bytes.NewBufferString(data.Encode()))
	if err != nil {
		return nil, err
	}
	err = s.DoRequest(req, &obj, 200)
	return &obj, err
}

// AppList retrieves the list of applications available in SecurePass
func (s *SecurePass) AppList(app *ApplicationDescriptor) (*AppListResponse, error) {
	var obj AppListResponse

	data := url.Values{}
	if app.Realm != "" {
		data.Set("REALM", app.Realm)
	}

	req, err := s.NewRequest("POST", "/api/v1/apps/list", bytes.NewBufferString(data.Encode()))
	if err != nil {
		return nil, err
	}
	err = s.DoRequest(req, &obj, 200)
	return &obj, err
}

// Ping reprenets the /api/v1/ping API call
func (s *SecurePass) Ping() (*PingResponse, error) {
	var obj PingResponse

	req, err := s.NewRequest("GET", "/api/v1/ping", nil)
	if err != nil {
		return nil, err
	}
	err = s.DoRequest(req, &obj, 200)
	return &obj, err
}
<|endoftext|>


<commit_before>// Copyright 2013 Google 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 main

import (
	"encoding/json"
	"html/template"
	"log"
	"net/http"
	"os"

	"appengine"
	"appengine/urlfetch"
	webfinger "github.com/ant0ine/go-webfinger"
	"github.com/gorilla/context"
)

var (
	lookupTemplate = template.Must(template.ParseFiles("lookup.html"))
)

const (
	webfingerHome = "http://webfinger.net/"
)

// logCatcher implements the io.Writer interface, writing all bytes to a string
// slice on the underlying http.Request.
type logCatcher struct {
	request *http.Request
}

func (l logCatcher) Write(p []byte) (n int, err error) {
	logs := context.Get(l.request, "logs").([]string)
	logs = append(logs, string(p))
	context.Set(l.request, "logs", logs)
	return len(p), nil
}

func lookup(w http.ResponseWriter, r *http.Request) {
	context.Set(r, "logs", []string{})
	flags := log.Flags()
	log.SetFlags(log.Ltime)
	log.SetOutput(logCatcher{r})

	ctx := appengine.NewContext(r)
	client := webfinger.NewClient(urlfetch.Client(ctx))
	client.AllowHTTP = true

	var jrd string

	input := r.FormValue("resource")
	if input == "" {
		http.Redirect(w, r, webfingerHome, http.StatusFound)
		return
	}

	j, err := client.Lookup(input, nil)
	if err != nil {
		log.Printf("Error getting JRD: %v", err.Error())
	} else {
		bytes, err := json.MarshalIndent(j, "", "  ")
		if err != nil {
			log.Printf("Error marshalling JRD: %v", err.Error())
		} else {
			jrd = string(bytes)
		}
	}

	// reset standard logger back to normal
	log.SetOutput(os.Stderr)
	log.SetFlags(flags)

	logs := context.Get(r, "logs").([]string)

	var data = struct {
		Resource string
		JRD      string
		Logs     []string
	}{input, jrd, logs}
	lookupTemplate.Execute(w, data)
}

func init() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		// redirect homepage to /lookup
		http.Redirect(w, r, webfingerHome, http.StatusFound)
	})
	http.HandleFunc("/lookup", lookup)
}
<commit_msg>add newline to keep goimports happy<commit_after>// Copyright 2013 Google 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 main

import (
	"encoding/json"
	"html/template"
	"log"
	"net/http"
	"os"

	"appengine"
	"appengine/urlfetch"

	webfinger "github.com/ant0ine/go-webfinger"
	"github.com/gorilla/context"
)

var (
	lookupTemplate = template.Must(template.ParseFiles("lookup.html"))
)

const (
	webfingerHome = "http://webfinger.net/"
)

// logCatcher implements the io.Writer interface, writing all bytes to a string
// slice on the underlying http.Request.
type logCatcher struct {
	request *http.Request
}

func (l logCatcher) Write(p []byte) (n int, err error) {
	logs := context.Get(l.request, "logs").([]string)
	logs = append(logs, string(p))
	context.Set(l.request, "logs", logs)
	return len(p), nil
}

func lookup(w http.ResponseWriter, r *http.Request) {
	context.Set(r, "logs", []string{})
	flags := log.Flags()
	log.SetFlags(log.Ltime)
	log.SetOutput(logCatcher{r})

	ctx := appengine.NewContext(r)
	client := webfinger.NewClient(urlfetch.Client(ctx))
	client.AllowHTTP = true

	var jrd string

	input := r.FormValue("resource")
	if input == "" {
		http.Redirect(w, r, webfingerHome, http.StatusFound)
		return
	}

	j, err := client.Lookup(input, nil)
	if err != nil {
		log.Printf("Error getting JRD: %v", err.Error())
	} else {
		bytes, err := json.MarshalIndent(j, "", "  ")
		if err != nil {
			log.Printf("Error marshalling JRD: %v", err.Error())
		} else {
			jrd = string(bytes)
		}
	}

	// reset standard logger back to normal
	log.SetOutput(os.Stderr)
	log.SetFlags(flags)

	logs := context.Get(r, "logs").([]string)

	var data = struct {
		Resource string
		JRD      string
		Logs     []string
	}{input, jrd, logs}
	lookupTemplate.Execute(w, data)
}

func init() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		// redirect "/" to webfinger.net
		http.Redirect(w, r, webfingerHome, http.StatusFound)
	})
	http.HandleFunc("/lookup", lookup)
}
<|endoftext|>


<commit_before>package slack

import (
	"log"
	"sync"
	"time"

	"golang.org/x/net/websocket"
)

// RTM represents a managed websocket connection. It also supports
// all the methods of the `Slack` type.
//
// Create this element with Client's NewRTM().
type RTM struct {
	mutex     sync.Mutex
	messageID int
	pings     map[int]time.Time

	// Connection life-cycle
	conn             *websocket.Conn
	IncomingEvents   chan SlackEvent
	outgoingMessages chan OutgoingMessage

	// Slack is the main API, embedded
	Client
	websocketURL string

	// UserDetails upon connection
	info *Info
}

// NewRTM returns a RTM, which provides a fully managed connection to
// Slack's websocket-based Real-Time Messaging protocol.
func newRTM(api *Client) *RTM {
	return &RTM{
		Client:         *api,
		pings:          make(map[int]time.Time),
		IncomingEvents: make(chan SlackEvent, 50),
	}
}

// Disconnect and wait, blocking until a successful disconnection.
func (rtm *RTM) Disconnect() error {
	log.Println("RTM::Disconnect not implemented!")
	return nil
}

// Reconnect only makes sense if you've successfully disconnectd with Disconnect().
func (rtm *RTM) Reconnect() error {
	log.Println("RTM::Reconnect not implemented!")
	return nil
}

// GetInfo returns the info structure received when calling
// "startrtm", holding all channels, groups and other metadata needed
// to implement a full chat client. It will be non-nil after a call to
// StartRTM().
func (rtm *RTM) GetInfo() *Info {
	return rtm.info
}

// SendMessage submits a simple message through the websocket.  For
// more complicated messages, use `rtm.PostMessage` with a complete
// struct describing your attachments and all.
func (rtm *RTM) SendMessage(msg *OutgoingMessage) {
	if msg == nil {
		rtm.Debugln("Error: Attempted to SendMessage(nil)")
		return
	}

	rtm.outgoingMessages <- *msg
}
<commit_msg>Fix the outgoingMessages pipe !<commit_after>package slack

import (
	"log"
	"sync"
	"time"

	"golang.org/x/net/websocket"
)

// RTM represents a managed websocket connection. It also supports
// all the methods of the `Slack` type.
//
// Create this element with Client's NewRTM().
type RTM struct {
	mutex     sync.Mutex
	messageID int
	pings     map[int]time.Time

	// Connection life-cycle
	conn             *websocket.Conn
	IncomingEvents   chan SlackEvent
	outgoingMessages chan OutgoingMessage

	// Slack is the main API, embedded
	Client
	websocketURL string

	// UserDetails upon connection
	info *Info
}

// NewRTM returns a RTM, which provides a fully managed connection to
// Slack's websocket-based Real-Time Messaging protocol.
func newRTM(api *Client) *RTM {
	return &RTM{
		Client:           *api,
		pings:            make(map[int]time.Time),
		IncomingEvents:   make(chan SlackEvent, 50),
		outgoingMessages: make(chan OutgoingMessage, 20),
	}
}

// Disconnect and wait, blocking until a successful disconnection.
func (rtm *RTM) Disconnect() error {
	log.Println("RTM::Disconnect not implemented!")
	return nil
}

// Reconnect only makes sense if you've successfully disconnectd with Disconnect().
func (rtm *RTM) Reconnect() error {
	log.Println("RTM::Reconnect not implemented!")
	return nil
}

// GetInfo returns the info structure received when calling
// "startrtm", holding all channels, groups and other metadata needed
// to implement a full chat client. It will be non-nil after a call to
// StartRTM().
func (rtm *RTM) GetInfo() *Info {
	return rtm.info
}

// SendMessage submits a simple message through the websocket.  For
// more complicated messages, use `rtm.PostMessage` with a complete
// struct describing your attachments and all.
func (rtm *RTM) SendMessage(msg *OutgoingMessage) {
	if msg == nil {
		rtm.Debugln("Error: Attempted to SendMessage(nil)")
		return
	}

	rtm.outgoingMessages <- *msg
}
<|endoftext|>


<commit_before>package v2

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"

	etcdErr "github.com/coreos/etcd/error"
	"github.com/coreos/etcd/log"
	"github.com/coreos/etcd/store"
	"github.com/coreos/go-raft"
	"github.com/gorilla/mux"
)

func GetHandler(w http.ResponseWriter, req *http.Request, s Server) error {
	var err error
	var event *store.Event

	vars := mux.Vars(req)
	key := "/" + vars["key"]

	// Help client to redirect the request to the current leader
	if req.FormValue("consistent") == "true" && s.State() != raft.Leader {
		leader := s.Leader()
		hostname, _ := s.PeerURL(leader)
		url := hostname + req.URL.Path
		log.Debugf("Redirect consistent get to %s", url)
		http.Redirect(w, req, url, http.StatusTemporaryRedirect)
		return nil
	}

	recursive := (req.FormValue("recursive") == "true")
	sorted := (req.FormValue("sorted") == "true")

	if req.FormValue("wait") == "true" { // watch
		// Create a command to watch from a given index (default 0).
		var sinceIndex uint64 = 0

		waitIndex := req.FormValue("waitIndex")
		if waitIndex != "" {
			sinceIndex, err = strconv.ParseUint(string(req.FormValue("waitIndex")), 10, 64)
			if err != nil {
				return etcdErr.NewError(etcdErr.EcodeIndexNaN, "Watch From Index", store.UndefIndex, store.UndefTerm)
			}
		}

		// Start the watcher on the store.
		eventChan, err := s.Store().Watch(key, recursive, sinceIndex, s.CommitIndex(), s.Term())
		if err != nil {
			return etcdErr.NewError(500, key, store.UndefIndex, store.UndefTerm)
		}

		cn, _ := w.(http.CloseNotifier)
		closeChan := cn.CloseNotify()

		select {
		case <-closeChan:
			return nil
		case event = <-eventChan:
		}

	} else { //get
		// Retrieve the key from the store.
		event, err = s.Store().Get(key, recursive, sorted, s.CommitIndex(), s.Term())
		if err != nil {
			return err
		}
	}

	w.Header().Add("X-Etcd-Index", fmt.Sprint(event.Index))
	w.Header().Add("X-Etcd-Term", fmt.Sprint(event.Term))
	w.WriteHeader(http.StatusOK)

	b, _ := json.Marshal(event)
	w.Write(b)

	return nil
}
<commit_msg>feat upgrade get_handler<commit_after>package v2

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"

	etcdErr "github.com/coreos/etcd/error"
	"github.com/coreos/etcd/log"
	"github.com/coreos/etcd/store"
	"github.com/coreos/go-raft"
	"github.com/gorilla/mux"
)

func GetHandler(w http.ResponseWriter, req *http.Request, s Server) error {
	var err error
	var event *store.Event
	events := make([]*store.Event, 0)

	vars := mux.Vars(req)
	key := "/" + vars["key"]

	// Help client to redirect the request to the current leader
	if req.FormValue("consistent") == "true" && s.State() != raft.Leader {
		leader := s.Leader()
		hostname, _ := s.PeerURL(leader)
		url := hostname + req.URL.Path
		log.Debugf("Redirect consistent get to %s", url)
		http.Redirect(w, req, url, http.StatusTemporaryRedirect)
		return nil
	}

	recursive := (req.FormValue("recursive") == "true")
	sorted := (req.FormValue("sorted") == "true")

	if req.FormValue("wait") == "true" { // watch
		// Create a command to watch from a given index (default 0).
		var sinceIndex uint64 = 0

		waitIndex := req.FormValue("waitIndex")
		if waitIndex != "" {
			sinceIndex, err = strconv.ParseUint(string(req.FormValue("waitIndex")), 10, 64)
			if err != nil {
				return etcdErr.NewError(etcdErr.EcodeIndexNaN, "Watch From Index", store.UndefIndex, store.UndefTerm)
			}
		}

		// Start the watcher on the store.
		eventChan, err := s.Store().Watch(key, recursive, sinceIndex, s.CommitIndex(), s.Term())
		if err != nil {
			return etcdErr.NewError(500, key, store.UndefIndex, store.UndefTerm)
		}

		cn, _ := w.(http.CloseNotifier)
		closeChan := cn.CloseNotify()

		for {
			select {
			case <-closeChan:
				return nil
			case event = <-eventChan:
				if event != nil && event.Action == store.Expire {
					events = append(events, event)
				} else {
					goto finish
				}
			}
		}

	} else { //get
		// Retrieve the key from the store.
		event, err = s.Store().Get(key, recursive, sorted, s.CommitIndex(), s.Term())
		if err != nil {
			return err
		}
	}

finish:

	w.Header().Add("X-Etcd-Index", fmt.Sprint(event.Index))
	w.Header().Add("X-Etcd-Term", fmt.Sprint(event.Term))
	w.WriteHeader(http.StatusOK)

	var b []byte

	if len(events) == 0 {
		b, _ = json.Marshal(event)
	} else {
		b, _ = json.Marshal(events)
	}
	w.Write(b)

	return nil
}
<|endoftext|>


<commit_before>package HologramGo

import (
	"fmt"
	"os"
	"strconv"
)

type Plan map[string]interface{}

// Plans is just a list of Plan(s).
type Plans []interface{}

// TODO: Add Plans data type for this call here.
// EFFECTS: Returns device data plans.
func GetDeviceDataPlans() Plans {

	req := createGetRequest("/plans/")

	resp, err := sendRequest(req)
	if err != nil {
		fmt.Printf("Could not send request: %v\n", err)
		os.Exit(1)
	}

	return unmarshallIntoArrayObject(resp)
}

// REQUIRES: A plan id.
// EFFECTS: Returns a given device data plan
func GetDeviceDataPlan(planid int) Plan {

	req := createGetRequest("/plans/" + strconv.Itoa(planid))

	resp, err := sendRequest(req)
	if err != nil {
		fmt.Printf("Could not send request: %v\n", err)
		os.Exit(1)
	}

	plans := unmarshallIntoArrayObject(resp)

	return (Plan)(plans[0].(map[string]interface{}))
}

///////////////////////////////////////////////////
// GENERIC PLAN GETTER FUNCTIONS
///////////////////////////////////////////////////

// EFFECTS: Returns the data plan id.
func (plan Plan) GetDataPlanId() float64 {
	return plan["id"].(float64)
}

// EFFECTS: Returns the data plan partner id.
func (plan Plan) GetDataPlanPartnerId() float64 {
	return plan["partnerid"].(float64)
}

// EFFECTS: Returns the data plan name.
func (plan Plan) GetDataPlanName() string {
	return plan["name"].(string)
}

// EFFECTS: Returns the data plan description.
func (plan Plan) GetDataPlanDescription() string {
	return plan["description"].(string)
}

// EFFECTS: Returns the data size.
func (plan Plan) GetDataPlanSize() float64 {
	return plan["data"].(float64)
}

// EFFECTS: Returns true if it is recurring.
func (plan Plan) IsDataPlanRecurring() bool {
	return plan["recurring"].(bool)
}

// EFFECTS: Returns true if the data plan is enabled.
func (plan Plan) IsDataPlanEnabled() bool {
	return plan["enabled"].(bool)
}

// EFFECTS: Returns the billing period.
func (plan Plan) GetDataPlanBillingPeriod() float64 {
	return plan["billingperiod"].(float64)
}

// EFFECTS: Returns the number of trial days left.
func (plan Plan) GetDataPlanTrialDays() float64 {
	return plan["trialdays"].(float64)
}

// EFFECTS: Returns the data plan template id.
func (plan Plan) GetDataPlanTemplateId() float64 {
	return plan["templateid"].(float64)
}

// EFFECTS: Returns the carrier id of the data plan.
func (plan Plan) GetDataPlanCarrierId() float64 {
	return plan["carrierid"].(float64)
}

// EFFECTS: Returns the groupid of the data plan.
func (plan Plan) GetDataPlanGroupId() float64 {
	return plan["groupid"].(float64)
}
<commit_msg>golint plan.go<commit_after>package HologramGo

import (
	"fmt"
	"os"
	"strconv"
)

// Plan is basically the returned Plan type in the response.
type Plan map[string]interface{}

// Plans is just a list of Plan(s).
type Plans []interface{}

// GetDeviceDataPlans returns device data plans.
func GetDeviceDataPlans() Plans {

	req := createGetRequest("/plans/")

	resp, err := sendRequest(req)
	if err != nil {
		fmt.Printf("Could not send request: %v\n", err)
		os.Exit(1)
	}

	return unmarshallIntoArrayObject(resp)
}

// GetDeviceDataPlan returns a given device data plan.
func GetDeviceDataPlan(planid int) Plan {

	req := createGetRequest("/plans/" + strconv.Itoa(planid))

	resp, err := sendRequest(req)
	if err != nil {
		fmt.Printf("Could not send request: %v\n", err)
		os.Exit(1)
	}

	plans := unmarshallIntoArrayObject(resp)

	return (Plan)(plans[0].(map[string]interface{}))
}

///////////////////////////////////////////////////
// GENERIC PLAN GETTER FUNCTIONS
///////////////////////////////////////////////////

// GetDataPlanId returns the data plan id.
func (plan Plan) GetDataPlanId() float64 {
	return plan["id"].(float64)
}

// GetDataPlanPartnerId returns the data plan partner id.
func (plan Plan) GetDataPlanPartnerId() float64 {
	return plan["partnerid"].(float64)
}

// GetDataPlanName returns the data plan name.
func (plan Plan) GetDataPlanName() string {
	return plan["name"].(string)
}

// GetDataPlanDescription returns the data plan description.
func (plan Plan) GetDataPlanDescription() string {
	return plan["description"].(string)
}

// GetDataPlanSize returns the data size.
func (plan Plan) GetDataPlanSize() float64 {
	return plan["data"].(float64)
}

// IsDataPlanRecurring returns true if it is recurring.
func (plan Plan) IsDataPlanRecurring() bool {
	return plan["recurring"].(bool)
}

// IsDataPlanEnabled returns true if the data plan is enabled.
func (plan Plan) IsDataPlanEnabled() bool {
	return plan["enabled"].(bool)
}

// GetDataPlanBillingPeriod returns the billing period.
func (plan Plan) GetDataPlanBillingPeriod() float64 {
	return plan["billingperiod"].(float64)
}

// GetDataPlanTrialDays returns the number of trial days left.
func (plan Plan) GetDataPlanTrialDays() float64 {
	return plan["trialdays"].(float64)
}

// GetDataPlanTemplateId returns the data plan template id.
func (plan Plan) GetDataPlanTemplateId() float64 {
	return plan["templateid"].(float64)
}

// GetDataPlanCarrierId returns the carrier id of the data plan.
func (plan Plan) GetDataPlanCarrierId() float64 {
	return plan["carrierid"].(float64)
}

// GetDataPlanGroupId returns the groupid of the data plan.
func (plan Plan) GetDataPlanGroupId() float64 {
	return plan["groupid"].(float64)
}
<|endoftext|>


<commit_before>package service

import (
	"github.com/Comcast/webpa-common/logging"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"testing"
)

func TestNewAccessorFactory(t *testing.T) {
	var (
		assert  = assert.New(t)
		require = require.New(t)
		logger  = logging.TestLogger(t)

		testData = []struct {
			endpoints        []string
			expectedBaseURLs []string
			expectsError     bool
		}{
			{
				endpoints:        nil,
				expectedBaseURLs: make([]string, 0),
				expectsError:     true,
			},
			{
				endpoints:        []string{},
				expectedBaseURLs: make([]string, 0),
				expectsError:     true,
			},
			{
				endpoints:        []string{"[http://localhost]:7500"},
				expectedBaseURLs: []string{"http://localhost:7500"},
				expectsError:     false,
			},
			{
				endpoints:        []string{"[https://host1.net]:123", "[http://host2.com]:9293"},
				expectedBaseURLs: []string{"http://host2.com:9293", "https://host1.net:123"},
				expectsError:     false,
			},
		}
	)

	for _, record := range testData {
		t.Logf("%v", record)

		for _, vnodeCount := range []uint{0, 200, 1700} {
			factory := NewAccessorFactory(&Options{Logger: logger, VnodeCount: vnodeCount})
			if !assert.NotNil(factory) {
				continue
			}

			accessor, actualBaseURLs := factory.New(record.endpoints)
			require.NotNil(accessor)
			assert.Equal(record.expectedBaseURLs, actualBaseURLs)

			endpoint, err := accessor.Get([]byte("key"))
			if record.expectsError {
				assert.Empty(endpoint)
				assert.Error(err)
			} else {
				assert.NotEmpty(endpoint)
				assert.NoError(err)
			}
		}
	}
}
<commit_msg>Tests around the host-and-port parsing for endpoints<commit_after>package service

import (
	"github.com/Comcast/webpa-common/logging"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"net/url"
	"testing"
)

func TestParseHostPort(t *testing.T) {
	var (
		assert = assert.New(t)

		testData = []struct {
			value           string
			expectedBaseURL string
			expectsError    bool
		}{
			{"localhost:8080", "http://localhost:8080", false},
			{"[http://something.comcast.net]:8080", "http://something.comcast.net:8080", false},
			{"[https://65.71.145.16]:8080", "https://65.71.145.16:8080", false},
			{"", "", true},
			{"localhost", "", true},
			{"something.comcast.net", "", true},
			{"65.71.145.16", "", true},
		}
	)

	for _, record := range testData {
		t.Logf("%@v", record)

		actualBaseURL, err := ParseHostPort(record.value)
		assert.Equal(record.expectedBaseURL, actualBaseURL)
		assert.Equal(record.expectsError, err != nil)
	}
}

func TestReplaceHostPort(t *testing.T) {
	var (
		assert   = assert.New(t)
		testData = []struct {
			hostPort       string
			originalURL    url.URL
			expectedResult string
		}{
			{
				"http://localhost:8080",
				url.URL{},
				"http://localhost:8080",
			},
			{
				"https://something.comcast.net:16008",
				url.URL{
					Scheme: "http",
					Host:   "original.com",
					Path:   "/foo/bar",
				},
				"https://something.comcast.net:16008/foo/bar",
			},
			{
				"http://192.168.1.1:3412",
				url.URL{
					Scheme: "https",
					Host:   "original.com",
					Path:   "api/v2/device",
				},
				"http://192.168.1.1:3412/api/v2/device",
			},
			{
				"https://node1.comcast.net:342",
				url.URL{
					Scheme:     "https",
					Host:       "original.com",
					Path:       "api/v2/device",
					ForceQuery: true,
				},
				"https://node1.comcast.net:342/api/v2/device?",
			},
			{
				"http://28.77.145.1:9044",
				url.URL{
					Scheme:   "https",
					Host:     "another.original.com",
					Path:     "/list/something",
					RawQuery: "test=true&index=17",
				},
				"http://28.77.145.1:9044/list/something?test=true&index=17",
			},
			{
				"localhost:4455",
				url.URL{
					Scheme:   "https",
					Host:     "another.original.com",
					Path:     "path",
					RawQuery: "i=abc",
					Fragment: "location",
				},
				"localhost:4455/path?i=abc#location",
			},
			{
				"now.for.something.different.net",
				url.URL{
					Host:     "nopath.com",
					RawQuery: "i=abc",
					Fragment: "location",
				},
				"now.for.something.different.net?i=abc#location",
			},
			{
				"http://now.for.something.different.net",
				url.URL{
					Host:     "noquery.com",
					Fragment: "location",
				},
				"http://now.for.something.different.net#location",
			},
		}
	)

	for _, record := range testData {
		t.Logf("%#v", record)

		actualResult := ReplaceHostPort(record.hostPort, &record.originalURL)
		assert.Equal(record.expectedResult, actualResult)
	}
}

func TestNewAccessorFactory(t *testing.T) {
	var (
		assert  = assert.New(t)
		require = require.New(t)
		logger  = logging.TestLogger(t)

		testData = []struct {
			endpoints        []string
			expectedBaseURLs []string
			expectsError     bool
		}{
			{
				endpoints:        nil,
				expectedBaseURLs: make([]string, 0),
				expectsError:     true,
			},
			{
				endpoints:        []string{},
				expectedBaseURLs: make([]string, 0),
				expectsError:     true,
			},
			{
				endpoints:        []string{"[http://localhost]:7500"},
				expectedBaseURLs: []string{"http://localhost:7500"},
				expectsError:     false,
			},
			{
				endpoints:        []string{"[https://host1.net]:123", "[http://host2.com]:9293"},
				expectedBaseURLs: []string{"http://host2.com:9293", "https://host1.net:123"},
				expectsError:     false,
			},
			{
				endpoints:        []string{"localhost:8081", "this.is.not.valid", "[https://webpa.comcast.net]:7676"},
				expectedBaseURLs: []string{"http://localhost:8081", "https://webpa.comcast.net:7676"},
				expectsError:     false,
			},
			{
				endpoints:        []string{"this.is.not.valid"},
				expectedBaseURLs: []string{},
				expectsError:     true,
			},
			{
				endpoints:        []string{"this.is.not.valid", "neither.is.this"},
				expectedBaseURLs: []string{},
				expectsError:     true,
			},
		}
	)

	for _, record := range testData {
		t.Logf("%#v", record)

		for _, vnodeCount := range []uint{0, 200, 1700} {
			factory := NewAccessorFactory(&Options{Logger: logger, VnodeCount: vnodeCount})
			if !assert.NotNil(factory) {
				continue
			}

			accessor, actualBaseURLs := factory.New(record.endpoints)
			require.NotNil(accessor)
			assert.Equal(record.expectedBaseURLs, actualBaseURLs)

			endpoint, err := accessor.Get([]byte("key"))
			if record.expectsError {
				assert.Empty(endpoint)
				assert.Error(err)
			} else {
				assert.NotEmpty(endpoint)
				assert.NoError(err)
			}
		}
	}
}
<|endoftext|>


<commit_before>package commands

import (
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/github/git-lfs/git"
	"github.com/github/git-lfs/lfs"
	"github.com/github/git-lfs/vendor/_nuts/github.com/spf13/cobra"
)

var (
	cloneCmd = &cobra.Command{
		Use: "clone",
		Run: cloneCommand,
	}
)

func cloneCommand(cmd *cobra.Command, args []string) {

	// We pass all args to git clone
	err := git.CloneWithoutFilters(args)
	if err != nil {
		Panic(err, "Error(s) during clone")
	}

	// now execute pull (need to be inside dir)
	cwd, err := os.Getwd()
	if err != nil {
		Panic(err, "Unable to derive current working dir")
	}

	// Either the last argument was a relative or local dir, or we have to
	// derive it from the clone URL
	clonedir, err := filepath.Abs(args[len(args)-1])
	if err != nil || !lfs.DirExists(clonedir) {
		// Derive from clone URL instead
		base := path.Base(args[len(args)-1])
		if strings.HasSuffix(base, ".git") {
			base = base[:len(base)-4]
		}
		clonedir, _ = filepath.Abs(base)
		if !lfs.DirExists(clonedir) {
			Exit("Unable to find clone dir at %q", clonedir)
		}
	}

	err = os.Chdir(clonedir)
	if err != nil {
		Panic(err, "Unable to change directory to clone dir %q", clonedir)
	}

	// Make sure we pop back to dir we started in at the end
	defer os.Chdir(cwd)

	// Also need to derive dirs now
	lfs.ResolveDirs()
	requireInRepo()

	// Now just call pull with default args
	lfs.Config.CurrentRemote = "origin" // always origin after clone
	pull(nil, nil)

}

func init() {
	RootCmd.AddCommand(cloneCmd)
}
<commit_msg>Use Exit instead of Panic in lfs clone<commit_after>package commands

import (
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/github/git-lfs/git"
	"github.com/github/git-lfs/lfs"
	"github.com/github/git-lfs/vendor/_nuts/github.com/spf13/cobra"
)

var (
	cloneCmd = &cobra.Command{
		Use: "clone",
		Run: cloneCommand,
	}
)

func cloneCommand(cmd *cobra.Command, args []string) {

	// We pass all args to git clone
	err := git.CloneWithoutFilters(args)
	if err != nil {
		Exit("Error(s) during clone:\n%v", err)
	}

	// now execute pull (need to be inside dir)
	cwd, err := os.Getwd()
	if err != nil {
		Exit("Unable to derive current working dir: %v", err)
	}

	// Either the last argument was a relative or local dir, or we have to
	// derive it from the clone URL
	clonedir, err := filepath.Abs(args[len(args)-1])
	if err != nil || !lfs.DirExists(clonedir) {
		// Derive from clone URL instead
		base := path.Base(args[len(args)-1])
		if strings.HasSuffix(base, ".git") {
			base = base[:len(base)-4]
		}
		clonedir, _ = filepath.Abs(base)
		if !lfs.DirExists(clonedir) {
			Exit("Unable to find clone dir at %q", clonedir)
		}
	}

	err = os.Chdir(clonedir)
	if err != nil {
		Exit("Unable to change directory to clone dir %q: %v", clonedir, err)
	}

	// Make sure we pop back to dir we started in at the end
	defer os.Chdir(cwd)

	// Also need to derive dirs now
	lfs.ResolveDirs()
	requireInRepo()

	// Now just call pull with default args
	lfs.Config.CurrentRemote = "origin" // always origin after clone
	pull(nil, nil)

}

func init() {
	RootCmd.AddCommand(cloneCmd)
}
<|endoftext|>