<commit_before>package smi

import (
	"unsafe"

	"github.com/sleepinggenius2/gosmi/smi/internal"
	"github.com/sleepinggenius2/gosmi/types"
)

// SmiImport *smiGetFirstImport(SmiModule *smiModulePtr)
func GetFirstImport(smiModulePtr *types.SmiModule) *types.SmiImport {
	if smiModulePtr == nil {
		return nil
	}
	modulePtr := (*internal.Module)(unsafe.Pointer(smiModulePtr))
	importPtr := modulePtr.Imports.First
	if importPtr == nil {
		return nil
	}
	return &importPtr.SmiImport
}

// SmiImport *smiGetNextImport(SmiImport *smiImportPtr)
func GetNextImport(smiImportPtr *types.SmiImport) *types.SmiImport {
	if smiImportPtr != nil {
		return nil
	}
	importPtr := (*internal.Import)(unsafe.Pointer(smiImportPtr))
	if importPtr.Next == nil {
		return nil
	}
	return &importPtr.Next.SmiImport
}

// int smiIsImported(SmiModule *smiModulePtr, SmiModule *importedModulePtr, char *importedName)
func IsImported(smiModulePtr *types.SmiModule, importedModulePtr *types.SmiModule, importedName string) bool {
	if smiModulePtr == nil || importedName == "" {
		return false
	}
	modulePtr := (*internal.Module)(unsafe.Pointer(smiModulePtr))
	importPtr := modulePtr.Imports.Get(types.SmiIdentifier(importedName))
	if importPtr == nil {
		return false
	}
	return importedModulePtr == nil || importPtr.Module == importedModulePtr.Name
}
<commit_msg>Fixes typo in GetNextImport<commit_after>package smi

import (
	"unsafe"

	"github.com/sleepinggenius2/gosmi/smi/internal"
	"github.com/sleepinggenius2/gosmi/types"
)

// SmiImport *smiGetFirstImport(SmiModule *smiModulePtr)
func GetFirstImport(smiModulePtr *types.SmiModule) *types.SmiImport {
	if smiModulePtr == nil {
		return nil
	}
	modulePtr := (*internal.Module)(unsafe.Pointer(smiModulePtr))
	importPtr := modulePtr.Imports.First
	if importPtr == nil {
		return nil
	}
	return &importPtr.SmiImport
}

// SmiImport *smiGetNextImport(SmiImport *smiImportPtr)
func GetNextImport(smiImportPtr *types.SmiImport) *types.SmiImport {
	if smiImportPtr == nil {
		return nil
	}
	importPtr := (*internal.Import)(unsafe.Pointer(smiImportPtr))
	if importPtr.Next == nil {
		return nil
	}
	return &importPtr.Next.SmiImport
}

// int smiIsImported(SmiModule *smiModulePtr, SmiModule *importedModulePtr, char *importedName)
func IsImported(smiModulePtr *types.SmiModule, importedModulePtr *types.SmiModule, importedName string) bool {
	if smiModulePtr == nil || importedName == "" {
		return false
	}
	modulePtr := (*internal.Module)(unsafe.Pointer(smiModulePtr))
	importPtr := modulePtr.Imports.Get(types.SmiIdentifier(importedName))
	if importPtr == nil {
		return false
	}
	return importedModulePtr == nil || importPtr.Module == importedModulePtr.Name
}
<|endoftext|>


<commit_before>// Copyright 2018 The Prometheus 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 procfs

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"strconv"
	"strings"
)

// For the proc file format details,
// see https://elixir.bootlin.com/linux/v4.17/source/net/unix/af_unix.c#L2815
// and https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/net.h#L48.

const (
	netUnixKernelPtrIdx = 0
	netUnixRefCountIdx  = 1
	netUnixFlagsIdx     = 3
	netUnixTypeIdx      = 4
	netUnixStateIdx     = 5
)

const (
	netUnixTypeStream    = 1
	netUnixTypeDgram     = 2
	netUnixTypeSeqpacket = 5

	netUnixFlagListen = 1 << 16

	netUnixStateUnconnected  = 1
	netUnixStateConnecting   = 2
	netUnixStateConnected    = 3
	netUnixStateDisconnected = 4
)

var errInvalidKernelPtrFmt = errors.New("Invalid Num(kernal the kernel table slot number) format")

// NetUnixType is the type of the type field.
type NetUnixType uint64

// NetUnixFlags is the type of the flags field.
type NetUnixFlags uint64

// NetUnixState is the type of the state field.
type NetUnixState uint64

// NetUnixLine represents a line of /proc/net/unix.
type NetUnixLine struct {
	KernelPtr string
	RefCount  uint64
	Protocol  uint64
	Flags     NetUnixFlags
	Type      NetUnixType
	State     NetUnixState
	Inode     uint64
	Path      string
}

// NetUnix holds the data read from /proc/net/unix.
type NetUnix struct {
	Rows []*NetUnixLine
}

// NewNetUnix returns data read from /proc/net/unix.
func NewNetUnix() (*NetUnix, error) {
	fs, err := NewFS(DefaultMountPoint)
	if err != nil {
		return nil, err
	}

	return fs.NewNetUnix()
}

// NewNetUnix returns data read from /proc/net/unix.
func (fs FS) NewNetUnix() (*NetUnix, error) {
	return NewNetUnixByPath(fs.proc.Path("net/unix"))
}

// NewNetUnixByPath returns data read from /proc/net/unix by file path.
// It might returns an error with partial parsed data, if an error occur after some data parsed.
func NewNetUnixByPath(path string) (*NetUnix, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	nu := &NetUnix{
		Rows: make([]*NetUnixLine, 0, 32),
	}
	scanner := bufio.NewScanner(f)
	// Omit the header line.
	scanner.Scan()
	header := scanner.Text()
	// From the man page of proc(5), it dose not contain an Inode field,
	// but in actually it exists.
	// This code works for both cases.
	hasInode := strings.Contains(header, "Inode")
	for scanner.Scan() {
		line := scanner.Text()
		item, err := nu.parseLine(line, hasInode)
		if err != nil {
			return nu, err
		}
		nu.Rows = append(nu.Rows, item)
	}

	return nu, nil
}

func (u *NetUnix) parseLine(line string, hasInode bool) (*NetUnixLine, error) {
	fields := strings.Fields(line)
	kernelPtr, err := u.parseKernelPtr(fields[netUnixKernelPtrIdx])
	if err != nil {
		return nil, fmt.Errorf("Parse Unix domain num(%s) failed: %s", fields[netUnixKernelPtrIdx], err)
	}
	users, err := u.parseUsers(fields[netUnixRefCountIdx])
	if err != nil {
		return nil, fmt.Errorf("Parse Unix domain ref count(%s) failed: %s", fields[netUnixRefCountIdx], err)
	}
	flags, err := u.parseFlags(fields[netUnixFlagsIdx])
	if err != nil {
		return nil, fmt.Errorf("Parse Unix domain flags(%s) failed: %s", fields[netUnixFlagsIdx], err)
	}
	typ, err := u.parseType(fields[netUnixTypeIdx])
	if err != nil {
		return nil, fmt.Errorf("Parse Unix domain type(%s) failed: %s", fields[netUnixTypeIdx], err)
	}
	state, err := u.parseState(fields[netUnixStateIdx])
	if err != nil {
		return nil, fmt.Errorf("Parse Unix domain state(%s) failed: %s", fields[netUnixStateIdx], err)
	}
	var inode uint64
	if hasInode {
		inodeStr := fields[len(fields)-2]
		inode, err = u.parseInode(inodeStr)
		if err != nil {
			return nil, fmt.Errorf("Parse Unix domain inode(%s) failed: %s", inodeStr, err)
		}
	}

	nuLine := &NetUnixLine{
		KernelPtr: kernelPtr,
		RefCount:  users,
		Type:      typ,
		Flags:     flags,
		State:     state,
		Path:      fields[len(fields)-1],
		Inode:     inode,
	}

	return nuLine, nil
}

func (u NetUnix) parseKernelPtr(str string) (string, error) {
	if !strings.HasSuffix(str, ":") {
		return "", errInvalidKernelPtrFmt
	}
	return str[:len(str)-1], nil
}

func (u NetUnix) parseUsers(hexStr string) (uint64, error) {
	return strconv.ParseUint(hexStr, 16, 32)
}

func (u NetUnix) parseProtocol(hexStr string) (uint64, error) {
	return strconv.ParseUint(hexStr, 16, 32)
}

func (u NetUnix) parseType(hexStr string) (NetUnixType, error) {
	typ, err := strconv.ParseUint(hexStr, 16, 16)
	if err != nil {
		return 0, err
	}
	return NetUnixType(typ), nil
}

func (u NetUnix) parseFlags(hexStr string) (NetUnixFlags, error) {
	flags, err := strconv.ParseUint(hexStr, 16, 32)
	if err != nil {
		return 0, err
	}
	return NetUnixFlags(flags), nil
}

func (u NetUnix) parseState(hexStr string) (NetUnixState, error) {
	st, err := strconv.ParseInt(hexStr, 16, 8)
	if err != nil {
		return 0, err
	}
	return NetUnixState(st), nil
}

func (u NetUnix) parseInode(inodeStr string) (uint64, error) {
	return strconv.ParseUint(inodeStr, 10, 64)
}

func (t NetUnixType) String() string {
	switch t {
	case netUnixTypeStream:
		return "stream"
	case netUnixTypeDgram:
		return "dgram"
	case netUnixTypeSeqpacket:
		return "seqpacket"
	}
	return "unknown"
}

func (f NetUnixFlags) String() string {
	switch f {
	case netUnixFlagListen:
		return "accepton"
	default:
		return "default"
	}
}

func (s NetUnixState) String() string {
	switch s {
	case netUnixStateUnconnected:
		return "unconnected"
	case netUnixStateConnecting:
		return "connecting"
	case netUnixStateConnected:
		return "connected"
	case netUnixStateDisconnected:
		return "disconnected"
	}
	return "unknown"
}
<commit_msg>check error from scanner for unix domain parser<commit_after>// Copyright 2018 The Prometheus 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 procfs

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"strconv"
	"strings"
)

// For the proc file format details,
// see https://elixir.bootlin.com/linux/v4.17/source/net/unix/af_unix.c#L2815
// and https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/net.h#L48.

const (
	netUnixKernelPtrIdx = 0
	netUnixRefCountIdx  = 1
	netUnixFlagsIdx     = 3
	netUnixTypeIdx      = 4
	netUnixStateIdx     = 5
)

const (
	netUnixTypeStream    = 1
	netUnixTypeDgram     = 2
	netUnixTypeSeqpacket = 5

	netUnixFlagListen = 1 << 16

	netUnixStateUnconnected  = 1
	netUnixStateConnecting   = 2
	netUnixStateConnected    = 3
	netUnixStateDisconnected = 4
)

var errInvalidKernelPtrFmt = errors.New("Invalid Num(kernal the kernel table slot number) format")

// NetUnixType is the type of the type field.
type NetUnixType uint64

// NetUnixFlags is the type of the flags field.
type NetUnixFlags uint64

// NetUnixState is the type of the state field.
type NetUnixState uint64

// NetUnixLine represents a line of /proc/net/unix.
type NetUnixLine struct {
	KernelPtr string
	RefCount  uint64
	Protocol  uint64
	Flags     NetUnixFlags
	Type      NetUnixType
	State     NetUnixState
	Inode     uint64
	Path      string
}

// NetUnix holds the data read from /proc/net/unix.
type NetUnix struct {
	Rows []*NetUnixLine
}

// NewNetUnix returns data read from /proc/net/unix.
func NewNetUnix() (*NetUnix, error) {
	fs, err := NewFS(DefaultMountPoint)
	if err != nil {
		return nil, err
	}

	return fs.NewNetUnix()
}

// NewNetUnix returns data read from /proc/net/unix.
func (fs FS) NewNetUnix() (*NetUnix, error) {
	return NewNetUnixByPath(fs.proc.Path("net/unix"))
}

