<commit_before>package terraform

import (
	"fmt"
	"reflect"
	"regexp"
	"strconv"
	"strings"

	"github.com/hashicorp/terraform/config"
	"github.com/hashicorp/terraform/config/module"
)

// ResourceAddress is a way of identifying an individual resource (or,
// eventually, a subset of resources) within the state. It is used for Targets.
type ResourceAddress struct {
	// Addresses a resource falling somewhere in the module path
	// When specified alone, addresses all resources within a module path
	Path []string

	// Addresses a specific resource that occurs in a list
	Index int

	InstanceType    InstanceType
	InstanceTypeSet bool
	Name            string
	Type            string
	Mode            config.ResourceMode // significant only if InstanceTypeSet
}

// Copy returns a copy of this ResourceAddress
func (r *ResourceAddress) Copy() *ResourceAddress {
	if r == nil {
		return nil
	}

	n := &ResourceAddress{
		Path:         make([]string, 0, len(r.Path)),
		Index:        r.Index,
		InstanceType: r.InstanceType,
		Name:         r.Name,
		Type:         r.Type,
		Mode:         r.Mode,
	}
	for _, p := range r.Path {
		n.Path = append(n.Path, p)
	}
	return n
}

// String outputs the address that parses into this address.
func (r *ResourceAddress) String() string {
	var result []string
	for _, p := range r.Path {
		result = append(result, "module", p)
	}

	switch r.Mode {
	case config.ManagedResourceMode:
		// nothing to do
	case config.DataResourceMode:
		result = append(result, "data")
	default:
		panic(fmt.Errorf("unsupported resource mode %s", r.Mode))
	}

	if r.Type != "" {
		result = append(result, r.Type)
	}

	if r.Name != "" {
		name := r.Name
		if r.InstanceTypeSet {
			switch r.InstanceType {
			case TypePrimary:
				name += ".primary"
			case TypeDeposed:
				name += ".deposed"
			case TypeTainted:
				name += ".tainted"
			}
		}

		if r.Index >= 0 {
			name += fmt.Sprintf("[%d]", r.Index)
		}
		result = append(result, name)
	}

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

// HasResourceSpec returns true if the address has a resource spec, as
// defined in the documentation:
//    https://www.terraform.io/docs/internals/resource-addressing.html
// In particular, this returns false if the address contains only
// a module path, thus addressing the entire module.
func (r *ResourceAddress) HasResourceSpec() bool {
	return r.Type != "" && r.Name != ""
}

// WholeModuleAddress returns the resource address that refers to all
// resources in the same module as the receiver address.
func (r *ResourceAddress) WholeModuleAddress() *ResourceAddress {
	return &ResourceAddress{
		Path:            r.Path,
		Index:           -1,
		InstanceTypeSet: false,
	}
}

// MatchesConfig returns true if the receiver matches the given
// configuration resource within the given configuration module.
//
// Since resource configuration blocks represent all of the instances of
// a multi-instance resource, the index of the address (if any) is not
// considered.
func (r *ResourceAddress) MatchesConfig(mod *module.Tree, rc *config.Resource) bool {
	if r.HasResourceSpec() {
		if r.Mode != rc.Mode || r.Type != rc.Type || r.Name != rc.Name {
			return false
		}
	}

	addrPath := r.Path
	cfgPath := mod.Path()

	// normalize
	if len(addrPath) == 0 {
		addrPath = nil
	}
	if len(cfgPath) == 0 {
		cfgPath = nil
	}
	return reflect.DeepEqual(addrPath, cfgPath)
}

// stateId returns the ID that this resource should be entered with
// in the state. This is also used for diffs. In the future, we'd like to
// move away from this string field so I don't export this.
func (r *ResourceAddress) stateId() string {
	result := fmt.Sprintf("%s.%s", r.Type, r.Name)
	switch r.Mode {
	case config.ManagedResourceMode:
		// Done
	case config.DataResourceMode:
		result = fmt.Sprintf("data.%s", result)
	default:
		panic(fmt.Errorf("unknown resource mode: %s", r.Mode))
	}
	if r.Index >= 0 {
		result += fmt.Sprintf(".%d", r.Index)
	}

	return result
}

// parseResourceAddressConfig creates a resource address from a config.Resource
func parseResourceAddressConfig(r *config.Resource) (*ResourceAddress, error) {
	return &ResourceAddress{
		Type:         r.Type,
		Name:         r.Name,
		Index:        -1,
		InstanceType: TypePrimary,
		Mode:         r.Mode,
	}, nil
}

// parseResourceAddressInternal parses the somewhat bespoke resource
// identifier used in states and diffs, such as "instance.name.0".
func parseResourceAddressInternal(s string) (*ResourceAddress, error) {
	// Split based on ".". Every resource address should have at least two
	// elements (type and name).
	parts := strings.Split(s, ".")
	if len(parts) < 2 || len(parts) > 4 {
		return nil, fmt.Errorf("Invalid internal resource address format: %s", s)
	}

	// Data resource if we have at least 3 parts and the first one is data
	mode := config.ManagedResourceMode
	if len(parts) > 2 && parts[0] == "data" {
		mode = config.DataResourceMode
		parts = parts[1:]
	}

	// If we're not a data resource and we have more than 3, then it is an error
	if len(parts) > 3 && mode != config.DataResourceMode {
		return nil, fmt.Errorf("Invalid internal resource address format: %s", s)
	}

	// Build the parts of the resource address that are guaranteed to exist
	addr := &ResourceAddress{
		Type:         parts[0],
		Name:         parts[1],
		Index:        -1,
		InstanceType: TypePrimary,
		Mode:         mode,
	}

	// If we have more parts, then we have an index. Parse that.
	if len(parts) > 2 {
		idx, err := strconv.ParseInt(parts[2], 0, 0)
		if err != nil {
			return nil, fmt.Errorf("Error parsing resource address %q: %s", s, err)
		}

		addr.Index = int(idx)
	}

	return addr, nil
}

func ParseResourceAddress(s string) (*ResourceAddress, error) {
	matches, err := tokenizeResourceAddress(s)
	if err != nil {
		return nil, err
	}
	mode := config.ManagedResourceMode
	if matches["data_prefix"] != "" {
		mode = config.DataResourceMode
	}
	resourceIndex, err := ParseResourceIndex(matches["index"])
	if err != nil {
		return nil, err
	}
	instanceType, err := ParseInstanceType(matches["instance_type"])
	if err != nil {
		return nil, err
	}
	path := ParseResourcePath(matches["path"])

	// not allowed to say "data." without a type following
	if mode == config.DataResourceMode && matches["type"] == "" {
		return nil, fmt.Errorf(
			"invalid resource address %q: must target specific data instance",
			s,
		)
	}

	return &ResourceAddress{
		Path:            path,
		Index:           resourceIndex,
		InstanceType:    instanceType,
		InstanceTypeSet: matches["instance_type"] != "",
		Name:            matches["name"],
		Type:            matches["type"],
		Mode:            mode,
	}, nil
}

// Contains returns true if and only if the given node is contained within
// the receiver.
//
// Containment is defined in terms of the module and resource heirarchy:
// a resource is contained within its module and any ancestor modules,
// an indexed resource instance is contained with the unindexed resource, etc.
func (addr *ResourceAddress) Contains(other *ResourceAddress) bool {
	ourPath := addr.Path
	givenPath := other.Path
	if len(givenPath) < len(ourPath) {
		return false
	}
	for i := range ourPath {
		if ourPath[i] != givenPath[i] {
			return false
		}
	}

	// If the receiver is a whole-module address then the path prefix
	// matching is all we need.
	if !addr.HasResourceSpec() {
		return true
	}

	if addr.Type != other.Type || addr.Name != other.Name || addr.Mode != other.Mode {
		return false
	}

	if addr.Index != -1 && addr.Index != other.Index {
		return false
	}

	if addr.InstanceTypeSet && (addr.InstanceTypeSet != other.InstanceTypeSet || addr.InstanceType != other.InstanceType) {
		return false
	}

	return true
}

// Equals returns true if the receiver matches the given address.
//
// The name of this method is a misnomer, since it doesn't test for exact
// equality. Instead, it tests that the _specified_ parts of each
// address match, treating any unspecified parts as wildcards.
//
// See also Contains, which takes a more heirarchical approach to comparing
// addresses.
func (addr *ResourceAddress) Equals(raw interface{}) bool {
	other, ok := raw.(*ResourceAddress)
	if !ok {
		return false
	}

	pathMatch := len(addr.Path) == 0 && len(other.Path) == 0 ||
		reflect.DeepEqual(addr.Path, other.Path)

	indexMatch := addr.Index == -1 ||
		other.Index == -1 ||
		addr.Index == other.Index

	nameMatch := addr.Name == "" ||
		other.Name == "" ||
		addr.Name == other.Name

	typeMatch := addr.Type == "" ||
		other.Type == "" ||
		addr.Type == other.Type

	// mode is significant only when type is set
	modeMatch := addr.Type == "" ||
		other.Type == "" ||
		addr.Mode == other.Mode

	return pathMatch &&
		indexMatch &&
		addr.InstanceType == other.InstanceType &&
		nameMatch &&
		typeMatch &&
		modeMatch
}

// Less returns true if and only if the receiver should be sorted before
// the given address when presenting a list of resource addresses to
// an end-user.
//
// This sort uses lexicographic sorting for most components, but uses
// numeric sort for indices, thus causing index 10 to sort after
// index 9, rather than after index 1.
func (addr *ResourceAddress) Less(other *ResourceAddress) bool {

	switch {

	case len(addr.Path) < len(other.Path):
		return true

	case !reflect.DeepEqual(addr.Path, other.Path):
		// If the two paths are the same length but don't match, we'll just
		// cheat and compare the string forms since it's easier than
		// comparing all of the path segments in turn.
		addrStr := addr.String()
		otherStr := other.String()
		return addrStr < otherStr

	case addr.Mode == config.DataResourceMode && other.Mode != config.DataResourceMode:
		return true

	case addr.Type < other.Type:
		return true

	case addr.Name < other.Name:
		return true

	case addr.Index < other.Index:
		// Since "Index" is -1 for an un-indexed address, this also conveniently
		// sorts unindexed addresses before indexed ones, should they both
		// appear for some reason.
		return true

	case other.InstanceTypeSet && !addr.InstanceTypeSet:
		return true

	case addr.InstanceType < other.InstanceType:
		// InstanceType is actually an enum, so this is just an arbitrary
		// sort based on the enum numeric values, and thus not particularly
		// meaningful.
		return true

	default:
		return false

	}
}

func ParseResourceIndex(s string) (int, error) {
	if s == "" {
		return -1, nil
	}
	return strconv.Atoi(s)
}

func ParseResourcePath(s string) []string {
	if s == "" {
		return nil
	}
	parts := strings.Split(s, ".")
	path := make([]string, 0, len(parts))
	for _, s := range parts {
		// Due to the limitations of the regexp match below, the path match has
		// some noise in it we have to filter out :|
		if s == "" || s == "module" {
			continue
		}
		path = append(path, s)
	}
	return path
}

func ParseInstanceType(s string) (InstanceType, error) {
	switch s {
	case "", "primary":
		return TypePrimary, nil
	case "deposed":
		return TypeDeposed, nil
	case "tainted":
		return TypeTainted, nil
	default:
		return TypeInvalid, fmt.Errorf("Unexpected value for InstanceType field: %q", s)
	}
}

func tokenizeResourceAddress(s string) (map[string]string, error) {
	// Example of portions of the regexp below using the
	// string "aws_instance.web.tainted[1]"
	re := regexp.MustCompile(`\A` +
		// "module.foo.module.bar" (optional)
		`(?P<path>(?:module\.(?P<module_name>[^.]+)\.?)*)` +
		// possibly "data.", if targeting is a data resource
		`(?P<data_prefix>(?:data\.)?)` +
		// "aws_instance.web" (optional when module path specified)
		`(?:(?P<type>[^.]+)\.(?P<name>[^.[]+))?` +
		// "tainted" (optional, omission implies: "primary")
		`(?:\.(?P<instance_type>\w+))?` +
		// "1" (optional, omission implies: "0")
		`(?:\[(?P<index>\d+)\])?` +
		`\z`)

	groupNames := re.SubexpNames()
	rawMatches := re.FindAllStringSubmatch(s, -1)
	if len(rawMatches) != 1 {
		return nil, fmt.Errorf("invalid resource address %q", s)
	}

	matches := make(map[string]string)
	for i, m := range rawMatches[0] {
		matches[groupNames[i]] = m
	}

	return matches, nil
}
<commit_msg>core: ParseResourceAddressForInstanceDiff function<commit_after>package terraform

import (
	"fmt"
	"reflect"
	"regexp"
	"strconv"
	"strings"

	"github.com/hashicorp/terraform/config"
	"github.com/hashicorp/terraform/config/module"
)

// ResourceAddress is a way of identifying an individual resource (or,
// eventually, a subset of resources) within the state. It is used for Targets.
type ResourceAddress struct {
	// Addresses a resource falling somewhere in the module path
	// When specified alone, addresses all resources within a module path
	Path []string

	// Addresses a specific resource that occurs in a list
	Index int

	InstanceType    InstanceType
	InstanceTypeSet bool
	Name            string
	Type            string
	Mode            config.ResourceMode // significant only if InstanceTypeSet
}

// Copy returns a copy of this ResourceAddress
func (r *ResourceAddress) Copy() *ResourceAddress {
	if r == nil {
		return nil
	}

	n := &ResourceAddress{
		Path:         make([]string, 0, len(r.Path)),
		Index:        r.Index,
		InstanceType: r.InstanceType,
		Name:         r.Name,
		Type:         r.Type,
		Mode:         r.Mode,
	}
	for _, p := range r.Path {
		n.Path = append(n.Path, p)
	}
	return n
}

// String outputs the address that parses into this address.
func (r *ResourceAddress) String() string {
	var result []string
	for _, p := range r.Path {
		result = append(result, "module", p)
	}

	switch r.Mode {
	case config.ManagedResourceMode:
		// nothing to do
	case config.DataResourceMode:
		result = append(result, "data")
	default:
		panic(fmt.Errorf("unsupported resource mode %s", r.Mode))
	}

	if r.Type != "" {
		result = append(result, r.Type)
	}

	if r.Name != "" {
		name := r.Name
		if r.InstanceTypeSet {
			switch r.InstanceType {
			case TypePrimary:
				name += ".primary"
			case TypeDeposed:
				name += ".deposed"
			case TypeTainted:
				name += ".tainted"
			}
		}

		if r.Index >= 0 {
			name += fmt.Sprintf("[%d]", r.Index)
		}
		result = append(result, name)
	}

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

// HasResourceSpec returns true if the address has a resource spec, as
// defined in the documentation:
//    https://www.terraform.io/docs/internals/resource-addressing.html
// In particular, this returns false if the address contains only
// a module path, thus addressing the entire module.
func (r *ResourceAddress) HasResourceSpec() bool {
	return r.Type != "" && r.Name != ""
}

// WholeModuleAddress returns the resource address that refers to all
// resources in the same module as the receiver address.
func (r *ResourceAddress) WholeModuleAddress() *ResourceAddress {
	return &ResourceAddress{
		Path:            r.Path,
		Index:           -1,
		InstanceTypeSet: false,
	}
}

// MatchesConfig returns true if the receiver matches the given
// configuration resource within the given configuration module.
//
// Since resource configuration blocks represent all of the instances of
// a multi-instance resource, the index of the address (if any) is not
// considered.
func (r *ResourceAddress) MatchesConfig(mod *module.Tree, rc *config.Resource) bool {
	if r.HasResourceSpec() {
		if r.Mode != rc.Mode || r.Type != rc.Type || r.Name != rc.Name {
			return false
		}
	}

	addrPath := r.Path
	cfgPath := mod.Path()

	// normalize
	if len(addrPath) == 0 {
		addrPath = nil
	}
	if len(cfgPath) == 0 {
		cfgPath = nil
	}
	return reflect.DeepEqual(addrPath, cfgPath)
}

// stateId returns the ID that this resource should be entered with
// in the state. This is also used for diffs. In the future, we'd like to
// move away from this string field so I don't export this.
func (r *ResourceAddress) stateId() string {
	result := fmt.Sprintf("%s.%s", r.Type, r.Name)
	switch r.Mode {
	case config.ManagedResourceMode:
		// Done
	case config.DataResourceMode:
		result = fmt.Sprintf("data.%s", result)
	default:
		panic(fmt.Errorf("unknown resource mode: %s", r.Mode))
	}
	if r.Index >= 0 {
		result += fmt.Sprintf(".%d", r.Index)
	}

	return result
}

// parseResourceAddressConfig creates a resource address from a config.Resource
func parseResourceAddressConfig(r *config.Resource) (*ResourceAddress, error) {
	return &ResourceAddress{
		Type:         r.Type,
		Name:         r.Name,
		Index:        -1,
		InstanceType: TypePrimary,
		Mode:         r.Mode,
	}, nil
}

// parseResourceAddressInternal parses the somewhat bespoke resource
// identifier used in states and diffs, such as "instance.name.0".
func parseResourceAddressInternal(s string) (*ResourceAddress, error) {
	// Split based on ".". Every resource address should have at least two
	// elements (type and name).
	parts := strings.Split(s, ".")
	if len(parts) < 2 || len(parts) > 4 {
		return nil, fmt.Errorf("Invalid internal resource address format: %s", s)
	}

	// Data resource if we have at least 3 parts and the first one is data
	mode := config.ManagedResourceMode
	if len(parts) > 2 && parts[0] == "data" {
		mode = config.DataResourceMode
		parts = parts[1:]
	}

	// If we're not a data resource and we have more than 3, then it is an error
	if len(parts) > 3 && mode != config.DataResourceMode {
		return nil, fmt.Errorf("Invalid internal resource address format: %s", s)
	}

	// Build the parts of the resource address that are guaranteed to exist
	addr := &ResourceAddress{
		Type:         parts[0],
		Name:         parts[1],
		Index:        -1,
		InstanceType: TypePrimary,
		Mode:         mode,
	}

	// If we have more parts, then we have an index. Parse that.
	if len(parts) > 2 {
		idx, err := strconv.ParseInt(parts[2], 0, 0)
		if err != nil {
			return nil, fmt.Errorf("Error parsing resource address %q: %s", s, err)
		}

		addr.Index = int(idx)
	}

	return addr, nil
}

func ParseResourceAddress(s string) (*ResourceAddress, error) {
	matches, err := tokenizeResourceAddress(s)
	if err != nil {
		return nil, err
	}
	mode := config.ManagedResourceMode
	if matches["data_prefix"] != "" {
		mode = config.DataResourceMode
	}
	resourceIndex, err := ParseResourceIndex(matches["index"])
	if err != nil {
		return nil, err
	}
	instanceType, err := ParseInstanceType(matches["instance_type"])
	if err != nil {
		return nil, err
	}
	path := ParseResourcePath(matches["path"])

	// not allowed to say "data." without a type following
	if mode == config.DataResourceMode && matches["type"] == "" {
		return nil, fmt.Errorf(
			"invalid resource address %q: must target specific data instance",
			s,
		)
	}

	return &ResourceAddress{
		Path:            path,
		Index:           resourceIndex,
		InstanceType:    instanceType,
		InstanceTypeSet: matches["instance_type"] != "",
		Name:            matches["name"],
		Type:            matches["type"],
		Mode:            mode,
	}, nil
}

// ParseResourceAddressForInstanceDiff creates a ResourceAddress for a
// resource name as described in a module diff.
//
// For historical reasons a different addressing format is used in this
// context. The internal format should not be shown in the UI and instead
// this function should be used to translate to a ResourceAddress and
// then, where appropriate, use the String method to produce a canonical
// resource address string for display in the UI.
//
// The given path slice must be empty (or nil) for the root module, and
// otherwise consist of a sequence of module names traversing down into
// the module tree. If a non-nil path is provided, the caller must not
// modify its underlying array after passing it to this function.
func ParseResourceAddressForInstanceDiff(path []string, key string) (*ResourceAddress, error) {
	addr, err := parseResourceAddressInternal(key)
	if err != nil {
		return nil, err
	}
	addr.Path = path
	return addr, nil
}

// Contains returns true if and only if the given node is contained within
// the receiver.
//
// Containment is defined in terms of the module and resource heirarchy:
// a resource is contained within its module and any ancestor modules,
// an indexed resource instance is contained with the unindexed resource, etc.
func (addr *ResourceAddress) Contains(other *ResourceAddress) bool {
	ourPath := addr.Path
	givenPath := other.Path
	if len(givenPath) < len(ourPath) {
		return false
	}
	for i := range ourPath {
		if ourPath[i] != givenPath[i] {
			return false
		}
	}

	// If the receiver is a whole-module address then the path prefix
	// matching is all we need.
	if !addr.HasResourceSpec() {
		return true
	}

	if addr.Type != other.Type || addr.Name != other.Name || addr.Mode != other.Mode {
		return false
	}

	if addr.Index != -1 && addr.Index != other.Index {
		return false
	}

	if addr.InstanceTypeSet && (addr.InstanceTypeSet != other.InstanceTypeSet || addr.InstanceType != other.InstanceType) {
		return false
	}

	return true
}

// Equals returns true if the receiver matches the given address.
//
// The name of this method is a misnomer, since it doesn't test for exact
// equality. Instead, it tests that the _specified_ parts of each
// address match, treating any unspecified parts as wildcards.
//
// See also Contains, which takes a more heirarchical approach to comparing
// addresses.
func (addr *ResourceAddress) Equals(raw interface{}) bool {
	other, ok := raw.(*ResourceAddress)
	if !ok {
		return false
	}

	pathMatch := len(addr.Path) == 0 && len(other.Path) == 0 ||
		reflect.DeepEqual(addr.Path, other.Path)

	indexMatch := addr.Index == -1 ||
		other.Index == -1 ||
		addr.Index == other.Index

	nameMatch := addr.Name == "" ||
		other.Name == "" ||
		addr.Name == other.Name

	typeMatch := addr.Type == "" ||
		other.Type == "" ||
		addr.Type == other.Type

	// mode is significant only when type is set
	modeMatch := addr.Type == "" ||
		other.Type == "" ||
		addr.Mode == other.Mode

	return pathMatch &&
		indexMatch &&
		addr.InstanceType == other.InstanceType &&
		nameMatch &&
		typeMatch &&
		modeMatch
}

// Less returns true if and only if the receiver should be sorted before
// the given address when presenting a list of resource addresses to
// an end-user.
//
// This sort uses lexicographic sorting for most components, but uses
// numeric sort for indices, thus causing index 10 to sort after
// index 9, rather than after index 1.
func (addr *ResourceAddress) Less(other *ResourceAddress) bool {

	switch {

	case len(addr.Path) < len(other.Path):
		return true

	case !reflect.DeepEqual(addr.Path, other.Path):
		// If the two paths are the same length but don't match, we'll just
		// cheat and compare the string forms since it's easier than
		// comparing all of the path segments in turn.
		addrStr := addr.String()
		otherStr := other.String()
		return addrStr < otherStr

	case addr.Mode == config.DataResourceMode && other.Mode != config.DataResourceMode:
		return true

	case addr.Type < other.Type:
		return true

	case addr.Name < other.Name:
		return true

	case addr.Index < other.Index:
		// Since "Index" is -1 for an un-indexed address, this also conveniently
		// sorts unindexed addresses before indexed ones, should they both
		// appear for some reason.
		return true

	case other.InstanceTypeSet && !addr.InstanceTypeSet:
		return true

	case addr.InstanceType < other.InstanceType:
		// InstanceType is actually an enum, so this is just an arbitrary
		// sort based on the enum numeric values, and thus not particularly
		// meaningful.
		return true

	default:
		return false

	}
}

func ParseResourceIndex(s string) (int, error) {
	if s == "" {
		return -1, nil
	}
	return strconv.Atoi(s)
}

func ParseResourcePath(s string) []string {
	if s == "" {
		return nil
	}
	parts := strings.Split(s, ".")
	path := make([]string, 0, len(parts))
	for _, s := range parts {
		// Due to the limitations of the regexp match below, the path match has
		// some noise in it we have to filter out :|
		if s == "" || s == "module" {
			continue
		}
		path = append(path, s)
	}
	return path
}

func ParseInstanceType(s string) (InstanceType, error) {
	switch s {
	case "", "primary":
		return TypePrimary, nil
	case "deposed":
		return TypeDeposed, nil
	case "tainted":
		return TypeTainted, nil
	default:
		return TypeInvalid, fmt.Errorf("Unexpected value for InstanceType field: %q", s)
	}
}

func tokenizeResourceAddress(s string) (map[string]string, error) {
	// Example of portions of the regexp below using the
	// string "aws_instance.web.tainted[1]"
	re := regexp.MustCompile(`\A` +
		// "module.foo.module.bar" (optional)
		`(?P<path>(?:module\.(?P<module_name>[^.]+)\.?)*)` +
		// possibly "data.", if targeting is a data resource
		`(?P<data_prefix>(?:data\.)?)` +
		// "aws_instance.web" (optional when module path specified)
		`(?:(?P<type>[^.]+)\.(?P<name>[^.[]+))?` +
		// "tainted" (optional, omission implies: "primary")
		`(?:\.(?P<instance_type>\w+))?` +
		// "1" (optional, omission implies: "0")
		`(?:\[(?P<index>\d+)\])?` +
		`\z`)

	groupNames := re.SubexpNames()
	rawMatches := re.FindAllStringSubmatch(s, -1)
	if len(rawMatches) != 1 {
		return nil, fmt.Errorf("invalid resource address %q", s)
	}

	matches := make(map[string]string)
	for i, m := range rawMatches[0] {
		matches[groupNames[i]] = m
	}

	return matches, nil
}
<|endoftext|>


<commit_before>package drivers

import (
	"fmt"
	"strings"
)

type qemuBusEntry struct {
	bridgeDev int // Device number on the root bridge.
	bridgeFn  int // Function number on the root bridge.

	dev string // Existing device name.
	fn  int    // Function number on the existing device.
}

type qemuBus struct {
	name string           // Bus type.
	sb   *strings.Builder // String builder to use.

	portNum int // Next available port/chassis on the bridge.
	devNum  int // Next available device number on the bridge.

	rootPort *qemuBusEntry // Current root port.

	entries map[string]*qemuBusEntry // Map of qemuBusEntry for a particular shared device.
}

func (a *qemuBus) allocateRoot() *qemuBusEntry {
	if a.rootPort == nil {
		a.rootPort = &qemuBusEntry{
			bridgeDev: a.devNum,
		}
		a.devNum++
	} else {
		if a.rootPort.bridgeFn == 7 {
			a.rootPort.bridgeFn = 0
			a.rootPort.bridgeDev = a.devNum
			a.devNum++
		} else {
			a.rootPort.bridgeFn++
		}
	}

	return a.rootPort
}

// allocate() does any needed port allocation and  returns the bus name,
// address and whether the device needs to be configured as multi-function.
//
// The group parameter allows for grouping devices together as a single
// multi-function device. It automatically keeps track of the number of
// functions already used and will allocate a new device as needed.
func (a *qemuBus) allocate(group string) (string, string, bool) {
	if a.name == "ccw" {
		return "", "", false
	}

	// Find a device group if specified.
	var p *qemuBusEntry
	if group != "" {
		var ok bool
		p, ok = a.entries[group]
		if ok {
			// Check if group is full.
			if p.fn == 7 {
				p.fn = 0
				if a.name == "pci" {
					p.bridgeDev = a.devNum
					a.devNum++
				} else if a.name == "pcie" {
					r := a.allocateRoot()
					p.bridgeDev = r.bridgeDev
					p.bridgeFn = r.bridgeFn
				}
			} else {
				p.fn++
			}
		} else {
			// Create a new group.
			p = &qemuBusEntry{}

			if a.name == "pci" {
				p.bridgeDev = a.devNum
				a.devNum++
			} else if a.name == "pcie" {
				r := a.allocateRoot()
				p.bridgeDev = r.bridgeDev
				p.bridgeFn = r.bridgeFn
			}

			a.entries[group] = p
		}
	} else {
		// Create a new temporary group.
		p = &qemuBusEntry{}

		if a.name == "pci" {
			p.bridgeDev = a.devNum
			a.devNum++
		} else if a.name == "pcie" {
			r := a.allocateRoot()
			p.bridgeDev = r.bridgeDev
			p.bridgeFn = r.bridgeFn
		}
	}

	multi := p.fn == 0 && group != ""

	if a.name == "pci" {
		return "pci.0", fmt.Sprintf("%x.%d", p.bridgeDev, p.fn), multi
	}

	if a.name == "pcie" {
		if p.fn == 0 {
			qemuPCIe.Execute(a.sb, map[string]interface{}{
				"index":         a.portNum,
				"addr":          fmt.Sprintf("%x.%d", p.bridgeDev, p.bridgeFn),
				"multifunction": p.bridgeFn == 0,
			})
			p.dev = fmt.Sprintf("qemu_pcie%d", a.portNum)
			a.portNum++
		}

		return p.dev, fmt.Sprintf("00.%d", p.fn), multi
	}

	return "", "", false
}

func qemuNewBus(name string, sb *strings.Builder) *qemuBus {
	a := &qemuBus{
		name: name,
		sb:   sb,

		portNum: 0, // No PCIe ports are used in the default config.
		devNum:  1, // Address 0 is used by the DRAM controller.

		entries: map[string]*qemuBusEntry{},
	}

	return a
}
<commit_msg>lxd/instance/drivers/driver/qemu/bus: Adds comments, clarifies var names, and constants for defined multi-function groups<commit_after>package drivers

import (
	"fmt"
	"strings"
)

const busFunctionGroupNone = ""           // Add a non multi-function port.
const busFunctionGroupGeneric = "generic" // Add multi-function port to generic group (used for internal devices).
const busFunctionGroup9p = "9p"           // Add multi-function port to 9p group (used for 9p shares).

type qemuBusEntry struct {
	bridgeDev int // Device number on the root bridge.
	bridgeFn  int // Function number on the root bridge.

	dev string // Existing device name.
	fn  int    // Function number on the existing device.
}

type qemuBus struct {
	name string           // Bus type.
	sb   *strings.Builder // String builder to use.

	portNum int // Next available port/chassis on the bridge.
	devNum  int // Next available device number on the bridge.

	rootPort *qemuBusEntry // Current root port.

	entries map[string]*qemuBusEntry // Map of qemuBusEntry for a particular shared device.
}

func (a *qemuBus) allocateRoot() *qemuBusEntry {
	if a.rootPort == nil {
		a.rootPort = &qemuBusEntry{
			bridgeDev: a.devNum,
		}
		a.devNum++
	} else {
		if a.rootPort.bridgeFn == 7 {
			a.rootPort.bridgeFn = 0
			a.rootPort.bridgeDev = a.devNum
			a.devNum++
		} else {
			a.rootPort.bridgeFn++
		}
	}

	return a.rootPort
}

// allocate() does any needed port allocation and returns the bus name,
// address and whether the device needs to be configured as multi-function.
//
// The multiFunctionGroup parameter allows for grouping devices together as one or more multi-function devices.
// It automatically keeps track of the number of functions already used and will allocate new ports as needed.
func (a *qemuBus) allocate(multiFunctionGroup string) (string, string, bool) {
	if a.name == "ccw" {
		return "", "", false
	}

	// Find a device multi-function group if specified.
	var p *qemuBusEntry
	if multiFunctionGroup != "" {
		var ok bool
		p, ok = a.entries[multiFunctionGroup]
		if ok {
			// Check if existing multi-function group is full.
			if p.fn == 7 {
				p.fn = 0
				if a.name == "pci" {
					p.bridgeDev = a.devNum
					a.devNum++
				} else if a.name == "pcie" {
					r := a.allocateRoot()
					p.bridgeDev = r.bridgeDev
					p.bridgeFn = r.bridgeFn
				}
			} else {
				p.fn++
			}
		} else {
			// Create a new multi-function group.
			p = &qemuBusEntry{}

			if a.name == "pci" {
				p.bridgeDev = a.devNum
				a.devNum++
			} else if a.name == "pcie" {
				r := a.allocateRoot()
				p.bridgeDev = r.bridgeDev
				p.bridgeFn = r.bridgeFn
			}

			a.entries[multiFunctionGroup] = p
		}
	} else {
		// Create a temporary single function group.
		p = &qemuBusEntry{}

		if a.name == "pci" {
			p.bridgeDev = a.devNum
			a.devNum++
		} else if a.name == "pcie" {
			r := a.allocateRoot()
			p.bridgeDev = r.bridgeDev
			p.bridgeFn = r.bridgeFn
		}
	}

	// The first device added to a multi-function port needs to specify the multi-function feature.
	multi := p.fn == 0 && multiFunctionGroup != ""

	if a.name == "pci" {
		return "pci.0", fmt.Sprintf("%x.%d", p.bridgeDev, p.fn), multi
	}

	if a.name == "pcie" {
		if p.fn == 0 {
			qemuPCIe.Execute(a.sb, map[string]interface{}{
				"index": a.portNum,
				"addr":  fmt.Sprintf("%x.%d", p.bridgeDev, p.bridgeFn),

				// First root port added on a bridge bus address needs multi-function enabled.
				"multifunction": p.bridgeFn == 0,
			})
			p.dev = fmt.Sprintf("qemu_pcie%d", a.portNum)
			a.portNum++
		}

		return p.dev, fmt.Sprintf("00.%d", p.fn), multi
	}

	return "", "", false
}

// qemuNewBus instantiates a new qemu bus allocator. Accepts the type name of the bus and the qemu config builder
// which it will use to write root port config entries too as ports are allocated.
func qemuNewBus(name string, sb *strings.Builder) *qemuBus {
	a := &qemuBus{
		name: name,
		sb:   sb,

		portNum: 0, // No PCIe ports are used in the default config.
		devNum:  1, // Address 0 is used by the DRAM controller.

		entries: map[string]*qemuBusEntry{},
	}

	return a
}
<|endoftext|>


<commit_before>// Copyright 2013 Xing Xing <mikespook@gmail.com>.
// All rights reserved.
// Use of this source code is governed by a commercial
// license that can be found in the LICENSE file.

package iptpool

import (
	"sync"
)

var (
	DefaultMaxIdle = 32
)

type CreateFunc func() ScriptIpt
type EventFunc func(ScriptIpt) error

type ScriptIpt interface {
	Exec(name string, params interface{}) error
	Init(path string) error
	Final() error
	Bind(name string, item interface{}) error
}

type IptPool struct {
	p sync.Pool
    OnCreate EventFunc
}

func NewIptPool(create CreateFunc) *IptPool {
	iptPool := &IptPool{}
	f := func() interface{} {
		ipt := create()
		if iptPool.OnCreate != nil {
			iptPool.OnCreate(ipt)
		}
		return ipt
	}
	iptPool.p = sync.Pool{New: f}
	return iptPool
}

func (pool *IptPool) Get() (ipt ScriptIpt) {
	return pool.p.Get().(ScriptIpt)
}

func (pool *IptPool) Put(ipt ScriptIpt) {
	pool.p.Put(ipt)
}
<commit_msg>expose state<commit_after>// Copyright 2013 Xing Xing <mikespook@gmail.com>.
// All rights reserved.
// Use of this source code is governed by a commercial
// license that can be found in the LICENSE file.

package iptpool

import (
	"sync"
)

var (
	DefaultMaxIdle = 32
)

type CreateFunc func() ScriptIpt
type EventFunc func(ScriptIpt) error

type ScriptIpt interface {
	Exec(name string, params interface{}) error
	Init(path string) error
	Final() error
	Bind(name string, item interface{}) error
	State() interface{}
}

type IptPool struct {
	p        sync.Pool
	OnCreate EventFunc
}

func NewIptPool(create CreateFunc) *IptPool {
	iptPool := &IptPool{}
	f := func() interface{} {
		ipt := create()
		if iptPool.OnCreate != nil {
			iptPool.OnCreate(ipt)
		}
		return ipt
	}
	iptPool.p = sync.Pool{New: f}
	return iptPool
}

func (pool *IptPool) Get() (ipt ScriptIpt) {
	return pool.p.Get().(ScriptIpt)
}

func (pool *IptPool) Put(ipt ScriptIpt) {
	pool.p.Put(ipt)
}
<|endoftext|>


<commit_before>package iqshell

import (
	"context"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/qiniu/go-sdk/v7/auth"
	"github.com/qiniu/go-sdk/v7/auth/qbox"
	"github.com/qiniu/go-sdk/v7/conf"
	"github.com/qiniu/go-sdk/v7/storage"
)

// Get 接口返回的结构
type GetRet struct {
	URL      string `json:"url"`
	Hash     string `json:"hash"`
	MimeType string `json:"mimeType"`
	Fsize    int64  `json:"fsize"`
	Expiry   int64  `json:"expires"`
	Version  string `json:"version"`
}

type EntryPath struct {
	Bucket string
	Key    string
}

// 改变文件mime需要的信息
type ChgmEntryPath struct {
	EntryPath
	MimeType string
}

// 改变文件存储类型需要的信息
type ChtypeEntryPath struct {
	EntryPath
	FileType int
}

// 设置deleteAfterDays需要的参数
type DeleteAfterDaysEntryPath struct {
	EntryPath
	DeleteAfterDays int
}

type RenameEntryPath MoveEntryPath

type MoveEntryPath struct {
	SrcEntry EntryPath
	DstEntry EntryPath
	Force    bool
}

type CopyEntryPath MoveEntryPath

type BucketManager struct {
	*storage.BucketManager
}

type BucketDomainsRet []struct {
	Domain string `json:"domain"`
	Tbl    string `json:"tbl"`
	Owner  int    `json:"owner"`
}

// 获取一个存储空间绑定的CDN域名
func (m *BucketManager) DomainsOfBucket(bucket string) (domains []string, err error) {
	infos, err := m.ListBucketDomains(bucket)
	if err != nil {
		if e, ok := err.(*storage.ErrorInfo); ok {
			if e.Code != 404 {
				return
			}
			err = nil
		} else {
			return
		}
	}
	for _, d := range infos {
		domains = append(domains, d.Domain)
	}
	return
}

// 返回公有空间的下载链接，不可以用于私有空间的下载
func (m *BucketManager) MakePublicDownloadLink(domainOfBucket, fileKey string, useHttps bool) (fileUrl string) {
	if useHttps {
		fileUrl = fmt.Sprintf("https://%s/%s", domainOfBucket, url.PathEscape(fileKey))
	} else {
		fileUrl = fmt.Sprintf("http://%s/%s", domainOfBucket, url.PathEscape(fileKey))
	}
	return
}

// 返回私有空间的下载链接， 也可以用于公有空间的下载
func (m *BucketManager) MakePrivateDownloadLink(domainOfBucket, fileKey string, useHttps bool) (fileUrl string) {
	var publicUrl string
	if useHttps {
		publicUrl = fmt.Sprintf("https://%s/%s", domainOfBucket, url.PathEscape(fileKey))
	} else {
		publicUrl = fmt.Sprintf("http://%s/%s", domainOfBucket, url.PathEscape(fileKey))
	}
	deadline := time.Now().Add(time.Hour * 24 * 30).Unix()
	privateUrl, _ := m.PrivateUrl(publicUrl, deadline)
	fileUrl = privateUrl
	return
}

// 返回私有空间的下载链接， 也可以用于公有空间的下载
func (m *BucketManager) PrivateUrl(publicUrl string, deadline int64) (finalUrl string, err error) {
	srcUri, pErr := url.Parse(publicUrl)
	if pErr != nil {
		err = pErr
		return
	}

	h := hmac.New(sha1.New, m.Mac.SecretKey)

	urlToSign := srcUri.String()
	if strings.Contains(publicUrl, "?") {
		urlToSign = fmt.Sprintf("%s&e=%d", urlToSign, deadline)
	} else {
		urlToSign = fmt.Sprintf("%s?e=%d", urlToSign, deadline)
	}
	h.Write([]byte(urlToSign))

	sign := base64.URLEncoding.EncodeToString(h.Sum(nil))
	token := m.Mac.AccessKey + ":" + sign
	finalUrl = fmt.Sprintf("%s&token=%s", urlToSign, token)
	return
}

func (m *BucketManager) GetMac() *qbox.Mac {
	return m.Mac
}

func (m *BucketManager) rsHost(bucket string) (rsHost string, err error) {
	zone, err := m.Zone(bucket)
	if err != nil {
		return
	}

	rsHost = zone.GetRsHost(m.Cfg.UseHTTPS)
	return
}

// 从存储空间下载文件（不需要绑定CDN域名）
func (m *BucketManager) Get(bucket, key string, destFile string) (err error) {
	entryUri := strings.Join([]string{bucket, key}, ":")

	var (
		reqHost string
		reqErr  error
	)
	reqHost = RsHost()
	if reqHost == "" {
		reqHost, reqErr = m.rsHost(bucket)
		if reqErr != nil {
			err = reqErr
			return
		}
	}
	if !strings.HasPrefix(reqHost, "http") {
		reqHost = "http://" + reqHost
	}
	url := strings.Join([]string{reqHost, "get", Encode(entryUri)}, "/")

	var data GetRet

	ctx := auth.WithCredentials(context.Background(), m.Mac)
	headers := http.Header{}

	err = storage.DefaultClient.Call(ctx, &data, "GET", url, headers)
	if err != nil {
		return
	}
	resp, err := storage.DefaultClient.DoRequest(context.Background(), "GET", data.URL, headers)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	if resp.StatusCode/100 != 2 {
		body, rerr := ioutil.ReadAll(resp.Body)
		if rerr != nil {
			return rerr
		}
		fmt.Fprintf(os.Stderr, "Qget: http respcode: %d, respbody: %s\n", resp.StatusCode, string(body))
		os.Exit(1)
	}
	if strings.ContainsRune(destFile, os.PathSeparator) {
		destFile = filepath.Base(destFile)
	}
	f, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
	if err != nil {
		return
	}
	defer f.Close()

	io.Copy(f, resp.Body)
	return
}

func (m *BucketManager) Saveas(publicUrl, saveBucket, saveKey string) (string, error) {
	uri, parseErr := url.Parse(publicUrl)
	if parseErr != nil {
		return "", parseErr
	}
	baseUrl := uri.Host + uri.RequestURI()
	saveEntry := saveBucket + ":" + saveKey
	encodedSaveEntry := base64.URLEncoding.EncodeToString([]byte(saveEntry))
	baseUrl += "|saveas/" + encodedSaveEntry
	mac := m.GetMac()
	h := hmac.New(sha1.New, mac.SecretKey)
	h.Write([]byte(baseUrl))
	sign := h.Sum(nil)
	encodedSign := base64.URLEncoding.EncodeToString(sign)
	return publicUrl + "|saveas/" + encodedSaveEntry + "/sign/" + mac.AccessKey + ":" + encodedSign, nil
}

func (m *BucketManager) BatchStat(entries []EntryPath) (ret []storage.BatchOpRet, err error) {
	ops := make([]string, 0, len(entries))
	for _, entry := range entries {
		ops = append(ops, storage.URIStat(entry.Bucket, entry.Key))
	}
	return m.Batch(ops)
}

func (m *BucketManager) BatchDelete(entries []EntryPath) (ret []storage.BatchOpRet, err error) {
	ops := make([]string, 0, len(entries))
	for _, entry := range entries {
		ops = append(ops, storage.URIDelete(entry.Bucket, entry.Key))
	}
	return m.Batch(ops)
}

func (m *BucketManager) BatchCopy(entries []CopyEntryPath) (ret []storage.BatchOpRet, err error) {
	ops := make([]string, 0, len(entries))
	for _, entry := range entries {
		ops = append(ops, storage.URICopy(entry.SrcEntry.Bucket, entry.SrcEntry.Key, entry.DstEntry.Bucket, entry.DstEntry.Key, entry.Force))
	}
	return m.Batch(ops)
}

func (m *BucketManager) BatchMove(entries []MoveEntryPath) (ret []storage.BatchOpRet, err error) {
	ops := make([]string, 0, len(entries))
	for _, entry := range entries {
		ops = append(ops, storage.URIMove(entry.SrcEntry.Bucket, entry.SrcEntry.Key, entry.DstEntry.Bucket, entry.DstEntry.Key, entry.Force))
	}
	return m.Batch(ops)
}

func (m *BucketManager) BatchRename(entries []RenameEntryPath) (ret []storage.BatchOpRet, err error) {
	ops := make([]string, 0, len(entries))
	for _, entry := range entries {
		ops = append(ops, storage.URIMove(entry.SrcEntry.Bucket, entry.SrcEntry.Key, entry.DstEntry.Bucket, entry.DstEntry.Key, entry.Force))
	}
	return m.Batch(ops)
}

func (m *BucketManager) BatchChgm(entries []ChgmEntryPath) (ret []storage.BatchOpRet, err error) {
	ops := make([]string, 0, len(entries))
	for _, entry := range entries {
		ops = append(ops, storage.URIChangeMime(entry.Bucket, entry.Key, entry.MimeType))
	}
	return m.Batch(ops)
}

func (m *BucketManager) BatchChtype(entries []ChtypeEntryPath) (ret []storage.BatchOpRet, err error) {
	ops := make([]string, 0, len(entries))
	for _, entry := range entries {
		ops = append(ops, storage.URIChangeType(entry.Bucket, entry.Key, entry.FileType))
	}
	return m.Batch(ops)
}

func (m *BucketManager) CheckAsyncFetchStatus(bucket, id string) (ret storage.AsyncFetchRet, err error) {

	reqUrl, err := m.ApiReqHost(bucket)
	if err != nil {
		return
	}

	reqUrl += ("/sisyphus/fetch?id=" + id)

	ctx := auth.WithCredentialsType(context.Background(), m.Mac, auth.TokenQiniu)
	err = m.Client.Call(ctx, &ret, "GET", reqUrl, nil)
	return
}

// 禁用七牛存储中的对象
func (m *BucketManager) ChStatus(bucket, key string, forbidden bool) (err error) {
	ctx := auth.WithCredentials(context.Background(), m.Mac)
	reqHost, reqErr := m.RsReqHost(bucket)
	if reqErr != nil {
		err = reqErr
		return
	}
	var status int
	if forbidden {
		status = 1
	} else {
		status = 0
	}
	reqURL := fmt.Sprintf("%s%s", reqHost, fmt.Sprintf("/chstatus/%s/status/%d", storage.EncodedEntry(bucket, key), status))
	headers := http.Header{}
	headers.Add("Content-Type", conf.CONTENT_TYPE_FORM)
	err = m.Client.Call(ctx, nil, "POST", reqURL, headers)
	return

}

func (m *BucketManager) BatchDeleteAfterDays(entries []DeleteAfterDaysEntryPath) (ret []storage.BatchOpRet, err error) {
	ops := make([]string, 0, len(entries))
	for _, entry := range entries {
		ops = append(ops, storage.URIDeleteAfterDays(entry.Bucket, entry.Key, entry.DeleteAfterDays))
	}
	return m.Batch(ops)
}

func (m *BucketManager) BatchSign(urls []string, deadline int64) (ret []string, err error) {
	for _, url := range urls {
		finalUrl, pErr := m.PrivateUrl(url, deadline)
		if pErr != nil {
			err = pErr
			return
		}
		ret = append(ret, finalUrl)
	}
	return
}

// NewBucketManager 用来构建一个新的资源管理对象
func NewBucketManager(mac *qbox.Mac, cfg *storage.Config) *BucketManager {
	bm := storage.NewBucketManager(mac, cfg)

	return &BucketManager{
		BucketManager: bm,
	}
}

// NewBucketManagerEx 用来构建一个新的资源管理对象
func NewBucketManagerEx(mac *qbox.Mac, cfg *storage.Config, client *storage.Client) *BucketManager {
	bm := storage.NewBucketManagerEx(mac, cfg, client)
	return &BucketManager{
		BucketManager: bm,
	}
}

// GetBucketManager 返回一个BucketManager 指针
func GetBucketManagerWithConfig(cfg *storage.Config) *BucketManager {
	account, gErr := GetAccount()
	if gErr != nil {
		fmt.Fprintf(os.Stderr, "GetBucketManager: %v\n", gErr)
		os.Exit(1)
	}
	mac := qbox.NewMac(account.AccessKey, account.SecretKey)
	return NewBucketManager(mac, cfg)
}

func GetBucketManager() *BucketManager {
	account, gErr := GetAccount()
	if gErr != nil {
		fmt.Fprintf(os.Stderr, "GetBucketManager: %v\n", gErr)
		os.Exit(1)
	}
	mac := qbox.NewMac(account.AccessKey, account.SecretKey)
	cfg := storage.Config{
		UpHost:        UpHost(),
		IoHost:        IoHost(),
		RsHost:        RsHost(),
		ApiHost:       ApiHost(),
		RsfHost:       RsfHost(),
		CentralRsHost: RsHost(),
	}
	storage.UcHost = UcHost()
	return NewBucketManager(mac, &cfg)
}

func GetUpHost(cfg *storage.Config, ak, bucket string) (upHost string, err error) {

	var zone *storage.Zone
	if cfg.Zone != nil {
		zone = cfg.Zone
	} else {
		if v, zoneErr := storage.GetZone(ak, bucket); zoneErr != nil {
			err = zoneErr
			return
		} else {
			zone = v
		}
	}

	scheme := "http://"
	if cfg.UseHTTPS {
		scheme = "https://"
	}

	host := zone.SrcUpHosts[0]
	if cfg.UseCdnDomains {
		host = zone.CdnUpHosts[0]
	}

	upHost = fmt.Sprintf("%s%s", scheme, host)
	return
}
<commit_msg>get -o support dir<commit_after>package iqshell

import (
	"context"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/qiniu/go-sdk/v7/auth"
	"github.com/qiniu/go-sdk/v7/auth/qbox"
	"github.com/qiniu/go-sdk/v7/conf"
	"github.com/qiniu/go-sdk/v7/storage"
)

// Get 接口返回的结构
type GetRet struct {
	URL      string `json:"url"`
	Hash     string `json:"hash"`
	MimeType string `json:"mimeType"`
	Fsize    int64  `json:"fsize"`
	Expiry   int64  `json:"expires"`
	Version  string `json:"version"`
}

type EntryPath struct {
	Bucket string
	Key    string
}

// 改变文件mime需要的信息
type ChgmEntryPath struct {
	EntryPath
	MimeType string
}

// 改变文件存储类型需要的信息
type ChtypeEntryPath struct {
	EntryPath
	FileType int
}

// 设置deleteAfterDays需要的参数
type DeleteAfterDaysEntryPath struct {
	EntryPath
	DeleteAfterDays int
}

type RenameEntryPath MoveEntryPath

type MoveEntryPath struct {
	SrcEntry EntryPath
	DstEntry EntryPath
	Force    bool
}

type CopyEntryPath MoveEntryPath

type BucketManager struct {
	*storage.BucketManager
}

type BucketDomainsRet []struct {
	Domain string `json:"domain"`
	Tbl    string `json:"tbl"`
	Owner  int    `json:"owner"`
}

// 获取一个存储空间绑定的CDN域名
func (m *BucketManager) DomainsOfBucket(bucket string) (domains []string, err error) {
	infos, err := m.ListBucketDomains(bucket)
	if err != nil {
		if e, ok := err.(*storage.ErrorInfo); ok {
			if e.Code != 404 {
				return
			}
			err = nil
		} else {
			return
		}
	}
	for _, d := range infos {
		domains = append(domains, d.Domain)
	}
	return
}

// 返回公有空间的下载链接，不可以用于私有空间的下载
func (m *BucketManager) MakePublicDownloadLink(domainOfBucket, fileKey string, useHttps bool) (fileUrl string) {
	if useHttps {
		fileUrl = fmt.Sprintf("https://%s/%s", domainOfBucket, url.PathEscape(fileKey))
	} else {
		fileUrl = fmt.Sprintf("http://%s/%s", domainOfBucket, url.PathEscape(fileKey))
	}
	return
}

// 返回私有空间的下载链接， 也可以用于公有空间的下载
func (m *BucketManager) MakePrivateDownloadLink(domainOfBucket, fileKey string, useHttps bool) (fileUrl string) {
	var publicUrl string
	if useHttps {
		publicUrl = fmt.Sprintf("https://%s/%s", domainOfBucket, url.PathEscape(fileKey))
	} else {
		publicUrl = fmt.Sprintf("http://%s/%s", domainOfBucket, url.PathEscape(fileKey))
	}
	deadline := time.Now().Add(time.Hour * 24 * 30).Unix()
	privateUrl, _ := m.PrivateUrl(publicUrl, deadline)
	fileUrl = privateUrl
	return
}

// 返回私有空间的下载链接， 也可以用于公有空间的下载
func (m *BucketManager) PrivateUrl(publicUrl string, deadline int64) (finalUrl string, err error) {
	srcUri, pErr := url.Parse(publicUrl)
	if pErr != nil {
		err = pErr
		return
	}

	h := hmac.New(sha1.New, m.Mac.SecretKey)

	urlToSign := srcUri.String()
	if strings.Contains(publicUrl, "?") {
		urlToSign = fmt.Sprintf("%s&e=%d", urlToSign, deadline)
	} else {
		urlToSign = fmt.Sprintf("%s?e=%d", urlToSign, deadline)
	}
	h.Write([]byte(urlToSign))

	sign := base64.URLEncoding.EncodeToString(h.Sum(nil))
	token := m.Mac.AccessKey + ":" + sign
	finalUrl = fmt.Sprintf("%s&token=%s", urlToSign, token)
	return
}

func (m *BucketManager) GetMac() *qbox.Mac {
	return m.Mac
}

func (m *BucketManager) rsHost(bucket string) (rsHost string, err error) {
	zone, err := m.Zone(bucket)
	if err != nil {
		return
	}

	rsHost = zone.GetRsHost(m.Cfg.UseHTTPS)
	return
}

// 从存储空间下载文件（不需要绑定CDN域名）
func (m *BucketManager) Get(bucket, key string, destFile string) (err error) {
	entryUri := strings.Join([]string{bucket, key}, ":")

	var (
		reqHost string
		reqErr  error
	)
	reqHost = RsHost()
	if reqHost == "" {
		reqHost, reqErr = m.rsHost(bucket)
		if reqErr != nil {
			err = reqErr
			return
		}
	}
	if !strings.HasPrefix(reqHost, "http") {
		reqHost = "http://" + reqHost
	}
	url := strings.Join([]string{reqHost, "get", Encode(entryUri)}, "/")

	var data GetRet

	ctx := auth.WithCredentials(context.Background(), m.Mac)
	headers := http.Header{}

	err = storage.DefaultClient.Call(ctx, &data, "GET", url, headers)
	if err != nil {
		return
	}
	resp, err := storage.DefaultClient.DoRequest(context.Background(), "GET", data.URL, headers)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	if resp.StatusCode/100 != 2 {
		body, rerr := ioutil.ReadAll(resp.Body)
		if rerr != nil {
			return rerr
		}
		fmt.Fprintf(os.Stderr, "Qget: http respcode: %d, respbody: %s\n", resp.StatusCode, string(body))
		os.Exit(1)
	}

	//if strings.ContainsRune(destFile, os.PathSeparator) {
	//	destFile = filepath.Base(destFile)
	//}

	for {
		f, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
		if err == nil {
			io.Copy(f, resp.Body)
			f.Close()
			break
		} else if os.IsNotExist(err) {
			destDir := filepath.Dir(destFile)
			if err := os.MkdirAll(destDir, 0766); err != nil {
				fmt.Fprintf(os.Stderr, "Qget: err: %s\n", err)
				break
			}
		} else {
			fmt.Fprintf(os.Stderr, "Qget: err: %s\n", err)
			break
		}
	}

	return
}

func (m *BucketManager) Saveas(publicUrl, saveBucket, saveKey string) (string, error) {
	uri, parseErr := url.Parse(publicUrl)
	if parseErr != nil {
		return "", parseErr
	}
	baseUrl := uri.Host + uri.RequestURI()
	saveEntry := saveBucket + ":" + saveKey
	encodedSaveEntry := base64.URLEncoding.EncodeToString([]byte(saveEntry))
	baseUrl += "|saveas/" + encodedSaveEntry
	mac := m.GetMac()
	h := hmac.New(sha1.New, mac.SecretKey)
	h.Write([]byte(baseUrl))
	sign := h.Sum(nil)
	encodedSign := base64.URLEncoding.EncodeToString(sign)
	return publicUrl + "|saveas/" + encodedSaveEntry + "/sign/" + mac.AccessKey + ":" + encodedSign, nil
}

func (m *BucketManager) BatchStat(entries []EntryPath) (ret []storage.BatchOpRet, err error) {
	ops := make([]string, 0, len(entries))
	for _, entry := range entries {
		ops = append(ops, storage.URIStat(entry.Bucket, entry.Key))
	}
	return m.Batch(ops)
}

func (m *BucketManager) BatchDelete(entries []EntryPath) (ret []storage.BatchOpRet, err error) {
	ops := make([]string, 0, len(entries))
	for _, entry := range entries {
		ops = append(ops, storage.URIDelete(entry.Bucket, entry.Key))
	}
	return m.Batch(ops)
}

func (m *BucketManager) BatchCopy(entries []CopyEntryPath) (ret []storage.BatchOpRet, err error) {
	ops := make([]string, 0, len(entries))
	for _, entry := range entries {
		ops = append(ops, storage.URICopy(entry.SrcEntry.Bucket, entry.SrcEntry.Key, entry.DstEntry.Bucket, entry.DstEntry.Key, entry.Force))
	}
	return m.Batch(ops)
}

func (m *BucketManager) BatchMove(entries []MoveEntryPath) (ret []storage.BatchOpRet, err error) {
	ops := make([]string, 0, len(entries))
	for _, entry := range entries {
		ops = append(ops, storage.URIMove(entry.SrcEntry.Bucket, entry.SrcEntry.Key, entry.DstEntry.Bucket, entry.DstEntry.Key, entry.Force))
	}
	return m.Batch(ops)
}

func (m *BucketManager) BatchRename(entries []RenameEntryPath) (ret []storage.BatchOpRet, err error) {
	ops := make([]string, 0, len(entries))
	for _, entry := range entries {
		ops = append(ops, storage.URIMove(entry.SrcEntry.Bucket, entry.SrcEntry.Key, entry.DstEntry.Bucket, entry.DstEntry.Key, entry.Force))
	}
	return m.Batch(ops)
}

func (m *BucketManager) BatchChgm(entries []ChgmEntryPath) (ret []storage.BatchOpRet, err error) {
	ops := make([]string, 0, len(entries))
	for _, entry := range entries {
		ops = append(ops, storage.URIChangeMime(entry.Bucket, entry.Key, entry.MimeType))
	}
	return m.Batch(ops)
}

func (m *BucketManager) BatchChtype(entries []ChtypeEntryPath) (ret []storage.BatchOpRet, err error) {
	ops := make([]string, 0, len(entries))
	for _, entry := range entries {
		ops = append(ops, storage.URIChangeType(entry.Bucket, entry.Key, entry.FileType))
	}
	return m.Batch(ops)
}

func (m *BucketManager) CheckAsyncFetchStatus(bucket, id string) (ret storage.AsyncFetchRet, err error) {

	reqUrl, err := m.ApiReqHost(bucket)
	if err != nil {
		return
	}

	reqUrl += ("/sisyphus/fetch?id=" + id)

	ctx := auth.WithCredentialsType(context.Background(), m.Mac, auth.TokenQiniu)
	err = m.Client.Call(ctx, &ret, "GET", reqUrl, nil)
	return
}

// 禁用七牛存储中的对象
func (m *BucketManager) ChStatus(bucket, key string, forbidden bool) (err error) {
	ctx := auth.WithCredentials(context.Background(), m.Mac)
	reqHost, reqErr := m.RsReqHost(bucket)
	if reqErr != nil {
		err = reqErr
		return
	}
	var status int
	if forbidden {
		status = 1
	} else {
		status = 0
	}
	reqURL := fmt.Sprintf("%s%s", reqHost, fmt.Sprintf("/chstatus/%s/status/%d", storage.EncodedEntry(bucket, key), status))
	headers := http.Header{}
	headers.Add("Content-Type", conf.CONTENT_TYPE_FORM)
	err = m.Client.Call(ctx, nil, "POST", reqURL, headers)
	return

}

func (m *BucketManager) BatchDeleteAfterDays(entries []DeleteAfterDaysEntryPath) (ret []storage.BatchOpRet, err error) {
	ops := make([]string, 0, len(entries))
	for _, entry := range entries {
		ops = append(ops, storage.URIDeleteAfterDays(entry.Bucket, entry.Key, entry.DeleteAfterDays))
	}
	return m.Batch(ops)
}

func (m *BucketManager) BatchSign(urls []string, deadline int64) (ret []string, err error) {
	for _, url := range urls {
		finalUrl, pErr := m.PrivateUrl(url, deadline)
		if pErr != nil {
			err = pErr
			return
		}
		ret = append(ret, finalUrl)
	}
	return
}

// NewBucketManager 用来构建一个新的资源管理对象
func NewBucketManager(mac *qbox.Mac, cfg *storage.Config) *BucketManager {
	bm := storage.NewBucketManager(mac, cfg)

	return &BucketManager{
		BucketManager: bm,
	}
}

// NewBucketManagerEx 用来构建一个新的资源管理对象
func NewBucketManagerEx(mac *qbox.Mac, cfg *storage.Config, client *storage.Client) *BucketManager {
	bm := storage.NewBucketManagerEx(mac, cfg, client)
	return &BucketManager{
		BucketManager: bm,
	}
}

// GetBucketManager 返回一个BucketManager 指针
func GetBucketManagerWithConfig(cfg *storage.Config) *BucketManager {
	account, gErr := GetAccount()
	if gErr != nil {
		fmt.Fprintf(os.Stderr, "GetBucketManager: %v\n", gErr)
		os.Exit(1)
	}
	mac := qbox.NewMac(account.AccessKey, account.SecretKey)
	return NewBucketManager(mac, cfg)
}

func GetBucketManager() *BucketManager {
	account, gErr := GetAccount()
	if gErr != nil {
		fmt.Fprintf(os.Stderr, "GetBucketManager: %v\n", gErr)
		os.Exit(1)
	}
	mac := qbox.NewMac(account.AccessKey, account.SecretKey)
	cfg := storage.Config{
		UpHost:        UpHost(),
		IoHost:        IoHost(),
		RsHost:        RsHost(),
		ApiHost:       ApiHost(),
		RsfHost:       RsfHost(),
		CentralRsHost: RsHost(),
	}
	storage.UcHost = UcHost()
	return NewBucketManager(mac, &cfg)
}

func GetUpHost(cfg *storage.Config, ak, bucket string) (upHost string, err error) {

	var zone *storage.Zone
	if cfg.Zone != nil {
		zone = cfg.Zone
	} else {
		if v, zoneErr := storage.GetZone(ak, bucket); zoneErr != nil {
			err = zoneErr
			return
		} else {
			zone = v
		}
	}

	scheme := "http://"
	if cfg.UseHTTPS {
		scheme = "https://"
	}

	host := zone.SrcUpHosts[0]
	if cfg.UseCdnDomains {
		host = zone.CdnUpHosts[0]
	}

	upHost = fmt.Sprintf("%s%s", scheme, host)
	return
}
<|endoftext|>


<commit_before>package ai

import (
	"log"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/hysios/apiai-go"
)

type ApiAiOrder struct {
	AiResult apiai.Result
}

func (aa ApiAiOrder) Score() float64 {
	return aa.AiResult.Score
}

func (aa ApiAiOrder) Query() string {
	return aa.AiResult.ResolvedQuery
}

func (aa ApiAiOrder) Items() []Item {
	products := aa.Products()
	quantities := aa.Quantities()

	for i, q := range quantities {
		if len(products) >= i+1 {
			products[i].Quantity = q.Quantity
			products[i].Unit = q.Unit
		}
	}

	return products
}

func (aa ApiAiOrder) Products() []Item {
	return aa.ExtractProducts("products")
}

func (aa ApiAiOrder) Quantities() []Item {
	return aa.ExtractQuantities("quantity")
}

func (aa ApiAiOrder) GiftItems() []Item {
	gifts := aa.GiftProducts()
	quantities := aa.GiftQuantities()

	for i, q := range quantities {
		if len(gifts) >= i+1 {
			gifts[i].Quantity = q.Quantity
			products[i].Unit = q.Unit
		}
	}

	return gifts
}

func (aa ApiAiOrder) GiftProducts() []Item {
	return aa.ExtractProducts("gifts")
}

func (aa ApiAiOrder) GiftQuantities() []Item {
	return aa.ExtractQuantities("giftNumber")
}

func (aa ApiAiOrder) Address() string {
	if a, exist := aa.AiResult.Params["street-address"]; exist {

		rt := reflect.TypeOf(a)
		vals := reflect.ValueOf(a)

		switch rt.Kind() {
		case reflect.Slice:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.Array:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.String:
			return vals.Interface().(string)
		}
	}

	return ""
}

func (aa ApiAiOrder) Customer() string {
	if c, exist := aa.AiResult.Params["customer"]; exist {

		rt := reflect.TypeOf(c)
		vals := reflect.ValueOf(c)

		switch rt.Kind() {
		case reflect.Slice:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.Array:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.String:
			return vals.Interface().(string)
		}
	}

	return ""
}

func (aa ApiAiOrder) Time() time.Time {
	if t, exist := aa.AiResult.Params["date"]; exist {
		if aiTime, err := time.Parse("2006-01-02", t.(string)); err == nil {
			return aiTime
		}
	}

	return time.Time{}
}

func (aa ApiAiOrder) Fulfiled() bool {
	return true
}

func (aa ApiAiOrder) Note() string {
	if imp, exist := aa.AiResult.Params["important"]; exist {
		return imp.(string)
	}

	return ""
}

func (aa ApiAiOrder) ExtractProducts(t string) []Item {
	result := make([]Item, 0, 50)

	if products, exist := aa.AiResult.Params[t]; exist {
		ps := reflect.ValueOf(products)

		for i := 0; i < ps.Len(); i++ {
			p := ps.Index(i)
			name := p.Interface().(string)
			item := Item{Product: name}
			result = append(result, item)
		}
	}

	return result
}

func (aa ApiAiOrder) ExtractQuantities(t string) []Item {
	result := make([]Item, 0, 50)

	if quantities, exist := aa.AiResult.Params[t]; exist {
		qs := reflect.ValueOf(quantities)

		for i := 0; i < qs.Len(); i++ {
			q := qs.Index(i).Interface()

			switch t := q.(type) {
			case string:
				qs := q.(string)
				qi := extractQuantity(qs)
				item := Item{Quantity: qi}
				result = append(result, item)
			case float64:
				qf := q.(float64)
				item := Item{Quantity: int(qf)}
				result = append(result, item)
			case map[string]interface{}:
				log.Printf("....... quantity .........")
				qf := t["number"].(float64)
				quantity := int(qf)
				unit := t["unit"].(string)
				item := Item{Quantity: quantity, Unit: unit}
				result = append(result, item)
			default:
				log.Println("Unknown Quantity type: %v", t)
			}
		}
	}

	return result
}

func extractQuantity(s string) int {
	nums := strings.TrimFunc(s, TrimToNum)
	numsCgd := DBCtoSBC(nums)

	if len(numsCgd) > 0 {
		q, _ := strconv.Atoi(numsCgd)
		return q
	} else {
		return 0
	}
	// re := regexp.MustCompile("[0-9]+")
}

func TrimToNum(r rune) bool {
	if n := r - '0'; n >= 0 && n <= 9 {
		return false
	} else if m := r - '０'; m >= 0 && m <= 9 {
		return false
	}

	return true
}

func DBCtoSBC(s string) string {
	retstr := ""
	for _, i := range s {
		inside_code := i
		if inside_code == 12288 {
			inside_code = 32
		} else {
			inside_code -= 65248
		}
		if inside_code < 32 || inside_code > 126 {
			retstr += string(i)
		} else {
			retstr += string(inside_code)
		}
	}
	return retstr
}
<commit_msg>fix product unit<commit_after>package ai

import (
	"log"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/hysios/apiai-go"
)

type ApiAiOrder struct {
	AiResult apiai.Result
}

func (aa ApiAiOrder) Score() float64 {
	return aa.AiResult.Score
}

func (aa ApiAiOrder) Query() string {
	return aa.AiResult.ResolvedQuery
}

func (aa ApiAiOrder) Items() []Item {
	products := aa.Products()
	quantities := aa.Quantities()

	for i, q := range quantities {
		if len(products) >= i+1 {
			products[i].Quantity = q.Quantity
			products[i].Unit = q.Unit
		}
	}

	return products
}

func (aa ApiAiOrder) Products() []Item {
	return aa.ExtractProducts("products")
}

func (aa ApiAiOrder) Quantities() []Item {
	return aa.ExtractQuantities("quantity")
}

func (aa ApiAiOrder) GiftItems() []Item {
	gifts := aa.GiftProducts()
	quantities := aa.GiftQuantities()

	for i, q := range quantities {
		if len(gifts) >= i+1 {
			gifts[i].Quantity = q.Quantity
			gifts[i].Unit = q.Unit
		}
	}

	return gifts
}

func (aa ApiAiOrder) GiftProducts() []Item {
	return aa.ExtractProducts("gifts")
}

func (aa ApiAiOrder) GiftQuantities() []Item {
	return aa.ExtractQuantities("giftNumber")
}

func (aa ApiAiOrder) Address() string {
	if a, exist := aa.AiResult.Params["street-address"]; exist {

		rt := reflect.TypeOf(a)
		vals := reflect.ValueOf(a)

		switch rt.Kind() {
		case reflect.Slice:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.Array:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.String:
			return vals.Interface().(string)
		}
	}

	return ""
}

func (aa ApiAiOrder) Customer() string {
	if c, exist := aa.AiResult.Params["customer"]; exist {

		rt := reflect.TypeOf(c)
		vals := reflect.ValueOf(c)

		switch rt.Kind() {
		case reflect.Slice:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.Array:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.String:
			return vals.Interface().(string)
		}
	}

	return ""
}

func (aa ApiAiOrder) Time() time.Time {
	if t, exist := aa.AiResult.Params["date"]; exist {
		if aiTime, err := time.Parse("2006-01-02", t.(string)); err == nil {
			return aiTime
		}
	}

	return time.Time{}
}

func (aa ApiAiOrder) Fulfiled() bool {
	return true
}

func (aa ApiAiOrder) Note() string {
	if imp, exist := aa.AiResult.Params["important"]; exist {
		return imp.(string)
	}

	return ""
}

func (aa ApiAiOrder) ExtractProducts(t string) []Item {
	result := make([]Item, 0, 50)

	if products, exist := aa.AiResult.Params[t]; exist {
		ps := reflect.ValueOf(products)

		for i := 0; i < ps.Len(); i++ {
			p := ps.Index(i)
			name := p.Interface().(string)
			item := Item{Product: name}
			result = append(result, item)
		}
	}

	return result
}

func (aa ApiAiOrder) ExtractQuantities(t string) []Item {
	result := make([]Item, 0, 50)

	if quantities, exist := aa.AiResult.Params[t]; exist {
		qs := reflect.ValueOf(quantities)

		for i := 0; i < qs.Len(); i++ {
			q := qs.Index(i).Interface()

			switch t := q.(type) {
			case string:
				qs := q.(string)
				qi := extractQuantity(qs)
				item := Item{Quantity: qi}
				result = append(result, item)
			case float64:
				qf := q.(float64)
				item := Item{Quantity: int(qf)}
				result = append(result, item)
			case map[string]interface{}:
				log.Printf("....... quantity .........")
				qf := t["number"].(float64)
				quantity := int(qf)
				unit := t["unit"].(string)
				item := Item{Quantity: quantity, Unit: unit}
				result = append(result, item)
			default:
				log.Println("Unknown Quantity type: %v", t)
			}
		}
	}

	return result
}

func extractQuantity(s string) int {
	nums := strings.TrimFunc(s, TrimToNum)
	numsCgd := DBCtoSBC(nums)

	if len(numsCgd) > 0 {
		q, _ := strconv.Atoi(numsCgd)
		return q
	} else {
		return 0
	}
	// re := regexp.MustCompile("[0-9]+")
}

func TrimToNum(r rune) bool {
	if n := r - '0'; n >= 0 && n <= 9 {
		return false
	} else if m := r - '０'; m >= 0 && m <= 9 {
		return false
	}

	return true
}

func DBCtoSBC(s string) string {
	retstr := ""
	for _, i := range s {
		inside_code := i
		if inside_code == 12288 {
			inside_code = 32
		} else {
			inside_code -= 65248
		}
		if inside_code < 32 || inside_code > 126 {
			retstr += string(i)
		} else {
			retstr += string(inside_code)
		}
	}
	return retstr
}
<|endoftext|>


<commit_before>package ai

import (
	"log"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/hysios/apiai-go"
)

type ApiAiOrder struct {
	AiResult apiai.Result
}

func (aa ApiAiOrder) Score() float64 {
	return aa.AiResult.Score
}

func (aa ApiAiOrder) Query() string {
	return aa.AiResult.ResolvedQuery
}

func (aa ApiAiOrder) Items() []Item {
	products := aa.Products()
	quantities := aa.Quantities()

	return composeItems(products, quantities)

	// for i, q := range quantities {
	// 	if len(products) >= i+1 {
	// 		products[i].Quantity = q.Quantity
	// 		products[i].Unit = q.Unit
	// 	}
	// }

	// return products
}

func (aa ApiAiOrder) Products() []Item {
	return aa.ExtractProducts("products")
}

func (aa ApiAiOrder) Quantities() []Item {
	return aa.ExtractQuantities("quantity")
}

func (aa ApiAiOrder) GiftItems() []Item {
	gifts := aa.GiftProducts()
	quantities := aa.GiftQuantities()

	return composeItems(gifts, quantities)

	// for i, q := range quantities {
	// 	if len(gifts) >= i+1 {
	// 		gifts[i].Quantity = q.Quantity
	// 		gifts[i].Unit = q.Unit
	// 	}
	// }

	// return gifts
}

func composeItems(products []Item, quantities []Item) []Item {
	result := make([]Item, 0, 0)
	l := len(products)
	qlen := len(quantities)

	if l < qlen {
		l = qlen
	}

	for i := 0; i < l; i++ {
		item := Item{}

		if len(products) >= i+1 {
			p := products[i]
			item.Product = p.Product
		}

		if len(quantities) >= i+1 {
			q := quantities[i]
			item.Quantity = q.Quantity
			item.Unit = q.Unit
		}

		result = append(result, item)
	}

	return result
}

func (aa ApiAiOrder) GiftProducts() []Item {
	return aa.ExtractProducts("gifts")
}

func (aa ApiAiOrder) GiftQuantities() []Item {
	return aa.ExtractQuantities("giftNumber")
}

func (aa ApiAiOrder) Address() string {
	if a, exist := aa.AiResult.Params["street-address"]; exist {

		rt := reflect.TypeOf(a)
		vals := reflect.ValueOf(a)

		switch rt.Kind() {
		case reflect.Slice:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.Array:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.String:
			return vals.Interface().(string)
		}
	}

	return ""
}

func (aa ApiAiOrder) Customer() string {
	if c, exist := aa.AiResult.Params["customer"]; exist {

		rt := reflect.TypeOf(c)
		vals := reflect.ValueOf(c)

		switch rt.Kind() {
		case reflect.Slice:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.Array:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.String:
			return vals.Interface().(string)
		}
	}

	return ""
}

func (aa ApiAiOrder) Count() int {
	if c, exist := aa.AiResult.Params["number"]; exist {
		switch c.(type) {
		case float64:
			fval := c.(float64)
			return int(fval)
		case float32:
			fval := c.(float32)
			return int(fval)
		case int:
			return c.(int)
		case string:
			sval := c.(string)
			ival, err := strconv.Atoi(sval)
			if err != nil {
				return 0
			} else {
				return ival
			}
		}
	}

	return 0
}

func (aa ApiAiOrder) Duration() string {
	if c, exist := aa.AiResult.Params["duration"]; exist {
		return c.(string)
	}

	return ""
}

func (aa ApiAiOrder) Time() time.Time {
	if t, exist := aa.AiResult.Params["date"]; exist {
		if aiTime, err := time.Parse("2006-01-02", t.(string)); err == nil {
			return aiTime
		}
	}

	return time.Time{}
}

func (aa ApiAiOrder) Fulfiled() bool {
	return true
}

func (aa ApiAiOrder) Note() string {
	if imp, exist := aa.AiResult.Params["important"]; exist {
		return imp.(string)
	}

	return ""
}

func (aa ApiAiOrder) ExtractProducts(t string) []Item {
	result := make([]Item, 0, 50)

	if products, exist := aa.AiResult.Params[t]; exist {
		ps := reflect.ValueOf(products)

		for i := 0; i < ps.Len(); i++ {
			p := ps.Index(i)
			name := p.Interface().(string)
			item := Item{Product: name}
			result = append(result, item)
		}
	}

	return result
}

func (aa ApiAiOrder) ExtractQuantities(t string) []Item {
	result := make([]Item, 0, 50)

	if quantities, exist := aa.AiResult.Params[t]; exist {
		qs := reflect.ValueOf(quantities)

		for i := 0; i < qs.Len(); i++ {
			q := qs.Index(i).Interface()

			switch t := q.(type) {
			case string:
				qs := q.(string)
				qi := extractQuantity(qs)
				item := Item{Quantity: qi}
				result = append(result, item)
			case float64:
				qf := q.(float64)
				item := Item{Quantity: int(qf)}
				result = append(result, item)
			case map[string]interface{}:
				log.Printf("quantity: %v\n", t)
				qf := t["number"].(float64)
				quantity := int(qf)
				item := Item{Quantity: quantity}

				if unit, ok := t["unit"].(string); ok {
					unit = strings.Replace(unit, "龘", "", -1)
					unit = strings.Replace(unit, " ", "", -1)
					item.Unit = unit
				}

				result = append(result, item)
			default:
				log.Println("Unknown Quantity type: %v", t)
			}
		}
	}

	return result
}

func extractQuantity(s string) int {
	nums := strings.TrimFunc(s, TrimToNum)
	numsCgd := DBCtoSBC(nums)

	if len(numsCgd) > 0 {
		q, _ := strconv.Atoi(numsCgd)
		return q
	} else {
		return 0
	}
	// re := regexp.MustCompile("[0-9]+")
}

func TrimToNum(r rune) bool {
	if n := r - '0'; n >= 0 && n <= 9 {
		return false
	} else if m := r - '０'; m >= 0 && m <= 9 {
		return false
	}

	return true
}

func DBCtoSBC(s string) string {
	retstr := ""
	for _, i := range s {
		inside_code := i
		if inside_code == 12288 {
			inside_code = 32
		} else {
			inside_code -= 65248
		}
		if inside_code < 32 || inside_code > 126 {
			retstr += string(i)
		} else {
			retstr += string(inside_code)
		}
	}
	return retstr
}
<commit_msg>mode2<commit_after>package ai

import (
	"log"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/hysios/apiai-go"
)

type ApiAiOrder struct {
	AiResult apiai.Result
}

func (aa ApiAiOrder) Mode() int {
	mode := 1

	if _, ok := aa.AiResult.Params["productItems"]; ok {
		mode = 2
	}

	return mode
}

func (aa ApiAiOrder) Score() float64 {
	return aa.AiResult.Score
}

func (aa ApiAiOrder) Query() string {
	return aa.AiResult.ResolvedQuery
}

func (aa ApiAiOrder) Items() []Item {
	if aa.Mode() == 2 {
		return aa.ExtractProductItems("productItems")
	}

	products := aa.Products()
	quantities := aa.Quantities()

	return composeItems(products, quantities)

	// for i, q := range quantities {
	// 	if len(products) >= i+1 {
	// 		products[i].Quantity = q.Quantity
	// 		products[i].Unit = q.Unit
	// 	}
	// }

	// return products
}

func (aa ApiAiOrder) Products() []Item {
	return aa.ExtractProducts("products")
}

func (aa ApiAiOrder) Quantities() []Item {
	return aa.ExtractQuantities("quantity")
}

func (aa ApiAiOrder) GiftItems() []Item {
	if aa.Mode() == 2 {
		return aa.ExtractProductItems("giftItems")
	}

	gifts := aa.GiftProducts()
	quantities := aa.GiftQuantities()

	return composeItems(gifts, quantities)

	// for i, q := range quantities {
	// 	if len(gifts) >= i+1 {
	// 		gifts[i].Quantity = q.Quantity
	// 		gifts[i].Unit = q.Unit
	// 	}
	// }

	// return gifts
}

func composeItems(products []Item, quantities []Item) []Item {
	result := make([]Item, 0, 0)
	l := len(products)
	qlen := len(quantities)

	if l < qlen {
		l = qlen
	}

	for i := 0; i < l; i++ {
		item := Item{}

		if len(products) >= i+1 {
			p := products[i]
			item.Product = p.Product
		}

		if len(quantities) >= i+1 {
			q := quantities[i]
			item.Quantity = q.Quantity
			item.Unit = q.Unit
		}

		result = append(result, item)
	}

	return result
}

func (aa ApiAiOrder) GiftProducts() []Item {
	return aa.ExtractProducts("gifts")
}

func (aa ApiAiOrder) GiftQuantities() []Item {
	return aa.ExtractQuantities("giftNumber")
}

func (aa ApiAiOrder) Address() string {
	if a, exist := aa.AiResult.Params["street-address"]; exist {

		rt := reflect.TypeOf(a)
		vals := reflect.ValueOf(a)

		switch rt.Kind() {
		case reflect.Slice:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.Array:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.String:
			return vals.Interface().(string)
		}
	}

	return ""
}

func (aa ApiAiOrder) Customer() string {
	if c, exist := aa.AiResult.Params["customer"]; exist {

		rt := reflect.TypeOf(c)
		vals := reflect.ValueOf(c)

		switch rt.Kind() {
		case reflect.Slice:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.Array:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.String:
			return vals.Interface().(string)
		}
	}

	return ""
}

func (aa ApiAiOrder) Count() int {
	if c, exist := aa.AiResult.Params["number"]; exist {
		switch c.(type) {
		case float64:
			fval := c.(float64)
			return int(fval)
		case float32:
			fval := c.(float32)
			return int(fval)
		case int:
			return c.(int)
		case string:
			sval := c.(string)
			ival, err := strconv.Atoi(sval)
			if err != nil {
				return 0
			} else {
				return ival
			}
		}
	}

	return 0
}

func (aa ApiAiOrder) Duration() string {
	if c, exist := aa.AiResult.Params["duration"]; exist {
		return c.(string)
	}

	return ""
}

func (aa ApiAiOrder) Time() time.Time {
	if t, exist := aa.AiResult.Params["date"]; exist {
		if aiTime, err := time.Parse("2006-01-02", t.(string)); err == nil {
			return aiTime
		}
	}

	return time.Time{}
}

func (aa ApiAiOrder) Fulfiled() bool {
	return true
}

func (aa ApiAiOrder) Note() string {
	if imp, exist := aa.AiResult.Params["important"]; exist {
		return imp.(string)
	}

	return ""
}

// MODE 1 extracting, by key products
func (aa ApiAiOrder) ExtractProducts(t string) []Item {
	result := make([]Item, 0, 50)

	if products, exist := aa.AiResult.Params[t]; exist {
		ps := reflect.ValueOf(products)

		for i := 0; i < ps.Len(); i++ {
			p := ps.Index(i)
			name := p.Interface().(string)
			item := Item{Product: name}
			result = append(result, item)
		}
	}

	return result
}

// MODE 2 extracting, by key productItems
func (aa ApiAiOrder) ExtractProductItems(s string) []Item {
	result := make([]Item, 0)

	if prodItems, ok := aa.AiResult.Params[s]; ok {
		ps := reflect.ValueOf(prodItems)

		for i := 0; i < ps.Len(); i++ {
			var name, unit string
			var quantity int

			p := ps.Index(i)
			prodItem := p.Interface().(map[string]interface{})
			name, _ = prodItem["product"].(string)
			quanMap, _ := prodItem["quantity"].(map[string]interface{})
			numberFloat, ok := quanMap["number"].(float64)
			if ok {
				quantity = int(numberFloat)
			}

			unit, _ = quanMap["unit"].(string)

			item := Item{
				Product:  name,
				Quantity: quantity,
				Unit:     unit,
			}
			result = append(result, item)
		}
	}

	return result
}

func (aa ApiAiOrder) ExtractQuantities(t string) []Item {
	result := make([]Item, 0, 50)

	if quantities, exist := aa.AiResult.Params[t]; exist {
		qs := reflect.ValueOf(quantities)

		for i := 0; i < qs.Len(); i++ {
			q := qs.Index(i).Interface()

			switch t := q.(type) {
			case string:
				qs := q.(string)
				qi := extractQuantity(qs)
				item := Item{Quantity: qi}
				result = append(result, item)
			case float64:
				qf := q.(float64)
				item := Item{Quantity: int(qf)}
				result = append(result, item)
			case map[string]interface{}:
				log.Printf("quantity: %v\n", t)
				qf := t["number"].(float64)
				quantity := int(qf)
				item := Item{Quantity: quantity}

				if unit, ok := t["unit"].(string); ok {
					unit = strings.Replace(unit, "龘", "", -1)
					unit = strings.Replace(unit, " ", "", -1)
					item.Unit = unit
				}

				result = append(result, item)
			default:
				log.Println("Unknown Quantity type: %v", t)
			}
		}
	}

	return result
}

func extractQuantity(s string) int {
	nums := strings.TrimFunc(s, TrimToNum)
	numsCgd := DBCtoSBC(nums)

	if len(numsCgd) > 0 {
		q, _ := strconv.Atoi(numsCgd)
		return q
	} else {
		return 0
	}
	// re := regexp.MustCompile("[0-9]+")
}

func TrimToNum(r rune) bool {
	if n := r - '0'; n >= 0 && n <= 9 {
		return false
	} else if m := r - '０'; m >= 0 && m <= 9 {
		return false
	}

	return true
}

func DBCtoSBC(s string) string {
	retstr := ""
	for _, i := range s {
		inside_code := i
		if inside_code == 12288 {
			inside_code = 32
		} else {
			inside_code -= 65248
		}
		if inside_code < 32 || inside_code > 126 {
			retstr += string(i)
		} else {
			retstr += string(inside_code)
		}
	}
	return retstr
}
<|endoftext|>


<commit_before>package image // import "github.com/docker/docker/image"

import (
	"runtime"

	"github.com/docker/docker/layer"
	"github.com/sirupsen/logrus"
)

// TypeLayers is used for RootFS.Type for filesystems organized into layers.
const TypeLayers = "layers"

// typeLayersWithBase is an older format used by Windows up to v1.12. We
// explicitly handle this as an error case to ensure that a daemon which still
// has an older image like this on disk can still start, even though the
// image itself is not usable. See https://github.com/docker/docker/pull/25806.
const typeLayersWithBase = "layers+base"

// RootFS describes images root filesystem
// This is currently a placeholder that only supports layers. In the future
// this can be made into an interface that supports different implementations.
type RootFS struct {
	Type    string         `json:"type"`
	DiffIDs []layer.DiffID `json:"diff_ids,omitempty"`
}

// NewRootFS returns empty RootFS struct
func NewRootFS() *RootFS {
	return &RootFS{Type: TypeLayers}
}

// Append appends a new diffID to rootfs
func (r *RootFS) Append(id layer.DiffID) {
	r.DiffIDs = append(r.DiffIDs, id)
}

// Clone returns a copy of the RootFS
func (r *RootFS) Clone() *RootFS {
	newRoot := NewRootFS()
	newRoot.Type = r.Type
	newRoot.DiffIDs = append(r.DiffIDs)
	return newRoot
}

// ChainID returns the ChainID for the top layer in RootFS.
func (r *RootFS) ChainID() layer.ChainID {
	if runtime.GOOS == "windows" && r.Type == typeLayersWithBase {
		logrus.Warnf("Layer type is unsupported on this platform. DiffIDs: '%v'", r.DiffIDs)
		return ""
	}
	return layer.CreateChainID(r.DiffIDs)
}
<commit_msg>image: do actual RootFS.DiffIDs copying in Clone()<commit_after>package image // import "github.com/docker/docker/image"

import (
	"runtime"

	"github.com/docker/docker/layer"
	"github.com/sirupsen/logrus"
)

// TypeLayers is used for RootFS.Type for filesystems organized into layers.
const TypeLayers = "layers"

// typeLayersWithBase is an older format used by Windows up to v1.12. We
// explicitly handle this as an error case to ensure that a daemon which still
// has an older image like this on disk can still start, even though the
// image itself is not usable. See https://github.com/docker/docker/pull/25806.
const typeLayersWithBase = "layers+base"

// RootFS describes images root filesystem
// This is currently a placeholder that only supports layers. In the future
// this can be made into an interface that supports different implementations.
type RootFS struct {
	Type    string         `json:"type"`
	DiffIDs []layer.DiffID `json:"diff_ids,omitempty"`
}

// NewRootFS returns empty RootFS struct
func NewRootFS() *RootFS {
	return &RootFS{Type: TypeLayers}
}

// Append appends a new diffID to rootfs
func (r *RootFS) Append(id layer.DiffID) {
	r.DiffIDs = append(r.DiffIDs, id)
}

// Clone returns a copy of the RootFS
func (r *RootFS) Clone() *RootFS {
	newRoot := NewRootFS()
	newRoot.Type = r.Type
	newRoot.DiffIDs = make([]layer.DiffID, len(r.DiffIDs))
	copy(newRoot.DiffIDs, r.DiffIDs)
	return newRoot
}

// ChainID returns the ChainID for the top layer in RootFS.
func (r *RootFS) ChainID() layer.ChainID {
	if runtime.GOOS == "windows" && r.Type == typeLayersWithBase {
		logrus.Warnf("Layer type is unsupported on this platform. DiffIDs: '%v'", r.DiffIDs)
		return ""
	}
	return layer.CreateChainID(r.DiffIDs)
}
<|endoftext|>


<commit_before>package litebrite

import (
	"bytes"
	"fmt"
	"go/scanner"
	"go/token"
	"html/template"
	"sort"
)

type codeSegment struct {
	Code  string // a segment of source code with the same style
	Pos   int    // the position of the segment in the source
	Class string // the CSS class for the segment
}

// token types
const (
	KEYWORD  = "keyword"
	IDENT    = "ident"
	LITERAL  = "literal"
	OPERATOR = "operator"
)

// getClass returns the CSS class name for the specified token type.
func getClass(tok token.Token) (class string) {
	switch {
	case tok.IsKeyword():
		return KEYWORD
	case tok.IsLiteral():
		if tok == token.IDENT {
			return IDENT
		} else {
			return LITERAL
		}
	case tok.IsOperator():
		return OPERATOR
	default:
		panic("unknown token type!")
	}
	return
}

// getClasses returns a map from source token positions to CSS class names.
func getClasses(src []byte) map[int]string {
	tokens := make(map[int]string)

	var s scanner.Scanner
	fset := token.NewFileSet()
	file := fset.AddFile("", fset.Base(), len(src))
	s.Init(file, src, nil, 0)
	for {
		pos, tok, _ := s.Scan()
		if tok == token.EOF {
			break
		}
		tokens[int(pos)-1] = getClass(tok) // WTF -1
	}

	return tokens
}

// getSegments splits the source into same-token-type chunks.
func getSegments(src []byte) map[int]*codeSegment {
	segments := make(map[int]*codeSegment)
	positions := make([]int, 0)

	// find the starting positions of all tokens
	var s scanner.Scanner
	fset := token.NewFileSet()
	file := fset.AddFile("", fset.Base(), len(src))
	s.Init(file, src, nil, 0)
	for {
		pos, tok, _ := s.Scan()
		if tok == token.EOF {
			break
		}
		positions = append(positions, int(pos)-1) // WTF -1
	}

	// to help with slicing, add one more position at the end
	positions = append(positions, positions[len(positions)-1]+1)

	// split the source at each position to get segments
	for i := 1; i < len(positions); i++ {
		start, end := positions[i-1], positions[i]
		segment := string(src[start:end])
		segments[start] = &codeSegment{Code: segment, Pos: start}
	}

	return segments
}

// styleSegments adds the CSS class names in classes to the segments in src.
// The class name classes[i] is applied to the segment src[i].
func styleSegments(src map[int]*codeSegment, classes map[int]string) {
	for pos, class := range classes {
		src[pos].Class = class
	}
}

const CODE = "
%s
"
const ELEM = `<div class="{{.Class}}">{{.Code}}</div>`

var elemT = template.Must(template.New("golang-elem").Parse(ELEM))

// buildHTML constructs an HTML string of elements from the segments in src.
func buildHTML(src map[int]*codeSegment) string {
	indices := make([]int, 0)
	for pos := range src {
		indices = append(indices, pos)
	}
	sort.Ints(indices)

	var b bytes.Buffer
	for _, pos := range indices {
		elemT.Execute(&b, src[pos])
	}

	return fmt.Sprintf(CODE, string(b.Bytes()))
}

// Highlight returns an HTML fragment containing elements for all Go tokens
// in src.  The elements will be of the form
CODE
, where
// TYPE is the token type ("keyword", "operator", "literal", or "ident")
// and CODE is the source fragment.  The entire fragment is wrapped with

// and  tags.
func Highlight(src string) string {
	data := []byte(src)
	segs := getSegments(data)
	classes := getClasses(data)
	styleSegments(segs, classes)
	return buildHTML(segs)
}
<commit_msg>custom highlighter types<commit_after>package litebrite

import (
	"bytes"
	"go/scanner"
	"go/token"
	"html/template"
)

type codeSegment struct {
	Code  string // a segment of source code with the same style
	Pos   int    // the position of the segment in the source
	Tok   token.Token // the token type of the segment
	Class string
}

// getSegments splits the source into same-token-type chunks.
func getSegments(src []byte) []*codeSegment {
	segments := make([]*codeSegment, 0)

	// find the starting positions of all segments
	var s scanner.Scanner
	fset := token.NewFileSet()
	file := fset.AddFile("", fset.Base(), len(src))
	s.Init(file, src, nil, 1)
	for {
		pos, tok, _ := s.Scan()
		if tok == token.EOF {
			break
		}
		segment := &codeSegment{Pos: int(pos)-1, Tok: tok} // WTF -1
		segments = append(segments, segment)
	}

	// split the source at each position to get segments
	for i, segment := range segments {
		if i+1 == len(segments) {
			segment.Code = string(src[segment.Pos:])
		} else {
			next := segments[i+1]
			segment.Code = string(src[segment.Pos:next.Pos])
		}
	}

	return segments
}

const ELEM = `{{with .Class}}<div class="{{.}}">{{end}}{{.Code}}{{with .Class}}</div>{{end}}`

var elemT = template.Must(template.New("golang-elem").Parse(ELEM))

// buildHTML constructs an HTML string of elements from the segments in src.
func buildHTML(src []*codeSegment) string {
	var b bytes.Buffer
	for _, segment := range src {
		elemT.Execute(&b, segment)
	}

	return string(b.Bytes())
}

// Highlighter contains the CSS class names that are applied to the
// corresponding source code token types.
type Highlighter struct {
	OperatorClass string
	IdentClass string
	LiteralClass string
	KeywordClass string
	CommentClass string
}

// highlightSegment adds the CSS class name specified by h to the segment.
func (h *Highlighter) highlightSegment(s *codeSegment) {
	switch {
	case s.Tok.IsKeyword():
		s.Class = h.KeywordClass
	case s.Tok.IsLiteral():
		if s.Tok == token.IDENT {
			s.Class = h.IdentClass
		} else {
			s.Class = h.LiteralClass
		}
	case s.Tok.IsOperator():
		if s.Tok == token.SEMICOLON && s.Code != ";" {
			return
		}
		s.Class = h.OperatorClass
	case s.Tok == token.COMMENT:
		s.Class = h.CommentClass
	default:
		panic("unknown token type!")
	}
}

// Highlight returns an HTML fragment containing elements for all Go tokens
// in src.  The elements will be of the form
CODE

// where TYPE_CLASS is the CSS class name provided in h corresponding to the
// token type of CODE.  For instance, if CODE is a keyword, then TYPE_CLASS
// will be h.keywordClass.
func (h *Highlighter) Highlight(src string) string {
	data := []byte(src)
	segments := getSegments(data)
	for _, segment := range segments {
		h.highlightSegment(segment)
	}
	return buildHTML(segments)
}
<|endoftext|>


<commit_before>// Package imagscale is middleware handler for scaling image in golang. Use for serving images in different predefined formats.
//
//
//  package main
//
//	import (
//		"fmt"
//		"github.com/codegangsta/negroni"
//		"github.com/go-martini/martini"
//		"github.com/gographics/imagick/imagick"
//		"github.com/vanng822/imgscale/imgscale"
//		"net/http"
//	)
//
//	func main() {
//		imagick.Initialize()
//		defer imagick.Terminate()
//		// Negroni
//		n := negroni.New()
//		handler := imgscale.Configure("./config/formats.json")
//		// Example how to run an arbitrary remote image provider
//		handler.SetImageProvider(imgscale.NewImageProviderHTTP(""))
//		n.UseHandler(handler)
//		go http.ListenAndServe(fmt.Sprintf("%s:%d", "127.0.0.1", 8081), n)
//
//		// Martini
//		app := martini.Classic()
//		app.Use(imgscale.Configure("./config/formats.json").ServeHTTP)
//		go http.ListenAndServe(fmt.Sprintf("%s:%d", "127.0.0.1", 8080), app)
//
//		// http.Handle
//		handler2 := imgscale.Configure("./config/formats.json")
//		// Example how to run an host limited remote image provider, can not run arbitrary here
//		handler2.SetImageProvider(imgscale.NewImageProviderHTTP("http://127.0.0.1:8080/img/original/"))
//		http.Handle("/", handler2)
//		http.ListenAndServe(fmt.Sprintf("%s:%d", "", 8082), nil)
//	}
package imgscale
<commit_msg>Fix indenting<commit_after>// Package imagscale is middleware handler for scaling image in golang. Use for serving images in different predefined formats.
//
//
//	package main
//
//	import (
//		"fmt"
//		"github.com/codegangsta/negroni"
//		"github.com/go-martini/martini"
//		"github.com/gographics/imagick/imagick"
//		"github.com/vanng822/imgscale/imgscale"
//		"net/http"
//	)
//
//	func main() {
//		imagick.Initialize()
//		defer imagick.Terminate()
//		// Negroni
//		n := negroni.New()
//		handler := imgscale.Configure("./config/formats.json")
//		// Example how to run an arbitrary remote image provider
//		handler.SetImageProvider(imgscale.NewImageProviderHTTP(""))
//		n.UseHandler(handler)
//		go http.ListenAndServe(fmt.Sprintf("%s:%d", "127.0.0.1", 8081), n)
//
//		// Martini
//		app := martini.Classic()
//		app.Use(imgscale.Configure("./config/formats.json").ServeHTTP)
//		go http.ListenAndServe(fmt.Sprintf("%s:%d", "127.0.0.1", 8080), app)
//
//		// http.Handle
//		handler2 := imgscale.Configure("./config/formats.json")
//		// Example how to run an host limited remote image provider, can not run arbitrary here
//		handler2.SetImageProvider(imgscale.NewImageProviderHTTP("http://127.0.0.1:8080/img/original/"))
//		http.Handle("/", handler2)
//		http.ListenAndServe(fmt.Sprintf("%s:%d", "", 8082), nil)
//	}
package imgscale
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package auth

import (
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"time"

	"k8s.io/api/certificates/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	v1beta1client "k8s.io/client-go/kubernetes/typed/certificates/v1beta1"
	"k8s.io/client-go/util/cert"
	"k8s.io/kubernetes/test/e2e/framework"

	. "github.com/onsi/ginkgo"
)

var _ = SIGDescribe("Certificates API", func() {
	f := framework.NewDefaultFramework("certificates")

	It("should support building a client with a CSR", func() {
		const commonName = "tester-csr"

		pk, err := cert.NewPrivateKey()
		framework.ExpectNoError(err)

		pkder := x509.MarshalPKCS1PrivateKey(pk)
		pkpem := pem.EncodeToMemory(&pem.Block{
			Type:  "RSA PRIVATE KEY",
			Bytes: pkder,
		})

		csrb, err := cert.MakeCSR(pk, &pkix.Name{CommonName: commonName, Organization: []string{"system:masters"}}, nil, nil)
		framework.ExpectNoError(err)

		csr := &v1beta1.CertificateSigningRequest{
			ObjectMeta: metav1.ObjectMeta{
				GenerateName: commonName + "-",
			},
			Spec: v1beta1.CertificateSigningRequestSpec{
				Request: csrb,
				Usages: []v1beta1.KeyUsage{
					v1beta1.UsageSigning,
					v1beta1.UsageKeyEncipherment,
					v1beta1.UsageClientAuth,
				},
			},
		}
		csrs := f.ClientSet.CertificatesV1beta1().CertificateSigningRequests()

		framework.Logf("creating CSR")
		csr, err = csrs.Create(csr)
		framework.ExpectNoError(err)

		csrName := csr.Name

		framework.Logf("approving CSR")
		framework.ExpectNoError(wait.Poll(5*time.Second, time.Minute, func() (bool, error) {
			csr.Status.Conditions = []v1beta1.CertificateSigningRequestCondition{
				{
					Type:    v1beta1.CertificateApproved,
					Reason:  "E2E",
					Message: "Set from an e2e test",
				},
			}
			csr, err = csrs.UpdateApproval(csr)
			if err != nil {
				csr, _ = csrs.Get(csrName, metav1.GetOptions{})
				framework.Logf("err updating approval: %v", err)
				return false, nil
			}
			return true, nil
		}))

		framework.Logf("waiting for CSR to be signed")
		framework.ExpectNoError(wait.Poll(5*time.Second, time.Minute, func() (bool, error) {
			csr, _ = csrs.Get(csrName, metav1.GetOptions{})
			if err != nil {
				return false, err
			}
			if len(csr.Status.Certificate) == 0 {
				framework.Logf("csr not signed yet")
				return false, nil
			}
			return true, nil
		}))

		framework.Logf("testing the client")
		rcfg, err := framework.LoadConfig()
		framework.ExpectNoError(err)

		rcfg.TLSClientConfig.CertData = csr.Status.Certificate
		rcfg.TLSClientConfig.KeyData = pkpem
		rcfg.TLSClientConfig.CertFile = ""
		rcfg.BearerToken = ""
		rcfg.AuthProvider = nil
		rcfg.Username = ""
		rcfg.Password = ""

		newClient, err := v1beta1client.NewForConfig(rcfg)
		framework.ExpectNoError(err)
		framework.ExpectNoError(newClient.CertificateSigningRequests().Delete(csrName, nil))
	})
})
<commit_msg>should get return err and check it<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package auth

import (
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"time"

	"k8s.io/api/certificates/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	v1beta1client "k8s.io/client-go/kubernetes/typed/certificates/v1beta1"
	"k8s.io/client-go/util/cert"
	"k8s.io/kubernetes/test/e2e/framework"

	. "github.com/onsi/ginkgo"
)

var _ = SIGDescribe("Certificates API", func() {
	f := framework.NewDefaultFramework("certificates")

	It("should support building a client with a CSR", func() {
		const commonName = "tester-csr"

		pk, err := cert.NewPrivateKey()
		framework.ExpectNoError(err)

		pkder := x509.MarshalPKCS1PrivateKey(pk)
		pkpem := pem.EncodeToMemory(&pem.Block{
			Type:  "RSA PRIVATE KEY",
			Bytes: pkder,
		})

		csrb, err := cert.MakeCSR(pk, &pkix.Name{CommonName: commonName, Organization: []string{"system:masters"}}, nil, nil)
		framework.ExpectNoError(err)

		csr := &v1beta1.CertificateSigningRequest{
			ObjectMeta: metav1.ObjectMeta{
				GenerateName: commonName + "-",
			},
			Spec: v1beta1.CertificateSigningRequestSpec{
				Request: csrb,
				Usages: []v1beta1.KeyUsage{
					v1beta1.UsageSigning,
					v1beta1.UsageKeyEncipherment,
					v1beta1.UsageClientAuth,
				},
			},
		}
		csrs := f.ClientSet.CertificatesV1beta1().CertificateSigningRequests()

		framework.Logf("creating CSR")
		csr, err = csrs.Create(csr)
		framework.ExpectNoError(err)

		csrName := csr.Name

		framework.Logf("approving CSR")
		framework.ExpectNoError(wait.Poll(5*time.Second, time.Minute, func() (bool, error) {
			csr.Status.Conditions = []v1beta1.CertificateSigningRequestCondition{
				{
					Type:    v1beta1.CertificateApproved,
					Reason:  "E2E",
					Message: "Set from an e2e test",
				},
			}
			csr, err = csrs.UpdateApproval(csr)
			if err != nil {
				csr, _ = csrs.Get(csrName, metav1.GetOptions{})
				framework.Logf("err updating approval: %v", err)
				return false, nil
			}
			return true, nil
		}))

		framework.Logf("waiting for CSR to be signed")
		framework.ExpectNoError(wait.Poll(5*time.Second, time.Minute, func() (bool, error) {
			csr, err = csrs.Get(csrName, metav1.GetOptions{})
			if err != nil {
				framework.Logf("error getting csr: %v", err)
				return false, nil
			}
			if len(csr.Status.Certificate) == 0 {
				framework.Logf("csr not signed yet")
				return false, nil
			}
			return true, nil
		}))

		framework.Logf("testing the client")
		rcfg, err := framework.LoadConfig()
		framework.ExpectNoError(err)

		rcfg.TLSClientConfig.CertData = csr.Status.Certificate
		rcfg.TLSClientConfig.KeyData = pkpem
		rcfg.TLSClientConfig.CertFile = ""
		rcfg.BearerToken = ""
		rcfg.AuthProvider = nil
		rcfg.Username = ""
		rcfg.Password = ""

		newClient, err := v1beta1client.NewForConfig(rcfg)
		framework.ExpectNoError(err)
		framework.ExpectNoError(newClient.CertificateSigningRequests().Delete(csrName, nil))
	})
})
<|endoftext|>