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

package charset

import (
	"fmt"
	"regexp"
	"sort"
	"strings"
	"unicode"
	"unicode/utf8"

	"code.gitea.io/gitea/modules/translation"

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

// VScode defaultWordRegexp
var defaultWordRegexp = regexp.MustCompile(`(-?\d*\.\d\w*)|([^\` + "`" + `\~\!\@\#\$\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s\x00-\x1f]+)`)

func NewEscapeStreamer(locale translation.Locale, next HTMLStreamer, allowed ...rune) HTMLStreamer {
	return &escapeStreamer{
		escaped:                 &EscapeStatus{},
		PassthroughHTMLStreamer: *NewPassthroughStreamer(next),
		locale:                  locale,
		ambiguousTables:         AmbiguousTablesForLocale(locale),
		allowed:                 allowed,
	}
}

type escapeStreamer struct {
	PassthroughHTMLStreamer
	escaped         *EscapeStatus
	locale          translation.Locale
	ambiguousTables []*AmbiguousTable
	allowed         []rune
}

func (e *escapeStreamer) EscapeStatus() *EscapeStatus {
	return e.escaped
}

// Text tells the next streamer there is a text
func (e *escapeStreamer) Text(data string) error {
	sb := &strings.Builder{}
	pos, until, next := 0, 0, 0
	if len(data) > len(UTF8BOM) && data[:len(UTF8BOM)] == string(UTF8BOM) {
		_, _ = sb.WriteString(data[:len(UTF8BOM)])
		pos = len(UTF8BOM)
	}
	for pos < len(data) {
		nextIdxs := defaultWordRegexp.FindStringIndex(data[pos:])
		if nextIdxs == nil {
			until = len(data)
			next = until
		} else {
			until, next = nextIdxs[0]+pos, nextIdxs[1]+pos
		}

		// from pos until until we know that the runes are not \r\t\n or even ' '
		runes := make([]rune, 0, next-until)
		positions := make([]int, 0, next-until+1)

		for pos < until {
			r, sz := utf8.DecodeRune([]byte(data)[pos:])
			positions = positions[:0]
			positions = append(positions, pos, pos+sz)
			types, confusables, _ := e.runeTypes(r)
			if err := e.handleRunes(data, []rune{r}, positions, types, confusables, sb); err != nil {
				return err
			}
			pos += sz
		}

		for i := pos; i < next; {
			r, sz := utf8.DecodeRune([]byte(data)[i:])
			runes = append(runes, r)
			positions = append(positions, i)
			i += sz
		}
		positions = append(positions, next)
		types, confusables, runeCounts := e.runeTypes(runes...)
		if runeCounts.needsEscape() {
			if err := e.handleRunes(data, runes, positions, types, confusables, sb); err != nil {
				return err
			}
		} else {
			_, _ = sb.Write([]byte(data)[pos:next])
		}
		pos = next
	}
	if sb.Len() > 0 {
		if err := e.PassthroughHTMLStreamer.Text(sb.String()); err != nil {
			return err
		}
	}
	return nil
}

func (e *escapeStreamer) handleRunes(data string, runes []rune, positions []int, types []runeType, confusables []rune, sb *strings.Builder) error {
	for i, r := range runes {
		switch types[i] {
		case brokenRuneType:
			if sb.Len() > 0 {
				if err := e.PassthroughHTMLStreamer.Text(sb.String()); err != nil {
					return err
				}
				sb.Reset()
			}
			end := positions[i+1]
			start := positions[i]
			if err := e.brokenRune([]byte(data)[start:end]); err != nil {
				return err
			}
		case ambiguousRuneType:
			if sb.Len() > 0 {
				if err := e.PassthroughHTMLStreamer.Text(sb.String()); err != nil {
					return err
				}
				sb.Reset()
			}
			if err := e.ambiguousRune(r, confusables[0]); err != nil {
				return err
			}
			confusables = confusables[1:]
		case invisibleRuneType:
			if sb.Len() > 0 {
				if err := e.PassthroughHTMLStreamer.Text(sb.String()); err != nil {
					return err
				}
				sb.Reset()
			}
			if err := e.invisibleRune(r); err != nil {
				return err
			}
		default:
			_, _ = sb.WriteRune(r)
		}
	}
	return nil
}

func (e *escapeStreamer) brokenRune(bs []byte) error {
	e.escaped.Escaped = true
	e.escaped.HasBadRunes = true

	if err := e.PassthroughHTMLStreamer.StartTag("span", html.Attribute{
		Key: "class",
		Val: "broken-code-point",
	}); err != nil {
		return err
	}
	if err := e.PassthroughHTMLStreamer.Text(fmt.Sprintf("<%X>", bs)); err != nil {
		return err
	}

	return e.PassthroughHTMLStreamer.EndTag("span")
}

func (e *escapeStreamer) ambiguousRune(r, c rune) error {
	e.escaped.Escaped = true
	e.escaped.HasAmbiguous = true

	if err := e.PassthroughHTMLStreamer.StartTag("span", html.Attribute{
		Key: "class",
		Val: "ambiguous-code-point tooltip",
	}, html.Attribute{
		Key: "data-content",
		Val: e.locale.Tr("repo.ambiguous_character", r, c),
	}); err != nil {
		return err
	}
	if err := e.PassthroughHTMLStreamer.StartTag("span", html.Attribute{
		Key: "class",
		Val: "char",
	}); err != nil {
		return err
	}
	if err := e.PassthroughHTMLStreamer.Text(string(r)); err != nil {
		return err
	}
	if err := e.PassthroughHTMLStreamer.EndTag("span"); err != nil {
		return err
	}

	return e.PassthroughHTMLStreamer.EndTag("span")
}

func (e *escapeStreamer) invisibleRune(r rune) error {
	e.escaped.Escaped = true
	e.escaped.HasInvisible = true

	if err := e.PassthroughHTMLStreamer.StartTag("span", html.Attribute{
		Key: "class",
		Val: "escaped-code-point",
	}, html.Attribute{
		Key: "data-escaped",
		Val: fmt.Sprintf("[U+%04X]", r),
	}); err != nil {
		return err
	}
	if err := e.PassthroughHTMLStreamer.StartTag("span", html.Attribute{
		Key: "class",
		Val: "char",
	}); err != nil {
		return err
	}
	if err := e.PassthroughHTMLStreamer.Text(string(r)); err != nil {
		return err
	}
	if err := e.PassthroughHTMLStreamer.EndTag("span"); err != nil {
		return err
	}

	return e.PassthroughHTMLStreamer.EndTag("span")
}

type runeCountType struct {
	numBasicRunes                int
	numNonConfusingNonBasicRunes int
	numAmbiguousRunes            int
	numInvisibleRunes            int
	numBrokenRunes               int
}

func (counts runeCountType) needsEscape() bool {
	if counts.numBrokenRunes > 0 {
		return true
	}
	if counts.numBasicRunes == 0 &&
		counts.numNonConfusingNonBasicRunes > 0 {
		return false
	}
	return counts.numAmbiguousRunes > 0 || counts.numInvisibleRunes > 0
}

type runeType int

const (
	basicASCIIRuneType runeType = iota //nolint // <- This is technically deadcode but its self-documenting so it should stay
	brokenRuneType
	nonBasicASCIIRuneType
	ambiguousRuneType
	invisibleRuneType
)

func (e *escapeStreamer) runeTypes(runes ...rune) (types []runeType, confusables []rune, runeCounts runeCountType) {
	types = make([]runeType, len(runes))
	for i, r := range runes {
		var confusable rune
		switch {
		case r == utf8.RuneError:
			types[i] = brokenRuneType
			runeCounts.numBrokenRunes++
		case r == ' ' || r == '\t' || r == '\n':
			runeCounts.numBasicRunes++
		case e.isAllowed(r):
			if r > 0x7e || r < 0x20 {
				types[i] = nonBasicASCIIRuneType
				runeCounts.numNonConfusingNonBasicRunes++
			} else {
				runeCounts.numBasicRunes++
			}
		case unicode.Is(InvisibleRanges, r):
			types[i] = invisibleRuneType
			runeCounts.numInvisibleRunes++
		case unicode.IsControl(r):
			types[i] = invisibleRuneType
			runeCounts.numInvisibleRunes++
		case isAmbiguous(r, &confusable, e.ambiguousTables...):
			confusables = append(confusables, confusable)
			types[i] = ambiguousRuneType
			runeCounts.numAmbiguousRunes++
		case r > 0x7e || r < 0x20:
			types[i] = nonBasicASCIIRuneType
			runeCounts.numNonConfusingNonBasicRunes++
		default:
			runeCounts.numBasicRunes++
		}
	}
	return types, confusables, runeCounts
}

func (e *escapeStreamer) isAllowed(r rune) bool {
	if len(e.allowed) == 0 {
		return false
	}
	if len(e.allowed) == 1 {
		return e.allowed[0] == r
	}

	return sort.Search(len(e.allowed), func(i int) bool {
		return e.allowed[i] >= r
	}) >= 0
}
<commit_msg>Avoid frequent string2bytes conversions (#20940)<commit_after>// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package charset

import (
	"fmt"
	"regexp"
	"sort"
	"strings"
	"unicode"
	"unicode/utf8"

	"code.gitea.io/gitea/modules/translation"

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

// VScode defaultWordRegexp
var defaultWordRegexp = regexp.MustCompile(`(-?\d*\.\d\w*)|([^\` + "`" + `\~\!\@\#\$\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s\x00-\x1f]+)`)

func NewEscapeStreamer(locale translation.Locale, next HTMLStreamer, allowed ...rune) HTMLStreamer {
	return &escapeStreamer{
		escaped:                 &EscapeStatus{},
		PassthroughHTMLStreamer: *NewPassthroughStreamer(next),
		locale:                  locale,
		ambiguousTables:         AmbiguousTablesForLocale(locale),
		allowed:                 allowed,
	}
}

type escapeStreamer struct {
	PassthroughHTMLStreamer
	escaped         *EscapeStatus
	locale          translation.Locale
	ambiguousTables []*AmbiguousTable
	allowed         []rune
}

func (e *escapeStreamer) EscapeStatus() *EscapeStatus {
	return e.escaped
}

// Text tells the next streamer there is a text
func (e *escapeStreamer) Text(data string) error {
	sb := &strings.Builder{}
	pos, until, next := 0, 0, 0
	if len(data) > len(UTF8BOM) && data[:len(UTF8BOM)] == string(UTF8BOM) {
		_, _ = sb.WriteString(data[:len(UTF8BOM)])
		pos = len(UTF8BOM)
	}
	dataBytes := []byte(data)
	for pos < len(data) {
		nextIdxs := defaultWordRegexp.FindStringIndex(data[pos:])
		if nextIdxs == nil {
			until = len(data)
			next = until
		} else {
			until, next = nextIdxs[0]+pos, nextIdxs[1]+pos
		}

		// from pos until until we know that the runes are not \r\t\n or even ' '
		runes := make([]rune, 0, next-until)
		positions := make([]int, 0, next-until+1)

		for pos < until {
			r, sz := utf8.DecodeRune(dataBytes[pos:])
			positions = positions[:0]
			positions = append(positions, pos, pos+sz)
			types, confusables, _ := e.runeTypes(r)
			if err := e.handleRunes(dataBytes, []rune{r}, positions, types, confusables, sb); err != nil {
				return err
			}
			pos += sz
		}

		for i := pos; i < next; {
			r, sz := utf8.DecodeRune(dataBytes[i:])
			runes = append(runes, r)
			positions = append(positions, i)
			i += sz
		}
		positions = append(positions, next)
		types, confusables, runeCounts := e.runeTypes(runes...)
		if runeCounts.needsEscape() {
			if err := e.handleRunes(dataBytes, runes, positions, types, confusables, sb); err != nil {
				return err
			}
		} else {
			_, _ = sb.Write(dataBytes[pos:next])
		}
		pos = next
	}
	if sb.Len() > 0 {
		if err := e.PassthroughHTMLStreamer.Text(sb.String()); err != nil {
			return err
		}
	}
	return nil
}

func (e *escapeStreamer) handleRunes(data []byte, runes []rune, positions []int, types []runeType, confusables []rune, sb *strings.Builder) error {
	for i, r := range runes {
		switch types[i] {
		case brokenRuneType:
			if sb.Len() > 0 {
				if err := e.PassthroughHTMLStreamer.Text(sb.String()); err != nil {
					return err
				}
				sb.Reset()
			}
			end := positions[i+1]
			start := positions[i]
			if err := e.brokenRune(data[start:end]); err != nil {
				return err
			}
		case ambiguousRuneType:
			if sb.Len() > 0 {
				if err := e.PassthroughHTMLStreamer.Text(sb.String()); err != nil {
					return err
				}
				sb.Reset()
			}
			if err := e.ambiguousRune(r, confusables[0]); err != nil {
				return err
			}
			confusables = confusables[1:]
		case invisibleRuneType:
			if sb.Len() > 0 {
				if err := e.PassthroughHTMLStreamer.Text(sb.String()); err != nil {
					return err
				}
				sb.Reset()
			}
			if err := e.invisibleRune(r); err != nil {
				return err
			}
		default:
			_, _ = sb.WriteRune(r)
		}
	}
	return nil
}

func (e *escapeStreamer) brokenRune(bs []byte) error {
	e.escaped.Escaped = true
	e.escaped.HasBadRunes = true

	if err := e.PassthroughHTMLStreamer.StartTag("span", html.Attribute{
		Key: "class",
		Val: "broken-code-point",
	}); err != nil {
		return err
	}
	if err := e.PassthroughHTMLStreamer.Text(fmt.Sprintf("<%X>", bs)); err != nil {
		return err
	}

	return e.PassthroughHTMLStreamer.EndTag("span")
}

func (e *escapeStreamer) ambiguousRune(r, c rune) error {
	e.escaped.Escaped = true
	e.escaped.HasAmbiguous = true

	if err := e.PassthroughHTMLStreamer.StartTag("span", html.Attribute{
		Key: "class",
		Val: "ambiguous-code-point tooltip",
	}, html.Attribute{
		Key: "data-content",
		Val: e.locale.Tr("repo.ambiguous_character", r, c),
	}); err != nil {
		return err
	}
	if err := e.PassthroughHTMLStreamer.StartTag("span", html.Attribute{
		Key: "class",
		Val: "char",
	}); err != nil {
		return err
	}
	if err := e.PassthroughHTMLStreamer.Text(string(r)); err != nil {
		return err
	}
	if err := e.PassthroughHTMLStreamer.EndTag("span"); err != nil {
		return err
	}

	return e.PassthroughHTMLStreamer.EndTag("span")
}

func (e *escapeStreamer) invisibleRune(r rune) error {
	e.escaped.Escaped = true
	e.escaped.HasInvisible = true

	if err := e.PassthroughHTMLStreamer.StartTag("span", html.Attribute{
		Key: "class",
		Val: "escaped-code-point",
	}, html.Attribute{
		Key: "data-escaped",
		Val: fmt.Sprintf("[U+%04X]", r),
	}); err != nil {
		return err
	}
	if err := e.PassthroughHTMLStreamer.StartTag("span", html.Attribute{
		Key: "class",
		Val: "char",
	}); err != nil {
		return err
	}
	if err := e.PassthroughHTMLStreamer.Text(string(r)); err != nil {
		return err
	}
	if err := e.PassthroughHTMLStreamer.EndTag("span"); err != nil {
		return err
	}

	return e.PassthroughHTMLStreamer.EndTag("span")
}

type runeCountType struct {
	numBasicRunes                int
	numNonConfusingNonBasicRunes int
	numAmbiguousRunes            int
	numInvisibleRunes            int
	numBrokenRunes               int
}

func (counts runeCountType) needsEscape() bool {
	if counts.numBrokenRunes > 0 {
		return true
	}
	if counts.numBasicRunes == 0 &&
		counts.numNonConfusingNonBasicRunes > 0 {
		return false
	}
	return counts.numAmbiguousRunes > 0 || counts.numInvisibleRunes > 0
}

type runeType int

const (
	basicASCIIRuneType runeType = iota //nolint // <- This is technically deadcode but its self-documenting so it should stay
	brokenRuneType
	nonBasicASCIIRuneType
	ambiguousRuneType
	invisibleRuneType
)

func (e *escapeStreamer) runeTypes(runes ...rune) (types []runeType, confusables []rune, runeCounts runeCountType) {
	types = make([]runeType, len(runes))
	for i, r := range runes {
		var confusable rune
		switch {
		case r == utf8.RuneError:
			types[i] = brokenRuneType
			runeCounts.numBrokenRunes++
		case r == ' ' || r == '\t' || r == '\n':
			runeCounts.numBasicRunes++
		case e.isAllowed(r):
			if r > 0x7e || r < 0x20 {
				types[i] = nonBasicASCIIRuneType
				runeCounts.numNonConfusingNonBasicRunes++
			} else {
				runeCounts.numBasicRunes++
			}
		case unicode.Is(InvisibleRanges, r):
			types[i] = invisibleRuneType
			runeCounts.numInvisibleRunes++
		case unicode.IsControl(r):
			types[i] = invisibleRuneType
			runeCounts.numInvisibleRunes++
		case isAmbiguous(r, &confusable, e.ambiguousTables...):
			confusables = append(confusables, confusable)
			types[i] = ambiguousRuneType
			runeCounts.numAmbiguousRunes++
		case r > 0x7e || r < 0x20:
			types[i] = nonBasicASCIIRuneType
			runeCounts.numNonConfusingNonBasicRunes++
		default:
			runeCounts.numBasicRunes++
		}
	}
	return types, confusables, runeCounts
}

func (e *escapeStreamer) isAllowed(r rune) bool {
	if len(e.allowed) == 0 {
		return false
	}
	if len(e.allowed) == 1 {
		return e.allowed[0] == r
	}

	return sort.Search(len(e.allowed), func(i int) bool {
		return e.allowed[i] >= r
	}) >= 0
}
<|endoftext|>


<commit_before>package packer

import (
	"github.com/mitchellh/iochan"
	"io"
	"strings"
	"sync"
)

// RemoteCmd represents a remote command being prepared or run.
type RemoteCmd struct {
	// Command is the command to run remotely. This is executed as if
	// it were a shell command, so you are expected to do any shell escaping
	// necessary.
	Command string

	// Stdin specifies the process's standard input. If Stdin is
	// nil, the process reads from an empty bytes.Buffer.
	Stdin io.Reader

	// Stdout and Stderr represent the process's standard output and
	// error.
	//
	// If either is nil, it will be set to ioutil.Discard.
	Stdout io.Writer
	Stderr io.Writer

	// This will be set to true when the remote command has exited. It
	// shouldn't be set manually by the user, but there is no harm in
	// doing so.
	Exited bool

	// Once Exited is true, this will contain the exit code of the process.
	ExitStatus int

	// Internal locks and such used for safely setting some shared variables
	l      sync.Mutex
	exitCh chan struct{}
}

// A Communicator is the interface used to communicate with the machine
// that exists that will eventually be packaged into an image. Communicators
// allow you to execute remote commands, upload files, etc.
//
// Communicators must be safe for concurrency, meaning multiple calls to
// Start or any other method may be called at the same time.
type Communicator interface {
	// Start takes a RemoteCmd and starts it. The RemoteCmd must not be
	// modified after being used with Start, and it must not be used with
	// Start again. The Start method returns immediately once the command
	// is started. It does not wait for the command to complete. The
	// RemoteCmd.Exited field should be used for this.
	Start(*RemoteCmd) error

	// Upload uploads a file to the machine to the given path with the
	// contents coming from the given reader. This method will block until
	// it completes.
	Upload(string, io.Reader) error

	// Download downloads a file from the machine from the given remote path
	// with the contents writing to the given writer. This method will
	// block until it completes.
	Download(string, io.Writer) error
}

// StartWithUi runs the remote command and streams the output to any
// configured Writers for stdout/stderr, while also writing each line
// as it comes to a Ui.
func (r *RemoteCmd) StartWithUi(c Communicator, ui Ui) error {
	stdout_r, stdout_w := io.Pipe()
	stderr_r, stderr_w := io.Pipe()
	defer stdout_w.Close()
	defer stderr_w.Close()

	// Set the writers for the output so that we get it streamed to us
	if r.Stdout == nil {
		r.Stdout = stdout_w
	} else {
		r.Stdout = io.MultiWriter(r.Stdout, stdout_w)
	}

	if r.Stderr == nil {
		r.Stderr = stderr_w
	} else {
		r.Stderr = io.MultiWriter(r.Stderr, stderr_w)
	}

	// Start the command
	if err := c.Start(r); err != nil {
		return err
	}

	// Create the channels we'll use for data
	exitCh := make(chan int, 1)
	stdoutCh := iochan.DelimReader(stdout_r, '\n')
	stderrCh := iochan.DelimReader(stderr_r, '\n')

	// Start the goroutine to watch for the exit
	go func() {
		defer stdout_w.Close()
		defer stderr_w.Close()
		r.Wait()
		exitCh <- r.ExitStatus
	}()

	// Loop and get all our output
OutputLoop:
	for {
		select {
		case output := <-stderrCh:
			ui.Message(strings.TrimSpace(output))
		case output := <-stdoutCh:
			ui.Message(strings.TrimSpace(output))
		case <-exitCh:
			break OutputLoop
		}
	}

	// Make sure we finish off stdout/stderr because we may have gotten
	// a message from the exit channel before finishing these first.
	for output := range stdoutCh {
		ui.Message(strings.TrimSpace(output))
	}

	for output := range stderrCh {
		ui.Message(strings.TrimSpace(output))
	}

	return nil
}

// SetExited is a helper for setting that this process is exited. This
// should be called by communicators who are running a remote command in
// order to set that the command is done.
func (r *RemoteCmd) SetExited(status int) {
	r.l.Lock()
	defer r.l.Unlock()

	if r.exitCh == nil {
		r.exitCh = make(chan struct{})
	}

	r.Exited = true
	r.ExitStatus = status
	close(r.exitCh)
}

// Wait waits for the remote command to complete.
func (r *RemoteCmd) Wait() {
	// Make sure our condition variable is initialized.
	r.l.Lock()
	if r.exitCh == nil {
		r.exitCh = make(chan struct{})
	}
	r.l.Unlock()

	<-r.exitCh
}
<commit_msg>packer: replace stdout/stderr after StartWithUi<commit_after>package packer

import (
	"github.com/mitchellh/iochan"
	"io"
	"strings"
	"sync"
)

// RemoteCmd represents a remote command being prepared or run.
type RemoteCmd struct {
	// Command is the command to run remotely. This is executed as if
	// it were a shell command, so you are expected to do any shell escaping
	// necessary.
	Command string

	// Stdin specifies the process's standard input. If Stdin is
	// nil, the process reads from an empty bytes.Buffer.
	Stdin io.Reader

	// Stdout and Stderr represent the process's standard output and
	// error.
	//
	// If either is nil, it will be set to ioutil.Discard.
	Stdout io.Writer
	Stderr io.Writer

	// This will be set to true when the remote command has exited. It
	// shouldn't be set manually by the user, but there is no harm in
	// doing so.
	Exited bool

	// Once Exited is true, this will contain the exit code of the process.
	ExitStatus int

	// Internal locks and such used for safely setting some shared variables
	l      sync.Mutex
	exitCh chan struct{}
}

// A Communicator is the interface used to communicate with the machine
// that exists that will eventually be packaged into an image. Communicators
// allow you to execute remote commands, upload files, etc.
//
// Communicators must be safe for concurrency, meaning multiple calls to
// Start or any other method may be called at the same time.
type Communicator interface {
	// Start takes a RemoteCmd and starts it. The RemoteCmd must not be
	// modified after being used with Start, and it must not be used with
	// Start again. The Start method returns immediately once the command
	// is started. It does not wait for the command to complete. The
	// RemoteCmd.Exited field should be used for this.
	Start(*RemoteCmd) error

	// Upload uploads a file to the machine to the given path with the
	// contents coming from the given reader. This method will block until
	// it completes.
	Upload(string, io.Reader) error

	// Download downloads a file from the machine from the given remote path
	// with the contents writing to the given writer. This method will
	// block until it completes.
	Download(string, io.Writer) error
}

// StartWithUi runs the remote command and streams the output to any
// configured Writers for stdout/stderr, while also writing each line
// as it comes to a Ui.
func (r *RemoteCmd) StartWithUi(c Communicator, ui Ui) error {
	stdout_r, stdout_w := io.Pipe()
	stderr_r, stderr_w := io.Pipe()
	defer stdout_w.Close()
	defer stderr_w.Close()

	// Retain the original stdout/stderr that we can replace back in.
	originalStdout := r.Stdout
	originalStderr := r.Stderr
	defer func() {
		r.Stdout = originalStdout
		r.Stderr = originalStderr
	}()

	// Set the writers for the output so that we get it streamed to us
	if r.Stdout == nil {
		r.Stdout = stdout_w
	} else {
		r.Stdout = io.MultiWriter(r.Stdout, stdout_w)
	}

	if r.Stderr == nil {
		r.Stderr = stderr_w
	} else {
		r.Stderr = io.MultiWriter(r.Stderr, stderr_w)
	}

	// Start the command
	if err := c.Start(r); err != nil {
		return err
	}

	// Create the channels we'll use for data
	exitCh := make(chan int, 1)
	stdoutCh := iochan.DelimReader(stdout_r, '\n')
	stderrCh := iochan.DelimReader(stderr_r, '\n')

	// Start the goroutine to watch for the exit
	go func() {
		defer stdout_w.Close()
		defer stderr_w.Close()
		r.Wait()
		exitCh <- r.ExitStatus
	}()

	// Loop and get all our output
OutputLoop:
	for {
		select {
		case output := <-stderrCh:
			ui.Message(strings.TrimSpace(output))
		case output := <-stdoutCh:
			ui.Message(strings.TrimSpace(output))
		case <-exitCh:
			break OutputLoop
		}
	}

	// Make sure we finish off stdout/stderr because we may have gotten
	// a message from the exit channel before finishing these first.
	for output := range stdoutCh {
		ui.Message(strings.TrimSpace(output))
	}

	for output := range stderrCh {
		ui.Message(strings.TrimSpace(output))
	}

	return nil
}

// SetExited is a helper for setting that this process is exited. This
// should be called by communicators who are running a remote command in
// order to set that the command is done.
func (r *RemoteCmd) SetExited(status int) {
	r.l.Lock()
	defer r.l.Unlock()

	if r.exitCh == nil {
		r.exitCh = make(chan struct{})
	}

	r.Exited = true
	r.ExitStatus = status
	close(r.exitCh)
}

// Wait waits for the remote command to complete.
func (r *RemoteCmd) Wait() {
	// Make sure our condition variable is initialized.
	r.l.Lock()
	if r.exitCh == nil {
		r.exitCh = make(chan struct{})
	}
	r.l.Unlock()

	<-r.exitCh
}
<|endoftext|>


<commit_before>/*
Copyright 2022 Gravitational, Inc.

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 config

import (
	"reflect"

	"github.com/gravitational/trace"
	"gopkg.in/yaml.v3"
)

// Database is the config for a database access request.
type Database struct {
	// Service is the service name of the Teleport database. Generally this is
	// the name of the Teleport resource.
	Service string `yaml:"service,omitempty"`

	// Database is the name of the database to request access to.
	Database string `yaml:"database,omitempty"`

	// Username is the database username to request access as.
	Username string `yaml:"username,omitempty"`
}

func (dc *Database) CheckAndSetDefaults() error {
	if dc.Service == "" {
		return trace.BadParameter("database `service` field must specify a database service name")
	}

	// Note: tsh has special checks for MongoDB and Redis. We don't know the
	// protocol at this point so we'll need to defer those checks.

	return nil
}

// KubernetesCluster is a Kubernetes cluster certificate request.
type KubernetesCluster struct {
	// ClusterName is the name of the Kubernetes cluster in Teleport.
	ClusterName string
}

func (kc *KubernetesCluster) UnmarshalYAML(node *yaml.Node) error {
	// We don't care for multiple YAML shapes here, we just want our Kubernetes
	// config field to be compatible with CheckAndSetDefaults().

	var clusterName string
	if err := node.Decode(&clusterName); err != nil {
		return trace.Wrap(err)
	}

	kc.ClusterName = clusterName
	return nil
}

func (kc *KubernetesCluster) MarshalYAML() (interface{}, error) {
	return kc.ClusterName, nil
}

func (kc *KubernetesCluster) CheckAndSetDefaults() error {
	if kc.ClusterName == "" {
		return trace.BadParameter("Kubernetes cluster name must not be empty")
	}

	return nil
}

// App is a cert request for app access.
type App struct {
	App string `yaml:"app,omitempty"`
}

func (ac *App) UnmarshalYAML(node *yaml.Node) error {
	// As with KubernetesCluster, this is a plain string field that we want to
	// implement CheckAndSetDefaults().

	var app string
	if err := node.Decode(&app); err != nil {
		return trace.Wrap(err)
	}

	ac.App = app
	return nil
}

func (ac *App) MarshalYAML() (interface{}, error) {
	// The marshaler needs to match the unmarshaler.
	return ac.App, nil
}

func (ac *App) CheckAndSetDefaults() error {
	if ac.App == "" {
		return trace.BadParameter("app name must not be empty")
	}

	return nil
}

// DestinationConfig configures a user certificate destination.
type DestinationConfig struct {
	DestinationMixin `yaml:",inline"`

	Roles   []string         `yaml:"roles,omitempty"`
	Configs []TemplateConfig `yaml:"configs,omitempty"`

	// Kinds is a deprecated and unused field that remains for compatibility
	// reasons.
	// DELETE IN 11.0.0: Kinds should be removed after a grace period.
	Kinds []string `yaml:"kinds,omitempty"`

	// Database is a database to request access to. Mutually exclusive with
	// `kubernetes_cluster` and other special cert requests.
	Database *Database `yaml:"database,omitempty"`

	// KubernetesCluster is a cluster to request access to. Mutually exclusive
	// with `database` and other special cert requests.
	KubernetesCluster *KubernetesCluster `yaml:"kubernetes_cluster,omitempty"`

	// App is an app access request. Mutually exclusive with `database`,
	// `kubernetes_cluster`, and other special cert requests.
	App *App `yaml:"app,omitempty"`
}

// destinationDefaults applies defaults for an output sink's destination. Since
// these have no sane defaults, in practice it just returns an error if no
// config is provided.
func destinationDefaults(dm *DestinationMixin) error {
	return trace.BadParameter("destinations require some valid output sink")
}

// addRequiredConfigs adds all configs with default parameters that were not
// explicitly requested by users. Several configs, including `identity`, `tls`,
// and `ssh_client`, are always generated (with defaults set, if any) but will
// not be overridden if already included by the user.
func (dc *DestinationConfig) addRequiredConfigs() {
	if dc.GetConfigByName(TemplateSSHClientName) == nil {
		dc.Configs = append(dc.Configs, TemplateConfig{
			SSHClient: &TemplateSSHClient{},
		})
	}

	if dc.GetConfigByName(TemplateIdentityName) == nil {
		dc.Configs = append(dc.Configs, TemplateConfig{
			Identity: &TemplateIdentity{},
		})
	}

	if dc.GetConfigByName(TemplateTLSCAsName) == nil {
		dc.Configs = append(dc.Configs, TemplateConfig{
			TLSCAs: &TemplateTLSCAs{},
		})
	}

	// If a k8s request exists, enable the kubernetes template.
	if dc.KubernetesCluster != nil && dc.GetConfigByName(TemplateKubernetesName) == nil {
		dc.Configs = append(dc.Configs, TemplateConfig{
			Kubernetes: &TemplateKubernetes{},
		})
	}
}

func (dc *DestinationConfig) CheckAndSetDefaults() error {
	if err := dc.DestinationMixin.CheckAndSetDefaults(destinationDefaults); err != nil {
		return trace.Wrap(err)
	}

	certRequests := []interface{ CheckAndSetDefaults() error }{
		dc.Database,
		dc.KubernetesCluster,
		dc.App,
	}
	notNilCount := 0
	for _, request := range certRequests {
		// Note: this check is fragile and will fail if the templates aren't
		// all simple pointer types. They are, though, and the "correct"
		// solution is insane, so we'll stick with this.
		if reflect.ValueOf(request).IsNil() {
			continue
		}

		if request != nil {
			if err := request.CheckAndSetDefaults(); err != nil {
				return trace.Wrap(err)
			}

			notNilCount++
		}
	}

	if notNilCount > 1 {
		return trace.BadParameter("a destination can make at most one " +
			"special certificate request (database, kubernetes_cluster, etc)")
	}

	// Note: empty roles is allowed; interpreted to mean "all" at generation
	// time

	dc.addRequiredConfigs()

	for _, cfg := range dc.Configs {
		if err := cfg.CheckAndSetDefaults(); err != nil {
			return trace.Wrap(err)
		}
	}

	if len(dc.Kinds) > 0 {
		log.Warnf("The `kinds` configuration field has been deprecated and " +
			"will be removed in a future release. It is now a no-op and can " +
			"safely be removed from the configuration file.")
	}

	return nil
}

// ListSubdirectories lists all subdirectories that should be contained within
// this destination. Primarily used for on-the-fly directory creation.
func (dc *DestinationConfig) ListSubdirectories() ([]string, error) {
	// Note: currently no standard identity.Artifacts create subdirs. If that
	// ever changes, we'll need to adapt this to ensure we initialize them
	// properly on the fly.
	var subdirs []string

	dest, err := dc.GetDestination()
	if err != nil {
		return nil, trace.Wrap(err)
	}

	for _, config := range dc.Configs {
		template, err := config.GetConfigTemplate()
		if err != nil {
			return nil, trace.Wrap(err)
		}

		for _, file := range template.Describe(dest) {
			if file.IsDir {
				subdirs = append(subdirs, file.Name)
			}
		}
	}

	return subdirs, nil
}

// GetConfigByName returns the first valid template with the given name
// contained within this destination.
func (dc *DestinationConfig) GetConfigByName(name string) Template {
	for _, cfg := range dc.Configs {
		tpl, err := cfg.GetConfigTemplate()
		if err != nil {
			continue
		}

		if tpl.Name() == name {
			return tpl
		}
	}

	return nil
}

// GetRequiredConfig returns the static list of all default / required config
// templates.
func GetRequiredConfigs() []string {
	return []string{TemplateTLSCAsName, TemplateSSHClientName, TemplateIdentityName}
}
<commit_msg>Remove deprecated kinds field from `tbot` config (#18439)<commit_after>/*
Copyright 2022 Gravitational, Inc.

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 config

import (
	"reflect"

	"github.com/gravitational/trace"
	"gopkg.in/yaml.v3"
)

// Database is the config for a database access request.
type Database struct {
	// Service is the service name of the Teleport database. Generally this is
	// the name of the Teleport resource.
	Service string `yaml:"service,omitempty"`

	// Database is the name of the database to request access to.
	Database string `yaml:"database,omitempty"`

	// Username is the database username to request access as.
	Username string `yaml:"username,omitempty"`
}

func (dc *Database) CheckAndSetDefaults() error {
	if dc.Service == "" {
		return trace.BadParameter("database `service` field must specify a database service name")
	}

	// Note: tsh has special checks for MongoDB and Redis. We don't know the
	// protocol at this point so we'll need to defer those checks.

	return nil
}

// KubernetesCluster is a Kubernetes cluster certificate request.
type KubernetesCluster struct {
	// ClusterName is the name of the Kubernetes cluster in Teleport.
	ClusterName string
}

func (kc *KubernetesCluster) UnmarshalYAML(node *yaml.Node) error {
	// We don't care for multiple YAML shapes here, we just want our Kubernetes
	// config field to be compatible with CheckAndSetDefaults().

	var clusterName string
	if err := node.Decode(&clusterName); err != nil {
		return trace.Wrap(err)
	}

	kc.ClusterName = clusterName
	return nil
}

func (kc *KubernetesCluster) MarshalYAML() (interface{}, error) {
	return kc.ClusterName, nil
}

func (kc *KubernetesCluster) CheckAndSetDefaults() error {
	if kc.ClusterName == "" {
		return trace.BadParameter("Kubernetes cluster name must not be empty")
	}

	return nil
}

// App is a cert request for app access.
type App struct {
	App string `yaml:"app,omitempty"`
}

func (ac *App) UnmarshalYAML(node *yaml.Node) error {
	// As with KubernetesCluster, this is a plain string field that we want to
	// implement CheckAndSetDefaults().

	var app string
	if err := node.Decode(&app); err != nil {
		return trace.Wrap(err)
	}

	ac.App = app
	return nil
}

func (ac *App) MarshalYAML() (interface{}, error) {
	// The marshaler needs to match the unmarshaler.
	return ac.App, nil
}

func (ac *App) CheckAndSetDefaults() error {
	if ac.App == "" {
		return trace.BadParameter("app name must not be empty")
	}

	return nil
}

// DestinationConfig configures a user certificate destination.
type DestinationConfig struct {
	DestinationMixin `yaml:",inline"`

	Roles   []string         `yaml:"roles,omitempty"`
	Configs []TemplateConfig `yaml:"configs,omitempty"`

	// Database is a database to request access to. Mutually exclusive with
	// `kubernetes_cluster` and other special cert requests.
	Database *Database `yaml:"database,omitempty"`

	// KubernetesCluster is a cluster to request access to. Mutually exclusive
	// with `database` and other special cert requests.
	KubernetesCluster *KubernetesCluster `yaml:"kubernetes_cluster,omitempty"`

	// App is an app access request. Mutually exclusive with `database`,
	// `kubernetes_cluster`, and other special cert requests.
	App *App `yaml:"app,omitempty"`
}

// destinationDefaults applies defaults for an output sink's destination. Since
// these have no sane defaults, in practice it just returns an error if no
// config is provided.
func destinationDefaults(dm *DestinationMixin) error {
	return trace.BadParameter("destinations require some valid output sink")
}

// addRequiredConfigs adds all configs with default parameters that were not
// explicitly requested by users. Several configs, including `identity`, `tls`,
// and `ssh_client`, are always generated (with defaults set, if any) but will
// not be overridden if already included by the user.
func (dc *DestinationConfig) addRequiredConfigs() {
	if dc.GetConfigByName(TemplateSSHClientName) == nil {
		dc.Configs = append(dc.Configs, TemplateConfig{
			SSHClient: &TemplateSSHClient{},
		})
	}

	if dc.GetConfigByName(TemplateIdentityName) == nil {
		dc.Configs = append(dc.Configs, TemplateConfig{
			Identity: &TemplateIdentity{},
		})
	}

	if dc.GetConfigByName(TemplateTLSCAsName) == nil {
		dc.Configs = append(dc.Configs, TemplateConfig{
			TLSCAs: &TemplateTLSCAs{},
		})
	}

	// If a k8s request exists, enable the kubernetes template.
	if dc.KubernetesCluster != nil && dc.GetConfigByName(TemplateKubernetesName) == nil {
		dc.Configs = append(dc.Configs, TemplateConfig{
			Kubernetes: &TemplateKubernetes{},
		})
	}
}

func (dc *DestinationConfig) CheckAndSetDefaults() error {
	if err := dc.DestinationMixin.CheckAndSetDefaults(destinationDefaults); err != nil {
		return trace.Wrap(err)
	}

	certRequests := []interface{ CheckAndSetDefaults() error }{
		dc.Database,
		dc.KubernetesCluster,
		dc.App,
	}
	notNilCount := 0
	for _, request := range certRequests {
		// Note: this check is fragile and will fail if the templates aren't
		// all simple pointer types. They are, though, and the "correct"
		// solution is insane, so we'll stick with this.
		if reflect.ValueOf(request).IsNil() {
			continue
		}

		if request != nil {
			if err := request.CheckAndSetDefaults(); err != nil {
				return trace.Wrap(err)
			}

			notNilCount++
		}
	}

	if notNilCount > 1 {
		return trace.BadParameter("a destination can make at most one " +
			"special certificate request (database, kubernetes_cluster, etc)")
	}

	// Note: empty roles is allowed; interpreted to mean "all" at generation
	// time

	dc.addRequiredConfigs()

	for _, cfg := range dc.Configs {
		if err := cfg.CheckAndSetDefaults(); err != nil {
			return trace.Wrap(err)
		}
	}

	return nil
}

// ListSubdirectories lists all subdirectories that should be contained within
// this destination. Primarily used for on-the-fly directory creation.
func (dc *DestinationConfig) ListSubdirectories() ([]string, error) {
	// Note: currently no standard identity.Artifacts create subdirs. If that
	// ever changes, we'll need to adapt this to ensure we initialize them
	// properly on the fly.
	var subdirs []string

	dest, err := dc.GetDestination()
	if err != nil {
		return nil, trace.Wrap(err)
	}

	for _, config := range dc.Configs {
		template, err := config.GetConfigTemplate()
		if err != nil {
			return nil, trace.Wrap(err)
		}

		for _, file := range template.Describe(dest) {
			if file.IsDir {
				subdirs = append(subdirs, file.Name)
			}
		}
	}

	return subdirs, nil
}

// GetConfigByName returns the first valid template with the given name
// contained within this destination.
func (dc *DestinationConfig) GetConfigByName(name string) Template {
	for _, cfg := range dc.Configs {
		tpl, err := cfg.GetConfigTemplate()
		if err != nil {
			continue
		}

		if tpl.Name() == name {
			return tpl
		}
	}

	return nil
}

// GetRequiredConfig returns the static list of all default / required config
// templates.
func GetRequiredConfigs() []string {
	return []string{TemplateTLSCAsName, TemplateSSHClientName, TemplateIdentityName}
}
<|endoftext|>


<commit_before>package constants

const (
	SubPortNumber                = 6969
	DomPortNumber                = 6970
	ImageServerPortNumber        = 6971
	BasicFileGenServerPortNumber = 6972

	DefaultNetworkSpeedPercent = 10
)

var RequiredPaths = map[string]rune{
	"/etc":        'd',
	"/etc/passwd": 'f',
	"/usr":        'd',
	"/usr/bin":    'd',
}

var ScanExcludeList = []string{
	"/home/.*",
	"/tmp/.*",
	"/var/log/.*",
	"/var/mail/.*",
	"/var/spool/.*",
	"/var/tmp/.*",
}
<commit_msg>Add lib/constants.AssignedOIDBase<commit_after>package constants

const (
	SubPortNumber                = 6969
	DomPortNumber                = 6970
	ImageServerPortNumber        = 6971
	BasicFileGenServerPortNumber = 6972

	DefaultNetworkSpeedPercent = 10

	AssignedOIDBase = "1.3.6.1.4.1.9586.100,7"
)

var RequiredPaths = map[string]rune{
	"/etc":        'd',
	"/etc/passwd": 'f',
	"/usr":        'd',
	"/usr/bin":    'd',
}

var ScanExcludeList = []string{
	"/home/.*",
	"/tmp/.*",
	"/var/log/.*",
	"/var/mail/.*",
	"/var/spool/.*",
	"/var/tmp/.*",
}
<|endoftext|>


<commit_before>package lib

import(
    "os/exec"
    "fmt"
    "strconv"
    "os"
)

/*
*创建容器
*@param imageName 镜像名称
*@param port 端口映射名称
*@param shareDirPath 镜像名称
*@return 新建容器的id（string）， 创建结果（bool）
*/
func BuildContainer(imageName string, port int, appId int)(containerId string, result bool){

    containerId = "0"
    result = true

    portData := strconv.Itoa(port) + ":80"
    shareDirPath := GetSettingValue("applicationPath") + "/" + strconv.Itoa(appId)

    //判断共享目录是否有文件，如果没有则需要创建必须文件
    if !checkDirExist(shareDirPath + "/code"){
        os.MkdirAll(shareDirPath+"/code", 0777)
    }
    if !checkDirExist(shareDirPath + "/log"){
        os.MkdirAll(shareDirPath+"/log", 0777)
    }

    shareData := "  -v  " + shareDirPath + ":/data "

    command := "docker run -d -p " + portData + shareData +  imageName + "  /bin/bash /var/script/start.sh"
    cmd := exec.Command("/bin/bash", "-c", command)
    data,_ := cmd.Output()
    containerId = string(data)
    //cmd.Run()
    fmt.Println("执行命令：" + command)
    fmt.Println(containerId)
    return containerId, result
}

/*
*启动容器
*@param containerId 容器ID
*/
func StartContainer(containerId string){
    command := "docker start " + containerId
    cmd := exec.Command("/bin/bash", "-c", command)
    cmd.Start()
    fmt.Println("执行命令：" + command)
}

/*
*停止容器
*@param containerId 容器ID
*/
func StopContainer(containerId string){
    command := "docker stop " + containerId
    cmd := exec.Command("/bin/bash", "-c", command)
    cmd.Run()
    fmt.Println("执行命令：" + command)
}

/*
*重启容器
*@param containerId 容器ID
*/
func RestartContainer(containerId string){
    command := "docker restart " + containerId
    cmd := exec.Command("/bin/bash", "-c", command)
    cmd.Start()
    fmt.Println("执行命令：" + command)
}

/*
*删除容器
*@param containerId 容器ID
*/
func RemoveContainer(containerId string){
    StopContainer(containerId)//删除容器前，先停止容器
    command := "docker rm " + containerId
    cmd := exec.Command("/bin/bash", "-c", command)
    cmd.Start()
    fmt.Println("执行命令：" + command)
}<commit_msg>修正返回的容器ID错误问题<commit_after>package lib

import(
    "os/exec"
    "fmt"
    "strconv"
    "os"
    "strings"
)

/*
*创建容器
*@param imageName 镜像名称
*@param port 端口映射名称
*@param shareDirPath 镜像名称
*@return 新建容器的id（string）， 创建结果（bool）
*/
func BuildContainer(imageName string, port int, appId int)(containerId string, result bool){

    containerId = "0"
    result = true

    portData := strconv.Itoa(port) + ":80"
    shareDirPath := GetSettingValue("applicationPath") + "/" + strconv.Itoa(appId)

    //判断共享目录是否有文件，如果没有则需要创建必须文件
    if !checkDirExist(shareDirPath + "/code"){
        os.MkdirAll(shareDirPath+"/code", 0777)
    }
    if !checkDirExist(shareDirPath + "/log"){
        os.MkdirAll(shareDirPath+"/log", 0777)
    }

    shareData := "  -v  " + shareDirPath + ":/data "

    command := "docker run -d -p " + portData + shareData +  imageName + "  /bin/bash /var/script/start.sh"
    cmd := exec.Command("/bin/bash", "-c", command)
    data,_ := cmd.Output()
    containerId = string(data)
    containerId = strings.Replace(containerId, "\n", "", -1)

    fmt.Println("执行命令：" + command)
    fmt.Println(containerId)
    return containerId, result
}

/*
*启动容器
*@param containerId 容器ID
*/
func StartContainer(containerId string){
    command := "docker start " + containerId
    cmd := exec.Command("/bin/bash", "-c", command)
    cmd.Start()
    fmt.Println("执行命令：" + command)
}

/*
*停止容器
*@param containerId 容器ID
*/
func StopContainer(containerId string){
    command := "docker stop " + containerId
    cmd := exec.Command("/bin/bash", "-c", command)
    cmd.Run()
    fmt.Println("执行命令：" + command)
}

/*
*重启容器
*@param containerId 容器ID
*/
func RestartContainer(containerId string){
    command := "docker restart " + containerId
    cmd := exec.Command("/bin/bash", "-c", command)
    cmd.Start()
    fmt.Println("执行命令：" + command)
}

/*
*删除容器
*@param containerId 容器ID
*/
func RemoveContainer(containerId string){
    StopContainer(containerId)//删除容器前，先停止容器
    command := "docker rm " + containerId
    cmd := exec.Command("/bin/bash", "-c", command)
    cmd.Start()
    fmt.Println("执行命令：" + command)
}<|endoftext|>


<commit_before>package main

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

var i = 0

func solve(n int, ans []int, preorder, inorder []int) []int {
	inorderIndex := -1
	for j := 0; j < len(inorder); j++ {
		v := inorder[j]
		if preorder[i] == v {
			inorderIndex = j
		}
	}

	leftTree := inorder[:inorderIndex]
	rightTree := inorder[inorderIndex+1:]

	switch len(leftTree) {
	case 0:
		// NOP
	case 1:
		i++
		ans = append(ans, leftTree[0])
	default:
		i++
		ans = solve(n, ans, preorder, leftTree)
	}

	switch len(rightTree) {
	case 0:
		// NOP
	case 1:
		i++
		ans = append(ans, rightTree[0])
	default:
		i++
		ans = solve(n, ans, preorder, rightTree)
	}

	ans = append(ans, inorder[inorderIndex])
	return ans
}

func nextInt(sc *bufio.Scanner) int {
	sc.Scan()
	n, err := strconv.Atoi(sc.Text())
	if err != nil {
		panic(err)
	}
	return n
}

func printArray(xs []int) {
	fmt.Println(strings.Trim(fmt.Sprint(xs), "[]"))
}

func main() {
	sc := bufio.NewScanner(os.Stdin)
	sc.Split(bufio.ScanWords)
	n := nextInt(sc)
	preorder := make([]int, n)
	inorder := make([]int, n)
	for i := 0; i < n; i++ {
		v := nextInt(sc)
		preorder[i] = v
	}
	for i := 0; i < n; i++ {
		v := nextInt(sc)
		inorder[i] = v
	}

	ans := []int{}
	ans = solve(n, ans, preorder, inorder)
	printArray(ans)
}
<commit_msg>update ALDS1_7_D.go<commit_after>package main

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

type Node struct {
	id     int
	parent *Node
	left   *Node
	right  *Node
}

var pos = 0
var preOrder []int

func reconstruct(inOrder []int, parent *Node) *Node {
	if len(inOrder) == 0 {
		return nil
	}

	id := preOrder[pos]
	node := &Node{id: id, parent: parent}
	pos++

	rootIdx := 0
	for i, v := range inOrder {
		if id == v {
			rootIdx = i
			break
		}
	}
	node.left = reconstruct(inOrder[:rootIdx], node)
	node.right = reconstruct(inOrder[rootIdx+1:], node)
	if parent == nil {
		fmt.Printf("%d\n", node.id)
	} else {
		fmt.Printf("%d ", node.id)
	}
	return node
}

func main() {
	sc := bufio.NewScanner(os.Stdin)
	sc.Split(bufio.ScanWords)
	n := nextInt(sc)
	preOrder = make([]int, n)
	inOrder := make([]int, n)
	for i := 0; i < n; i++ {
		preOrder[i] = nextInt(sc)
	}
	for i := 0; i < n; i++ {
		inOrder[i] = nextInt(sc)
	}
	reconstruct(inOrder, nil)
}

// ----------

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func nextString(sc *bufio.Scanner) string {
	sc.Scan()
	return sc.Text()
}

func nextNumber(sc *bufio.Scanner) float64 {
	sc.Scan()
	f, err := strconv.ParseFloat(sc.Text(), 32)
	if err != nil {
		panic(err)
	}
	return f
}

func nextInt(sc *bufio.Scanner) int {
	sc.Scan()
	n, err := strconv.Atoi(sc.Text())
	if err != nil {
		panic(err)
	}
	return n
}

func printArray(xs []int) {
	fmt.Println(strings.Trim(fmt.Sprint(xs), "[]"))
}

func debugPrintf(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
}
<|endoftext|>


<commit_before>package ecs

import (
	"time"

	"github.com/denverdino/aliyungo/util"
)

type CreateVpcArgs struct {
	RegionId    Region
	CidrBlock   string //192.168.0.0/16 or 172.16.0.0/16 (default)
	VpcName     string
	Description string
	ClientToken string
}

type CreateVpcResponse struct {
	CommonResponse
	VpcId        string
	VRouterId    string
	RouteTableId string
}

// CreateVpc creates Virtual Private Cloud
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/vpc&createvpc
func (client *Client) CreateVpc(args *CreateVpcArgs) (resp *CreateVpcResponse, err error) {
	response := CreateVpcResponse{}
	err = client.Invoke("CreateVpc", args, &response)
	if err != nil {
		return nil, err
	}
	return &response, err
}

type DeleteVpcArgs struct {
	VpcId string
}

type DeleteVpcResponse struct {
	CommonResponse
}

// DeleteVpc deletes Virtual Private Cloud
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/vpc&deletevpc
func (client *Client) DeleteVpc(vpcId string) error {
	args := DeleteVpcArgs{
		VpcId: vpcId,
	}
	response := DeleteVpcResponse{}
	return client.Invoke("DeleteVpc", &args, &response)
}

type VpcStatus string

const (
	VpcStatusPending   = VpcStatus("Pending")
	VpcStatusAvailable = VpcStatus("Available")
)

type DescribeVpcsArgs struct {
	VpcId    string
	RegionId Region
	Pagination
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&vpcsettype
type VpcSetType struct {
	VpcId      string
	RegionId   Region
	Status     VpcStatus // enum Pending | Available
	VpcName    string
	VSwitchIds struct {
		VSwitchId []string
	}
	CidrBlock    string
	VRouterId    string
	Description  string
	CreationTime util.ISO6801Time
}

type DescribeVpcsResponse struct {
	CommonResponse
	PaginationResult
	Vpcs struct {
		Vpc []VpcSetType
	}
}

// DescribeInstanceStatus describes instance status
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/vpc&describevpcs
func (client *Client) DescribeVpcs(args *DescribeVpcsArgs) (vpcs []VpcSetType, pagination *PaginationResult, err error) {
	args.validate()
	response := DescribeVpcsResponse{}

	err = client.Invoke("DescribeVpcs", args, &response)

	if err == nil {
		return response.Vpcs.Vpc, &response.PaginationResult, nil
	}

	return nil, nil, err
}

type ModifyVpcAttributeArgs struct {
	VpcId       string
	VpcName     string
	Description string
}

type ModifyVpcAttributeResponse struct {
	CommonResponse
}

// ModifyVpcAttribute modifies attribute of Virtual Private Cloud
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/vpc&modifyvpcattribute
func (client *Client) ModifyVpcAttribute(args *ModifyVpcAttributeArgs) error {
	response := ModifyVpcAttributeResponse{}
	return client.Invoke("ModifyVpcAttribute", args, &response)
}

// WaitForInstance waits for instance to given status
func (client *Client) WaitForVpcAvailable(regionId Region, vpcId string, timeout int) error {
	if timeout <= 0 {
		timeout = DefaultTimeout
	}
	args := DescribeVpcsArgs{
		RegionId: regionId,
		VpcId:    vpcId,
	}
	for {
		vpcs, _, err := client.DescribeVpcs(&args)
		if err != nil {
			return err
		}
		if vpcs[0].Status == VpcStatusAvailable {
			break
		}
		timeout = timeout - DefaultWaitForInterval
		if timeout <= 0 {
			return getECSErrorFromString("Timeout")
		}
		time.Sleep(DefaultWaitForInterval * time.Second)
	}
	return nil
}
<commit_msg>Check the VPC describe result<commit_after>package ecs

import (
	"time"

	"github.com/denverdino/aliyungo/util"
)

type CreateVpcArgs struct {
	RegionId    Region
	CidrBlock   string //192.168.0.0/16 or 172.16.0.0/16 (default)
	VpcName     string
	Description string
	ClientToken string
}

type CreateVpcResponse struct {
	CommonResponse
	VpcId        string
	VRouterId    string
	RouteTableId string
}

// CreateVpc creates Virtual Private Cloud
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/vpc&createvpc
func (client *Client) CreateVpc(args *CreateVpcArgs) (resp *CreateVpcResponse, err error) {
	response := CreateVpcResponse{}
	err = client.Invoke("CreateVpc", args, &response)
	if err != nil {
		return nil, err
	}
	return &response, err
}

type DeleteVpcArgs struct {
	VpcId string
}

type DeleteVpcResponse struct {
	CommonResponse
}

// DeleteVpc deletes Virtual Private Cloud
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/vpc&deletevpc
func (client *Client) DeleteVpc(vpcId string) error {
	args := DeleteVpcArgs{
		VpcId: vpcId,
	}
	response := DeleteVpcResponse{}
	return client.Invoke("DeleteVpc", &args, &response)
}

type VpcStatus string

const (
	VpcStatusPending   = VpcStatus("Pending")
	VpcStatusAvailable = VpcStatus("Available")
)

type DescribeVpcsArgs struct {
	VpcId    string
	RegionId Region
	Pagination
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&vpcsettype
type VpcSetType struct {
	VpcId      string
	RegionId   Region
	Status     VpcStatus // enum Pending | Available
	VpcName    string
	VSwitchIds struct {
		VSwitchId []string
	}
	CidrBlock    string
	VRouterId    string
	Description  string
	CreationTime util.ISO6801Time
}

type DescribeVpcsResponse struct {
	CommonResponse
	PaginationResult
	Vpcs struct {
		Vpc []VpcSetType
	}
}

// DescribeInstanceStatus describes instance status
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/vpc&describevpcs
func (client *Client) DescribeVpcs(args *DescribeVpcsArgs) (vpcs []VpcSetType, pagination *PaginationResult, err error) {
	args.validate()
	response := DescribeVpcsResponse{}

	err = client.Invoke("DescribeVpcs", args, &response)

	if err == nil {
		return response.Vpcs.Vpc, &response.PaginationResult, nil
	}

	return nil, nil, err
}

type ModifyVpcAttributeArgs struct {
	VpcId       string
	VpcName     string
	Description string
}

type ModifyVpcAttributeResponse struct {
	CommonResponse
}

// ModifyVpcAttribute modifies attribute of Virtual Private Cloud
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/vpc&modifyvpcattribute
func (client *Client) ModifyVpcAttribute(args *ModifyVpcAttributeArgs) error {
	response := ModifyVpcAttributeResponse{}
	return client.Invoke("ModifyVpcAttribute", args, &response)
}

// WaitForInstance waits for instance to given status
func (client *Client) WaitForVpcAvailable(regionId Region, vpcId string, timeout int) error {
	if timeout <= 0 {
		timeout = DefaultTimeout
	}
	args := DescribeVpcsArgs{
		RegionId: regionId,
		VpcId:    vpcId,
	}
	for {
		vpcs, _, err := client.DescribeVpcs(&args)
		if err != nil {
			return err
		}
		if len(vpcs) > 0 && vpcs[0].Status == VpcStatusAvailable {
			break
		}
		timeout = timeout - DefaultWaitForInterval
		if timeout <= 0 {
			return getECSErrorFromString("Timeout")
		}
		time.Sleep(DefaultWaitForInterval * time.Second)
	}
	return nil
}
<|endoftext|>


<commit_before>package arel

import "log"

type ToSqlVisitor struct {
	conn *Connection
	BaseVisitor
}

const (
	WHERE    = " WHERE "
	SPACE    = " "
	COMMA    = ", "
	GROUP_BY = " GROUP BY "
	ORDER_BY = " ORDER BY "
	WINDOW   = " WINDOW "
	AND      = " AND "
	DISTINCT = "DISTINCT"
)

func NewToSqlVisitor(c *Connection) ToSqlVisitor {
	return ToSqlVisitor{conn: c, BaseVisitor: BaseVisitor{}}
}

func (v ToSqlVisitor) Accept(a AstNode) string {
	return v.Visit(a)
}

func (v ToSqlVisitor) Visit(a AstNode) string {
	log.Printf("%T", a)
	switch val := a.(type) {
	case SelectStatement:
		return VisitSelectStatement(val)
	case AndNode:
		return VisitAndNode(val)
	case InNode:
		return VisitInNode(val)
	case SqlLiteralNode:
		return VisitSqlLiteralNode(val)
	}
	return ""
}

func (v ToSqlVisitor) VisitAndNode(a AndNode) string {
	return "AndNode"
}

func (v ToSqlVisitor) VisitInNode(a InNode) string {
	return "InNode"
}

func (v ToSqlVisitor) VisitSqlLiteralNode(a SqlLiteralNode) string {
	return a.Raw
}

func (v ToSqlVisitor) VisitSelectStatement(s SelectStatement) string {
	return ""
}
<commit_msg>Use buffer to append to bytes<commit_after>package arel

import (
	"bytes"
	"log"
)

type ToSqlVisitor struct {
	conn *Connection
	BaseVisitor
}

const (
	WHERE    = " WHERE "
	SPACE    = " "
	COMMA    = ", "
	GROUP_BY = " GROUP BY "
	ORDER_BY = " ORDER BY "
	WINDOW   = " WINDOW "
	AND      = " AND "
	DISTINCT = "DISTINCT"
)

func NewToSqlVisitor(c *Connection) ToSqlVisitor {
	return ToSqlVisitor{conn: c, BaseVisitor: BaseVisitor{}}
}

func (v ToSqlVisitor) Accept(a AstNode) string {
	return v.Visit(a)
}

func (v ToSqlVisitor) Visit(a AstNode) string {
	log.Printf("%T", a)
	switch val := a.(type) {
	case SelectStatement:
		return VisitSelectStatement(val)
	case AndNode:
		return VisitAndNode(val)
	case InNode:
		return VisitInNode(val)
	case SqlLiteralNode:
		return VisitSqlLiteralNode(val)
	}
	return ""
}

func (v ToSqlVisitor) VisitAndNode(a AndNode) string {
	return "AndNode"
}

func (v ToSqlVisitor) VisitInNode(a InNode) string {
	return "InNode"
}

func (v ToSqlVisitor) VisitSqlLiteralNode(a SqlLiteralNode) string {
	return a.Raw
}

func (v ToSqlVisitor) VisitSelectStatement(s SelectStatement) string {
	var buf bytes.Buffer
	if s.With != nil {
		buf.WriteString(v.Visit(s.With))
	}
	return buf.String()
}
<|endoftext|>


<commit_before>package jwt

import (
    "github.com/kataras/iris"
    "github.com/kataras/iris/core/router"
)

type jwtRouter struct {
    standard Standard
}

func (r *jwtRouter) Routes(server *iris.Application) {

    jwtRoutes := server.Party("/jwt")
    {
        jwtRoutes.Post("/generate", r.generate)

        jwtRoutes.Post("/auth", r.auth)

        jwtRoutes.Put("/upgrade", r.upgrade)
    }
}

func NewRouter(standard Standard) router.Router {
    return &jwtRouter{
        standard: standard,
    }
}<commit_msg>fix bug<commit_after>package jwt

import (
    "github.com/kataras/iris"
    "github.com/kataras/iris/core/router"
)

type jwtRouter struct {
    standard Standard
}

func (r *jwtRouter) Routes(server *iris.Application) {

    jwtRoutes := server.Party("/jwt")
    {
        jwtRoutes.Post("/generate", r.generate)

        jwtRoutes.Post("/auth", r.auth)

        jwtRoutes.Put("/upgrade", r.upgrade)
    }
}

func NewRouter(standard Standard) *router.Router {
    return &jwtRouter{
        standard: standard,
    }
}<|endoftext|>


<commit_before>//go:build cgo && seccomp
// +build cgo,seccomp

package seccomp

import (
	"errors"
	"fmt"

	libseccomp "github.com/seccomp/libseccomp-golang"
	"github.com/sirupsen/logrus"
	"golang.org/x/sys/unix"

	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/opencontainers/runc/libcontainer/seccomp/patchbpf"
)

var (
	actAllow  = libseccomp.ActAllow
	actTrap   = libseccomp.ActTrap
	actKill   = libseccomp.ActKill
	actTrace  = libseccomp.ActTrace.SetReturnCode(int16(unix.EPERM))
	actLog    = libseccomp.ActLog
	actErrno  = libseccomp.ActErrno.SetReturnCode(int16(unix.EPERM))
	actNotify = libseccomp.ActNotify
)

const (
	// Linux system calls can have at most 6 arguments
	syscallMaxArguments int = 6
)

// InitSeccomp installs the seccomp filters to be used in the container as
// specified in config.
// Returns the seccomp file descriptor if any of the filters include a
// SCMP_ACT_NOTIFY action, otherwise returns -1.
func InitSeccomp(config *configs.Seccomp) (int, error) {
	if config == nil {
		return -1, errors.New("cannot initialize Seccomp - nil config passed")
	}

	defaultAction, err := getAction(config.DefaultAction, config.DefaultErrnoRet)
	if err != nil {
		return -1, errors.New("error initializing seccomp - invalid default action")
	}

	// Ignore the error since pre-2.4 libseccomp is treated as API level 0.
	apiLevel, _ := libseccomp.GetAPI()
	for _, call := range config.Syscalls {
		if call.Action == configs.Notify {
			if apiLevel < 6 {
				return -1, fmt.Errorf("seccomp notify unsupported: API level: got %d, want at least 6. Please try with libseccomp >= 2.5.0 and Linux >= 5.7", apiLevel)
			}

			// We can't allow the write syscall to notify to the seccomp agent.
			// After InitSeccomp() is called, we need to syncParentSeccomp() to write the seccomp fd plain
			// number, so the parent sends it to the seccomp agent. If we use SCMP_ACT_NOTIFY on write, we
			// never can write the seccomp fd to the parent and therefore the seccomp agent never receives
			// the seccomp fd and runc is hang during initialization.
			//
			// Note that read()/close(), that are also used in syncParentSeccomp(), _can_ use SCMP_ACT_NOTIFY.
			// Because we write the seccomp fd on the pipe to the parent, the parent is able to proceed and
			// send the seccomp fd to the agent (it is another process and not subject to the seccomp
			// filter). We will be blocked on read()/close() inside syncParentSeccomp() but if the seccomp
			// agent allows those syscalls to proceed, initialization works just fine and the agent can
			// handle future read()/close() syscalls as it wanted.
			if call.Name == "write" {
				return -1, errors.New("SCMP_ACT_NOTIFY cannot be used for the write syscall")
			}
		}
	}

	// See comment on why write is not allowed. The same reason applies, as this can mean handling write too.
	if defaultAction == actNotify {
		return -1, errors.New("SCMP_ACT_NOTIFY cannot be used as default action")
	}

	filter, err := libseccomp.NewFilter(defaultAction)
	if err != nil {
		return -1, fmt.Errorf("error creating filter: %w", err)
	}

	// Add extra architectures
	for _, arch := range config.Architectures {
		scmpArch, err := libseccomp.GetArchFromString(arch)
		if err != nil {
			return -1, fmt.Errorf("error validating Seccomp architecture: %w", err)
		}
		if err := filter.AddArch(scmpArch); err != nil {
			return -1, fmt.Errorf("error adding architecture to seccomp filter: %w", err)
		}
	}

	// Unset no new privs bit
	if err := filter.SetNoNewPrivsBit(false); err != nil {
		return -1, fmt.Errorf("error setting no new privileges: %w", err)
	}

	// Add a rule for each syscall
	for _, call := range config.Syscalls {
		if call == nil {
			return -1, errors.New("encountered nil syscall while initializing Seccomp")
		}

		if err := matchCall(filter, call, defaultAction); err != nil {
			return -1, err
		}
	}

	seccompFd, err := patchbpf.PatchAndLoad(config, filter)
	if err != nil {
		return -1, fmt.Errorf("error loading seccomp filter into kernel: %w", err)
	}

	return seccompFd, nil
}

// Convert Libcontainer Action to Libseccomp ScmpAction
func getAction(act configs.Action, errnoRet *uint) (libseccomp.ScmpAction, error) {
	switch act {
	case configs.Kill:
		return actKill, nil
	case configs.Errno:
		if errnoRet != nil {
			return libseccomp.ActErrno.SetReturnCode(int16(*errnoRet)), nil
		}
		return actErrno, nil
	case configs.Trap:
		return actTrap, nil
	case configs.Allow:
		return actAllow, nil
	case configs.Trace:
		if errnoRet != nil {
			return libseccomp.ActTrace.SetReturnCode(int16(*errnoRet)), nil
		}
		return actTrace, nil
	case configs.Log:
		return actLog, nil
	case configs.Notify:
		return actNotify, nil
	default:
		return libseccomp.ActInvalid, errors.New("invalid action, cannot use in rule")
	}
}

// Convert Libcontainer Operator to Libseccomp ScmpCompareOp
func getOperator(op configs.Operator) (libseccomp.ScmpCompareOp, error) {
	switch op {
	case configs.EqualTo:
		return libseccomp.CompareEqual, nil
	case configs.NotEqualTo:
		return libseccomp.CompareNotEqual, nil
	case configs.GreaterThan:
		return libseccomp.CompareGreater, nil
	case configs.GreaterThanOrEqualTo:
		return libseccomp.CompareGreaterEqual, nil
	case configs.LessThan:
		return libseccomp.CompareLess, nil
	case configs.LessThanOrEqualTo:
		return libseccomp.CompareLessOrEqual, nil
	case configs.MaskEqualTo:
		return libseccomp.CompareMaskedEqual, nil
	default:
		return libseccomp.CompareInvalid, errors.New("invalid operator, cannot use in rule")
	}
}

// Convert Libcontainer Arg to Libseccomp ScmpCondition
func getCondition(arg *configs.Arg) (libseccomp.ScmpCondition, error) {
	cond := libseccomp.ScmpCondition{}

	if arg == nil {
		return cond, errors.New("cannot convert nil to syscall condition")
	}

	op, err := getOperator(arg.Op)
	if err != nil {
		return cond, err
	}

	return libseccomp.MakeCondition(arg.Index, op, arg.Value, arg.ValueTwo)
}

// Add a rule to match a single syscall
func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall, defAct libseccomp.ScmpAction) error {
	if call == nil || filter == nil {
		return errors.New("cannot use nil as syscall to block")
	}

	if len(call.Name) == 0 {
		return errors.New("empty string is not a valid syscall")
	}

	// Convert the call's action to the libseccomp equivalent
	callAct, err := getAction(call.Action, call.ErrnoRet)
	if err != nil {
		return fmt.Errorf("action in seccomp profile is invalid: %w", err)
	}
	if callAct == defAct {
		// This rule is redundant, silently skip it
		// to avoid error from AddRule.
		return nil
	}

	// If we can't resolve the syscall, assume it is not supported
	// by this kernel. Warn about it, don't error out.
	callNum, err := libseccomp.GetSyscallFromName(call.Name)
	if err != nil {
		logrus.Debugf("unknown seccomp syscall %q ignored", call.Name)
		return nil
	}

	// Unconditional match - just add the rule
	if len(call.Args) == 0 {
		if err := filter.AddRule(callNum, callAct); err != nil {
			return fmt.Errorf("error adding seccomp filter rule for syscall %s: %w", call.Name, err)
		}
	} else {
		// If two or more arguments have the same condition,
		// Revert to old behavior, adding each condition as a separate rule
		argCounts := make([]uint, syscallMaxArguments)
		conditions := []libseccomp.ScmpCondition{}

		for _, cond := range call.Args {
			newCond, err := getCondition(cond)
			if err != nil {
				return fmt.Errorf("error creating seccomp syscall condition for syscall %s: %w", call.Name, err)
			}

			argCounts[cond.Index] += 1

			conditions = append(conditions, newCond)
		}

		hasMultipleArgs := false
		for _, count := range argCounts {
			if count > 1 {
				hasMultipleArgs = true
				break
			}
		}

		if hasMultipleArgs {
			// Revert to old behavior
			// Add each condition attached to a separate rule
			for _, cond := range conditions {
				condArr := []libseccomp.ScmpCondition{cond}

				if err := filter.AddRuleConditional(callNum, callAct, condArr); err != nil {
					return fmt.Errorf("error adding seccomp rule for syscall %s: %w", call.Name, err)
				}
			}
		} else {
			// No conditions share same argument
			// Use new, proper behavior
			if err := filter.AddRuleConditional(callNum, callAct, conditions); err != nil {
				return fmt.Errorf("error adding seccomp rule for syscall %s: %w", call.Name, err)
			}
		}
	}

	return nil
}

// Version returns major, minor, and micro.
func Version() (uint, uint, uint) {
	return libseccomp.GetLibraryVersion()
}
<commit_msg>seccomp: drop unnecessary const SCMP_ACT_* defines<commit_after>//go:build cgo && seccomp
// +build cgo,seccomp

package seccomp

import (
	"errors"
	"fmt"

	libseccomp "github.com/seccomp/libseccomp-golang"
	"github.com/sirupsen/logrus"
	"golang.org/x/sys/unix"

	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/opencontainers/runc/libcontainer/seccomp/patchbpf"
)

var (
	actTrace = libseccomp.ActTrace.SetReturnCode(int16(unix.EPERM))
	actErrno = libseccomp.ActErrno.SetReturnCode(int16(unix.EPERM))
)

const (
	// Linux system calls can have at most 6 arguments
	syscallMaxArguments int = 6
)

// InitSeccomp installs the seccomp filters to be used in the container as
// specified in config.
// Returns the seccomp file descriptor if any of the filters include a
// SCMP_ACT_NOTIFY action, otherwise returns -1.
func InitSeccomp(config *configs.Seccomp) (int, error) {
	if config == nil {
		return -1, errors.New("cannot initialize Seccomp - nil config passed")
	}

	defaultAction, err := getAction(config.DefaultAction, config.DefaultErrnoRet)
	if err != nil {
		return -1, errors.New("error initializing seccomp - invalid default action")
	}

	// Ignore the error since pre-2.4 libseccomp is treated as API level 0.
	apiLevel, _ := libseccomp.GetAPI()
	for _, call := range config.Syscalls {
		if call.Action == configs.Notify {
			if apiLevel < 6 {
				return -1, fmt.Errorf("seccomp notify unsupported: API level: got %d, want at least 6. Please try with libseccomp >= 2.5.0 and Linux >= 5.7", apiLevel)
			}

			// We can't allow the write syscall to notify to the seccomp agent.
			// After InitSeccomp() is called, we need to syncParentSeccomp() to write the seccomp fd plain
			// number, so the parent sends it to the seccomp agent. If we use SCMP_ACT_NOTIFY on write, we
			// never can write the seccomp fd to the parent and therefore the seccomp agent never receives
			// the seccomp fd and runc is hang during initialization.
			//
			// Note that read()/close(), that are also used in syncParentSeccomp(), _can_ use SCMP_ACT_NOTIFY.
			// Because we write the seccomp fd on the pipe to the parent, the parent is able to proceed and
			// send the seccomp fd to the agent (it is another process and not subject to the seccomp
			// filter). We will be blocked on read()/close() inside syncParentSeccomp() but if the seccomp
			// agent allows those syscalls to proceed, initialization works just fine and the agent can
			// handle future read()/close() syscalls as it wanted.
			if call.Name == "write" {
				return -1, errors.New("SCMP_ACT_NOTIFY cannot be used for the write syscall")
			}
		}
	}

	// See comment on why write is not allowed. The same reason applies, as this can mean handling write too.
	if defaultAction == libseccomp.ActNotify {
		return -1, errors.New("SCMP_ACT_NOTIFY cannot be used as default action")
	}

	filter, err := libseccomp.NewFilter(defaultAction)
	if err != nil {
		return -1, fmt.Errorf("error creating filter: %w", err)
	}

	// Add extra architectures
	for _, arch := range config.Architectures {
		scmpArch, err := libseccomp.GetArchFromString(arch)
		if err != nil {
			return -1, fmt.Errorf("error validating Seccomp architecture: %w", err)
		}
		if err := filter.AddArch(scmpArch); err != nil {
			return -1, fmt.Errorf("error adding architecture to seccomp filter: %w", err)
		}
	}

	// Unset no new privs bit
	if err := filter.SetNoNewPrivsBit(false); err != nil {
		return -1, fmt.Errorf("error setting no new privileges: %w", err)
	}

	// Add a rule for each syscall
	for _, call := range config.Syscalls {
		if call == nil {
			return -1, errors.New("encountered nil syscall while initializing Seccomp")
		}

		if err := matchCall(filter, call, defaultAction); err != nil {
			return -1, err
		}
	}

	seccompFd, err := patchbpf.PatchAndLoad(config, filter)
	if err != nil {
		return -1, fmt.Errorf("error loading seccomp filter into kernel: %w", err)
	}

	return seccompFd, nil
}

// Convert Libcontainer Action to Libseccomp ScmpAction
func getAction(act configs.Action, errnoRet *uint) (libseccomp.ScmpAction, error) {
	switch act {
	case configs.Kill:
		return libseccomp.ActKill, nil
	case configs.Errno:
		if errnoRet != nil {
			return libseccomp.ActErrno.SetReturnCode(int16(*errnoRet)), nil
		}
		return actErrno, nil
	case configs.Trap:
		return libseccomp.ActTrap, nil
	case configs.Allow:
		return libseccomp.ActAllow, nil
	case configs.Trace:
		if errnoRet != nil {
			return libseccomp.ActTrace.SetReturnCode(int16(*errnoRet)), nil
		}
		return actTrace, nil
	case configs.Log:
		return libseccomp.ActLog, nil
	case configs.Notify:
		return libseccomp.ActNotify, nil
	default:
		return libseccomp.ActInvalid, errors.New("invalid action, cannot use in rule")
	}
}

// Convert Libcontainer Operator to Libseccomp ScmpCompareOp
func getOperator(op configs.Operator) (libseccomp.ScmpCompareOp, error) {
	switch op {
	case configs.EqualTo:
		return libseccomp.CompareEqual, nil
	case configs.NotEqualTo:
		return libseccomp.CompareNotEqual, nil
	case configs.GreaterThan:
		return libseccomp.CompareGreater, nil
	case configs.GreaterThanOrEqualTo:
		return libseccomp.CompareGreaterEqual, nil
	case configs.LessThan:
		return libseccomp.CompareLess, nil
	case configs.LessThanOrEqualTo:
		return libseccomp.CompareLessOrEqual, nil
	case configs.MaskEqualTo:
		return libseccomp.CompareMaskedEqual, nil
	default:
		return libseccomp.CompareInvalid, errors.New("invalid operator, cannot use in rule")
	}
}

// Convert Libcontainer Arg to Libseccomp ScmpCondition
func getCondition(arg *configs.Arg) (libseccomp.ScmpCondition, error) {
	cond := libseccomp.ScmpCondition{}

	if arg == nil {
		return cond, errors.New("cannot convert nil to syscall condition")
	}

	op, err := getOperator(arg.Op)
	if err != nil {
		return cond, err
	}

	return libseccomp.MakeCondition(arg.Index, op, arg.Value, arg.ValueTwo)
}

// Add a rule to match a single syscall
func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall, defAct libseccomp.ScmpAction) error {
	if call == nil || filter == nil {
		return errors.New("cannot use nil as syscall to block")
	}

	if len(call.Name) == 0 {
		return errors.New("empty string is not a valid syscall")
	}

	// Convert the call's action to the libseccomp equivalent
	callAct, err := getAction(call.Action, call.ErrnoRet)
	if err != nil {
		return fmt.Errorf("action in seccomp profile is invalid: %w", err)
	}
	if callAct == defAct {
		// This rule is redundant, silently skip it
		// to avoid error from AddRule.
		return nil
	}

	// If we can't resolve the syscall, assume it is not supported
	// by this kernel. Warn about it, don't error out.
	callNum, err := libseccomp.GetSyscallFromName(call.Name)
	if err != nil {
		logrus.Debugf("unknown seccomp syscall %q ignored", call.Name)
		return nil
	}

	// Unconditional match - just add the rule
	if len(call.Args) == 0 {
		if err := filter.AddRule(callNum, callAct); err != nil {
			return fmt.Errorf("error adding seccomp filter rule for syscall %s: %w", call.Name, err)
		}
	} else {
		// If two or more arguments have the same condition,
		// Revert to old behavior, adding each condition as a separate rule
		argCounts := make([]uint, syscallMaxArguments)
		conditions := []libseccomp.ScmpCondition{}

		for _, cond := range call.Args {
			newCond, err := getCondition(cond)
			if err != nil {
				return fmt.Errorf("error creating seccomp syscall condition for syscall %s: %w", call.Name, err)
			}

			argCounts[cond.Index] += 1

			conditions = append(conditions, newCond)
		}

		hasMultipleArgs := false
		for _, count := range argCounts {
			if count > 1 {
				hasMultipleArgs = true
				break
			}
		}

		if hasMultipleArgs {
			// Revert to old behavior
			// Add each condition attached to a separate rule
			for _, cond := range conditions {
				condArr := []libseccomp.ScmpCondition{cond}

				if err := filter.AddRuleConditional(callNum, callAct, condArr); err != nil {
					return fmt.Errorf("error adding seccomp rule for syscall %s: %w", call.Name, err)
				}
			}
		} else {
			// No conditions share same argument
			// Use new, proper behavior
			if err := filter.AddRuleConditional(callNum, callAct, conditions); err != nil {
				return fmt.Errorf("error adding seccomp rule for syscall %s: %w", call.Name, err)
			}
		}
	}

	return nil
}

// Version returns major, minor, and micro.
func Version() (uint, uint, uint) {
	return libseccomp.GetLibraryVersion()
}
<|endoftext|>


<commit_before>package scepserver_test

import (
	"bytes"
	"context"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"errors"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"

	kitlog "github.com/go-kit/kit/log"

	"github.com/micromdm/scep/depot"
	filedepot "github.com/micromdm/scep/depot/file"
	scepserver "github.com/micromdm/scep/server"
)

func TestCACaps(t *testing.T) {
	server, _ := newServer(t)
	defer server.Close()
	url := server.URL + "/scep?operation=GetCACaps"
	resp, err := http.Get(url)
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != http.StatusOK {
		t.Error("expected", http.StatusOK, "got", resp.StatusCode)
	}
}

func TestEncodePKCSReq_Request(t *testing.T) {
	pkcsreq := loadTestFile(t, "../scep/testdata/PKCSReq.der")
	msg := scepserver.SCEPRequest{
		Operation: "PKIOperation",
		Message:   pkcsreq,
	}
	methods := []string{"POST", "GET"}
	for _, method := range methods {
		t.Run(method, func(t *testing.T) {
			r := httptest.NewRequest(method, "http://acme.co/scep", nil)
			rr := *r
			if err := scepserver.EncodeSCEPRequest(context.Background(), &rr, msg); err != nil {
				t.Fatal(err)
			}

			q := r.URL.Query()
			if have, want := q.Get("operation"), msg.Operation; have != want {
				t.Errorf("have %s, want %s", have, want)
			}

			if method == "POST" {
				if have, want := rr.ContentLength, int64(len(msg.Message)); have != want {
					t.Errorf("have %d, want %d", have, want)
				}
			}

			if method == "GET" {
				if q.Get("message") == "" {
					t.Errorf("expected GET PKIOperation to have a non-empty message field")
				}
			}

		})
	}

}

func TestPKIOperation(t *testing.T) {
	server, _ := newServer(t)
	defer server.Close()
	pkcsreq := loadTestFile(t, "../scep/testdata/PKCSReq.der")
	body := bytes.NewReader(pkcsreq)
	url := server.URL + "/scep?operation=PKIOperation"
	resp, err := http.Post(url, "", body)
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != http.StatusOK {
		t.Error("expected", http.StatusOK, "got", resp.StatusCode)
	}
}

func newServer(t *testing.T, opts ...scepserver.ServiceOption) (*httptest.Server, scepserver.Service) {
	var err error
	var depot depot.Depot // cert storage
	{
		depot, err = filedepot.NewFileDepot("../scep/testdata/testca")
		if err != nil {
			t.Fatal(err)
		}
	}
	var svc scepserver.Service // scep service
	{
		svc, err = scepserver.NewService(depot, opts...)
		if err != nil {
			t.Fatal(err)
		}
	}
	logger := kitlog.NewNopLogger()
	e := scepserver.MakeServerEndpoints(svc)
	handler := scepserver.MakeHTTPHandler(e, svc, logger)
	server := httptest.NewServer(handler)
	return server, svc
}

/* helpers */
const (
	rsaPrivateKeyPEMBlockType = "RSA PRIVATE KEY"
	certificatePEMBlockType   = "CERTIFICATE"
)

func loadTestFile(t *testing.T, path string) []byte {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		t.Fatal(err)
	}
	return data
}

// create a new RSA private key
func newRSAKey(bits int) (*rsa.PrivateKey, error) {
	private, err := rsa.GenerateKey(rand.Reader, bits)
	if err != nil {
		return nil, err
	}
	return private, nil
}

// create a CSR using the same parameters as Keychain Access would produce
func newCSR(priv *rsa.PrivateKey, email, country, cname string) ([]byte, error) {
	subj := pkix.Name{
		Country:    []string{country},
		CommonName: cname,
		ExtraNames: []pkix.AttributeTypeAndValue{pkix.AttributeTypeAndValue{
			Type:  []int{1, 2, 840, 113549, 1, 9, 1},
			Value: email,
		}},
	}
	template := &x509.CertificateRequest{
		Subject: subj,
	}
	return x509.CreateCertificateRequest(rand.Reader, template, priv)
}
func loadCACredentials(t *testing.T) (*x509.Certificate, *rsa.PrivateKey) {
	cert, err := loadCertFromFile("../scep/testdata/testca/ca.crt")
	if err != nil {
		t.Fatal(err)
	}
	key, err := loadKeyFromFile("../scep/testdata/testca/ca.key")
	if err != nil {
		t.Fatal(err)
	}
	return cert, key
}

func loadClientCredentials(t *testing.T) (*x509.Certificate, *rsa.PrivateKey) {
	cert, err := loadCertFromFile("../scep/testdata/testclient/client.pem")
	if err != nil {
		t.Fatal(err)
	}
	key, err := loadKeyFromFile("../scep/testdata/testclient/client.key")
	if err != nil {
		t.Fatal(err)
	}
	return cert, key
}

func loadCertFromFile(path string) (*x509.Certificate, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	pemBlock, _ := pem.Decode(data)
	if pemBlock == nil {
		return nil, errors.New("PEM decode failed")
	}
	if pemBlock.Type != certificatePEMBlockType {
		return nil, errors.New("unmatched type or headers")
	}
	return x509.ParseCertificate(pemBlock.Bytes)
}

// load an encrypted private key from disk
func loadKeyFromFile(path string) (*rsa.PrivateKey, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	pemBlock, _ := pem.Decode(data)
	if pemBlock == nil {
		return nil, errors.New("PEM decode failed")
	}
	if pemBlock.Type != rsaPrivateKeyPEMBlockType {
		return nil, errors.New("unmatched type or headers")
	}

	// testca key has a password
	if len(pemBlock.Headers) > 0 {
		password := []byte("")
		b, err := x509.DecryptPEMBlock(pemBlock, password)
		if err != nil {
			return nil, err
		}
		return x509.ParsePKCS1PrivateKey(b)
	}

	return x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
}
<commit_msg>cleanup files after running tests (#57)<commit_after>package scepserver_test

import (
	"bytes"
	"context"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"errors"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"

	kitlog "github.com/go-kit/kit/log"

	"github.com/micromdm/scep/depot"
	filedepot "github.com/micromdm/scep/depot/file"
	scepserver "github.com/micromdm/scep/server"
)

func TestCACaps(t *testing.T) {
	server, _, teardown := newServer(t)
	defer teardown()
	url := server.URL + "/scep?operation=GetCACaps"
	resp, err := http.Get(url)
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != http.StatusOK {
		t.Error("expected", http.StatusOK, "got", resp.StatusCode)
	}
}

func TestEncodePKCSReq_Request(t *testing.T) {
	pkcsreq := loadTestFile(t, "../scep/testdata/PKCSReq.der")
	msg := scepserver.SCEPRequest{
		Operation: "PKIOperation",
		Message:   pkcsreq,
	}
	methods := []string{"POST", "GET"}
	for _, method := range methods {
		t.Run(method, func(t *testing.T) {
			r := httptest.NewRequest(method, "http://acme.co/scep", nil)
			rr := *r
			if err := scepserver.EncodeSCEPRequest(context.Background(), &rr, msg); err != nil {
				t.Fatal(err)
			}

			q := r.URL.Query()
			if have, want := q.Get("operation"), msg.Operation; have != want {
				t.Errorf("have %s, want %s", have, want)
			}

			if method == "POST" {
				if have, want := rr.ContentLength, int64(len(msg.Message)); have != want {
					t.Errorf("have %d, want %d", have, want)
				}
			}

			if method == "GET" {
				if q.Get("message") == "" {
					t.Errorf("expected GET PKIOperation to have a non-empty message field")
				}
			}

		})
	}

}

func TestPKIOperation(t *testing.T) {
	server, _, teardown := newServer(t)
	defer teardown()
	pkcsreq := loadTestFile(t, "../scep/testdata/PKCSReq.der")
	body := bytes.NewReader(pkcsreq)
	url := server.URL + "/scep?operation=PKIOperation"
	resp, err := http.Post(url, "", body)
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != http.StatusOK {
		t.Error("expected", http.StatusOK, "got", resp.StatusCode)
	}
}

func newServer(t *testing.T, opts ...scepserver.ServiceOption) (*httptest.Server, scepserver.Service, func()) {
	var err error
	var depot depot.Depot // cert storage
	{
		depot, err = filedepot.NewFileDepot("../scep/testdata/testca")
		if err != nil {
			t.Fatal(err)
		}
		depot = &noopDepot{depot}
	}
	var svc scepserver.Service // scep service
	{
		svc, err = scepserver.NewService(depot, opts...)
		if err != nil {
			t.Fatal(err)
		}
	}
	logger := kitlog.NewNopLogger()
	e := scepserver.MakeServerEndpoints(svc)
	handler := scepserver.MakeHTTPHandler(e, svc, logger)
	server := httptest.NewServer(handler)
	teardown := func() {
		server.Close()
		os.Remove("../scep/testdata/testca/serial")
		os.Remove("../scep/testdata/testca/index.txt")
	}
	return server, svc, teardown
}

type noopDepot struct{ depot.Depot }

func (d *noopDepot) Put(name string, crt *x509.Certificate) error {
	return nil
}

/* helpers */
const (
	rsaPrivateKeyPEMBlockType = "RSA PRIVATE KEY"
	certificatePEMBlockType   = "CERTIFICATE"
)

func loadTestFile(t *testing.T, path string) []byte {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		t.Fatal(err)
	}
	return data
}

// create a new RSA private key
func newRSAKey(bits int) (*rsa.PrivateKey, error) {
	private, err := rsa.GenerateKey(rand.Reader, bits)
	if err != nil {
		return nil, err
	}
	return private, nil
}

// create a CSR using the same parameters as Keychain Access would produce
func newCSR(priv *rsa.PrivateKey, email, country, cname string) ([]byte, error) {
	subj := pkix.Name{
		Country:    []string{country},
		CommonName: cname,
		ExtraNames: []pkix.AttributeTypeAndValue{pkix.AttributeTypeAndValue{
			Type:  []int{1, 2, 840, 113549, 1, 9, 1},
			Value: email,
		}},
	}
	template := &x509.CertificateRequest{
		Subject: subj,
	}
	return x509.CreateCertificateRequest(rand.Reader, template, priv)
}
func loadCACredentials(t *testing.T) (*x509.Certificate, *rsa.PrivateKey) {
	cert, err := loadCertFromFile("../scep/testdata/testca/ca.crt")
	if err != nil {
		t.Fatal(err)
	}
	key, err := loadKeyFromFile("../scep/testdata/testca/ca.key")
	if err != nil {
		t.Fatal(err)
	}
	return cert, key
}

func loadClientCredentials(t *testing.T) (*x509.Certificate, *rsa.PrivateKey) {
	cert, err := loadCertFromFile("../scep/testdata/testclient/client.pem")
	if err != nil {
		t.Fatal(err)
	}
	key, err := loadKeyFromFile("../scep/testdata/testclient/client.key")
	if err != nil {
		t.Fatal(err)
	}
	return cert, key
}

func loadCertFromFile(path string) (*x509.Certificate, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	pemBlock, _ := pem.Decode(data)
	if pemBlock == nil {
		return nil, errors.New("PEM decode failed")
	}
	if pemBlock.Type != certificatePEMBlockType {
		return nil, errors.New("unmatched type or headers")
	}
	return x509.ParseCertificate(pemBlock.Bytes)
}

// load an encrypted private key from disk
func loadKeyFromFile(path string) (*rsa.PrivateKey, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	pemBlock, _ := pem.Decode(data)
	if pemBlock == nil {
		return nil, errors.New("PEM decode failed")
	}
	if pemBlock.Type != rsaPrivateKeyPEMBlockType {
		return nil, errors.New("unmatched type or headers")
	}

	// testca key has a password
	if len(pemBlock.Headers) > 0 {
		password := []byte("")
		b, err := x509.DecryptPEMBlock(pemBlock, password)
		if err != nil {
			return nil, err
		}
		return x509.ParsePKCS1PrivateKey(b)
	}

	return x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
}
<|endoftext|>


<commit_before>package ai

import (
	"bytes"
	"log"

	"nelhage.com/tak/ptn"
	"nelhage.com/tak/tak"
)

const (
	maxEval      int64 = 1 << 30
	minEval            = -maxEval
	winThreshold       = 1 << 29
)

type MinimaxAI struct {
	depth int

	Debug bool
}

func formatpv(ms []tak.Move) string {
	var out bytes.Buffer
	out.WriteString("[")
	for i, m := range ms {
		if i != 0 {
			out.WriteString(" ")
		}
		out.WriteString(ptn.FormatMove(&m))
	}
	out.WriteString("]")
	return out.String()
}

func (m *MinimaxAI) GetMove(p *tak.Position) tak.Move {
	ms, _ := m.Analyze(p)
	return ms[0]
}

func (m *MinimaxAI) Analyze(p *tak.Position) ([]tak.Move, int64) {
	var ms []tak.Move
	var v int64
	for i := 1; i <= m.depth; i++ {
		ms, v = m.minimax(p, i, ms, maxEval-1, maxEval+1)
		if m.Debug {
			log.Printf("[minimax] depth=%d val=%d pv=%s",
				i, v, formatpv(ms))
		}
		if v > winThreshold || v < -winThreshold {
			break
		}
	}
	return ms, v
}

func (ai *MinimaxAI) minimax(
	p *tak.Position,
	depth int,
	pv []tak.Move,
	α, β int64) ([]tak.Move, int64) {
	over, _ := p.GameOver()
	if depth == 0 || over {
		return nil, ai.evaluate(p)
	}

	if p.MoveNumber() < 2 {
		for _, c := range [][]int{{0, 0}, {p.Size() - 1, 0}, {0, p.Size() - 1}, {p.Size() - 1, p.Size() - 1}} {
			x, y := c[0], c[1]
			if len(p.At(x, y)) == 0 {
				return []tak.Move{{X: x, Y: y, Type: tak.PlaceFlat}}, 0
			}
		}
	}
	moves := p.AllMoves()
	if len(pv) > 0 {
		for i, m := range moves {
			if m.Equal(&pv[0]) {
				moves[0], moves[i] = moves[i], moves[0]
				break
			}
		}
	}

	best := make([]tak.Move, 0, depth)
	max := minEval - 1
	for _, m := range moves {
		child, e := p.Move(&m)
		if e != nil {
			continue
		}
		var ms []tak.Move
		var v int64
		if len(best) == 0 {
			ms, v = ai.minimax(child, depth-1, nil, -β, -α)
		} else {
			ms, v = ai.minimax(child, depth-1, best[1:], -β, -α)
		}
		v = -v
		if v > max {
			max = v
			best = append(best[:0], m)
			best = append(best, ms...)
		}
		if v > α {
			α = v
			if α >= β {
				break
			}
		}
	}
	return best, max
}

func imin(a, b int) int {
	if a < b {
		return a
	}
	return b
}

const (
	weightFlat       = 2
	weightCaptured   = 1
	weightControlled = 5
	weightCapstone   = -1
)

func (m *MinimaxAI) evaluate(p *tak.Position) int64 {
	if over, winner := p.GameOver(); over {
		switch winner {
		case tak.NoColor:
			return 0
		case p.ToMove():
			return maxEval - int64(p.MoveNumber())
		default:
			return minEval + int64(p.MoveNumber())
		}
	}
	mine, theirs := 0, 0
	me := p.ToMove()
	addw := func(c tak.Color, w int) {
		if c == me {
			mine += w
		} else {
			theirs += w
		}
	}
	for x := 0; x < p.Size(); x++ {
		for y := 0; y < p.Size(); y++ {
			sq := p.At(x, y)
			if len(sq) == 0 {
				continue
			}
			addw(sq[0].Color(), weightControlled)
			if sq[0].Kind() == tak.Capstone {
				addw(sq[0].Color(), weightCapstone)
			}
			for i, stone := range sq {
				if i > 0 && i < p.Size() {
					addw(sq[0].Color(), weightCaptured)
				}
				if stone.Kind() == tak.Flat {
					addw(stone.Color(), weightFlat)
				}
			}
		}
	}

	return int64(mine - theirs)
}

func NewMinimax(depth int) *MinimaxAI {
	return &MinimaxAI{depth: depth}
}
<commit_msg>woops<commit_after>package ai

import (
	"bytes"
	"log"

	"nelhage.com/tak/ptn"
	"nelhage.com/tak/tak"
)

const (
	maxEval      int64 = 1 << 30
	minEval            = -maxEval
	winThreshold       = 1 << 29
)

type MinimaxAI struct {
	depth int

	Debug bool
}

func formatpv(ms []tak.Move) string {
	var out bytes.Buffer
	out.WriteString("[")
	for i, m := range ms {
		if i != 0 {
			out.WriteString(" ")
		}
		out.WriteString(ptn.FormatMove(&m))
	}
	out.WriteString("]")
	return out.String()
}

func (m *MinimaxAI) GetMove(p *tak.Position) tak.Move {
	ms, _ := m.Analyze(p)
	return ms[0]
}

func (m *MinimaxAI) Analyze(p *tak.Position) ([]tak.Move, int64) {
	var ms []tak.Move
	var v int64
	for i := 1; i <= m.depth; i++ {
		ms, v = m.minimax(p, i, ms, minEval-1, maxEval+1)
		if m.Debug {
			log.Printf("[minimax] depth=%d val=%d pv=%s",
				i, v, formatpv(ms))
		}
		if v > winThreshold || v < -winThreshold {
			break
		}
	}
	return ms, v
}

func (ai *MinimaxAI) minimax(
	p *tak.Position,
	depth int,
	pv []tak.Move,
	α, β int64) ([]tak.Move, int64) {
	over, _ := p.GameOver()
	if depth == 0 || over {
		return nil, ai.evaluate(p)
	}

	if p.MoveNumber() < 2 {
		for _, c := range [][]int{{0, 0}, {p.Size() - 1, 0}, {0, p.Size() - 1}, {p.Size() - 1, p.Size() - 1}} {
			x, y := c[0], c[1]
			if len(p.At(x, y)) == 0 {
				return []tak.Move{{X: x, Y: y, Type: tak.PlaceFlat}}, 0
			}
		}
	}
	moves := p.AllMoves()
	if len(pv) > 0 {
		for i, m := range moves {
			if m.Equal(&pv[0]) {
				moves[0], moves[i] = moves[i], moves[0]
				break
			}
		}
	}

	best := make([]tak.Move, 0, depth)
	max := minEval - 1
	for _, m := range moves {
		child, e := p.Move(&m)
		if e != nil {
			continue
		}
		var ms []tak.Move
		var v int64
		if len(best) == 0 {
			ms, v = ai.minimax(child, depth-1, nil, -β, -α)
		} else {
			ms, v = ai.minimax(child, depth-1, best[1:], -β, -α)
		}
		v = -v
		if v > max {
			max = v
			best = append(best[:0], m)
			best = append(best, ms...)
		}
		if v > α {
			α = v
			if α >= β {
				break
			}
		}
	}
	return best, max
}

func imin(a, b int) int {
	if a < b {
		return a
	}
	return b
}

const (
	weightFlat       = 2
	weightCaptured   = 1
	weightControlled = 5
	weightCapstone   = -1
)

func (m *MinimaxAI) evaluate(p *tak.Position) int64 {
	if over, winner := p.GameOver(); over {
		switch winner {
		case tak.NoColor:
			return 0
		case p.ToMove():
			return maxEval - int64(p.MoveNumber())
		default:
			return minEval + int64(p.MoveNumber())
		}
	}
	mine, theirs := 0, 0
	me := p.ToMove()
	addw := func(c tak.Color, w int) {
		if c == me {
			mine += w
		} else {
			theirs += w
		}
	}
	for x := 0; x < p.Size(); x++ {
		for y := 0; y < p.Size(); y++ {
			sq := p.At(x, y)
			if len(sq) == 0 {
				continue
			}
			addw(sq[0].Color(), weightControlled)
			if sq[0].Kind() == tak.Capstone {
				addw(sq[0].Color(), weightCapstone)
			}
			for i, stone := range sq {
				if i > 0 && i < p.Size() {
					addw(sq[0].Color(), weightCaptured)
				}
				if stone.Kind() == tak.Flat {
					addw(stone.Color(), weightFlat)
				}
			}
		}
	}

	return int64(mine - theirs)
}

func NewMinimax(depth int) *MinimaxAI {
	return &MinimaxAI{depth: depth}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"regexp"

	"github.com/ptt/pttweb/pttbbs"
	"github.com/ptt/pttweb/richcontent"

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

var aidPatterns = []struct {
	Pattern *regexp.Regexp
	Handler func(ctx context.Context, input []byte, m richcontent.MatchIndices) (link string, err error)
}{
	{
		Pattern: regexp.MustCompile(`#([0-9A-Za-z\-_\@]{8,10}) \(([0-9A-Za-z\-_]{1,12})\)`),
		Handler: handleAidBoardText,
	},
	{
		Pattern: regexp.MustCompile(`#([0-9A-Za-z\-_\@]{8,10})`),
		Handler: handleAidText,
	},
}

func init() {
	richcontent.RegisterFinder(findAidText)
}

func findAidText(ctx context.Context, input []byte) (rcs []richcontent.RichContent, err error) {
	for _, p := range aidPatterns {
		all := p.Pattern.FindAllStringSubmatchIndex(string(input), -1)
		for _, m := range all {
			link, err := p.Handler(ctx, input, richcontent.MatchIndices(m))
			if err != nil {
				return nil, err
			}
			if link != "" {
				rcs = append(rcs, richcontent.MakeRichContent(m[0], m[1], link, nil))
			}
		}
	}
	return rcs, nil
}

func handleAidText(ctx context.Context, input []byte, m richcontent.MatchIndices) (string, error) {
	req := ctx.Value(CtxKeyArticleRequest).(*ArticleRequest)
	if req == nil {
		log.Println("no ArticleRequest present")
		return "", nil // Silently fail
	}

	aidString := string(m.ByteSliceOf(input, 1))
	return aidAndBrdnameToArticle(req.Brd.BrdName, aidString)
}

func handleAidBoardText(ctx context.Context, input []byte, m richcontent.MatchIndices) (string, error) {
	aidString := string(m.ByteSliceOf(input, 1))
	brdname := string(m.ByteSliceOf(input, 2))
	return aidAndBrdnameToArticle(brdname, aidString)
}

func aidAndBrdnameToArticle(brdname, aidString string) (string, error) {
	aid, err := pttbbs.ParseAid(aidString)
	if err != nil {
		return "", nil // Silently fail
	}

	u, err := router.Get("bbsarticle").URLPath("brdname", brdname, "filename", aid.Filename())
	if err != nil {
		return "", err
	}
	return u.String(), nil
}
<commit_msg>Fix panic on nil.<commit_after>package main

import (
	"log"
	"regexp"

	"github.com/ptt/pttweb/pttbbs"
	"github.com/ptt/pttweb/richcontent"

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

var aidPatterns = []struct {
	Pattern *regexp.Regexp
	Handler func(ctx context.Context, input []byte, m richcontent.MatchIndices) (link string, err error)
}{
	{
		Pattern: regexp.MustCompile(`#([0-9A-Za-z\-_\@]{8,10}) \(([0-9A-Za-z\-_]{1,12})\)`),
		Handler: handleAidBoardText,
	},
	{
		Pattern: regexp.MustCompile(`#([0-9A-Za-z\-_\@]{8,10})`),
		Handler: handleAidText,
	},
}

func init() {
	richcontent.RegisterFinder(findAidText)
}

func findAidText(ctx context.Context, input []byte) (rcs []richcontent.RichContent, err error) {
	for _, p := range aidPatterns {
		all := p.Pattern.FindAllStringSubmatchIndex(string(input), -1)
		for _, m := range all {
			link, err := p.Handler(ctx, input, richcontent.MatchIndices(m))
			if err != nil {
				return nil, err
			}
			if link != "" {
				rcs = append(rcs, richcontent.MakeRichContent(m[0], m[1], link, nil))
			}
		}
	}
	return rcs, nil
}

func handleAidText(ctx context.Context, input []byte, m richcontent.MatchIndices) (string, error) {
	req, ok := ctx.Value(CtxKeyArticleRequest).(*ArticleRequest)
	if !ok {
		log.Println("no ArticleRequest present")
		return "", nil // Silently fail
	}

	aidString := string(m.ByteSliceOf(input, 1))
	return aidAndBrdnameToArticle(req.Brd.BrdName, aidString)
}

func handleAidBoardText(ctx context.Context, input []byte, m richcontent.MatchIndices) (string, error) {
	aidString := string(m.ByteSliceOf(input, 1))
	brdname := string(m.ByteSliceOf(input, 2))
	return aidAndBrdnameToArticle(brdname, aidString)
}

func aidAndBrdnameToArticle(brdname, aidString string) (string, error) {
	aid, err := pttbbs.ParseAid(aidString)
	if err != nil {
		return "", nil // Silently fail
	}

	u, err := router.Get("bbsarticle").URLPath("brdname", brdname, "filename", aid.Filename())
	if err != nil {
		return "", err
	}
	return u.String(), nil
}
<|endoftext|>