// NewNetUnixByPath returns data read from /proc/net/unix by file path.
// It might returns an error with partial parsed data, if an error occur after some data parsed.
func NewNetUnixByPath(path string) (*NetUnix, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	nu := &NetUnix{
		Rows: make([]*NetUnixLine, 0, 32),
	}
	scanner := bufio.NewScanner(f)
	// Omit the header line.
	scanner.Scan()
	header := scanner.Text()
	// From the man page of proc(5), it dose not contain an Inode field,
	// but in actually it exists.
	// This code works for both cases.
	hasInode := strings.Contains(header, "Inode")
	for scanner.Scan() {
		line := scanner.Text()
		item, err := nu.parseLine(line, hasInode)
		if err != nil {
			return nu, err
		}
		nu.Rows = append(nu.Rows, item)
	}

	return nu, scanner.Err()
}

func (u *NetUnix) parseLine(line string, hasInode bool) (*NetUnixLine, error) {
	fields := strings.Fields(line)
	kernelPtr, err := u.parseKernelPtr(fields[netUnixKernelPtrIdx])
	if err != nil {
		return nil, fmt.Errorf("Parse Unix domain num(%s) failed: %s", fields[netUnixKernelPtrIdx], err)
	}
	users, err := u.parseUsers(fields[netUnixRefCountIdx])
	if err != nil {
		return nil, fmt.Errorf("Parse Unix domain ref count(%s) failed: %s", fields[netUnixRefCountIdx], err)
	}
	flags, err := u.parseFlags(fields[netUnixFlagsIdx])
	if err != nil {
		return nil, fmt.Errorf("Parse Unix domain flags(%s) failed: %s", fields[netUnixFlagsIdx], err)
	}
	typ, err := u.parseType(fields[netUnixTypeIdx])
	if err != nil {
		return nil, fmt.Errorf("Parse Unix domain type(%s) failed: %s", fields[netUnixTypeIdx], err)
	}
	state, err := u.parseState(fields[netUnixStateIdx])
	if err != nil {
		return nil, fmt.Errorf("Parse Unix domain state(%s) failed: %s", fields[netUnixStateIdx], err)
	}
	var inode uint64
	if hasInode {
		inodeStr := fields[len(fields)-2]
		inode, err = u.parseInode(inodeStr)
		if err != nil {
			return nil, fmt.Errorf("Parse Unix domain inode(%s) failed: %s", inodeStr, err)
		}
	}

	nuLine := &NetUnixLine{
		KernelPtr: kernelPtr,
		RefCount:  users,
		Type:      typ,
		Flags:     flags,
		State:     state,
		Path:      fields[len(fields)-1],
		Inode:     inode,
	}

	return nuLine, nil
}

func (u NetUnix) parseKernelPtr(str string) (string, error) {
	if !strings.HasSuffix(str, ":") {
		return "", errInvalidKernelPtrFmt
	}
	return str[:len(str)-1], nil
}

func (u NetUnix) parseUsers(hexStr string) (uint64, error) {
	return strconv.ParseUint(hexStr, 16, 32)
}

func (u NetUnix) parseProtocol(hexStr string) (uint64, error) {
	return strconv.ParseUint(hexStr, 16, 32)
}

func (u NetUnix) parseType(hexStr string) (NetUnixType, error) {
	typ, err := strconv.ParseUint(hexStr, 16, 16)
	if err != nil {
		return 0, err
	}
	return NetUnixType(typ), nil
}

func (u NetUnix) parseFlags(hexStr string) (NetUnixFlags, error) {
	flags, err := strconv.ParseUint(hexStr, 16, 32)
	if err != nil {
		return 0, err
	}
	return NetUnixFlags(flags), nil
}

func (u NetUnix) parseState(hexStr string) (NetUnixState, error) {
	st, err := strconv.ParseInt(hexStr, 16, 8)
	if err != nil {
		return 0, err
	}
	return NetUnixState(st), nil
}

func (u NetUnix) parseInode(inodeStr string) (uint64, error) {
	return strconv.ParseUint(inodeStr, 10, 64)
}

func (t NetUnixType) String() string {
	switch t {
	case netUnixTypeStream:
		return "stream"
	case netUnixTypeDgram:
		return "dgram"
	case netUnixTypeSeqpacket:
		return "seqpacket"
	}
	return "unknown"
}

func (f NetUnixFlags) String() string {
	switch f {
	case netUnixFlagListen:
		return "accepton"
	default:
		return "default"
	}
}

func (s NetUnixState) String() string {
	switch s {
	case netUnixStateUnconnected:
		return "unconnected"
	case netUnixStateConnecting:
		return "connecting"
	case netUnixStateConnected:
		return "connected"
	case netUnixStateDisconnected:
		return "disconnected"
	}
	return "unknown"
}
<|endoftext|>


<commit_before>package linenotify

import (
	"bytes"
	"fmt"
	"io"
	"sync/atomic"

	"github.com/utahta/go-linenotify"
	"github.com/utahta/momoclo-channel/lib/backoff"
	"github.com/utahta/momoclo-channel/lib/config"
	"github.com/utahta/momoclo-channel/lib/log"
	"github.com/utahta/momoclo-channel/model"
	"github.com/utahta/momoclo-channel/model/linenotification"
	"golang.org/x/net/context"
	"golang.org/x/sync/errgroup"
	"google.golang.org/appengine/urlfetch"
)

type client struct {
	*linenotify.Client
	users   []*model.LineNotification
	context context.Context
}

func newClient(ctx context.Context) (*client, error) {
	c := &client{
		Client:  linenotify.New(),
		context: ctx,
	}
	c.HTTPClient = urlfetch.Client(ctx)

	users, err := linenotification.Repository.GetAll(ctx)
	if err != nil {
		return nil, err
	}
	c.users = users

	return c, nil
}

func (c *client) notifyChannelItem(param *ChannelParam) error {
	message := fmt.Sprintf("\n%s\n%s\n%s", param.Title, param.Item.Title, param.Item.Url)

	if len(param.Item.Images) > 0 {
		image := param.Item.Images[0]
		if err := c.notifyMessage(message, image.Url); err != nil {
			return err
		}

		for _, image := range param.Item.Images[1:] {
			c.notifyMessage(" ", image.Url) // go on
		}
	} else {
		return c.notifyMessage(message, "")
	}
	return nil
}

func (c *client) notifyMessage(message, imageURL string) error {
	if config.C.Linenotify.Disabled {
		return nil
	}

	// prepare cache image
	if imageURL != "" {
		_, err := fetchImage(c.HTTPClient, imageURL)
		if err != nil {
			return err
		}
		defer clearImage(imageURL)
	}

	var (
		ctx             = c.context
		count     int32 = 0
		workQueue       = make(chan bool, 100) // max goroutine
	)
	defer close(workQueue)

	eg := &errgroup.Group{}
	for _, user := range c.users {
		workQueue <- true
		user := user

		eg.Go(func() error {
			defer func() {
				<-workQueue
			}()

			token, err := user.Token()
			if err != nil {
				log.Errorf(ctx, "Failed to get token. hash:%v err:%v", user.Id, err)
				return err
			}

			var image io.Reader
			if b := cacheImage(imageURL); b != nil {
				image = bytes.NewReader(b)
			}

			err = backoff.Retry(3, func() error {
				err := c.Notify(token, message, "", "", image)
				if err == linenotify.ErrNotifyInvalidAccessToken {
					err = nil
					user.Delete(c.context)
					log.Infof(ctx, "Delete LINE Notify token. hash:%s", user.Id)
				}
				return err
			})
			if err != nil {
				log.Errorf(ctx, "Failed to LINE Notify. hash:%v err:%v", user.Id, err)
				return err
			}
			atomic.AddInt32(&count, 1)
			return nil
		})
	}
	eg.Wait()

	log.Infof(ctx, "LINE Notify. message:%s imageURL:%s len:%v/%d", message, imageURL, count, len(c.users))
	return nil
}
<commit_msg>Fix log output<commit_after>package linenotify

import (
	"bytes"
	"fmt"
	"io"
	"sync/atomic"

	"github.com/utahta/go-linenotify"
	"github.com/utahta/momoclo-channel/lib/backoff"
	"github.com/utahta/momoclo-channel/lib/config"
	"github.com/utahta/momoclo-channel/lib/log"
	"github.com/utahta/momoclo-channel/model"
	"github.com/utahta/momoclo-channel/model/linenotification"
	"golang.org/x/net/context"
	"golang.org/x/sync/errgroup"
	"google.golang.org/appengine/urlfetch"
)

type client struct {
	*linenotify.Client
	users   []*model.LineNotification
	context context.Context
}

func newClient(ctx context.Context) (*client, error) {
	c := &client{
		Client:  linenotify.New(),
		context: ctx,
	}
	c.HTTPClient = urlfetch.Client(ctx)

	users, err := linenotification.Repository.GetAll(ctx)
	if err != nil {
		return nil, err
	}
	c.users = users

	return c, nil
}

func (c *client) notifyChannelItem(param *ChannelParam) error {
	message := fmt.Sprintf("\n%s\n%s\n%s", param.Title, param.Item.Title, param.Item.Url)

	if len(param.Item.Images) > 0 {
		image := param.Item.Images[0]
		if err := c.notifyMessage(message, image.Url); err != nil {
			return err
		}

		for _, image := range param.Item.Images[1:] {
			c.notifyMessage(" ", image.Url) // go on
		}
	} else {
		return c.notifyMessage(message, "")
	}
	return nil
}

func (c *client) notifyMessage(message, imageURL string) error {
	if config.C.Linenotify.Disabled {
		return nil
	}

	// prepare cache image
	if imageURL != "" {
		_, err := fetchImage(c.HTTPClient, imageURL)
		if err != nil {
			return err
		}
		defer clearImage(imageURL)
	}

	var (
		ctx             = c.context
		count     int32 = 0
		workQueue       = make(chan bool, 100) // max goroutine
	)
	defer close(workQueue)

	eg := &errgroup.Group{}
	for _, user := range c.users {
		workQueue <- true
		user := user

		eg.Go(func() error {
			defer func() {
				<-workQueue
			}()

			token, err := user.Token()
			if err != nil {
				log.Errorf(ctx, "Failed to get token. hash:%v err:%v", user.Id, err)
				return err
			}

			var image io.Reader
			if b := cacheImage(imageURL); b != nil {
				image = bytes.NewReader(b)
			}

			err = backoff.Retry(3, func() error {
				err := c.Notify(token, message, "", "", image)
				if err == linenotify.ErrNotifyInvalidAccessToken {
					err = nil
					user.Delete(c.context)
					log.Infof(ctx, "Delete LINE Notify token. user:%#v", user)
				}
				return err
			})
			if err != nil {
				log.Errorf(ctx, "Failed to LINE Notify. hash:%v err:%v", user.Id, err)
				return err
			}
			atomic.AddInt32(&count, 1)
			return nil
		})
	}
	eg.Wait()

	log.Infof(ctx, "LINE Notify. message:%s imageURL:%s len:%v/%d", message, imageURL, count, len(c.users))
	return nil
}
<|endoftext|>


<commit_before>package exec

import (
	"fmt"
	"gosubli.me/mg"
	"gosubli.me/sink"
	"os/exec"
	"regexp"
	"strings"
	"sync"
	"time"
)

var (
	zChunk  = []byte{}
	zChunks = [][]byte{}

	caseCache = struct {
		sync.Mutex
		m map[string]*regexp.Regexp
	}{m: map[string]*regexp.Regexp{}}
)

type StreamRes struct {
	Chunks [][]byte
	Stream string
	End    bool
}

type Res struct {
	Attrs  []Attr
	Chunks [][]byte
	Ok     bool
	Dur    string
	Mem    string
}

type Attr map[string]string

type Switch struct {
	Case        []string
	Negative    bool
	Discard     bool
	Fallthrough bool

	cases []*regexp.Regexp
	attrs []Attr
}

type Exec struct {
	Cid    string
	Stream string

	Wd            string
	Fn            string
	Input         string
	DiscardStdout bool
	DiscardStderr bool
	Env           map[string]string
	Cmd           string
	Args          []string
	Switch        []Switch
	SwitchOk      bool

	filter   func([]byte) []byte
	fini     func()
	switches []*Switch
	brk      *mg.Broker
	sink     *sink.Chan
	buf      struct {
		s     [][]byte
		n     int
		merge bool
	}
}

func (e *Exec) Call() (interface{}, string) {
	e.initSwitches()
	cl, err := e.cl()

	if e.fini != nil {
		defer e.fini()
	}

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

	wg := &sync.WaitGroup{}
	wg.Add(1)
	go e.stream(wg)
	var c *exec.Cmd
	var dur mg.MsDuration

	for _, c = range cl {
		err, dur = procs.Run(e.Cid, c)
		if err != nil {
			break
		}
	}

	e.sink.Close()
	wg.Wait()

	res := Res{
		Chunks: e.chunks(),
		Mem:    maxRss(c.ProcessState),
		Dur:    dur.String(),
	}
	res.Attrs, res.Ok = e.cmdAttrsOk(c)

	return res, mg.Err(err)
}

func (e *Exec) cl() ([]*exec.Cmd, error) {
	switch e.Cmd {
	case ".play":
		return playCmd(e)
	default:
		return []*exec.Cmd{mkCmd(e, e.Input, e.Cmd, e.Args...)}, nil
	}
}

func (e *Exec) stream(wg *sync.WaitGroup) {
	defer wg.Done()

	tck := time.NewTicker(500 * time.Millisecond)
	for {
		select {
		case s, ok := <-e.sink.C:
			if e.filter != nil {
				s = e.filter(s)
			}

			eof := !ok
			s = e.sw(s)
			e.put(s, eof)
			if eof {
				return
			}
		case <-tck.C:
			if len(e.buf.s) != 0 {
				e.flush(false)
			}
		}
	}
}

func (e *Exec) put(s []byte, eof bool) {
	switch {
	case crSuffix(s):
		e.buf.merge = false
		e.buf.s = append(e.buf.s, s)
	case !e.buf.merge || len(e.buf.s) == 0:
		e.buf.merge = true
		e.buf.s = append(e.buf.s, zChunk)
		fallthrough
	default:
		i := len(e.buf.s) - 1
		e.buf.s[i] = append(e.buf.s[i], s...)
	}

	e.buf.n += len(s)
	if eof || e.buf.n >= 32*1024 {
		e.flush(eof)
	}
}

func (e *Exec) chunks() [][]byte {
	if e.buf.s != nil {
		return e.buf.s
	}
	// be nice to the client by not sending them `null` when they expect an array
	return zChunks
}

func (e *Exec) flush(eof bool) {
	if e.Stream == "" {
		return
	}

	e.brk.Send(mg.Response{
		Token: e.Stream,
		Data: StreamRes{
			Chunks: e.chunks(),
			End:    eof,
		},
	})

	for i, s := range e.buf.s {
		e.buf.s[i] = s[:0]
	}
	e.buf.s = e.buf.s[:0]
	e.buf.n = 0
}

func (e *Exec) initSwitches() error {
	for i, _ := range e.Switch {
		sw := &e.Switch[i]
		for _, s := range sw.Case {
			if s != "" {
				rx, err := rx(s)
				if err != nil {
					return err
				}
				sw.cases = append(sw.cases, rx)
			}
		}
		e.switches = append(e.switches, sw)
	}
	return nil
}

func (e *Exec) cmdAttrsOk(c *exec.Cmd) ([]Attr, bool) {
	attrs, swOk := e.collectAttrs()
	if e.SwitchOk && len(e.Switch) > 0 {
		return attrs, swOk
	}
	return attrs, c.ProcessState != nil && c.ProcessState.Success()
}

func (e *Exec) collectAttrs() ([]Attr, bool) {
	attrs := []Attr{}
	ok := true
	for _, sw := range e.switches {
		if len(sw.attrs) > 0 {
			ok = false
			attrs = append(attrs, sw.attrs...)
		}
	}
	return attrs, ok
}

func (e *Exec) sw(s []byte) []byte {
	discard := false

	for _, sw := range e.switches {
		al, matched := sw.match(s)
		sw.attrs = append(sw.attrs, al...)

		if matched != sw.Negative {
			if sw.Discard {
				discard = true
			}

			if !sw.Fallthrough {
				break
			}
		}
	}

	if discard {
		return nil
	}
	return s
}

func (s *Switch) match(p []byte) ([]Attr, bool) {
	if len(s.cases) == 0 {
		return nil, true
	}

	for _, rx := range s.cases {
		ml := rx.FindAllSubmatch(p, -1)
		if len(ml) > 0 {
			// p (and by extension ml, mt) is owned by the caller so make sure it gets copied
			names := rx.SubexpNames()
			al := []Attr{}
			for _, mt := range ml {
				attr := Attr{}
				if len(mt) == len(names) {
					for i, k := range names {
						if k != "" {
							attr[k] = string(mt[i])
						}
					}
				}
				if len(mt) != 0 {
					al = append(al, attr)
				}
			}
			return al, true
		}
	}

	return nil, false
}

func rx(s string) (*regexp.Regexp, error) {
	caseCache.Lock()
	defer caseCache.Unlock()

	if rx, ok := caseCache.m[s]; ok {
		return rx, nil
	}

	rx, err := regexp.Compile(s)
	if err != nil {
		return nil, fmt.Errorf("cannot compile regexp `%v`: %v", s, err.Error())
	}

	caseCache.m[s] = rx
	return rx, nil
}

func crSuffix(s []byte) bool {
	i := len(s) - 1
	return i >= 0 && s[i] == '\r'
}

func mkCmd(e *Exec, input string, cmd string, args ...string) *exec.Cmd {
	c := exec.Command(cmd, args...)
	c.Dir = e.Wd
	c.Env = mg.Env(e.Env)
	if !e.DiscardStdout {
		c.Stdout = e.sink
	}
	if !e.DiscardStderr {
		c.Stderr = e.sink
	}
	if input != "" {
		c.Stdin = strings.NewReader(input)
	}
	return c
}

func init() {
	mg.Register("exec", func(b *mg.Broker) mg.Caller {
		return &Exec{
			brk:  b,
			sink: sink.NewBufferedChan(100),
		}
	})
}
<commit_msg>* remove the line terminators from the chunks so users don't need to worry about it<commit_after>package exec

import (
	"bytes"
	"fmt"
	"gosubli.me/mg"
	"gosubli.me/sink"
	"os/exec"
	"regexp"
	"strings"
	"sync"
	"time"
)

var (
	zChunk  = []byte{}
	zChunks = [][]byte{}

	caseCache = struct {
		sync.Mutex
		m map[string]*regexp.Regexp
	}{m: map[string]*regexp.Regexp{}}
)

type StreamRes struct {
	Chunks [][]byte
	Stream string
	End    bool
}

type Res struct {
	Attrs  []Attr
	Chunks [][]byte
	Ok     bool
	Dur    string
	Mem    string
}

type Attr map[string]string

type Switch struct {
	Case        []string
	Negative    bool
	Discard     bool
	Fallthrough bool

	cases []*regexp.Regexp
	attrs []Attr
}

type Exec struct {
	Cid    string
	Stream string

	Wd            string
	Fn            string
	Input         string
	DiscardStdout bool
	DiscardStderr bool
	Env           map[string]string
	Cmd           string
	Args          []string
	Switch        []Switch
	SwitchOk      bool

	filter   func([]byte) []byte
	fini     func()
	switches []*Switch
	brk      *mg.Broker
	sink     *sink.Chan
	buf      struct {
		s     [][]byte
		n     int
		merge bool
	}
}

func (e *Exec) Call() (interface{}, string) {
	e.initSwitches()
	cl, err := e.cl()

	if e.fini != nil {
		defer e.fini()
	}

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

	wg := &sync.WaitGroup{}
	wg.Add(1)
	go e.stream(wg)
	var c *exec.Cmd
	var dur mg.MsDuration

	for _, c = range cl {
		err, dur = procs.Run(e.Cid, c)
		if err != nil {
			break
		}
	}

	e.sink.Close()
	wg.Wait()

	res := Res{
		Chunks: e.chunks(),
		Mem:    maxRss(c.ProcessState),
		Dur:    dur.String(),
	}
	res.Attrs, res.Ok = e.cmdAttrsOk(c)

	return res, mg.Err(err)
}

func (e *Exec) cl() ([]*exec.Cmd, error) {
	switch e.Cmd {
	case ".play":
		return playCmd(e)
	default:
		return []*exec.Cmd{mkCmd(e, e.Input, e.Cmd, e.Args...)}, nil
	}
}

func (e *Exec) stream(wg *sync.WaitGroup) {
	defer wg.Done()

	tck := time.NewTicker(500 * time.Millisecond)
	for {
		select {
		case s, ok := <-e.sink.C:
			if e.filter != nil {
				s = e.filter(s)
			}

			eof := !ok
			s = e.sw(s)
			e.put(s, eof)
			if eof {
				return
			}
		case <-tck.C:
			if len(e.buf.s) != 0 {
				e.flush(false)
			}
		}
	}
}

func (e *Exec) put(s []byte, eof bool) {
	switch {
	case crSuffix(s):
		e.buf.merge = false
		e.buf.s = append(e.buf.s, s)
	case !e.buf.merge || len(e.buf.s) == 0:
		e.buf.merge = true
		e.buf.s = append(e.buf.s, zChunk)
		fallthrough
	default:
		i := len(e.buf.s) - 1
		e.buf.s[i] = append(e.buf.s[i], s...)
	}

	e.buf.n += len(s)
	if eof || e.buf.n >= 32*1024 {
		e.flush(eof)
	}
}

func (e *Exec) chunks() [][]byte {
	if e.buf.s != nil {
		return e.buf.s
	}
	// be nice to the client by not sending them `null` when they expect an array
	return zChunks
}

func (e *Exec) flush(eof bool) {
	if e.Stream == "" {
		return
	}

	e.brk.Send(mg.Response{
		Token: e.Stream,
		Data: StreamRes{
			Chunks: e.chunks(),
			End:    eof,
		},
	})

	for i, s := range e.buf.s {
		e.buf.s[i] = s[:0]
	}
	e.buf.s = e.buf.s[:0]
	e.buf.n = 0
}

func (e *Exec) initSwitches() error {
	for i, _ := range e.Switch {
		sw := &e.Switch[i]
		for _, s := range sw.Case {
			if s != "" {
				rx, err := rx(s)
				if err != nil {
					return err
				}
				sw.cases = append(sw.cases, rx)
			}
		}
		e.switches = append(e.switches, sw)
	}
	return nil
}

func (e *Exec) cmdAttrsOk(c *exec.Cmd) ([]Attr, bool) {
	attrs, swOk := e.collectAttrs()
	if e.SwitchOk && len(e.Switch) > 0 {
		return attrs, swOk
	}
	return attrs, c.ProcessState != nil && c.ProcessState.Success()
}

func (e *Exec) collectAttrs() ([]Attr, bool) {
	attrs := []Attr{}
	ok := true
	for _, sw := range e.switches {
		if len(sw.attrs) > 0 {
			ok = false
			attrs = append(attrs, sw.attrs...)
		}
	}
	return attrs, ok
}

func (e *Exec) sw(s []byte) []byte {
	discard := false

	for _, sw := range e.switches {
		al, matched := sw.match(s)
		sw.attrs = append(sw.attrs, al...)

		if matched != sw.Negative {
			if sw.Discard {
				discard = true
			}

			if !sw.Fallthrough {
				break
			}
		}
	}

	if discard {
		return nil
	}
	return s
}

func (s *Switch) match(p []byte) ([]Attr, bool) {
	if len(s.cases) == 0 {
		return nil, true
	}

	for _, rx := range s.cases {
		ml := rx.FindAllSubmatch(bytes.TrimRight(p, "\r\n"), -1)
		if len(ml) > 0 {
			// p (and by extension ml, mt) is owned by the caller so make sure it gets copied
			names := rx.SubexpNames()
			al := []Attr{}
			for _, mt := range ml {
				attr := Attr{}
				if len(mt) == len(names) {
					for i, k := range names {
						if k != "" {
							attr[k] = string(mt[i])
						}
					}
				}
				if len(mt) != 0 {
					al = append(al, attr)
				}
			}
			return al, true
		}
	}

	return nil, false
}

func rx(s string) (*regexp.Regexp, error) {
	caseCache.Lock()
	defer caseCache.Unlock()

	if rx, ok := caseCache.m[s]; ok {
		return rx, nil
	}

	rx, err := regexp.Compile(s)
	if err != nil {
		return nil, fmt.Errorf("cannot compile regexp `%v`: %v", s, err.Error())
	}

	caseCache.m[s] = rx
	return rx, nil
}

func crSuffix(s []byte) bool {
	i := len(s) - 1
	return i >= 0 && s[i] == '\r'
}

func mkCmd(e *Exec, input string, cmd string, args ...string) *exec.Cmd {
	c := exec.Command(cmd, args...)
	c.Dir = e.Wd
	c.Env = mg.Env(e.Env)
	if !e.DiscardStdout {
		c.Stdout = e.sink
	}
	if !e.DiscardStderr {
		c.Stderr = e.sink
	}
	if input != "" {
		c.Stdin = strings.NewReader(input)
	}
	return c
}

func init() {
	mg.Register("exec", func(b *mg.Broker) mg.Caller {
		return &Exec{
			brk:  b,
			sink: sink.NewBufferedChan(100),
		}
	})
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)

//var loginURL = "https://developer.nike.com/content/nike-developer-cq/us/en_us/index/login.html"

type nikeDataSimple struct {
	Data []struct {
		ActivityId    string
		ActivityType  string
		StartTime     string
		Status        string
		MetricSummary struct {
			Distance string
			Duration string
		}
	}
	Paging struct {
		Next     string
		Previous string
	}
}

type nikeDataComplete struct {
	Links []struct {
		Rel  string
		Href string
	}
	ActivityId       string
	ActivityType     string
	StartTime        string
	ActivityTimeZone string
	Status           string
	DeviceType       string
	MetricSummary    struct {
		Calories string
		Distance string
		Duration string
	}
	Paging struct {
		Next     string
		Previous string
	}
	Tags []struct {
		TagType  string
		TagValue string
	}
	Metrics []struct {
		IntervalMetric float64
		IntervalUnit   string
		MetricType     string
		Values         []string
	}
	IsGPSActivity  bool
	ElevationLoss  float64
	ElevationGain  float64
	ElevationMax   float64
	ElevationMin   float64
	IntervalMetric float64
	IntervalUnit   string
	Waypoints      []struct {
		Latitude  float64
		Longitude float64
		Elevation float64
	}
}

/*func main() {
	var nike nikeDataSimple
	json.Unmarshal([]byte(NikeBasic10), &nike)
	fmt.Println(nike)
}*/

func wrangleJSON(token string) {

	var nikeList nikeDataSimple
	var ActList = "https://api.nike.com/v1/me/sport/activities?access_token=ShQeydt0MoWobetAG39mWX26Yhss&count=20"
 	var ActDetails = "https://api.nike.com/v1/me/sport/activities/"

	url := ActList
	res, err := http.Get(url)

	if err != nil {
		panic(err.Error())
	}
	body, err := ioutil.ReadAll(res.Body)

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

	json.Unmarshal(body, &nikeList)
	for _, m := range nikeList.Data {
		if m.ActivityType == "RUN" {
			var nikeActs nikeDataComplete

			url := ActDetails + m.ActivityId + "?access_token=" + token
			res, err := http.Get(url)

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

			body, err := ioutil.ReadAll(res.Body)

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

			json.Unmarshal(body, &nikeActs)

			if nikeActs.IsGPSActivity {
				gpsUrl := ActDetails + m.ActivityId + "/gps?access_token=" + token
				res, err = http.Get(gpsUrl)

				if err != nil {
					panic(err.Error())
				}
				body, err = ioutil.ReadAll(res.Body)

				if err != nil {
					panic(err.Error())
				}
				json.Unmarshal(body, &nikeActs)
			}

			fmt.Println("Activity ID:", nikeActs.ActivityId)
			fmt.Println("Distance:", nikeActs.MetricSummary.Distance, "km")
			fmt.Println("Date:", nikeActs.StartTime)
			for _, m := range nikeActs.Tags {
				fmt.Println(strings.ToLower(m.TagType), ":", strings.ToLower(m.TagValue))
			}
			if nikeActs.IsGPSActivity {
				fmt.Println("Activity has GPS data:", nikeActs.IsGPSActivity)
				fmt.Println("GPS read interval is", nikeActs.IntervalMetric, strings.ToLower(nikeActs.IntervalUnit))
				fmt.Println(nikeActs.Waypoints[0].Latitude, nikeActs.Waypoints[0].Longitude)
			}
			fmt.Println()
		}
	}
}
<commit_msg>Refactor URL generator code into functions<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
)

//var loginURL = "https://developer.nike.com/content/nike-developer-cq/us/en_us/index/login.html"

type nikeDataSimple struct {
	Data []struct {
		ActivityId    string
		ActivityType  string
		StartTime     string
		Status        string
		MetricSummary struct {
			Distance string
			Duration string
		}
	}
	Paging struct {
		Next     string
		Previous string
	}
}

type nikeDataComplete struct {
	Links []struct {
		Rel  string
		Href string
	}
	ActivityId       string
	ActivityType     string
	StartTime        string
	ActivityTimeZone string
	Status           string
	DeviceType       string
	MetricSummary    struct {
		Calories string
		Distance string
		Duration string
	}
	Paging struct {
		Next     string
		Previous string
	}
	Tags []struct {
		TagType  string
		TagValue string
	}
	Metrics []struct {
		IntervalMetric float64
		IntervalUnit   string
		MetricType     string
		Values         []string
	}
	IsGPSActivity  bool
	ElevationLoss  float64
	ElevationGain  float64
	ElevationMax   float64
	ElevationMin   float64
	IntervalMetric float64
	IntervalUnit   string
	Waypoints      []struct {
		Latitude  float64
		Longitude float64
		Elevation float64
	}
}

/*func main() {
	var nike nikeDataSimple
	json.Unmarshal([]byte(NikeBasic10), &nike)
	fmt.Println(nike)
}*/

func makeActivityURL(token string, count int) string {
	return "https://api.nike.com/v1/me/sport/activities?access_token=" + token + "&count=" + strconv.Itoa(count)
}

func makeDetailsURL(token string, activityId string) string {
	return "https://api.nike.com/v1/me/sport/activities/" + activityId + "?access_token=" + token
}

func makeGpsURL(token string, activityId string) string {
	return "https://api.nike.com/v1/me/sport/activities/" + activityId + "/gps?access_token=" + token
}

func wrangleJSON(token string) {

	var nikeList nikeDataSimple

	url := makeActivityURL(token, 20)
	res, err := http.Get(url)

	if err != nil {
		panic(err.Error())
	}
	body, err := ioutil.ReadAll(res.Body)

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

	json.Unmarshal(body, &nikeList)
	for _, m := range nikeList.Data {
		if m.ActivityType == "RUN" {
			var nikeActs nikeDataComplete

			url := makeDetailsURL(token, m.ActivityId)
			res, err := http.Get(url)

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

			body, err := ioutil.ReadAll(res.Body)

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

			json.Unmarshal(body, &nikeActs)

			if nikeActs.IsGPSActivity {
				gpsUrl := makeGpsURL(token, m.ActivityId)
				res, err = http.Get(gpsUrl)

				if err != nil {
					panic(err.Error())
				}
				body, err = ioutil.ReadAll(res.Body)

				if err != nil {
					panic(err.Error())
				}
				json.Unmarshal(body, &nikeActs)
			}

			fmt.Println("Activity ID:", nikeActs.ActivityId)
			fmt.Println("Distance:", nikeActs.MetricSummary.Distance, "km")
			fmt.Println("Date:", nikeActs.StartTime)
			for _, m := range nikeActs.Tags {
				fmt.Println(strings.ToLower(m.TagType), ":", strings.ToLower(m.TagValue))
			}
			if nikeActs.IsGPSActivity {
				fmt.Println("Activity has GPS data:", nikeActs.IsGPSActivity)
				fmt.Println("GPS read interval is", nikeActs.IntervalMetric, strings.ToLower(nikeActs.IntervalUnit))
				fmt.Println(nikeActs.Waypoints[0].Latitude, nikeActs.Waypoints[0].Longitude)
			}
			fmt.Println()
		}
	}
}
<|endoftext|>


<commit_before>package lang

import (
	. "jvmgo/any"
	"jvmgo/jvm/rtda"
	rtc "jvmgo/jvm/rtda/class"
	"jvmgo/util"
)

func init() {
	_class(desiredAssertionStatus0, "desiredAssertionStatus0", "(Ljava/lang/Class;)Z")
	_class(forName0, "forName0", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;")
	_class(getClassLoader0, "getClassLoader0", "()Ljava/lang/ClassLoader;")
	_class(getComponentType, "getComponentType", "()Ljava/lang/Class;")
	_class(getConstantPool, "getConstantPool", "()Lsun/reflect/ConstantPool;")
	_class(getEnclosingMethod0, "getEnclosingMethod0", "()[Ljava/lang/Object;")
	_class(getInterfaces, "getInterfaces", "()[Ljava/lang/Class;")
	_class(getModifiers, "getModifiers", "()I")
	_class(getName0, "getName0", "()Ljava/lang/String;")
	_class(getPrimitiveClass, "getPrimitiveClass", "(Ljava/lang/String;)Ljava/lang/Class;")
	_class(getSuperclass, "getSuperclass", "()Ljava/lang/Class;")
	_class(isAssignableFrom, "isAssignableFrom", "(Ljava/lang/Class;)Z")
	_class(isArray, "isArray", "()Z")
	_class(isInterface, "isInterface", "()Z")
	_class(isPrimitive, "isPrimitive", "()Z")
}

func _class(method Any, name, desc string) {
	rtc.RegisterNativeMethod("java/lang/Class", name, desc, method)
}

// private native Class<?>[]   getDeclaredClasses0();

// private static native boolean desiredAssertionStatus0(Class<?> clazz);
// (Ljava/lang/Class;)Z
func desiredAssertionStatus0(frame *rtda.Frame) {
	// todo
	stack := frame.OperandStack()
	//stack.PopRef() // this
	stack.PushBoolean(false)
}

// private static native Class<?> forName0(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException;
// (Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;
func forName0(frame *rtda.Frame) {
	vars := frame.LocalVars()
	jName := vars.GetRef(0)
	initialize := vars.GetBoolean(1)
	//jLoader := vars.GetRef(2)

	goName := rtda.GoString(jName)
	goName = util.ReplaceAll(goName, ".", "/")
	goClass := frame.ClassLoader().LoadClass(goName)
	jClass := goClass.JClass()

	if initialize && goClass.InitializationNotStarted() {
		// undo forName0
		thread := frame.Thread()
		frame.SetNextPC(thread.PC())
		// init class
		thread.InitClass(goClass)
	} else {
		stack := frame.OperandStack()
		stack.PushRef(jClass)
	}
}

// native ClassLoader getClassLoader0();
// ()Ljava/lang/ClassLoader;
func getClassLoader0(frame *rtda.Frame) {
	// todo
	// _ = stack.PopRef() // this
	stack := frame.OperandStack()
	stack.PushRef(nil)
}

// public native Class<?> getComponentType();
// ()Ljava/lang/Class;
func getComponentType(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	componentClass := class.ComponentClass()
	componentClassObj := componentClass.JClass()

	stack := frame.OperandStack()
	stack.PushRef(componentClassObj)
}

// native ConstantPool getConstantPool();
// ()Lsun/reflect/ConstantPool;
func getConstantPool(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	cpClass := class.ClassLoader().LoadClass("sun/reflect/ConstantPool")
	if cpClass.InitializationNotStarted() {
		frame.RevertNextPC()
		frame.Thread().InitClass(cpClass)
		return
	}

	cp := class.ConstantPool()
	cpObj := cpClass.NewObjWithExtra(cp) // todo init cpObj
	frame.OperandStack().PushRef(cpObj)
}

// private native Object[] getEnclosingMethod0();
// ()[Ljava/lang/Object;
func getEnclosingMethod0(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	emInfo := class.Attributes().EnclosingMethod()
	emInfoObj := _createEnclosintMethodInfo(frame.ClassLoader(), emInfo)
	frame.OperandStack().PushRef(emInfoObj)
}

func _createEnclosintMethodInfo(classLoader *rtc.ClassLoader, emInfo *rtc.EnclosingMethod) *rtc.Obj {
	if emInfo == nil {
		return nil
	}

	enclosingClass := classLoader.LoadClass(emInfo.ClassName())
	enclosingClassObj := enclosingClass.JClass()
	var methodNameObj, methodDescriptorObj *rtc.Obj
	if emInfo.MethodName() != "" {
		methodNameObj = rtda.NewJString(emInfo.MethodName(), classLoader)
		methodDescriptorObj = rtda.NewJString(emInfo.MethodDescriptor(), classLoader)
	} else {
		methodNameObj, methodDescriptorObj = nil, nil
	}

	objs := []*rtc.Obj{enclosingClassObj, methodNameObj, methodDescriptorObj}
	return rtc.NewRefArray2(classLoader.JLObjectClass(), objs) // Object[]
}

// private native Class<?>[] getInterfaces();
// ()[Ljava/lang/Class;
func getInterfaces(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	interfaces := class.Interfaces()
	interfaceObjs := make([]*rtc.Obj, len(interfaces))
	for i, iface := range interfaces {
		interfaceObjs[i] = iface.JClass()
	}

	jlClassClass := class.ClassLoader().JLClassClass()
	interfaceArr := rtc.NewRefArray2(jlClassClass, interfaceObjs)

	stack := frame.OperandStack()
	stack.PushRef(interfaceArr)
}

// private native String getName0();
// ()Ljava/lang/String;
func getName0(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	name := class.JlsName()
	nameObj := rtda.NewJString(name, frame)

	stack := frame.OperandStack()
	stack.PushRef(nameObj)
}

// public native int getModifiers();
// ()I
func getModifiers(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	modifiers := class.GetAccessFlags()

	stack := frame.OperandStack()
	stack.PushInt(int32(modifiers))
}

// static native Class<?> getPrimitiveClass(String name);
// (Ljava/lang/String;)Ljava/lang/Class;
func getPrimitiveClass(frame *rtda.Frame) {
	vars := frame.LocalVars()
	nameObj := vars.GetRef(0)

	name := rtda.GoString(nameObj)
	classLoader := frame.ClassLoader()
	class := classLoader.GetPrimitiveClass(name)
	classObj := class.JClass()

	stack := frame.OperandStack()
	stack.PushRef(classObj)
}

// public native Class<? super T> getSuperclass();
// ()Ljava/lang/Class;
func getSuperclass(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	superClass := class.SuperClass()

	stack := frame.OperandStack()
	if superClass != nil {
		stack.PushRef(superClass.JClass())
	} else {
		stack.PushNull()
	}
}

// public native boolean isAssignableFrom(Class<?> cls);
// (Ljava/lang/Class;)Z
func isAssignableFrom(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()
	cls := vars.GetRef(1)

	thisClass := this.Extra().(*rtc.Class)
	clsClass := cls.Extra().(*rtc.Class)
	ok := thisClass.IsAssignableFrom(clsClass)
	frame.OperandStack().PushBoolean(ok)
}

// public native boolean isArray();
// ()Z
func isArray(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	stack := frame.OperandStack()
	stack.PushBoolean(class.IsArray())
}

// public native boolean isInterface();
// ()Z
func isInterface(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	stack := frame.OperandStack()
	stack.PushBoolean(class.IsInterface())
}

// public native boolean isPrimitive();
// ()Z
func isPrimitive(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	stack := frame.OperandStack()
	stack.PushBoolean(class.IsPrimitive())
}
<commit_msg>native: Class. getDeclaringClass() ..<commit_after>package lang

import (
	. "jvmgo/any"
	"jvmgo/jvm/rtda"
	rtc "jvmgo/jvm/rtda/class"
	"jvmgo/util"
)

func init() {
	_class(desiredAssertionStatus0, "desiredAssertionStatus0", "(Ljava/lang/Class;)Z")
	_class(forName0, "forName0", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;")
	_class(getClassLoader0, "getClassLoader0", "()Ljava/lang/ClassLoader;")
	_class(getComponentType, "getComponentType", "()Ljava/lang/Class;")
	_class(getConstantPool, "getConstantPool", "()Lsun/reflect/ConstantPool;")
	_class(getDeclaringClass, "getDeclaringClass", "()Ljava/lang/Class;")
	_class(getEnclosingMethod0, "getEnclosingMethod0", "()[Ljava/lang/Object;")
	_class(getInterfaces, "getInterfaces", "()[Ljava/lang/Class;")
	_class(getModifiers, "getModifiers", "()I")
	_class(getName0, "getName0", "()Ljava/lang/String;")
	_class(getPrimitiveClass, "getPrimitiveClass", "(Ljava/lang/String;)Ljava/lang/Class;")
	_class(getSuperclass, "getSuperclass", "()Ljava/lang/Class;")
	_class(isAssignableFrom, "isAssignableFrom", "(Ljava/lang/Class;)Z")
	_class(isArray, "isArray", "()Z")
	_class(isInterface, "isInterface", "()Z")
	_class(isPrimitive, "isPrimitive", "()Z")
}

func _class(method Any, name, desc string) {
	rtc.RegisterNativeMethod("java/lang/Class", name, desc, method)
}

// private static native boolean desiredAssertionStatus0(Class<?> clazz);
// (Ljava/lang/Class;)Z
func desiredAssertionStatus0(frame *rtda.Frame) {
	// todo
	stack := frame.OperandStack()
	//stack.PopRef() // this
	stack.PushBoolean(false)
}

// private static native Class<?> forName0(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException;
// (Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;
func forName0(frame *rtda.Frame) {
	vars := frame.LocalVars()
	jName := vars.GetRef(0)
	initialize := vars.GetBoolean(1)
	//jLoader := vars.GetRef(2)

	goName := rtda.GoString(jName)
	goName = util.ReplaceAll(goName, ".", "/")
	goClass := frame.ClassLoader().LoadClass(goName)
	jClass := goClass.JClass()

	if initialize && goClass.InitializationNotStarted() {
		// undo forName0
		thread := frame.Thread()
		frame.SetNextPC(thread.PC())
		// init class
		thread.InitClass(goClass)
	} else {
		stack := frame.OperandStack()
		stack.PushRef(jClass)
	}
}

// native ClassLoader getClassLoader0();
// ()Ljava/lang/ClassLoader;
func getClassLoader0(frame *rtda.Frame) {
	// todo
	// _ = stack.PopRef() // this
	stack := frame.OperandStack()
	stack.PushRef(nil)
}

// public native Class<?> getComponentType();
// ()Ljava/lang/Class;
func getComponentType(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	componentClass := class.ComponentClass()
	componentClassObj := componentClass.JClass()

	stack := frame.OperandStack()
	stack.PushRef(componentClassObj)
}

// native ConstantPool getConstantPool();
// ()Lsun/reflect/ConstantPool;
func getConstantPool(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	cpClass := class.ClassLoader().LoadClass("sun/reflect/ConstantPool")
	if cpClass.InitializationNotStarted() {
		frame.RevertNextPC()
		frame.Thread().InitClass(cpClass)
		return
	}

	cp := class.ConstantPool()
	cpObj := cpClass.NewObjWithExtra(cp) // todo init cpObj
	frame.OperandStack().PushRef(cpObj)
}

// private native Class<?> getDeclaringClass();
// ()Ljava/lang/Class;
func getDeclaringClass(frame *rtda.Frame) {
	panic("getDeclaringClass")
}

// private native Object[] getEnclosingMethod0();
// ()[Ljava/lang/Object;
func getEnclosingMethod0(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	emInfo := class.Attributes().EnclosingMethod()
	emInfoObj := _createEnclosintMethodInfo(frame.ClassLoader(), emInfo)
	frame.OperandStack().PushRef(emInfoObj)
}

func _createEnclosintMethodInfo(classLoader *rtc.ClassLoader, emInfo *rtc.EnclosingMethod) *rtc.Obj {
	if emInfo == nil {
		return nil
	}

	enclosingClass := classLoader.LoadClass(emInfo.ClassName())
	enclosingClassObj := enclosingClass.JClass()
	var methodNameObj, methodDescriptorObj *rtc.Obj
	if emInfo.MethodName() != "" {
		methodNameObj = rtda.NewJString(emInfo.MethodName(), classLoader)
		methodDescriptorObj = rtda.NewJString(emInfo.MethodDescriptor(), classLoader)
	} else {
		methodNameObj, methodDescriptorObj = nil, nil
	}

	objs := []*rtc.Obj{enclosingClassObj, methodNameObj, methodDescriptorObj}
	return rtc.NewRefArray2(classLoader.JLObjectClass(), objs) // Object[]
}

// private native Class<?>[] getInterfaces();
// ()[Ljava/lang/Class;
func getInterfaces(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	interfaces := class.Interfaces()
	interfaceObjs := make([]*rtc.Obj, len(interfaces))
	for i, iface := range interfaces {
		interfaceObjs[i] = iface.JClass()
	}

	jlClassClass := class.ClassLoader().JLClassClass()
	interfaceArr := rtc.NewRefArray2(jlClassClass, interfaceObjs)

	stack := frame.OperandStack()
	stack.PushRef(interfaceArr)
}

// private native String getName0();
// ()Ljava/lang/String;
func getName0(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	name := class.JlsName()
	nameObj := rtda.NewJString(name, frame)

	stack := frame.OperandStack()
	stack.PushRef(nameObj)
}

// public native int getModifiers();
// ()I
func getModifiers(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	modifiers := class.GetAccessFlags()

	stack := frame.OperandStack()
	stack.PushInt(int32(modifiers))
}

// static native Class<?> getPrimitiveClass(String name);
// (Ljava/lang/String;)Ljava/lang/Class;
func getPrimitiveClass(frame *rtda.Frame) {
	vars := frame.LocalVars()
	nameObj := vars.GetRef(0)

	name := rtda.GoString(nameObj)
	classLoader := frame.ClassLoader()
	class := classLoader.GetPrimitiveClass(name)
	classObj := class.JClass()

	stack := frame.OperandStack()
	stack.PushRef(classObj)
}

// public native Class<? super T> getSuperclass();
// ()Ljava/lang/Class;
func getSuperclass(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	superClass := class.SuperClass()

	stack := frame.OperandStack()
	if superClass != nil {
		stack.PushRef(superClass.JClass())
	} else {
		stack.PushNull()
	}
}

// public native boolean isAssignableFrom(Class<?> cls);
// (Ljava/lang/Class;)Z
func isAssignableFrom(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()
	cls := vars.GetRef(1)

	thisClass := this.Extra().(*rtc.Class)
	clsClass := cls.Extra().(*rtc.Class)
	ok := thisClass.IsAssignableFrom(clsClass)
	frame.OperandStack().PushBoolean(ok)
}

// public native boolean isArray();
// ()Z
func isArray(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	stack := frame.OperandStack()
	stack.PushBoolean(class.IsArray())
}

// public native boolean isInterface();
// ()Z
func isInterface(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	stack := frame.OperandStack()
	stack.PushBoolean(class.IsInterface())
}

// public native boolean isPrimitive();
// ()Z
func isPrimitive(frame *rtda.Frame) {
	vars := frame.LocalVars()
	this := vars.GetThis()

	class := this.Extra().(*rtc.Class)
	stack := frame.OperandStack()
	stack.PushBoolean(class.IsPrimitive())
}
<|endoftext|>


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

// +build linux,386

package raw

import (
	"syscall"
	"unsafe"
)

const (
	sysSETSOCKOPT = 0xe
)

func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno)

// setsockopt provides access to the setsockopt syscall.
func setsockopt(fd, level, name int, v unsafe.Pointer, l uint32) error {
	_, errno := socketcall(
		sysSETSOCKOPT,
		uintptr(fd),
		uintptr(level),
		uintptr(name),
		uintptr(v),
		uintptr(l),
		0,
	)
	if errno != 0 {
		return error(errno)
	}

	return nil
}
<commit_msg>netlink: fix 32-bit Linux builds<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build linux,386

package netlink

import (
	"syscall"
	"unsafe"
)

const (
	sysSETSOCKOPT = 0xe
)

func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno)

// setsockopt provides access to the setsockopt syscall.
func setsockopt(fd, level, name int, v unsafe.Pointer, l uint32) error {
	_, errno := socketcall(
		sysSETSOCKOPT,
		uintptr(fd),
		uintptr(level),
		uintptr(name),
		uintptr(v),
		uintptr(l),
		0,
	)
	if errno != 0 {
		return error(errno)
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Peter Mrekaj. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE.txt file.

package sorting

import (
	"math/rand"
	"sort"
)

// BubbleSort sorts given data and has next properties:
//
// - Stable
// - O(1) extra space needed
// - O(n*n) comparisons and swaps
// - Adaptive: O(n) when nearly sorted
//
func BubbleSort(data sort.Interface) {
	var isSorted bool
	for i := 1; !isSorted && i < data.Len(); i++ { // Invariant: data[0:i-1] consist of sorted elements that are smaller (or equal) then data[i:len(data)].
		isSorted = true
		for j := data.Len() - 1; j >= i; j-- { // Invariant: data[j:len(data)] will have the smallest element on position j.
			if data.Less(j, j-1) {
				data.Swap(j, j-1)
				isSorted = false
			}
		}
	}
}

// SelectionSort sorts given data and has next properties:
//
// - Not stable
// - O(1) extra space
// - Θ(n*n) comparisons
// - Θ(n) swaps
// - Not adaptive
//
func SelectionSort(data sort.Interface) {
	for i := 0; i < data.Len()-1; i++ { // Invariant: data[0:i] holds the number of i smallest elements in sorted order from data[:].
		k := i
		for j := i + 1; j < data.Len(); j++ { // Invariant: data[k] is the smallest element in data[i:j].
			if data.Less(j, k) {
				k = j
			}
		}
		data.Swap(i, k)
	}
}

// InsertionSort sorts given data and has next properties:
//
// - Stable
// - O(1) extra space
// - O(n*n) comparisons and swaps
// - Adaptive: O(n) time when nearly sorted
// - Very low overhead
//
func InsertionSort(data sort.Interface) {
	for i := 1; i < data.Len(); i++ { // Invariant: at the start of each iteration, the data[0:i] consist of the elements originally in data[0:i], but in sorted order.
		for k := i; k > 0 && data.Less(k, k-1); k-- { // Invariant: data[k:i] will have the smallest element on position k.
			data.Swap(k, k-1)
		}
	}
}

// InsertionSort sorts given data and has next properties:
//
// - Not stable
// - O(1) extra space
// - O(n*lg(n)) time
// - Not really adaptive
//
func HeapSort(data sort.Interface) {
	// down restores order of heap.
	down := func(root, n int) {
		for {
			lch := 2*root + 1
			if lch >= n || lch < 0 { // child < 0 when int overflow.
				break
			}
			if rch := lch + 1; rch < n && data.Less(lch, rch) { // lch+1 == 2*root + 2 // Right child.
				lch = rch
			}
			if !data.Less(root, lch) { // Heap is ordered.
				return
			}
			data.Swap(root, lch)
			root = lch
		}
	}

	// Heapify (build a max heap).
	for i := (data.Len() - 1) / 2; i >= 0; i-- {
		down(i, data.Len())
	}

	// Pop elements, largest first, into end of data.
	for i := data.Len() - 1; i >= 0; i-- { // Invariant: data[i:] contains the data.Len()-1-i largest elements of maxHeap and the maxHeap contains i+1 smallest elements.
		data.Swap(0, i)
		down(0, i)
	}
}

// quickSortFn is a recursive function that sorts data[l:r+1].
func quickSortFn(data sort.Interface, p, r int) {
	if p < r {
		// Partition (divide). The time complexity is O(n). The O(1) additional space is needed.
		q := p
		data.Swap(rand.Intn(r-p+1)+p, r) // Select random pivot and move it on r position (the end position).
		// Invariant:
		// each element in data[p:q] is less than or equal to the pivot;
		// each element in data[q:u] is greater than the pivot;
		// each element in data[u:r] is unsorted;
		// the element data[r] holds the pivot.
		for u := q; u < r; u++ {
			if data.Less(u, r) {
				data.Swap(u, q)
				q++
			}
		}
		data.Swap(r, q)

		quickSortFn(data, p, q-1) // Conquer.
		quickSortFn(data, q+1, r) // Conquer.
		// Because the sub-arrays are already sorted, no work is needed to combine them.
	}
}

// InsertionSort sorts given data and has next properties:
//
// - Not stable
// - O(n) extra space in worst case; O(lg(n)) typically
// - O(n*n) time when few unique keys, but typically O(n*lg(n)) time
// - Not adaptive
//
func QuickSort(data sort.Interface) {
	quickSortFn(data, 0, data.Len()-1)
}
<commit_msg>Make comments about loop invariant more readable<commit_after>// Copyright (c) 2015, Peter Mrekaj. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE.txt file.

package sorting

import (
	"math/rand"
	"sort"
)

// BubbleSort sorts given data and has next properties:
//
// - Stable
// - O(1) extra space needed
// - O(n*n) comparisons and swaps
// - Adaptive: O(n) when nearly sorted
//
func BubbleSort(data sort.Interface) {
	var isSorted bool
	// Loop invariant: data[0:i-1] consist of sorted elements
	// that are smaller (or equal) then data[i:len(data)].
	for i := 1; !isSorted && i < data.Len(); i++ {
		isSorted = true
		// Loop invariant: data[j:len(data)] will
		// have the smallest element on position j.
		for j := data.Len() - 1; j >= i; j-- {
			if data.Less(j, j-1) {
				data.Swap(j, j-1)
				isSorted = false
			}
		}
	}
}

// SelectionSort sorts given data and has next properties:
//
// - Not stable
// - O(1) extra space
// - Θ(n*n) comparisons
// - Θ(n) swaps
// - Not adaptive
//
func SelectionSort(data sort.Interface) {
	// Loop invariant: data[0:i] holds the number of i
	// smallest elements in sorted order from data[:].
	for i := 0; i < data.Len()-1; i++ {
		k := i
		// Loop invariant: data[k] is the smallest element in data[i:j].
		for j := i + 1; j < data.Len(); j++ {
			if data.Less(j, k) {
				k = j
			}
		}
		data.Swap(i, k)
	}
}

// InsertionSort sorts given data and has next properties:
//
// - Stable
// - O(1) extra space
// - O(n*n) comparisons and swaps
// - Adaptive: O(n) time when nearly sorted
// - Very low overhead
//
func InsertionSort(data sort.Interface) {
	// Loop invariant: at the start of each iteration, the data[0:i] consist
	// of the elements originally in data[0:i], but in sorted order.
	for i := 1; i < data.Len(); i++ {
		// Loop invariant: data[k:i] will have the smallest element on position k.
		for k := i; k > 0 && data.Less(k, k-1); k-- {
			data.Swap(k, k-1)
		}
	}
}

// InsertionSort sorts given data and has next properties:
//
// - Not stable
// - O(1) extra space
// - O(n*lg(n)) time
// - Not really adaptive
//
func HeapSort(data sort.Interface) {
	// down restores order of heap.
	down := func(root, n int) {
		for {
			lch := 2*root + 1
			if lch >= n || lch < 0 { // child < 0 when int overflow.
				break
			}
			if rch := lch + 1; rch < n && data.Less(lch, rch) { // lch+1 == 2*root + 2 // Right child.
				lch = rch
			}
			if !data.Less(root, lch) { // Heap is ordered.
				return
			}
			data.Swap(root, lch)
			root = lch
		}
	}

	// Heapify (build a max heap).
	for i := (data.Len() - 1) / 2; i >= 0; i-- {
		down(i, data.Len())
	}

	// Pop elements, largest first, into end of data.
	// Loop invariant: data[i:] contains the data.Len()-1-i largest elements
	// of maxHeap and the maxHeap contains i+1 smallest elements.
	for i := data.Len() - 1; i >= 0; i-- {
		data.Swap(0, i)
		down(0, i)
	}
}

// quickSortFn is a recursive function that sorts data[l:r+1].
func quickSortFn(data sort.Interface, p, r int) {
	if p < r {
		// Partition (divide). The time complexity is O(n). The O(1) additional space is needed.
		q := p
		data.Swap(rand.Intn(r-p+1)+p, r) // Select random pivot and move it on r position (the end position).
		// Loop invariant:
		// each element in data[p:q] is less than or equal to the pivot;
		// each element in data[q:u] is greater than the pivot;
		// each element in data[u:r] is unsorted;
		// the element data[r] holds the pivot.
		for u := q; u < r; u++ {
			if data.Less(u, r) {
				data.Swap(u, q)
				q++
			}
		}
		data.Swap(r, q)

		quickSortFn(data, p, q-1) // Conquer.
		quickSortFn(data, q+1, r) // Conquer.
		// Because the sub-arrays are already sorted, no work is needed to combine them.
	}
}

// InsertionSort sorts given data and has next properties:
//
// - Not stable
// - O(n) extra space in worst case; O(lg(n)) typically
// - O(n*n) time when few unique keys, but typically O(n*lg(n)) time
// - Not adaptive
//
func QuickSort(data sort.Interface) {
	quickSortFn(data, 0, data.Len()-1)
}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2017 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package zmqutil

import (
	"bytes"
	"crypto/rand"
	"encoding/hex"
	"github.com/bitmark-inc/bitmarkd/fault"
	"github.com/bitmark-inc/bitmarkd/util"
	zmq "github.com/pebbe/zmq4"
	"sync"
	"time"
)

// structure to hold a client connection
//
// prefix:
//   REQ socket this adds an item before send
//   SUB socket this adds/changes subscription
type Client struct {
	sync.Mutex

	publicKey       []byte
	privateKey      []byte
	serverPublicKey []byte
	address         string
	prefix          string
	v6              bool
	socketType      zmq.Type
	socket          *zmq.Socket
	poller          *Poller
	events          zmq.State
	timeout         time.Duration
	timestamp       time.Time
}

const (
	publicKeySize  = 32
	privateKeySize = 32
	identifierSize = 32
)

type globalClientDataType struct {
	sync.Mutex
	clients map[*zmq.Socket]*Client
}

var globalClientData = globalClientDataType{
	clients: make(map[*zmq.Socket]*Client),
}

// create a client socket ususlly of type zmq.REQ or zmq.SUB
func NewClient(socketType zmq.Type, privateKey []byte, publicKey []byte, timeout time.Duration) (*Client, error) {

	if len(publicKey) != publicKeySize {
		return nil, fault.ErrInvalidPublicKey
	}
	if len(privateKey) != privateKeySize {
		return nil, fault.ErrInvalidPrivateKey
	}

	client := &Client{
		publicKey:       make([]byte, publicKeySize),
		privateKey:      make([]byte, privateKeySize),
		serverPublicKey: make([]byte, publicKeySize),
		address:         "",
		v6:              false,
		socketType:      socketType,
		socket:          nil,
		poller:          nil,
		events:          0,
		timeout:         timeout,
		timestamp:       time.Now(),
	}
	copy(client.privateKey, privateKey)
	copy(client.publicKey, publicKey)
	return client, nil
}

// create a socket and connect to specific server with specifed key
func (client *Client) openSocket() error {
	client.Lock()
	defer client.Unlock()

	socket, err := zmq.NewSocket(client.socketType)
	if nil != err {
		return err
	}

	// create a secure random identifier
	randomIdBytes := make([]byte, identifierSize)
	_, err = rand.Read(randomIdBytes)
	if nil != err {
		return err
	}
	randomIdentifier := string(randomIdBytes)

	// set up as client
	err = socket.SetCurveServer(0)
	if nil != err {
		goto failure
	}
	err = socket.SetCurvePublickey(string(client.publicKey))
	if nil != err {
		goto failure
	}
	err = socket.SetCurveSecretkey(string(client.privateKey))
	if nil != err {
		goto failure
	}

	// local identitity is a random value
	err = socket.SetIdentity(randomIdentifier)
	if nil != err {
		goto failure
	}

	// destination identity is its public key
	err = socket.SetCurveServerkey(string(client.serverPublicKey))
	if nil != err {
		goto failure
	}

	// only queue messages sent to connected peers
	socket.SetImmediate(true)

	// zero => do not set timeout
	if 0 != client.timeout {
		err = socket.SetSndtimeo(client.timeout)
		if nil != err {
			goto failure
		}
		err = socket.SetRcvtimeo(client.timeout)
		if nil != err {
			goto failure
		}
	}
	err = socket.SetLinger(100 * time.Millisecond)
	if nil != err {
		goto failure
	}

	// stype specific options
	switch client.socketType {
	case zmq.REQ:
		err = socket.SetReqCorrelate(1)
		if nil != err {
			goto failure
		}
		err = socket.SetReqRelaxed(1)
		if nil != err {
			goto failure
		}

	case zmq.SUB:
		// set subscription prefix - empty => receive everything
		err = socket.SetSubscribe(client.prefix)
		if nil != err {
			goto failure
		}

	default:
	}

	err = socket.SetTcpKeepalive(1)
	if nil != err {
		goto failure
	}
	err = socket.SetTcpKeepaliveCnt(5)
	if nil != err {
		goto failure
	}
	err = socket.SetTcpKeepaliveIdle(60)
	if nil != err {
		goto failure
	}
	err = socket.SetTcpKeepaliveIntvl(60)
	if nil != err {
		goto failure
	}

	// ***** FIX THIS: enabling this causes complete failure
	// ***** FIX THIS: socket disconnects, perhaps after IVL value
	// heartbeat (constants from socket.go)
	// err = socket.SetHeartbeatIvl(heartbeatInterval)
	// if nil != err {
	// 	goto failure
	// }
	// err = socket.SetHeartbeatTimeout(heartbeatTimeout)
	// if nil != err {
	// 	goto failure
	// }
	// err = socket.SetHeartbeatTtl(heartbeatTTL)
	// if nil != err {
	// 	goto failure
	// }

	// set IPv6 state before connect
	err = socket.SetIpv6(client.v6)
	if nil != err {
		goto failure
	}

	// new connection
	err = socket.Connect(client.address)
	if nil != err {
		goto failure
	}

	client.socket = socket

	// register client globally
	globalClientData.Lock()
	globalClientData.clients[socket] = client
	globalClientData.Unlock()

	// add to poller
	if nil != client.poller {
		client.poller.Add(client.socket, client.events)
	}
	return nil
failure:
	socket.Close()
	return err
}

// destroy the socket, but leave other connection info so can reconnect
// to the same endpoint again
func (client *Client) closeSocket() error {
	client.Lock()
	defer client.Unlock()

	if nil == client.socket {
		return nil
	}

	// stop any polling
	if nil != client.poller {
		client.poller.Remove(client.socket)
	}

	// if already connected, disconnect first
	if "" != client.address {
		client.socket.Disconnect(client.address)
	}

	// unregister client globally
	globalClientData.Lock()
	delete(globalClientData.clients, client.socket)
	globalClientData.Unlock()

	// close socket
	err := client.socket.Close()
	client.socket = nil
	return err
}

// disconnect old address and connect to new
func (client *Client) Connect(conn *util.Connection, serverPublicKey []byte, prefix string) error {

	// if already connected, disconnect first
	err := client.closeSocket()
	if nil != err {
		return err
	}
	client.address = ""
	client.prefix = prefix

	// small delay to allow any backgroud socket closing
	// and to restrict rate of reconnection
	time.Sleep(5 * time.Millisecond)

	copy(client.serverPublicKey, serverPublicKey)

	client.address, client.v6 = conn.CanonicalIPandPort("tcp://")

	client.timestamp = time.Now()

	return client.openSocket()
}

// check if connected to a node
func (client *Client) IsConnected() bool {
	return "" != client.address
}

// check if connected to a specific node
func (client *Client) IsConnectedTo(serverPublicKey []byte) bool {
	return bytes.Equal(client.serverPublicKey, serverPublicKey)
}

// // check if not connected to any node
// func (client *Client) IsDisconnected() bool {
// 	return "" == client.address
// }

// // get the age of connection
// func (client *Client) Age() time.Duration {
// 	return time.Since(client.timestamp)
// }

// close and reopen the connection
func (client *Client) Reconnect() error {
	_, err := client.ReconnectReturningSocket()
	return err
}

// close and reopen the connection
func (client *Client) ReconnectReturningSocket() (*zmq.Socket, error) {

	err := client.closeSocket()
	if nil != err {
		return nil, err
	}
	err = client.openSocket()
	if nil != err {
		return nil, err
	}
	return client.socket, nil
}

// disconnect old address and close
func (client *Client) Close() error {
	return client.closeSocket()
}

// disconnect old addresses and close all
func CloseClients(clients []*Client) {
	for _, client := range clients {
		if nil != client {
			client.Close()
		}
	}
}

// send a message
func (client *Client) Send(items ...interface{}) error {
	client.Lock()
	defer client.Unlock()

	if "" == client.address {
		return fault.ErrNotConnected
	}

	flag := zmq.SNDMORE

	if "" != client.prefix {
		_, err := client.socket.Send(client.prefix, flag)
		if nil != err {
			return err
		}
	}

	last := len(items) - 1
	for i, item := range items {
		if i == last {
			flag = 0
		}
		switch it := item.(type) {
		case string:
			_, err := client.socket.Send(it, flag)
			if nil != err {
				return err
			}
		case []byte:
			_, err := client.socket.SendBytes(it, flag)
			if nil != err {
				return err
			}
		}
	}
	return nil
}

// receive a reply
func (client *Client) Receive(flags zmq.Flag) ([][]byte, error) {
	client.Lock()
	defer client.Unlock()

	if "" == client.address {
		return nil, fault.ErrNotConnected
	}
	data, err := client.socket.RecvMessageBytes(flags)
	return data, err
}

// add poller to client
func (client *Client) BeginPolling(poller *Poller, events zmq.State) *zmq.Socket {

	// if poller changed
	if nil != client.poller && nil != client.socket {
		client.poller.Remove(client.socket)
	}

	// add to new poller
	client.poller = poller
	client.events = events
	if nil != client.socket {
		poller.Add(client.socket, events)
	}
	return client.socket
}

// to string
func (client *Client) String() string {
	return client.address
}

type Connected struct {
	Address string `json:"address"`
	Server  string `json:"server"`
}

// to string
func (client *Client) ConnectedTo() *Connected {

	if "" == client.address {
		return nil
	}
	return &Connected{
		Address: client.address,
		Server:  hex.EncodeToString(client.serverPublicKey),
	}
}

// find the client corresponding to a socket
func ClientFromSocket(socket *zmq.Socket) *Client {
	globalClientData.Lock()
	client := globalClientData.clients[socket]
	globalClientData.Unlock()
	return client
}
<commit_msg>[zmqutil] fix send function (silent failure)<commit_after>// Copyright (c) 2014-2017 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package zmqutil

import (
	"bytes"
	"crypto/rand"
	"encoding/hex"
	"github.com/bitmark-inc/bitmarkd/fault"
	"github.com/bitmark-inc/bitmarkd/util"
	"github.com/bitmark-inc/logger"
	zmq "github.com/pebbe/zmq4"
	"sync"
	"time"
)

// structure to hold a client connection
//
// prefix:
//   REQ socket this adds an item before send
//   SUB socket this adds/changes subscription
type Client struct {
	sync.Mutex

	publicKey       []byte
	privateKey      []byte
	serverPublicKey []byte
	address         string
	prefix          string
	v6              bool
	socketType      zmq.Type
	socket          *zmq.Socket
	poller          *Poller
	events          zmq.State
	timeout         time.Duration
	timestamp       time.Time
}

const (
	publicKeySize  = 32
	privateKeySize = 32
	identifierSize = 32
)

type globalClientDataType struct {
	sync.Mutex
	clients map[*zmq.Socket]*Client
}

var globalClientData = globalClientDataType{
	clients: make(map[*zmq.Socket]*Client),
}

// create a client socket ususlly of type zmq.REQ or zmq.SUB
func NewClient(socketType zmq.Type, privateKey []byte, publicKey []byte, timeout time.Duration) (*Client, error) {

	if len(publicKey) != publicKeySize {
		return nil, fault.ErrInvalidPublicKey
	}
	if len(privateKey) != privateKeySize {
		return nil, fault.ErrInvalidPrivateKey
	}

	client := &Client{
		publicKey:       make([]byte, publicKeySize),
		privateKey:      make([]byte, privateKeySize),
		serverPublicKey: make([]byte, publicKeySize),
		address:         "",
		v6:              false,
		socketType:      socketType,
		socket:          nil,
		poller:          nil,
		events:          0,
		timeout:         timeout,
		timestamp:       time.Now(),
	}
	copy(client.privateKey, privateKey)
	copy(client.publicKey, publicKey)
	return client, nil
}

// create a socket and connect to specific server with specifed key
func (client *Client) openSocket() error {
	client.Lock()
	defer client.Unlock()

	socket, err := zmq.NewSocket(client.socketType)
	if nil != err {
		return err
	}

	// create a secure random identifier
	randomIdBytes := make([]byte, identifierSize)
	_, err = rand.Read(randomIdBytes)
	if nil != err {
		return err
	}
	randomIdentifier := string(randomIdBytes)

	// set up as client
	err = socket.SetCurveServer(0)
	if nil != err {
		goto failure
	}
	err = socket.SetCurvePublickey(string(client.publicKey))
	if nil != err {
		goto failure
	}
	err = socket.SetCurveSecretkey(string(client.privateKey))
	if nil != err {
		goto failure
	}

	// local identitity is a random value
	err = socket.SetIdentity(randomIdentifier)
	if nil != err {
		goto failure
	}

	// destination identity is its public key
	err = socket.SetCurveServerkey(string(client.serverPublicKey))
	if nil != err {
		goto failure
	}

	// only queue messages sent to connected peers
	socket.SetImmediate(true)

	// zero => do not set timeout
	if 0 != client.timeout {
		err = socket.SetSndtimeo(client.timeout)
		if nil != err {
			goto failure
		}
		err = socket.SetRcvtimeo(client.timeout)
		if nil != err {
			goto failure
		}
	}
	err = socket.SetLinger(100 * time.Millisecond)
	if nil != err {
		goto failure
	}

	// stype specific options
	switch client.socketType {
	case zmq.REQ:
		err = socket.SetReqCorrelate(1)
		if nil != err {
			goto failure
		}
		err = socket.SetReqRelaxed(1)
		if nil != err {
			goto failure
		}

	case zmq.SUB:
		// set subscription prefix - empty => receive everything
		err = socket.SetSubscribe(client.prefix)
		if nil != err {
			goto failure
		}

	default:
	}

	err = socket.SetTcpKeepalive(1)
	if nil != err {
		goto failure
	}
	err = socket.SetTcpKeepaliveCnt(5)
	if nil != err {
		goto failure
	}
	err = socket.SetTcpKeepaliveIdle(60)
	if nil != err {
		goto failure
	}
	err = socket.SetTcpKeepaliveIntvl(60)
	if nil != err {
		goto failure
	}

	// ***** FIX THIS: enabling this causes complete failure
	// ***** FIX THIS: socket disconnects, perhaps after IVL value
	// heartbeat (constants from socket.go)
	// err = socket.SetHeartbeatIvl(heartbeatInterval)
	// if nil != err {
	// 	goto failure
	// }
	// err = socket.SetHeartbeatTimeout(heartbeatTimeout)
	// if nil != err {
	// 	goto failure
	// }
	// err = socket.SetHeartbeatTtl(heartbeatTTL)
	// if nil != err {
	// 	goto failure
	// }

	// set IPv6 state before connect
	err = socket.SetIpv6(client.v6)
	if nil != err {
		goto failure
	}

	// new connection
	err = socket.Connect(client.address)
	if nil != err {
		goto failure
	}

	client.socket = socket

	// register client globally
	globalClientData.Lock()
	globalClientData.clients[socket] = client
	globalClientData.Unlock()

	// add to poller
	if nil != client.poller {
		client.poller.Add(client.socket, client.events)
	}
	return nil
failure:
	socket.Close()
	return err
}

// destroy the socket, but leave other connection info so can reconnect
// to the same endpoint again
func (client *Client) closeSocket() error {
	client.Lock()
	defer client.Unlock()

	if nil == client.socket {
		return nil
	}

	// stop any polling
	if nil != client.poller {
		client.poller.Remove(client.socket)
	}

	// if already connected, disconnect first
	if "" != client.address {
		client.socket.Disconnect(client.address)
	}

	// unregister client globally
	globalClientData.Lock()
	delete(globalClientData.clients, client.socket)
	globalClientData.Unlock()

	// close socket
	err := client.socket.Close()
	client.socket = nil
	return err
}

// disconnect old address and connect to new
func (client *Client) Connect(conn *util.Connection, serverPublicKey []byte, prefix string) error {

	// if already connected, disconnect first
	err := client.closeSocket()
	if nil != err {
		return err
	}
	client.address = ""
	client.prefix = prefix

	// small delay to allow any backgroud socket closing
	// and to restrict rate of reconnection
	time.Sleep(5 * time.Millisecond)

	copy(client.serverPublicKey, serverPublicKey)

	client.address, client.v6 = conn.CanonicalIPandPort("tcp://")

	client.timestamp = time.Now()

	return client.openSocket()
}

// check if connected to a node
func (client *Client) IsConnected() bool {
	return "" != client.address
}

// check if connected to a specific node
func (client *Client) IsConnectedTo(serverPublicKey []byte) bool {
	return bytes.Equal(client.serverPublicKey, serverPublicKey)
}

// // check if not connected to any node
// func (client *Client) IsDisconnected() bool {
// 	return "" == client.address
// }

// // get the age of connection
// func (client *Client) Age() time.Duration {
// 	return time.Since(client.timestamp)
// }

// close and reopen the connection
func (client *Client) Reconnect() error {
	_, err := client.ReconnectReturningSocket()
	return err
}

// close and reopen the connection
func (client *Client) ReconnectReturningSocket() (*zmq.Socket, error) {

	err := client.closeSocket()
	if nil != err {
		return nil, err
	}
	err = client.openSocket()
	if nil != err {
		return nil, err
	}
	return client.socket, nil
}

// disconnect old address and close
func (client *Client) Close() error {
	return client.closeSocket()
}

// disconnect old addresses and close all
func CloseClients(clients []*Client) {
	for _, client := range clients {
		if nil != client {
			client.Close()
		}
	}
}

// send a message
func (client *Client) Send(items ...interface{}) error {
	client.Lock()
	defer client.Unlock()

	if "" == client.address {
		return fault.ErrNotConnected
	}

	if 0 == len(items) {
		logger.Panicf("zmqutil.Client.Send no arguments provided")
	}

	if "" != client.prefix {
		_, err := client.socket.Send(client.prefix, zmq.SNDMORE)
		if nil != err {
			return err
		}
	}

	n := len(items) - 1
	a := items[:n]
	final := items[n] // just the final item

	for i, item := range a {
		switch it := item.(type) {
		case string:
			_, err := client.socket.Send(it, zmq.SNDMORE)
			if nil != err {
				return err
			}
		case []byte:
			_, err := client.socket.SendBytes(it, zmq.SNDMORE)
			if nil != err {
				return err
			}
		case [][]byte:
			for _, sub := range it {
				_, err := client.socket.SendBytes(sub, zmq.SNDMORE)
				if nil != err {
					return err
				}
			}
		default:
			logger.Panicf("zmqutil.Client.Send cannot send[%d]: %#v", i, item)
		}
	}

	switch it := final.(type) {
	case string:
		_, err := client.socket.Send(it, 0)
		if nil != err {
			return err
		}
	case []byte:
		_, err := client.socket.SendBytes(it, 0)
		if nil != err {
			return err
		}
	case [][]byte:
		if 0 == len(it) {
			logger.Panicf("zmqutil.Client.Send empty [][]byte")
		}
		n := len(it) - 1
		a := it[:n]
		last := it[n] // just the final item []byte

		for _, sub := range a {
			_, err := client.socket.SendBytes(sub, zmq.SNDMORE)
			if nil != err {
				return err
			}
		}
		_, err := client.socket.SendBytes(last, 0)
		if nil != err {
			return err
		}

	default:
		logger.Panicf("zmqutil.Client.Send cannot send[%d]: %#v", n, final)
	}

	return nil
}

// receive a reply
func (client *Client) Receive(flags zmq.Flag) ([][]byte, error) {
	client.Lock()
	defer client.Unlock()

	if "" == client.address {
		return nil, fault.ErrNotConnected
	}
	data, err := client.socket.RecvMessageBytes(flags)
	return data, err
}

// add poller to client
func (client *Client) BeginPolling(poller *Poller, events zmq.State) *zmq.Socket {

	// if poller changed
	if nil != client.poller && nil != client.socket {
		client.poller.Remove(client.socket)
	}

	// add to new poller
	client.poller = poller
	client.events = events
	if nil != client.socket {
		poller.Add(client.socket, events)
	}
	return client.socket
}

// to string
func (client *Client) String() string {
	return client.address
}

type Connected struct {
	Address string `json:"address"`
	Server  string `json:"server"`
}

// to string
func (client *Client) ConnectedTo() *Connected {

	if "" == client.address {
		return nil
	}
	return &Connected{
		Address: client.address,
		Server:  hex.EncodeToString(client.serverPublicKey),
	}
}

// find the client corresponding to a socket
func ClientFromSocket(socket *zmq.Socket) *Client {
	globalClientData.Lock()
	client := globalClientData.clients[socket]
	globalClientData.Unlock()
	return client
}
<|endoftext|>


<commit_before>package build

import (
	"fmt"
	"neon/util"
	"os"
)

// Target is a structure for a target
type Target struct {
	Build   *Build
	Name    string
	Doc     string
	Depends []string
	Steps   Steps
}

// NewTarget makes a new target:
// - build: the build of the target
// - name: the name of the target
// - object: the body of the target as an interface
// Returns:
// - a pointer to the built target
// - an error if something went wrong
func NewTarget(build *Build, name string, object util.Object) (*Target, error) {
	target := &Target{
		Build: build,
		Name:  name,
	}
	if err := object.CheckFields([]string{"doc", "depends", "steps"}); err != nil {
		return nil, err
	}
	if err := ParseTargetDoc(object, target); err != nil {
		return nil, err
	}
	if err := ParseTargetDepends(object, target); err != nil {
		return nil, err
	}
	if err := ParseTargetSteps(object, target); err != nil {
		return nil, err
	}
	return target, nil
}

// ParseTargetDoc parses documentation of the target:
// - object: body of the target as an interface
// - target: the target to document
// Return: an error if something went wrong
func ParseTargetDoc(object util.Object, target *Target) error {
	if object.HasField("doc") {
		doc, err := object.GetString("doc")
		if err != nil {
			return fmt.Errorf("doc field in target '%s' must be a string", target.Name)
		}
		target.Doc = doc
	}
	return nil
}

// ParseTargetDepends parses target dependencies:
// - object: the target body as an interface
// - target: the target being parsed
// Return: an error if something went wrong
func ParseTargetDepends(object util.Object, target *Target) error {
	if object.HasField("depends") {
		depends, err := object.GetListStringsOrString("depends")
		if err != nil {
			return fmt.Errorf("depends field must be a string or list of strings")
		}
		target.Depends = depends
	}
	return nil
}

// ParseTargetSteps parses steps of a target:
// - object: the target body as an interface
// - target: the target being parsed
// Return: an error if something went wrong
func ParseTargetSteps(object util.Object, target *Target) error {
	if object.HasField("steps") {
		list, err := object.GetList("steps")
		if err != nil {
			return fmt.Errorf("parsig target '%s': steps must be a list", target.Name)
		}
		var steps []Step
		for index, object := range list {
			step, err := NewStep(object)
			if err != nil {
				return fmt.Errorf("in step %d: %v", index+1, err)
			}
			steps = append(steps, step)
		}
		target.Steps = steps
	}
	return nil
}

// Run target in given context:
// - context: the context of the build
// Return: an error if something went wrong
func (target *Target) Run(context *Context) error {
	for _, name := range target.Depends {
		if !context.Stack.Contains(name) {
			if err := target.Build.Root.RunTarget(context, name); err != nil {
				return err
			}
		}
	}
	if err := context.Stack.Push(target); err != nil {
		return err
	}
	Title(target.Name)
	if target.Build.Template {
		if err := os.Chdir(target.Build.Here); err != nil {
			return fmt.Errorf("changing to current directory '%s'", target.Build.Dir)
		}
	} else {
		if err := os.Chdir(target.Build.Dir); err != nil {
			return fmt.Errorf("changing to build directory '%s'", target.Build.Dir)
		}
	}
	err := target.Steps.Run(context)
	_ = context.Stack.Pop()
	return err
}
<commit_msg>Won't run targets already run<commit_after>package build

import (
	"fmt"
	"neon/util"
	"os"
)

// Target is a structure for a target
type Target struct {
	Build   *Build
	Name    string
	Doc     string
	Depends []string
	Steps   Steps
}

// NewTarget makes a new target:
// - build: the build of the target
// - name: the name of the target
// - object: the body of the target as an interface
// Returns:
// - a pointer to the built target
// - an error if something went wrong
func NewTarget(build *Build, name string, object util.Object) (*Target, error) {
	target := &Target{
		Build: build,
		Name:  name,
	}
	if err := object.CheckFields([]string{"doc", "depends", "steps"}); err != nil {
		return nil, err
	}
	if err := ParseTargetDoc(object, target); err != nil {
		return nil, err
	}
	if err := ParseTargetDepends(object, target); err != nil {
		return nil, err
	}
	if err := ParseTargetSteps(object, target); err != nil {
		return nil, err
	}
	return target, nil
}

// ParseTargetDoc parses documentation of the target:
// - object: body of the target as an interface
// - target: the target to document
// Return: an error if something went wrong
func ParseTargetDoc(object util.Object, target *Target) error {
	if object.HasField("doc") {
		doc, err := object.GetString("doc")
		if err != nil {
			return fmt.Errorf("doc field in target '%s' must be a string", target.Name)
		}
		target.Doc = doc
	}
	return nil
}

// ParseTargetDepends parses target dependencies:
// - object: the target body as an interface
// - target: the target being parsed
// Return: an error if something went wrong
func ParseTargetDepends(object util.Object, target *Target) error {
	if object.HasField("depends") {
		depends, err := object.GetListStringsOrString("depends")
		if err != nil {
			return fmt.Errorf("depends field must be a string or list of strings")
		}
		target.Depends = depends
	}
	return nil
}

// ParseTargetSteps parses steps of a target:
// - object: the target body as an interface
// - target: the target being parsed
// Return: an error if something went wrong
func ParseTargetSteps(object util.Object, target *Target) error {
	if object.HasField("steps") {
		list, err := object.GetList("steps")
		if err != nil {
			return fmt.Errorf("parsig target '%s': steps must be a list", target.Name)
		}
		var steps []Step
		for index, object := range list {
			step, err := NewStep(object)
			if err != nil {
				return fmt.Errorf("in step %d: %v", index+1, err)
			}
			steps = append(steps, step)
		}
		target.Steps = steps
	}
	return nil
}

// Run target in given context:
// - context: the context of the build
// Return: an error if something went wrong
func (target *Target) Run(context *Context) error {
	for _, name := range target.Depends {
		if !context.Stack.Contains(name) {
			if err := target.Build.Root.RunTarget(context, name); err != nil {
				return err
			}
		}
	}
	if err := context.Stack.Push(target); err != nil {
		return err
	}
	Title(target.Name)
	if target.Build.Template {
		if err := os.Chdir(target.Build.Here); err != nil {
			return fmt.Errorf("changing to current directory '%s'", target.Build.Dir)
		}
	} else {
		if err := os.Chdir(target.Build.Dir); err != nil {
			return fmt.Errorf("changing to build directory '%s'", target.Build.Dir)
		}
	}
	return target.Steps.Run(context)
}
<|endoftext|>