<commit_before>package http

import (
	"net/http"
	"time"

	"github.com/maxence-charriere/app/pkg/log"
)

// Watch returns a decorated version of the given handler that provide
// insight on the request.
func Watch(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		h.ServeHTTP(w, r)
		log.Info("request served").
			T("path", r.URL.Path).
			T("content-type", w.Header().Get("Content-Type")).
			T("content-lenght", w.Header().Get("Content-Length")).
			T("content-encoding", w.Header().Get("Content-Encoding")).
			T("header", w.Header()).
			T("duration", time.Now().Sub(start).String())
	})
}
<commit_msg>Update watch.go<commit_after>package http

import (
	"net/http"
	"time"

	"github.com/maxence-charriere/app/pkg/log"
)

// Watch returns a decorated version of the given handler that provide
// insight on the request.
func Watch(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		h.ServeHTTP(w, r)
		log.Info("request served").
			T("path", r.URL.Path).
			T("content-type", w.Header().Get("Content-Type")).
			T("content-length", w.Header().Get("Content-Length")).
			T("content-encoding", w.Header().Get("Content-Encoding")).
			T("header", w.Header()).
			T("duration", time.Now().Sub(start).String())
	})
}
<|endoftext|>


<commit_before>// Copyright 2016-2017 Authors of Cilium
//
// 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 k8s abstracts all Kubernetes specific behaviour
package k8s

import (
	goerrors "errors"
	"fmt"
	"net"
	"time"

	"github.com/cilium/cilium/api/v1/models"
	"github.com/cilium/cilium/pkg/annotation"
	"github.com/cilium/cilium/pkg/logging/logfields"

	go_version "github.com/hashicorp/go-version"
	"github.com/sirupsen/logrus"
	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)

var (
	// ErrNilNode is returned when the Kubernetes API server has returned a nil node
	ErrNilNode = goerrors.New("API server returned nil node")
)

// CreateConfig creates a rest.Config for a given endpoint using a kubeconfig file.
func createConfig(endpoint, kubeCfgPath string) (*rest.Config, error) {
	// If the endpoint and the kubeCfgPath are empty then we can try getting
	// the rest.Config from the InClusterConfig
	if endpoint == "" && kubeCfgPath == "" {
		return rest.InClusterConfig()
	}

	if kubeCfgPath != "" {
		return clientcmd.BuildConfigFromFlags("", kubeCfgPath)
	}

	config := &rest.Config{Host: endpoint}
	err := rest.SetKubernetesDefaults(config)

	return config, err
}

// CreateConfigFromAgentResponse creates a client configuration from a
// models.DaemonConfigurationResponse
func CreateConfigFromAgentResponse(resp *models.DaemonConfigurationResponse) (*rest.Config, error) {
	return createConfig(resp.K8sEndpoint, resp.K8sConfiguration)
}

// CreateConfig creates a client configuration based on the configured API
// server and Kubeconfig path
func CreateConfig() (*rest.Config, error) {
	return createConfig(GetAPIServer(), GetKubeconfigPath())
}

// CreateClient creates a new client to access the Kubernetes API
func CreateClient(config *rest.Config) (*kubernetes.Clientset, error) {
	cs, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, err
	}
	stop := make(chan struct{})
	timeout := time.NewTimer(time.Minute)
	defer timeout.Stop()
	wait.Until(func() {
		log.Info("Waiting for k8s api-server to be ready...")
		err = isConnReady(cs)
		if err == nil {
			close(stop)
			return
		}
		select {
		case <-timeout.C:
			log.WithError(err).WithField(logfields.IPAddr, config.Host).Error("Unable to contact k8s api-server")
			close(stop)
		default:
		}
	}, 5*time.Second, stop)
	if err == nil {
		log.WithField(logfields.IPAddr, config.Host).Info("Connected to k8s api-server")
	}
	return cs, err
}

// GetServerVersion returns the kubernetes api-server version.
func GetServerVersion() (*go_version.Version, error) {
	sv, err := Client().Discovery().ServerVersion()
	switch {
	case err != nil:
		return nil, err

	case sv.Major != "" && sv.Minor != "":
		return go_version.NewVersion(fmt.Sprintf("%s.%s", sv.Major, sv.Minor))

	case sv.GitVersion != "":
		// This is a string like "v1.9.0"
		return go_version.NewVersion(sv.GitVersion[1:])

	default:
		return nil, fmt.Errorf("Cannot parse k8s server version from %+v", sv)
	}
}

// isConnReady returns the err for the controller-manager status
func isConnReady(c *kubernetes.Clientset) error {
	_, err := c.CoreV1().ComponentStatuses().Get("controller-manager", metav1.GetOptions{})
	return err
}

func updateNodeAnnotation(c kubernetes.Interface, node *v1.Node, v4CIDR, v6CIDR *net.IPNet, v4HealthIP, v6HealthIP net.IP) (*v1.Node, error) {
	if node.Annotations == nil {
		node.Annotations = map[string]string{}
	}

	if v4CIDR != nil {
		node.Annotations[annotation.V4CIDRName] = v4CIDR.String()
	}
	if v6CIDR != nil {
		node.Annotations[annotation.V6CIDRName] = v6CIDR.String()
	}

	if v4HealthIP != nil {
		node.Annotations[annotation.V4HealthName] = v4HealthIP.String()
	}
	if v6HealthIP != nil {
		node.Annotations[annotation.V6HealthName] = v6HealthIP.String()
	}

	node, err := c.CoreV1().Nodes().Update(node)
	if err != nil {
		return nil, err
	}

	if node == nil {
		return nil, ErrNilNode
	}

	return node, nil
}

// AnnotateNode writes v4 and v6 CIDRs and health IPs in the given k8s node name.
// In case of failure while updating the node, this function while spawn a go
// routine to retry the node update indefinitely.
func AnnotateNode(c kubernetes.Interface, nodeName string, v4CIDR, v6CIDR *net.IPNet, v4HealthIP, v6HealthIP net.IP) error {
	scopedLog := log.WithFields(logrus.Fields{
		logfields.NodeName:   nodeName,
		logfields.V4Prefix:   v4CIDR,
		logfields.V6Prefix:   v6CIDR,
		logfields.V4HealthIP: v4HealthIP,
		logfields.V6HealthIP: v6HealthIP,
	})
	scopedLog.Debug("Updating node annotations with node CIDRs")

	go func(c kubernetes.Interface, nodeName string, v4CIDR, v6CIDR *net.IPNet, v4HealthIP, v6HealthIP net.IP) {
		var node *v1.Node
		var err error

		for n := 1; n <= maxUpdateRetries; n++ {
			node, err = GetNode(c, nodeName)
			if err == nil {
				node, err = updateNodeAnnotation(c, node, v4CIDR, v6CIDR, v4HealthIP, v6HealthIP)
			} else {
				if errors.IsNotFound(err) {
					err = ErrNilNode
				}
			}

			if err != nil {
				scopedLog.WithFields(logrus.Fields{
					fieldRetry:    n,
					fieldMaxRetry: maxUpdateRetries,
				}).WithError(err).Error("Unable to update node resource with annotation")
			} else {
				break
			}

			time.Sleep(time.Duration(n) * time.Second)
		}
	}(c, nodeName, v4CIDR, v6CIDR, v4HealthIP, v6HealthIP)

	return nil
}

var (
	client kubernetes.Interface
)

// Client returns the default Kubernetes client
func Client() kubernetes.Interface {
	return client
}

func createDefaultClient() error {
	restConfig, err := CreateConfig()
	if err != nil {
		return fmt.Errorf("unable to create k8s client rest configuration: %s", err)
	}

	k8sClient, err := CreateClient(restConfig)
	if err != nil {
		return fmt.Errorf("unable to create k8s client: %s", err)
	}

	client = k8sClient

	return nil
}
<commit_msg>pkg/k8s: parse GitVersion first for GetServerVersion<commit_after>// Copyright 2016-2017 Authors of Cilium
//
// 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 k8s abstracts all Kubernetes specific behaviour
package k8s

import (
	goerrors "errors"
	"fmt"
	"net"
	"time"

	"github.com/cilium/cilium/api/v1/models"
	"github.com/cilium/cilium/pkg/annotation"
	"github.com/cilium/cilium/pkg/logging/logfields"

	go_version "github.com/hashicorp/go-version"
	"github.com/sirupsen/logrus"
	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)

var (
	// ErrNilNode is returned when the Kubernetes API server has returned a nil node
	ErrNilNode = goerrors.New("API server returned nil node")
)

// CreateConfig creates a rest.Config for a given endpoint using a kubeconfig file.
func createConfig(endpoint, kubeCfgPath string) (*rest.Config, error) {
	// If the endpoint and the kubeCfgPath are empty then we can try getting
	// the rest.Config from the InClusterConfig
	if endpoint == "" && kubeCfgPath == "" {
		return rest.InClusterConfig()
	}

	if kubeCfgPath != "" {
		return clientcmd.BuildConfigFromFlags("", kubeCfgPath)
	}

	config := &rest.Config{Host: endpoint}
	err := rest.SetKubernetesDefaults(config)

	return config, err
}

// CreateConfigFromAgentResponse creates a client configuration from a
// models.DaemonConfigurationResponse
func CreateConfigFromAgentResponse(resp *models.DaemonConfigurationResponse) (*rest.Config, error) {
	return createConfig(resp.K8sEndpoint, resp.K8sConfiguration)
}

// CreateConfig creates a client configuration based on the configured API
// server and Kubeconfig path
func CreateConfig() (*rest.Config, error) {
	return createConfig(GetAPIServer(), GetKubeconfigPath())
}

// CreateClient creates a new client to access the Kubernetes API
func CreateClient(config *rest.Config) (*kubernetes.Clientset, error) {
	cs, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, err
	}
	stop := make(chan struct{})
	timeout := time.NewTimer(time.Minute)
	defer timeout.Stop()
	wait.Until(func() {
		log.Info("Waiting for k8s api-server to be ready...")
		err = isConnReady(cs)
		if err == nil {
			close(stop)
			return
		}
		select {
		case <-timeout.C:
			log.WithError(err).WithField(logfields.IPAddr, config.Host).Error("Unable to contact k8s api-server")
			close(stop)
		default:
		}
	}, 5*time.Second, stop)
	if err == nil {
		log.WithField(logfields.IPAddr, config.Host).Info("Connected to k8s api-server")
	}
	return cs, err
}

// GetServerVersion returns the kubernetes api-server version.
func GetServerVersion() (ver *go_version.Version, err error) {
	sv, err := Client().Discovery().ServerVersion()
	if err != nil {
		return nil, err
	}

	// Try GitVersion first. In case of error fallback to MajorMinor
	if sv.GitVersion != "" {
		// This is a string like "v1.9.0"
		ver, err = go_version.NewVersion(sv.GitVersion)
		if err == nil {
			return ver, err
		}
	}

	if sv.Major != "" && sv.Minor != "" {
		ver, err = go_version.NewVersion(fmt.Sprintf("%s.%s", sv.Major, sv.Minor))
		if err == nil {
			return ver, nil
		}
	}

	if err != nil {
		return nil, fmt.Errorf("cannot parse k8s server version from %+v: %s", sv, err)
	}
	return nil, fmt.Errorf("cannot parse k8s server version from %+v", sv)
}

// isConnReady returns the err for the controller-manager status
func isConnReady(c *kubernetes.Clientset) error {
	_, err := c.CoreV1().ComponentStatuses().Get("controller-manager", metav1.GetOptions{})
	return err
}

func updateNodeAnnotation(c kubernetes.Interface, node *v1.Node, v4CIDR, v6CIDR *net.IPNet, v4HealthIP, v6HealthIP net.IP) (*v1.Node, error) {
	if node.Annotations == nil {
		node.Annotations = map[string]string{}
	}

	if v4CIDR != nil {
		node.Annotations[annotation.V4CIDRName] = v4CIDR.String()
	}
	if v6CIDR != nil {
		node.Annotations[annotation.V6CIDRName] = v6CIDR.String()
	}

	if v4HealthIP != nil {
		node.Annotations[annotation.V4HealthName] = v4HealthIP.String()
	}
	if v6HealthIP != nil {
		node.Annotations[annotation.V6HealthName] = v6HealthIP.String()
	}

	node, err := c.CoreV1().Nodes().Update(node)
	if err != nil {
		return nil, err
	}

	if node == nil {
		return nil, ErrNilNode
	}

	return node, nil
}

// AnnotateNode writes v4 and v6 CIDRs and health IPs in the given k8s node name.
// In case of failure while updating the node, this function while spawn a go
// routine to retry the node update indefinitely.
func AnnotateNode(c kubernetes.Interface, nodeName string, v4CIDR, v6CIDR *net.IPNet, v4HealthIP, v6HealthIP net.IP) error {
	scopedLog := log.WithFields(logrus.Fields{
		logfields.NodeName:   nodeName,
		logfields.V4Prefix:   v4CIDR,
		logfields.V6Prefix:   v6CIDR,
		logfields.V4HealthIP: v4HealthIP,
		logfields.V6HealthIP: v6HealthIP,
	})
	scopedLog.Debug("Updating node annotations with node CIDRs")

	go func(c kubernetes.Interface, nodeName string, v4CIDR, v6CIDR *net.IPNet, v4HealthIP, v6HealthIP net.IP) {
		var node *v1.Node
		var err error

		for n := 1; n <= maxUpdateRetries; n++ {
			node, err = GetNode(c, nodeName)
			if err == nil {
				node, err = updateNodeAnnotation(c, node, v4CIDR, v6CIDR, v4HealthIP, v6HealthIP)
			} else {
				if errors.IsNotFound(err) {
					err = ErrNilNode
				}
			}

			if err != nil {
				scopedLog.WithFields(logrus.Fields{
					fieldRetry:    n,
					fieldMaxRetry: maxUpdateRetries,
				}).WithError(err).Error("Unable to update node resource with annotation")
			} else {
				break
			}

			time.Sleep(time.Duration(n) * time.Second)
		}
	}(c, nodeName, v4CIDR, v6CIDR, v4HealthIP, v6HealthIP)

	return nil
}

var (
	client kubernetes.Interface
)

// Client returns the default Kubernetes client
func Client() kubernetes.Interface {
	return client
}

func createDefaultClient() error {
	restConfig, err := CreateConfig()
	if err != nil {
		return fmt.Errorf("unable to create k8s client rest configuration: %s", err)
	}

	k8sClient, err := CreateClient(restConfig)
	if err != nil {
		return fmt.Errorf("unable to create k8s client: %s", err)
	}

	client = k8sClient

	return nil
}
<|endoftext|>


<commit_before>package controllers

import (
	"fmt"
	"net/http"
	"net/url"

	"github.com/yosssi/xpress/app/consts"
	"github.com/yosssi/xpress/app/models"
)

func SigninIndex(w http.ResponseWriter, r *http.Request, app *models.Application) {
	render("./app/views/signin/index.gold", nil, w, r, app)
}

func SigninCallback(w http.ResponseWriter, r *http.Request, app *models.Application) {
	// parse the URL.
	u, err := url.Parse(r.URL.String())

	if err != nil {
		handleError(w, r, app, err)
		return
	}

	// get a GitHub access token.
	accessToken, err := app.GitHubClient.GetAccessToken(u.Query().Get("code"))

	if err != nil {
		handleError(w, r, app, err)
		return
	}

	app.Logger.Debugf("accessToken: %s", accessToken)

	// get a GitHub user.
	ghUser, err := app.GitHubClient.GetAuthenticatedUser(accessToken)

	if err != nil {
		handleError(w, r, app, err)
		return
	}

	app.Logger.Debugf("ghUser: %+v", ghUser)

	// get a user.
	result := map[string]interface{}{}
	code, err := app.ElasticsearchClient.Search(consts.ElasticsearchIndexXpress, consts.ElasticsearchTypeUser, "", &result)

	if err != nil {
		handleError(w, r, app, err)
		return
	}

	if code != http.StatusOK {
		handleError(w, r, app, fmt.Errorf("Search API's HTTP status code is not OK. [code: %d]", code))
		return
	}

	app.Logger.Debugf("result: %+v", result)

	result = map[string]interface{}{}

	userMap := map[string]interface{}{"github_id": ghUser.ID, "access_token": accessToken}
	code, err = app.ElasticsearchClient.Create(consts.ElasticsearchIndexXpress, consts.ElasticsearchTypeUser, userMap, &result)
	app.Logger.Debugf("code: %d, result: %+v, err: %+v", code, result, err)

	render("./app/views/signin/index.gold", nil, w, r, app)
}
<commit_msg>Updated signin.go.<commit_after>package controllers

import (
	"fmt"
	"net/http"
	"net/url"

	"github.com/yosssi/xpress/app/consts"
	"github.com/yosssi/xpress/app/models"
)

func SigninIndex(w http.ResponseWriter, r *http.Request, app *models.Application) {
	render("./app/views/signin/index.gold", nil, w, r, app)
}

func SigninCallback(w http.ResponseWriter, r *http.Request, app *models.Application) {
	// parse the URL.
	u, err := url.Parse(r.URL.String())

	if err != nil {
		handleError(w, r, app, err)
		return
	}

	// get a GitHub access token.
	accessToken, err := app.GitHubClient.GetAccessToken(u.Query().Get("code"))

	if err != nil {
		handleError(w, r, app, err)
		return
	}

	app.Logger.Debugf("accessToken: %s", accessToken)

	// get a GitHub user.
	ghUser, err := app.GitHubClient.GetAuthenticatedUser(accessToken)

	if err != nil {
		handleError(w, r, app, err)
		return
	}

	app.Logger.Debugf("ghUser: %+v", ghUser)

	// get a user.
	result := map[string]interface{}{}
	code, err := app.ElasticsearchClient.Search(consts.ElasticsearchIndexXpress, consts.ElasticsearchTypeUser, "", &result)

	if err != nil {
		handleError(w, r, app, err)
		return
	}

	if code != http.StatusOK && code != http.StatusNotFound {
		handleError(w, r, app, fmt.Errorf("Search API's HTTP status code is not OK or NotFound. [code: %d]", code))
		return
	}

	app.Logger.Debugf("result: %+v", result)

	result = map[string]interface{}{}

	userMap := map[string]interface{}{"github_id": ghUser.ID, "access_token": accessToken}
	code, err = app.ElasticsearchClient.Create(consts.ElasticsearchIndexXpress, consts.ElasticsearchTypeUser, userMap, &result)
	app.Logger.Debugf("code: %d, result: %+v, err: %+v", code, result, err)

	render("./app/views/signin/index.gold", nil, w, r, app)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/md5"
	_ "expvar"
	"fmt"
	"github.com/quii/mockingjay-server/mockingjay"
	"github.com/quii/mockingjay-server/monkey"
	"io/ioutil"
	"log"
	"net/http"
	"path/filepath"
	"strings"
	"time"
)

var (
	// ErrCDCFail describes when a fake server is not compatible with a given URL
	ErrCDCFail = fmt.Errorf("At least one endpoint was incompatible with the real URL supplied")
)

type configLoader func(string) ([][]byte, []string, error)
type mockingjayLoader func([]byte) ([]mockingjay.FakeEndpoint, error)

type compatabilityChecker interface {
	CheckCompatibility(endpoints []mockingjay.FakeEndpoint, realURL string) bool
}

type serverMaker func([]mockingjay.FakeEndpoint, bool) *mockingjay.Server
type monkeyServerMaker func(http.Handler, string) (http.Handler, error)

type application struct {
	configLoader          configLoader
	mockingjayLoader      mockingjayLoader
	compatabilityChecker  compatabilityChecker
	mockingjayServerMaker serverMaker
	monkeyServerMaker     monkeyServerMaker
	logger                *log.Logger
	mjServer              *mockingjay.Server
	configPath            string
	monkeyConfigPath      string
	yamlMD5               [md5.Size]byte
}

func defaultApplication(logger *log.Logger, httpTimeout time.Duration) (app *application) {
	app = new(application)
	app.configLoader = globFileLoader
	app.mockingjayLoader = mockingjay.NewFakeEndpoints
	app.compatabilityChecker = NewCompatabilityChecker(logger, httpTimeout)
	app.mockingjayServerMaker = mockingjay.NewServer
	app.monkeyServerMaker = monkey.NewServer
	app.logger = logger

	return
}

func (a *application) PollConfig() {
	for range time.Tick(time.Millisecond * 500) {
		endpoints, err := a.loadConfig()
		if err != nil {
			log.Println(err)
		} else if len(endpoints) > 0 {
			a.logger.Println("Reloaded config")
			a.mjServer.Endpoints = endpoints
		}
	}
}

// CreateServer will create a fake server from the configuration found in configPath with optional performance constraints from configutation found in monkeyConfigPath
func (a *application) CreateServer(configPath string, monkeyConfigPath string, debugMode bool) (server http.Handler, err error) {
	a.configPath = configPath
	a.monkeyConfigPath = monkeyConfigPath
	endpoints, err := a.loadConfig()

	if err != nil || len(endpoints) == 0 {
		return
	}

	return a.createFakeServer(endpoints, debugMode)
}

// CheckCompatibility will run a MJ config against a realURL to see if it's compatible
func (a *application) CheckCompatibility(configPath string, realURL string) error {
	a.configPath = configPath
	endpoints, err := a.loadConfig()

	if err != nil {
		return err
	}

	if a.compatabilityChecker.CheckCompatibility(endpoints, realURL) {
		a.logger.Println("All endpoints are compatible")
		return nil
	}

	return ErrCDCFail
}

func (a *application) loadConfig() (endpoints []mockingjay.FakeEndpoint, err error) {

	configs, paths, err := a.configLoader(a.configPath)

	if err != nil {
		return
	}

	a.logger.Println("Loaded and merged into one config:", strings.Join(paths, ", "))

	if newMD5 := md5.Sum(bytes.Join(configs, []byte{})); newMD5 != a.yamlMD5 {
		a.yamlMD5 = newMD5

		for _, configData := range configs {
			mjEndpoint, err := a.mockingjayLoader(configData)

			if err != nil {
				return nil, err
			}

			endpoints = append(endpoints, mjEndpoint...)
		}
	}

	return
}

func (a *application) createFakeServer(endpoints []mockingjay.FakeEndpoint, debugMode bool) (server http.Handler, err error) {
	go a.PollConfig()
	a.mjServer = a.mockingjayServerMaker(endpoints, debugMode)
	monkeyServer, err := a.monkeyServerMaker(a.mjServer, a.monkeyConfigPath)

	if err != nil {
		return nil, err
	}

	router := http.NewServeMux()
	router.Handle("/", monkeyServer)

	return router, nil
}

func globFileLoader(path string) (data [][]byte, paths []string, err error) {
	files, err := filepath.Glob(path)

	if err != nil {
		return nil, nil, fmt.Errorf("Failed to get files from file path (glob) %s, %v", path, err)
	}

	if len(files) == 0 {
		return nil, nil, fmt.Errorf("No files found in path %s", path)
	}

	var configs [][]byte
	for _, file := range files {

		configData, err := ioutil.ReadFile(file)

		if err != nil {
			return nil, nil, err
		}

		configs = append(configs, configData)
	}

	return configs, files, nil
}
<commit_msg>logspam<commit_after>package main

import (
	"bytes"
	"crypto/md5"
	_ "expvar"
	"fmt"
	"github.com/quii/mockingjay-server/mockingjay"
	"github.com/quii/mockingjay-server/monkey"
	"io/ioutil"
	"log"
	"net/http"
	"path/filepath"
	"strings"
	"time"
)

var (
	// ErrCDCFail describes when a fake server is not compatible with a given URL
	ErrCDCFail = fmt.Errorf("At least one endpoint was incompatible with the real URL supplied")
)

type configLoader func(string) ([][]byte, []string, error)
type mockingjayLoader func([]byte) ([]mockingjay.FakeEndpoint, error)

type compatabilityChecker interface {
	CheckCompatibility(endpoints []mockingjay.FakeEndpoint, realURL string) bool
}

type serverMaker func([]mockingjay.FakeEndpoint, bool) *mockingjay.Server
type monkeyServerMaker func(http.Handler, string) (http.Handler, error)

type application struct {
	configLoader          configLoader
	mockingjayLoader      mockingjayLoader
	compatabilityChecker  compatabilityChecker
	mockingjayServerMaker serverMaker
	monkeyServerMaker     monkeyServerMaker
	logger                *log.Logger
	mjServer              *mockingjay.Server
	configPath            string
	monkeyConfigPath      string
	yamlMD5               [md5.Size]byte
}

func defaultApplication(logger *log.Logger, httpTimeout time.Duration) (app *application) {
	app = new(application)
	app.configLoader = globFileLoader
	app.mockingjayLoader = mockingjay.NewFakeEndpoints
	app.compatabilityChecker = NewCompatabilityChecker(logger, httpTimeout)
	app.mockingjayServerMaker = mockingjay.NewServer
	app.monkeyServerMaker = monkey.NewServer
	app.logger = logger

	return
}

func (a *application) PollConfig() {
	for range time.Tick(time.Millisecond * 500) {
		endpoints, err := a.loadConfig()
		if err != nil {
			log.Println(err)
		} else if len(endpoints) > 0 {
			a.logger.Println("Reloaded config")
			a.mjServer.Endpoints = endpoints
		}
	}
}

// CreateServer will create a fake server from the configuration found in configPath with optional performance constraints from configutation found in monkeyConfigPath
func (a *application) CreateServer(configPath string, monkeyConfigPath string, debugMode bool) (server http.Handler, err error) {
	a.configPath = configPath
	a.monkeyConfigPath = monkeyConfigPath
	endpoints, err := a.loadConfig()

	if err != nil || len(endpoints) == 0 {
		return
	}

	return a.createFakeServer(endpoints, debugMode)
}

// CheckCompatibility will run a MJ config against a realURL to see if it's compatible
func (a *application) CheckCompatibility(configPath string, realURL string) error {
	a.configPath = configPath
	endpoints, err := a.loadConfig()

	if err != nil {
		return err
	}

	if a.compatabilityChecker.CheckCompatibility(endpoints, realURL) {
		a.logger.Println("All endpoints are compatible")
		return nil
	}

	return ErrCDCFail
}

func (a *application) loadConfig() (endpoints []mockingjay.FakeEndpoint, err error) {

	configs, paths, err := a.configLoader(a.configPath)

	if err != nil {
		return
	}

	if newMD5 := md5.Sum(bytes.Join(configs, []byte{})); newMD5 != a.yamlMD5 {
		a.yamlMD5 = newMD5

		for _, configData := range configs {
			mjEndpoint, err := a.mockingjayLoader(configData)

			if err != nil {
				return nil, err
			}

			endpoints = append(endpoints, mjEndpoint...)
		}
	}

	return
}

func (a *application) createFakeServer(endpoints []mockingjay.FakeEndpoint, debugMode bool) (server http.Handler, err error) {
	go a.PollConfig()
	a.mjServer = a.mockingjayServerMaker(endpoints, debugMode)
	monkeyServer, err := a.monkeyServerMaker(a.mjServer, a.monkeyConfigPath)

	if err != nil {
		return nil, err
	}

	router := http.NewServeMux()
	router.Handle("/", monkeyServer)

	return router, nil
}

func globFileLoader(path string) (data [][]byte, paths []string, err error) {
	files, err := filepath.Glob(path)

	if err != nil {
		return nil, nil, fmt.Errorf("Failed to get files from file path (glob) %s, %v", path, err)
	}

	if len(files) == 0 {
		return nil, nil, fmt.Errorf("No files found in path %s", path)
	}

	var configs [][]byte
	for _, file := range files {

		configData, err := ioutil.ReadFile(file)

		if err != nil {
			return nil, nil, err
		}

		configs = append(configs, configData)
	}

	return configs, files, nil
}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package juju_test

import (
	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/bootstrap"
	"launchpad.net/juju-core/juju"
	"launchpad.net/juju-core/provider/dummy"
	coretesting "launchpad.net/juju-core/testing"
)

type NewAPIConnSuite struct {
	coretesting.LoggingSuite
}

var _ = gc.Suite(&NewAPIConnSuite{})

func (cs *NewAPIConnSuite) TearDownTest(c *gc.C) {
	dummy.Reset()
	cs.LoggingSuite.TearDownTest(c)
}

func (*NewAPIConnSuite) TestNewConn(c *gc.C) {
	attrs := map[string]interface{}{
		"name":            "erewhemos",
		"type":            "dummy",
		"state-server":    true,
		"authorized-keys": "i-am-a-key",
		"secret":          "pork",
		"admin-secret":    "really",
		"ca-cert":         coretesting.CACert,
		"ca-private-key":  coretesting.CAKey,
	}
	env, err := environs.NewFromAttrs(attrs)
	c.Assert(err, gc.IsNil)
	err = bootstrap.Bootstrap(env, constraints.Value{})
	c.Assert(err, gc.IsNil)

	conn, err := juju.NewConn(env)
	c.Assert(err, gc.IsNil)

	c.Assert(conn.Environ, gc.Equals, env)
	c.Assert(conn.State, gc.NotNil)

	c.Assert(conn.Close(), gc.IsNil)
}

type NewAPIClientSuite struct {
	coretesting.LoggingSuite
}

var _ = gc.Suite(&NewAPIClientSuite{})

func (cs *NewAPIClientSuite) TearDownTest(c *gc.C) {
	dummy.Reset()
	cs.LoggingSuite.TearDownTest(c)
}

func (*NewAPIClientSuite) TestNameDefault(c *gc.C) {
	defer coretesting.MakeMultipleEnvHome(c).Restore()
	// The default environment is "erewhemos", we should get it if we ask for ""
	defaultEnvName := "erewhemos"
	bootstrapEnv(c, defaultEnvName)
	apiclient, err := juju.NewAPIClientFromName("")
	c.Assert(err, gc.IsNil)
	defer apiclient.Close()
	envInfo, err := apiclient.EnvironmentInfo()
	c.Assert(err, gc.IsNil)
	c.Assert(envInfo.Name, gc.Equals, defaultEnvName)
}

func (*NewAPIClientSuite) TestNameNotDefault(c *gc.C) {
	defer coretesting.MakeMultipleEnvHome(c).Restore()
	// The default environment is "erewhemos", make sure we get the other one.
	const envName = "erewhemos-2"
	bootstrapEnv(c, envName)
	apiclient, err := juju.NewAPIClientFromName(envName)
	c.Assert(err, gc.IsNil)
	defer apiclient.Close()
	envInfo, err := apiclient.EnvironmentInfo()
	c.Assert(err, gc.IsNil)
	c.Assert(envInfo.Name, gc.Equals, envName)
}

func (*NewAPIClientSuite) TestMultipleCloseOk(c *gc.C) {
	defer coretesting.MakeSampleHome(c).Restore()
	bootstrapEnv(c, "")
	client, _ := juju.NewAPIClientFromName("")
	client.Close()
	client.Close()
	client.Close()
}

<commit_msg>go fmt<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package juju_test

import (
	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/bootstrap"
	"launchpad.net/juju-core/juju"
	"launchpad.net/juju-core/provider/dummy"
	coretesting "launchpad.net/juju-core/testing"
)

type NewAPIConnSuite struct {
	coretesting.LoggingSuite
}

var _ = gc.Suite(&NewAPIConnSuite{})

func (cs *NewAPIConnSuite) TearDownTest(c *gc.C) {
	dummy.Reset()
	cs.LoggingSuite.TearDownTest(c)
}

func (*NewAPIConnSuite) TestNewConn(c *gc.C) {
	attrs := map[string]interface{}{
		"name":            "erewhemos",
		"type":            "dummy",
		"state-server":    true,
		"authorized-keys": "i-am-a-key",
		"secret":          "pork",
		"admin-secret":    "really",
		"ca-cert":         coretesting.CACert,
		"ca-private-key":  coretesting.CAKey,
	}
	env, err := environs.NewFromAttrs(attrs)
	c.Assert(err, gc.IsNil)
	err = bootstrap.Bootstrap(env, constraints.Value{})
	c.Assert(err, gc.IsNil)

	conn, err := juju.NewConn(env)
	c.Assert(err, gc.IsNil)

	c.Assert(conn.Environ, gc.Equals, env)
	c.Assert(conn.State, gc.NotNil)

	c.Assert(conn.Close(), gc.IsNil)
}

type NewAPIClientSuite struct {
	coretesting.LoggingSuite
}

var _ = gc.Suite(&NewAPIClientSuite{})

func (cs *NewAPIClientSuite) TearDownTest(c *gc.C) {
	dummy.Reset()
	cs.LoggingSuite.TearDownTest(c)
}

func (*NewAPIClientSuite) TestNameDefault(c *gc.C) {
	defer coretesting.MakeMultipleEnvHome(c).Restore()
	// The default environment is "erewhemos", we should get it if we ask for ""
	defaultEnvName := "erewhemos"
	bootstrapEnv(c, defaultEnvName)
	apiclient, err := juju.NewAPIClientFromName("")
	c.Assert(err, gc.IsNil)
	defer apiclient.Close()
	envInfo, err := apiclient.EnvironmentInfo()
	c.Assert(err, gc.IsNil)
	c.Assert(envInfo.Name, gc.Equals, defaultEnvName)
}

func (*NewAPIClientSuite) TestNameNotDefault(c *gc.C) {
	defer coretesting.MakeMultipleEnvHome(c).Restore()
	// The default environment is "erewhemos", make sure we get the other one.
	const envName = "erewhemos-2"
	bootstrapEnv(c, envName)
	apiclient, err := juju.NewAPIClientFromName(envName)
	c.Assert(err, gc.IsNil)
	defer apiclient.Close()
	envInfo, err := apiclient.EnvironmentInfo()
	c.Assert(err, gc.IsNil)
	c.Assert(envInfo.Name, gc.Equals, envName)
}

func (*NewAPIClientSuite) TestMultipleCloseOk(c *gc.C) {
	defer coretesting.MakeSampleHome(c).Restore()
	bootstrapEnv(c, "")
	client, _ := juju.NewAPIClientFromName("")
	client.Close()
	client.Close()
	client.Close()
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 msg

// DataMsgRequestToKVs TODO
/*func DataMsgRequestToKVs(req *DataMsgRequest, keyPrefixes []string) map[string][]datasync.KeyVal {
	ret := map[string][]datasync.KeyVal{}
	for _, dataResync := range req.GetDataResyncs() {
		for _, keyPrefix := range keyPrefixes {
			if strings.HasPrefix(dataResync.Key, keyPrefix) {
				kvs, found := ret[keyPrefix]
				kv := syncbase.NewKeyValBytes(dataResync.Key, dataResync.Content, nil, 0)
				if !found {
					kvs = []datasync.KeyVal{kv}
				} else {
					kvs = append(kvs, kv)
				}
				ret[keyPrefix] = kvs
			}
		}
	}

	return ret
}*/
<commit_msg>Remove unused file<commit_after><|endoftext|>


<commit_before>package agent

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/ActiveState/tail"
	"github.com/tutumcloud/tutum-agent/utils"
)

type TunnelPatchForm struct {
	Tunnel  string `json:"tunnel:"`
	Version string `json:"agent_version"`
}

func NatTunnel(url, ngrokPath, ngrokLogPath, ngrokConfPath string) {
	if !utils.FileExist(ngrokPath) {
		Logger.Printf("Cannot find ngrok binary(%s), skipping NAT tunnel\n", ngrokPath)
		return
	}

	updateNgrokHost(url)
	createNgrokConfFile(ngrokConfPath)

	var cmd *exec.Cmd
	if *FlagNgrokToken != "" {
		Logger.Println("About to tunnel to public ngrok service")
		cmd = exec.Command(ngrokPath,
			"-log", "stdout",
			"-authtoken", *FlagNgrokToken,
			"-proto", "tcp",
			DockerHostPort)
	} else {
		Logger.Println("About to tunnel to private ngrok service")
		if !utils.FileExist(ngrokConfPath) {
			Logger.Println("Cannot find ngrok conf, skipping NAT tunnel")
			return
		}
		cmd = exec.Command(ngrokPath,
			"-config", ngrokConfPath,
			"-log", "stdout",
			"-proto", "tcp",
			DockerHostPort)
	}

	os.RemoveAll(ngrokLogPath)
	logFile, err := os.OpenFile(ngrokLogPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		Logger.Println(err)
	} else {
		defer logFile.Close()
		cmd.Stdout = logFile
	}

	Logger.Println("Starting montoring tunnel:", cmd.Args)
	go monitorTunnels(url, ngrokLogPath)
	Logger.Println("Starting NAT tunnel:", cmd.Args)

	for {
		runGronk(cmd)
		time.Sleep(10 * time.Second)
		Logger.Println("Restarting NAT tunnel:", cmd.Args)
	}
}

func runGronk(cmd *exec.Cmd) bool {
	if err := cmd.Start(); err != nil {
		return true
	}
	cmd.Wait()
	return true
}

func monitorTunnels(url, ngrokLogPath string) {
	update, _ := tail.TailFile(ngrokLogPath, tail.Config{
		Follow: true,
		ReOpen: true})
	for line := range update.Lines {
		if strings.Contains(line.Text, "[INFO] [client] Tunnel established at") {
			terms := strings.Split(line.Text, " ")
			tunnel := terms[len(terms)-1]
			Logger.Printf("Found new tunnel:%s\n", tunnel)
			patchTunnelToTutum(url, tunnel)
		}
	}
}

func patchTunnelToTutum(url, tunnel string) {
	Logger.Println("Patching tunnel address to Tutum")
	form := TunnelPatchForm{}
	form.Version = VERSION
	form.Tunnel = tunnel
	data, err := json.Marshal(form)
	if err != nil {
		Logger.Printf("Cannot marshal the TunnelPatch form:%s\f", err)
	}

	headers := []string{"Authorization TutumAgentToken " + Conf.TutumToken,
		"Content-Type", "application/json"}
	_, err = SendRequest("PATCH", utils.JoinURL(url, Conf.TutumUUID), data, headers)
	if err != nil {
		Logger.Println("Failed to patch tunnel address to Tutum,", err.Error())
	} else {
		Logger.Println("Successfully Patched tunnel address to Tutum")
	}
}

func DownloadNgrok(url, ngrokBinPath string) {
	if utils.FileExist(ngrokBinPath) {
		Logger.Printf("Found ngrok locally(%s), skip downloading\n", ngrokBinPath)
	} else {
		Logger.Println("No ngrok binary is found locally. Starting to download ngrok...")
		downloadFile(url, ngrokBinPath, "gnrok")
	}
}

func createNgrokConfFile(ngrokConfPath string) {
	ngrokConfStr := fmt.Sprintf("server_addr: %s\ntrust_host_root_certs: false", NgrokHost)
	Logger.Printf("Creating ngrok config file in %s ...\n", ngrokConfPath)
	if err := ioutil.WriteFile(ngrokConfPath, []byte(ngrokConfStr), 0666); err != nil {
		Logger.Println("Cannot create ngrok config file:", err.Error())
	}
}

func updateNgrokHost(url string) {
	if NgrokHost != "" {
		return
	}

	headers := []string{"Authorization TutumAgentToken " + Conf.TutumToken,
		"Content-Type application/json"}
	body, err := SendRequest("GET", utils.JoinURL(url, Conf.TutumUUID), nil, headers)
	if err != nil {
		Logger.Printf("Get registration info error, %s\n", err.Error())
	} else {
		var form RegGetForm
		if err = json.Unmarshal(body, &form); err != nil {
			Logger.Println("Cannot unmarshal the response, ", err.Error())
		} else {
			if form.NgrokHost != "" {
				NgrokHost = form.NgrokHost
				Logger.Println("Set ngrok server address to", NgrokHost)
			}
		}
	}
}
<commit_msg>fix typo<commit_after>package agent

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/ActiveState/tail"
	"github.com/tutumcloud/tutum-agent/utils"
)

type TunnelPatchForm struct {
	Tunnel  string `json:"tunnel"`
	Version string `json:"agent_version"`
}

func NatTunnel(url, ngrokPath, ngrokLogPath, ngrokConfPath string) {
	if !utils.FileExist(ngrokPath) {
		Logger.Printf("Cannot find ngrok binary(%s), skipping NAT tunnel\n", ngrokPath)
		return
	}

	updateNgrokHost(url)
	createNgrokConfFile(ngrokConfPath)

	var cmd *exec.Cmd
	if *FlagNgrokToken != "" {
		Logger.Println("About to tunnel to public ngrok service")
		cmd = exec.Command(ngrokPath,
			"-log", "stdout",
			"-authtoken", *FlagNgrokToken,
			"-proto", "tcp",
			DockerHostPort)
	} else {
		Logger.Println("About to tunnel to private ngrok service")
		if !utils.FileExist(ngrokConfPath) {
			Logger.Println("Cannot find ngrok conf, skipping NAT tunnel")
			return
		}
		cmd = exec.Command(ngrokPath,
			"-config", ngrokConfPath,
			"-log", "stdout",
			"-proto", "tcp",
			DockerHostPort)
	}

	os.RemoveAll(ngrokLogPath)
	logFile, err := os.OpenFile(ngrokLogPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		Logger.Println(err)
	} else {
		defer logFile.Close()
		cmd.Stdout = logFile
	}

	Logger.Println("Starting montoring tunnel:", cmd.Args)
	go monitorTunnels(url, ngrokLogPath)
	Logger.Println("Starting NAT tunnel:", cmd.Args)

	for {
		runGronk(cmd)
		time.Sleep(10 * time.Second)
		Logger.Println("Restarting NAT tunnel:", cmd.Args)
	}
}

func runGronk(cmd *exec.Cmd) bool {
	if err := cmd.Start(); err != nil {
		return true
	}
	cmd.Wait()
	return true
}

func monitorTunnels(url, ngrokLogPath string) {
	update, _ := tail.TailFile(ngrokLogPath, tail.Config{
		Follow: true,
		ReOpen: true})
	for line := range update.Lines {
		if strings.Contains(line.Text, "[INFO] [client] Tunnel established at") {
			terms := strings.Split(line.Text, " ")
			tunnel := terms[len(terms)-1]
			Logger.Printf("Found new tunnel:%s\n", tunnel)
			patchTunnelToTutum(url, tunnel)
		}
	}
}

func patchTunnelToTutum(url, tunnel string) {
	Logger.Println("Patching tunnel address to Tutum")
	form := TunnelPatchForm{}
	form.Version = VERSION
	form.Tunnel = tunnel
	data, err := json.Marshal(form)
	if err != nil {
		Logger.Printf("Cannot marshal the TunnelPatch form:%s\f", err)
	}

	headers := []string{"Authorization TutumAgentToken " + Conf.TutumToken,
		"Content-Type", "application/json"}
	_, err = SendRequest("PATCH", utils.JoinURL(url, Conf.TutumUUID), data, headers)
	if err != nil {
		Logger.Println("Failed to patch tunnel address to Tutum,", err.Error())
	} else {
		Logger.Println("Successfully Patched tunnel address to Tutum")
	}
}

func DownloadNgrok(url, ngrokBinPath string) {
	if utils.FileExist(ngrokBinPath) {
		Logger.Printf("Found ngrok locally(%s), skip downloading\n", ngrokBinPath)
	} else {
		Logger.Println("No ngrok binary is found locally. Starting to download ngrok...")
		downloadFile(url, ngrokBinPath, "gnrok")
	}
}

func createNgrokConfFile(ngrokConfPath string) {
	ngrokConfStr := fmt.Sprintf("server_addr: %s\ntrust_host_root_certs: false", NgrokHost)
	Logger.Printf("Creating ngrok config file in %s ...\n", ngrokConfPath)
	if err := ioutil.WriteFile(ngrokConfPath, []byte(ngrokConfStr), 0666); err != nil {
		Logger.Println("Cannot create ngrok config file:", err.Error())
	}
}

func updateNgrokHost(url string) {
	if NgrokHost != "" {
		return
	}

	headers := []string{"Authorization TutumAgentToken " + Conf.TutumToken,
		"Content-Type application/json"}
	body, err := SendRequest("GET", utils.JoinURL(url, Conf.TutumUUID), nil, headers)
	if err != nil {
		Logger.Printf("Get registration info error, %s\n", err.Error())
	} else {
		var form RegGetForm
		if err = json.Unmarshal(body, &form); err != nil {
			Logger.Println("Cannot unmarshal the response, ", err.Error())
		} else {
			if form.NgrokHost != "" {
				NgrokHost = form.NgrokHost
				Logger.Println("Set ngrok server address to", NgrokHost)
			}
		}
	}
}
<|endoftext|>


<commit_before>package mcts

import (
	"log"
	"math"
	"math/rand"
	"sort"
	"strings"
	"time"

	"context"

	"github.com/nelhage/taktician/ai"
	"github.com/nelhage/taktician/bitboard"
	"github.com/nelhage/taktician/ptn"
	"github.com/nelhage/taktician/tak"
)

type MCTSConfig struct {
	Debug int
	Limit time.Duration
	C     float64
	Seed  int64

	InitialVisits int
	MMDepth       int
	MaxRollout    int
	EvalThreshold int64
	Policy        string

	Size int

	DumpTree string
}

type Policy interface {
	Select(ctx context.Context, m *MonteCarloAI, p *tak.Position) *tak.Position
}

type MonteCarloAI struct {
	c bitboard.Constants

	cfg  MCTSConfig
	mm   *ai.MinimaxAI
	eval ai.EvaluationFunc

	policy Policy

	r *rand.Rand
}

type tree struct {
	position    *tak.Position
	move        tak.Move
	simulations int

	proven int
	value  int

	parent   *tree
	children []*tree
}

func (t *tree) ucb(C float64, N int) float64 {
	if t.proven > 0 {
		return -100
	} else if t.proven < 0 {
		return 100
	} else if t.simulations == 0 {
		return 10
	} else {
		return -float64(t.value)/float64(t.simulations) +
			C*math.Sqrt(math.Log(float64(N))/float64(t.simulations))
	}
}

type bySims []*tree

func (b bySims) Len() int           { return len(b) }
func (b bySims) Less(i, j int) bool { return b[j].simulations < b[i].simulations }
func (b bySims) Swap(i, j int) {
	b[i], b[j] = b[j], b[i]
}

func (ai *MonteCarloAI) GetMove(ctx context.Context, p *tak.Position) tak.Move {
	tree := &tree{
		position: p,
	}
	start := time.Now()
	deadline, limited := ctx.Deadline()
	if !limited || deadline.Sub(start) > ai.cfg.Limit {
		deadline = time.Now().Add(ai.cfg.Limit)
	}

	var tick <-chan time.Time
	if ai.cfg.Debug > 2 {
		ticker := time.NewTicker(time.Second)
		defer ticker.Stop()
		tick = ticker.C
	}
	for time.Now().Before(deadline) {
		node := ai.descend(tree)
		ai.populate(ctx, node)
		if tree.proven != 0 {
			break
		}
		var val int
		if node.proven == 0 {
			val = ai.rollout(ctx, node)
		}
		if ai.cfg.Debug > 4 {
			var s []string
			t := node
			for t.parent != nil {
				s = append(s, ptn.FormatMove(t.move))
				t = t.parent
			}
			log.Printf("evaluate: [%s] = %d p=%d",
				strings.Join(s, "<-"), val, node.proven)
		}

		ai.update(node, val)

		if tick != nil {
			select {
			case <-tick:
				ai.printdbg(tree)
			default:
			}
		}
	}

	if ai.cfg.DumpTree != "" {
		ai.dumpTree(tree)
	}

	if tree.proven != 0 {
		if len(tree.children) == 0 {
			return ai.mm.GetMove(ctx, p)
		}
		best := tree.children[0]
		for _, c := range tree.children {
			if c.proven < best.proven {
				best = c
			}
		}
		if ai.cfg.Debug > 1 {
			log.Printf("proven m=%s v=%d", ptn.FormatMove(best.move), -best.proven)
		}
		return best.move
	}
	best := tree.children[0]
	i := 0
	sort.Sort(bySims(tree.children))
	if ai.cfg.Debug > 1 {
		log.Printf("=== mcts done ===")
	}
	for _, c := range tree.children {
		if ai.cfg.Debug > 1 {
			log.Printf("[mcts][%s]: n=%d v=%d:%d(%0.3f) ucb=%f",
				ptn.FormatMove(c.move), c.simulations, c.proven, c.value,
				float64(c.value)/float64(c.simulations),
				c.ucb(ai.cfg.C, tree.simulations),
			)
		}
		if c.simulations > best.simulations {
			best = c
			i = 1
		} else if c.simulations == best.simulations {
			i++
			if ai.r.Intn(i) == 0 {
				best = c
				i = 1
			}
		}
	}
	if ai.cfg.Debug > 0 {
		log.Printf("[mcts] evaluated simulations=%d value=%d proven=%d", tree.simulations, tree.value, tree.proven)
	}
	return best.move
}

func (mc *MonteCarloAI) printdbg(t *tree) {
	log.Printf("===")
	for _, c := range t.children {
		if c.simulations*20 > t.simulations {
			log.Printf("[mcts][%s]: n=%d v=%d:%d(%0.3f) ucb=%f",
				ptn.FormatMove(c.move), c.simulations, c.proven, c.value,
				float64(c.value)/float64(c.simulations),
				c.ucb(mc.cfg.C, t.simulations),
			)
		}
	}
}

func (mc *MonteCarloAI) populate(ctx context.Context, t *tree) {
	_, v, _ := mc.mm.Analyze(ctx, t.position)
	if v > ai.WinThreshold {
		t.proven = 1
		return
	} else if v < -ai.WinThreshold {
		t.proven = -1
		return
	}

	moves := t.position.AllMoves(nil)
	t.children = make([]*tree, 0, len(moves))
	for _, m := range moves {
		child, e := t.position.Move(m)
		if e != nil {
			continue
		}
		t.children = append(t.children, &tree{
			position: child,
			move:     m,
			parent:   t,
		})
	}
}

func (ai *MonteCarloAI) descend(t *tree) *tree {
	for {
		if len(t.children) == 0 {
			return t
		}
		var best *tree
		var val float64 = math.Inf(-1)
		i := 0
		for _, c := range t.children {
			s := c.ucb(ai.cfg.C, t.simulations)

			if s > val {
				best = c
				val = s
				i = 1
			} else if s == val {
				i++
				if ai.r.Intn(i) == 0 {
					best = c
				}
			}
		}
		if best == nil {
			best = t.children[0]
		}
		t = best
	}
}

func (ai *MonteCarloAI) rollout(ctx context.Context, t *tree) int {
	p := t.position.Clone()

	for i := 0; i < ai.cfg.MaxRollout; i++ {
		if ok, c := p.GameOver(); ok {
			switch c {
			case tak.NoColor:
				return 0
			case t.position.ToMove():
				return 1
			default:
				return -1
			}
		}
		next := ai.policy.Select(ctx, ai, p)
		if next == nil {
			return 0
		}
		p = next
	}
	v := ai.eval(&ai.c, p)
	if v > ai.cfg.EvalThreshold {
		return 1
	} else if v < -ai.cfg.EvalThreshold {
		return -1
	}
	return 0
}

func (mc *MonteCarloAI) update(t *tree, value int) {
	for t != nil {
		t.simulations++
		if t.proven != 0 {
			if t.parent == nil {
				return
			}
			// Minimax backup
			if t.proven < 0 {
				// My best move is a loss; therefore
				// my parent should choose this branch
				// and win
				t.parent.proven = 1
				value = -1
			} else {
				// This move is a win for me; My
				// parent is a loss only if *all* of
				// its children are wins
				all := true
				for _, ch := range t.parent.children {
					if ch.proven <= 0 {
						all = false
						break
					}
				}
				if all {
					t.parent.proven = -1
				}
				value = 1
			}
		} else {
			t.value += value
		}
		value = -value
		t = t.parent
	}
}

func NewMonteCarlo(cfg MCTSConfig) *MonteCarloAI {
	mc := &MonteCarloAI{
		cfg: cfg,
		c:   bitboard.Precompute(uint(cfg.Size)),
	}
	if mc.cfg.C == 0 {
		mc.cfg.C = 0.7
	}
	if mc.cfg.Seed == 0 {
		mc.cfg.Seed = time.Now().Unix()
	}
	if mc.cfg.InitialVisits == 0 {
		mc.cfg.InitialVisits = 3
	}
	if mc.cfg.MMDepth == 0 {
		mc.cfg.MMDepth = 3
	}
	if mc.cfg.MaxRollout == 0 {
		mc.cfg.MaxRollout = 50
	}
	if mc.cfg.EvalThreshold == 0 {
		mc.cfg.EvalThreshold = 2000
	}
	mc.policy = mc.buildPolicy()
	mc.r = rand.New(rand.NewSource(mc.cfg.Seed))
	mc.mm = ai.NewMinimax(ai.MinimaxConfig{
		Size:     cfg.Size,
		Evaluate: ai.EvaluateWinner,
		Depth:    mc.cfg.MMDepth,
		Seed:     mc.cfg.Seed,
	})
	mc.eval = ai.MakeEvaluator(mc.cfg.Size, nil)
	return mc
}
<commit_msg>Add an option to force corners<commit_after>package mcts

import (
	"log"
	"math"
	"math/rand"
	"sort"
	"strings"
	"time"

	"context"

	"github.com/nelhage/taktician/ai"
	"github.com/nelhage/taktician/bitboard"
	"github.com/nelhage/taktician/ptn"
	"github.com/nelhage/taktician/tak"
)

type MCTSConfig struct {
	Debug int
	Limit time.Duration
	C     float64
	Seed  int64

	InitialVisits int
	MMDepth       int
	MaxRollout    int
	EvalThreshold int64
	Policy        string
	ForceCorners  bool

	Size int

	DumpTree string
}

type Policy interface {
	Select(ctx context.Context, m *MonteCarloAI, p *tak.Position) *tak.Position
}

type MonteCarloAI struct {
	c bitboard.Constants

	cfg  MCTSConfig
	mm   *ai.MinimaxAI
	eval ai.EvaluationFunc

	policy Policy

	r *rand.Rand
}

type tree struct {
	position    *tak.Position
	move        tak.Move
	simulations int

	proven int
	value  int

	parent   *tree
	children []*tree
}

func (t *tree) ucb(C float64, N int) float64 {
	if t.proven > 0 {
		return -100
	} else if t.proven < 0 {
		return 100
	} else if t.simulations == 0 {
		return 10
	} else {
		return -float64(t.value)/float64(t.simulations) +
			C*math.Sqrt(math.Log(float64(N))/float64(t.simulations))
	}
}

type bySims []*tree

func (b bySims) Len() int           { return len(b) }
func (b bySims) Less(i, j int) bool { return b[j].simulations < b[i].simulations }
func (b bySims) Swap(i, j int) {
	b[i], b[j] = b[j], b[i]
}

func (ai *MonteCarloAI) cornerMove(p *tak.Position) tak.Move {
	for {
		row := (p.Size() - 1) * ai.r.Intn(2)
		col := (p.Size() - 1) * ai.r.Intn(2)
		if len(p.At(row, col)) > 0 {
			continue
		}
		return tak.Move{
			X:    int8(row),
			Y:    int8(row),
			Type: tak.PlaceFlat,
		}
	}
}

func (ai *MonteCarloAI) GetMove(ctx context.Context, p *tak.Position) tak.Move {
	if ai.cfg.ForceCorners && p.MoveNumber() < 2 {
		return ai.cornerMove(p)
	}

	tree := &tree{
		position: p,
	}
	start := time.Now()
	deadline, limited := ctx.Deadline()
	if !limited || deadline.Sub(start) > ai.cfg.Limit {
		deadline = time.Now().Add(ai.cfg.Limit)
	}

	var tick <-chan time.Time
	if ai.cfg.Debug > 2 {
		ticker := time.NewTicker(time.Second)
		defer ticker.Stop()
		tick = ticker.C
	}
	for time.Now().Before(deadline) {
		node := ai.descend(tree)
		ai.populate(ctx, node)
		if tree.proven != 0 {
			break
		}
		var val int
		if node.proven == 0 {
			val = ai.rollout(ctx, node)
		}
		if ai.cfg.Debug > 4 {
			var s []string
			t := node
			for t.parent != nil {
				s = append(s, ptn.FormatMove(t.move))
				t = t.parent
			}
			log.Printf("evaluate: [%s] = %d p=%d",
				strings.Join(s, "<-"), val, node.proven)
		}

		ai.update(node, val)

		if tick != nil {
			select {
			case <-tick:
				ai.printdbg(tree)
			default:
			}
		}
	}

	if ai.cfg.DumpTree != "" {
		ai.dumpTree(tree)
	}

	if tree.proven != 0 {
		if len(tree.children) == 0 {
			return ai.mm.GetMove(ctx, p)
		}
		best := tree.children[0]
		for _, c := range tree.children {
			if c.proven < best.proven {
				best = c
			}
		}
		if ai.cfg.Debug > 1 {
			log.Printf("proven m=%s v=%d", ptn.FormatMove(best.move), -best.proven)
		}
		return best.move
	}
	best := tree.children[0]
	i := 0
	sort.Sort(bySims(tree.children))
	if ai.cfg.Debug > 1 {
		log.Printf("=== mcts done ===")
	}
	for _, c := range tree.children {
		if ai.cfg.Debug > 1 {
			log.Printf("[mcts][%s]: n=%d v=%d:%d(%0.3f) ucb=%f",
				ptn.FormatMove(c.move), c.simulations, c.proven, c.value,
				float64(c.value)/float64(c.simulations),
				c.ucb(ai.cfg.C, tree.simulations),
			)
		}
		if c.simulations > best.simulations {
			best = c
			i = 1
		} else if c.simulations == best.simulations {
			i++
			if ai.r.Intn(i) == 0 {
				best = c
				i = 1
			}
		}
	}
	if ai.cfg.Debug > 0 {
		log.Printf("[mcts] evaluated simulations=%d value=%d proven=%d", tree.simulations, tree.value, tree.proven)
	}
	return best.move
}

func (mc *MonteCarloAI) printdbg(t *tree) {
	log.Printf("===")
	for _, c := range t.children {
		if c.simulations*20 > t.simulations {
			log.Printf("[mcts][%s]: n=%d v=%d:%d(%0.3f) ucb=%f",
				ptn.FormatMove(c.move), c.simulations, c.proven, c.value,
				float64(c.value)/float64(c.simulations),
				c.ucb(mc.cfg.C, t.simulations),
			)
		}
	}
}

func (mc *MonteCarloAI) populate(ctx context.Context, t *tree) {
	_, v, _ := mc.mm.Analyze(ctx, t.position)
	if v > ai.WinThreshold {
		t.proven = 1
		return
	} else if v < -ai.WinThreshold {
		t.proven = -1
		return
	}

	moves := t.position.AllMoves(nil)
	t.children = make([]*tree, 0, len(moves))
	for _, m := range moves {
		child, e := t.position.Move(m)
		if e != nil {
			continue
		}
		t.children = append(t.children, &tree{
			position: child,
			move:     m,
			parent:   t,
		})
	}
}

func (ai *MonteCarloAI) descend(t *tree) *tree {
	for {
		if len(t.children) == 0 {
			return t
		}
		var best *tree
		var val float64 = math.Inf(-1)
		i := 0
		for _, c := range t.children {
			s := c.ucb(ai.cfg.C, t.simulations)

			if s > val {
				best = c
				val = s
				i = 1
			} else if s == val {
				i++
				if ai.r.Intn(i) == 0 {
					best = c
				}
			}
		}
		if best == nil {
			best = t.children[0]
		}
		t = best
	}
}

func (ai *MonteCarloAI) rollout(ctx context.Context, t *tree) int {
	p := t.position.Clone()

	for i := 0; i < ai.cfg.MaxRollout; i++ {
		if ok, c := p.GameOver(); ok {
			switch c {
			case tak.NoColor:
				return 0
			case t.position.ToMove():
				return 1
			default:
				return -1
			}
		}
		next := ai.policy.Select(ctx, ai, p)
		if next == nil {
			return 0
		}
		p = next
	}
	v := ai.eval(&ai.c, p)
	if v > ai.cfg.EvalThreshold {
		return 1
	} else if v < -ai.cfg.EvalThreshold {
		return -1
	}
	return 0
}

func (mc *MonteCarloAI) update(t *tree, value int) {
	for t != nil {
		t.simulations++
		if t.proven != 0 {
			if t.parent == nil {
				return
			}
			// Minimax backup
			if t.proven < 0 {
				// My best move is a loss; therefore
				// my parent should choose this branch
				// and win
				t.parent.proven = 1
				value = -1
			} else {
				// This move is a win for me; My
				// parent is a loss only if *all* of
				// its children are wins
				all := true
				for _, ch := range t.parent.children {
					if ch.proven <= 0 {
						all = false
						break
					}
				}
				if all {
					t.parent.proven = -1
				}
				value = 1
			}
		} else {
			t.value += value
		}
		value = -value
		t = t.parent
	}
}

func NewMonteCarlo(cfg MCTSConfig) *MonteCarloAI {
	mc := &MonteCarloAI{
		cfg: cfg,
		c:   bitboard.Precompute(uint(cfg.Size)),
	}
	if mc.cfg.C == 0 {
		mc.cfg.C = 0.7
	}
	if mc.cfg.Seed == 0 {
		mc.cfg.Seed = time.Now().Unix()
	}
	if mc.cfg.InitialVisits == 0 {
		mc.cfg.InitialVisits = 3
	}
	if mc.cfg.MMDepth == 0 {
		mc.cfg.MMDepth = 3
	}
	if mc.cfg.MaxRollout == 0 {
		mc.cfg.MaxRollout = 50
	}
	if mc.cfg.EvalThreshold == 0 {
		mc.cfg.EvalThreshold = 2000
	}
	mc.policy = mc.buildPolicy()
	mc.r = rand.New(rand.NewSource(mc.cfg.Seed))
	mc.mm = ai.NewMinimax(ai.MinimaxConfig{
		Size:     cfg.Size,
		Evaluate: ai.EvaluateWinner,
		Depth:    mc.cfg.MMDepth,
		Seed:     mc.cfg.Seed,
	})
	mc.eval = ai.MakeEvaluator(mc.cfg.Size, nil)
	return mc
}
<|endoftext|>


<commit_before>// Generated from LDE.g4 by ANTLR 4.7.

package listener // LDE

import (
	"strconv"

	"fmt"

	"strings"

	"github.com/antlr/antlr4/runtime/Go/antlr"
	"github.com/sirkon/ldetool/ast"
	"github.com/sirkon/ldetool/parser"
)

type appender interface {
	Append(i *ast.ActionItem)
}

// Listener is a complete listener for a parse tree produced by LDEParser.
type Listener struct {
	rules     []*ast.RuleItem
	ai        *ast.ActionItem
	actions   []appender
	target    *ast.Target
	expectEnd bool
}

func New() *Listener {
	return &Listener{}
}

func (l *Listener) Rules() []*ast.RuleItem {
	return l.rules
}

// VisitTerminal is called when a terminal node is visited.
func (l *Listener) VisitTerminal(node antlr.TerminalNode) {}

// VisitErrorNode is called when an error node is visited.
func (l *Listener) VisitErrorNode(node antlr.ErrorNode) {
}

// EnterEveryRule is called when any rule is entered.
func (l *Listener) EnterEveryRule(ctx antlr.ParserRuleContext) {
	if l.expectEnd {
		token := ctx.GetStart()
		panic(fmt.Sprintf(
			"%d:%d: previous action consumed the rest of the string, the rest will do nothing",
			token.GetLine(),
			token.GetColumn(),
		))
	}
}

// ExitEveryRule is called when any rule is exited.
func (l *Listener) ExitEveryRule(ctx antlr.ParserRuleContext) {}

// EnterRules is called when production rules is entered.
func (l *Listener) EnterRules(ctx *parser.RulesContext) {
}

func (l *Listener) seq() appender {
	res := l.actions[len(l.actions)-1]
	return res
}

// ExitRules is called when production rules is exited.
func (l *Listener) ExitRules(ctx *parser.RulesContext) {}

// EnterAtomicRule is called when production atomicRule is entered.
func (l *Listener) EnterAtomicRule(ctx *parser.AtomicRuleContext) {
	rule := ast.NewRule(ctx.Identifier().GetSymbol())
	l.rules = append(l.rules, rule)
	l.actions = append(l.actions, rule)
}

// ExitAtomicRule is called when production atomicRule is exited.
func (l *Listener) ExitAtomicRule(ctx *parser.AtomicRuleContext) {}

// EnterBaseAction is called when production baseAction is entered.
func (l *Listener) EnterBaseAction(ctx *parser.BaseActionContext) {
	if ctx.Stress() != nil {
		res := &ast.ActionItem{
			ErrorOnMismatch: true,
		}
		l.seq().Append(res)
		l.ai = nil
	}
}

// ExitBaseAction is called when production baseAction is exited.
func (l *Listener) ExitBaseAction(ctx *parser.BaseActionContext) {}

// EnterAtomicAction is called when production atomicAction is entered.
func (l *Listener) EnterAtomicAction(ctx *parser.AtomicActionContext) {
	i := &ast.ActionItem{}
	l.seq().Append(i)
	l.ai = i
}

// ExitAtomicAction is called when production atomicAction is exited.
func (l *Listener) ExitAtomicAction(ctx *parser.AtomicActionContext) {}

// EnterPassStringPrefix is called when production passStringPrefix is entered.
func (l *Listener) EnterPassStringPrefix(ctx *parser.PassStringPrefixContext) {
	//l.ai.StartWithString, _ = ast.StartsWithString(token.)
	l.ai.StartWithString, _ = ast.StartsWithString(ctx.StringLit().GetSymbol())
}

// ExitPassStringPrefix is called when production passStringPrefix is exited.
func (l *Listener) ExitPassStringPrefix(ctx *parser.PassStringPrefixContext) {}

// EnterPassCharPrefix is called when production passCharPrefix is entered.
func (l *Listener) EnterPassCharPrefix(ctx *parser.PassCharPrefixContext) {
	l.ai.StartWithChar, _ = ast.StartsWithChar(ctx.CharLit().GetSymbol())
}

// ExitPassCharPrefix is called when production passCharPrefix is exited.
func (l *Listener) ExitPassCharPrefix(ctx *parser.PassCharPrefixContext) {}

// EnterMayPassStringPrefix is called when production mayPassStringPrefix is entered.
func (l *Listener) EnterMayPassStringPrefix(ctx *parser.MayPassStringPrefixContext) {
	l.ai.MayBeStartWithString, _ = ast.MayBeStartsWithString(ctx.StringLit().GetSymbol())
}

// ExitMayPassStringPrefix is called when production mayPassStringPrefix is exited.
func (l *Listener) ExitMayPassStringPrefix(ctx *parser.MayPassStringPrefixContext) {}

// EnterMayPassCharPrefix is called when production mayPassCharPrefix is entered.
func (l *Listener) EnterMayPassCharPrefix(ctx *parser.MayPassCharPrefixContext) {
	l.ai.MayBeStartWithChar, _ = ast.MayBeStartsWithChar(ctx.CharLit().GetSymbol())
}

// ExitMayPassCharPrefix is called when production mayPassCharPrefix is exited.
func (l *Listener) ExitMayPassCharPrefix(ctx *parser.MayPassCharPrefixContext) {}

// EnterPassChars is called when production passChars is entered.
func (l *Listener) EnterPassChars(ctx *parser.PassCharsContext) {
	l.ai.PassFirst, _ = ast.PassFirst(ctx.IntLit().GetSymbol())
}

// ExitPassChars is called when production passChars is exited.
func (l *Listener) ExitPassChars(ctx *parser.PassCharsContext) {}

// EnterPassUntil is called when production passUntil is entered.
func (l *Listener) EnterPassUntil(ctx *parser.PassUntilContext) {
	l.ai.Pass, _ = ast.PassUntilTarget()
	l.target = l.ai.Pass.Limit
}

// ExitPassUntil is called when production passUntil is exited.
func (l *Listener) ExitPassUntil(ctx *parser.PassUntilContext) {}

// EnterMayPassUntil is called when production mayPassUntil is entered.
func (l *Listener) EnterMayPassUntil(ctx *parser.MayPassUntilContext) {
	l.ai.PassOrIgnore, _ = ast.PassUntilTargetOrIgnore()
	l.target = l.ai.PassOrIgnore.Limit
}

// ExitMayPassUntil is called when production mayPassUntil is exited.
func (l *Listener) ExitMayPassUntil(ctx *parser.MayPassUntilContext) {}

// EnterTakeUntil is called when production takeUntil is entered.
func (l *Listener) EnterTakeUntil(ctx *parser.TakeUntilContext) {
	l.ai.Take, _ = ast.TakeUntilTarget(ctx.Identifier().GetSymbol(), ctx.FieldType().GetStart())
	l.target = l.ai.Take.Limit
}

// ExitTakeUntil is called when production takeUntil is exited.
func (l *Listener) ExitTakeUntil(ctx *parser.TakeUntilContext) {}

// EnterTakeUntilOrRest is called when production takeUntilOrRest is entered.
func (l *Listener) EnterTakeUntilOrRest(ctx *parser.TakeUntilOrRestContext) {
	l.ai.TakeUntilOrRest, _ = ast.TakeUntilTargetOrRest(
		ctx.Identifier().GetSymbol(), ctx.FieldType().GetStart(),
	)
	l.target = l.ai.TakeUntilOrRest.Limit
}

// ExitTakeUntilOrRest is called when production takeUntilOrRest is exited.
func (l *Listener) ExitTakeUntilOrRest(ctx *parser.TakeUntilOrRestContext) {}

// EnterTakeUntilRest is called when production takeUntilRest is entered.
func (l *Listener) EnterTakeUntilRest(ctx *parser.TakeUntilRestContext) {
	l.ai.TakeRest, _ = ast.TakeTheRest(ctx.Identifier().GetSymbol(), ctx.FieldType().GetStart())
}

// ExitTakeUntilRest is called when production takeUntilRest is exited.
func (l *Listener) ExitTakeUntilRest(ctx *parser.TakeUntilRestContext) {
	l.expectEnd = true
}

// EnterOptionalNamedArea is called when production optionalNamedArea is entered.
func (l *Listener) EnterOptionalNamedArea(ctx *parser.OptionalNamedAreaContext) {
	l.ai.Option, _ = ast.Option(ctx.Identifier().GetSymbol())

	l.actions = append(l.actions, l.ai.Option)
}

// ExitOptionalNamedArea is called when production optionalNamedArea is exited.
func (l *Listener) ExitOptionalNamedArea(ctx *parser.OptionalNamedAreaContext) {
	l.actions = l.actions[:len(l.actions)-1]
}

// EnterOptionalArea is called when production optionalArea is entered.
func (l *Listener) EnterOptionalArea(ctx *parser.OptionalAreaContext) {
	l.ai.Anonymous, _ = ast.Anonymous(ctx.GetStart())
	l.actions = append(l.actions, l.ai.Anonymous)
}

// ExitOptionalArea is called when production optionalArea is exited.
func (l *Listener) ExitOptionalArea(ctx *parser.OptionalAreaContext) {
	l.actions = l.actions[:len(l.actions)-1]
}

// EnterAtEnd is called when production atEnd is entered.
func (l *Listener) EnterAtEnd(ctx *parser.AtEndContext) {
	l.ai.End, _ = ast.AtTheEnd()
}

// ExitAtEnd is called when production atEnd is exited.
func (l *Listener) ExitAtEnd(ctx *parser.AtEndContext) {}

// EnterTarget is called when production target is entered.
func (l *Listener) EnterTarget(ctx *parser.TargetContext) {
	if ctx.Target() != nil {
		l.target.SetClose()
	}
}

// ExitTarget is called when production target is exited.
func (l *Listener) ExitTarget(ctx *parser.TargetContext) {}

// EnterTargetLit is called when production targetLit is entered.
func (l *Listener) EnterTargetLit(ctx *parser.TargetLitContext) {
	if ctx.StringLit() != nil {
		l.target.SetString(ctx.StringLit().GetText())
	} else if ctx.CharLit() != nil {
		l.target.SetChar(ctx.CharLit().GetText())
	} else {
		panic("Integerity error")
	}
}

// ExitTargetLit is called when production targetLit is exited.
func (l *Listener) ExitTargetLit(ctx *parser.TargetLitContext) {}

// EnterBound is called when production bound is entered.
func (l *Listener) EnterBound(ctx *parser.BoundContext) {
	lower, _ := strconv.Atoi(ctx.IntLit(0).GetText())
	upper, _ := strconv.Atoi(ctx.IntLit(1).GetText())
	l.target.SetBound(lower, upper)
}

// ExitBound is called when production bound is exited.
func (l *Listener) ExitBound(ctx *parser.BoundContext) {}

// EnterLimit is called when production limit is entered.
func (l *Listener) EnterLimit(ctx *parser.LimitContext) {
	lower, _ := strconv.Atoi(ctx.IntLit().GetText())
	l.target.SetLimit(lower)
}

// ExitLimit is called when production limit is exited.
func (l *Listener) ExitLimit(ctx *parser.LimitContext) {}

// EnterExact is called when production exact is entered.
func (l *Listener) EnterExact(ctx *parser.ExactContext) {
	index, _ := strconv.Atoi(ctx.IntLit().GetText())
	l.target.SetBound(index, index)
}

// ExitExact is called when production exact is exited.
func (l *Listener) ExitExact(ctx *parser.ExactContext) {}

var acceptablesTypeList string
var acceptableTypesMap = func() map[string]struct{} {
	acceptableTypes := []string{
		"int8", "int16", "int32", "int64",
		"uint8", "uint16", "uint32", "uint64",
		"float32", "float64",
		"string",
	}
	res := map[string]struct{}{}
	for i, typeName := range acceptableTypes {
		res[typeName] = struct{}{}
		acceptableTypes[i] = fmt.Sprintf("\033[1m%s\033[0m", typeName)
	}
	acceptablesTypeList = strings.Join(acceptableTypes, ", ")
	return res
}()

// EnterFieldType is called when production fieldType is entered.
func (l *Listener) EnterFieldType(ctx *parser.FieldTypeContext) {
	typeName := ctx.Identifier().GetText()
	if _, ok := acceptableTypesMap[typeName]; ok {
		return
	}
	panic(fmt.Sprintf(
		"%d:%d: unsupported type `\033[1m%l\033[0m`, must be one of %l",
		ctx.Identifier().GetSymbol().GetLine(),
		ctx.Identifier().GetSymbol().GetColumn()+len(typeName)/2,
		typeName,
		acceptablesTypeList,
	))
}

// ExitFieldType is called when production fieldType is exited.
func (l *Listener) ExitFieldType(ctx *parser.FieldTypeContext) {}
<commit_msg>Value and named option names restriction<commit_after>// Generated from LDE.g4 by ANTLR 4.7.

package listener // LDE

import (
	"strconv"

	"fmt"

	"strings"

	"github.com/antlr/antlr4/runtime/Go/antlr"
	"github.com/sirkon/ldetool/ast"
	"github.com/sirkon/ldetool/parser"
)

type appender interface {
	Append(i *ast.ActionItem)
}

var reservedWords = map[string]struct{}{
	"Valid":   struct{}{},
	"Extract": struct{}{},
}

func checkReserved(token antlr.Token) {
	if _, ok := reservedWords[token.GetText()]; !ok {
		return
	}
	panic(
		fmt.Sprintf("%d:%d: \033[1m%s\033[0m is reserved identifier",
			token.GetLine(),
			token.GetColumn()+1,
			token.GetText(),
		),
	)
}

// Listener is a complete listener for a parse tree produced by LDEParser.
type Listener struct {
	rules     []*ast.RuleItem
	ai        *ast.ActionItem
	actions   []appender
	target    *ast.Target
	expectEnd bool
}

func New() *Listener {
	return &Listener{}
}

func (l *Listener) Rules() []*ast.RuleItem {
	return l.rules
}

// VisitTerminal is called when a terminal node is visited.
func (l *Listener) VisitTerminal(node antlr.TerminalNode) {}

// VisitErrorNode is called when an error node is visited.
func (l *Listener) VisitErrorNode(node antlr.ErrorNode) {
}

// EnterEveryRule is called when any rule is entered.
func (l *Listener) EnterEveryRule(ctx antlr.ParserRuleContext) {
	if l.expectEnd {
		token := ctx.GetStart()
		panic(fmt.Sprintf(
			"%d:%d: previous action consumed the rest of the string, the rest will do nothing",
			token.GetLine(),
			token.GetColumn(),
		))
	}
}

// ExitEveryRule is called when any rule is exited.
func (l *Listener) ExitEveryRule(ctx antlr.ParserRuleContext) {}

// EnterRules is called when production rules is entered.
func (l *Listener) EnterRules(ctx *parser.RulesContext) {
}

func (l *Listener) seq() appender {
	res := l.actions[len(l.actions)-1]
	return res
}

// ExitRules is called when production rules is exited.
func (l *Listener) ExitRules(ctx *parser.RulesContext) {}

// EnterAtomicRule is called when production atomicRule is entered.
func (l *Listener) EnterAtomicRule(ctx *parser.AtomicRuleContext) {
	rule := ast.NewRule(ctx.Identifier().GetSymbol())
	l.rules = append(l.rules, rule)
	l.actions = append(l.actions, rule)
}

// ExitAtomicRule is called when production atomicRule is exited.
func (l *Listener) ExitAtomicRule(ctx *parser.AtomicRuleContext) {}

// EnterBaseAction is called when production baseAction is entered.
func (l *Listener) EnterBaseAction(ctx *parser.BaseActionContext) {
	if ctx.Stress() != nil {
		res := &ast.ActionItem{
			ErrorOnMismatch: true,
		}
		l.seq().Append(res)
		l.ai = nil
	}
}

// ExitBaseAction is called when production baseAction is exited.
func (l *Listener) ExitBaseAction(ctx *parser.BaseActionContext) {}

// EnterAtomicAction is called when production atomicAction is entered.
func (l *Listener) EnterAtomicAction(ctx *parser.AtomicActionContext) {
	i := &ast.ActionItem{}
	l.seq().Append(i)
	l.ai = i
}

// ExitAtomicAction is called when production atomicAction is exited.
func (l *Listener) ExitAtomicAction(ctx *parser.AtomicActionContext) {}

// EnterPassStringPrefix is called when production passStringPrefix is entered.
func (l *Listener) EnterPassStringPrefix(ctx *parser.PassStringPrefixContext) {
	//l.ai.StartWithString, _ = ast.StartsWithString(token.)
	l.ai.StartWithString, _ = ast.StartsWithString(ctx.StringLit().GetSymbol())
}

// ExitPassStringPrefix is called when production passStringPrefix is exited.
func (l *Listener) ExitPassStringPrefix(ctx *parser.PassStringPrefixContext) {}

// EnterPassCharPrefix is called when production passCharPrefix is entered.
func (l *Listener) EnterPassCharPrefix(ctx *parser.PassCharPrefixContext) {
	l.ai.StartWithChar, _ = ast.StartsWithChar(ctx.CharLit().GetSymbol())
}

// ExitPassCharPrefix is called when production passCharPrefix is exited.
func (l *Listener) ExitPassCharPrefix(ctx *parser.PassCharPrefixContext) {}

// EnterMayPassStringPrefix is called when production mayPassStringPrefix is entered.
func (l *Listener) EnterMayPassStringPrefix(ctx *parser.MayPassStringPrefixContext) {
	l.ai.MayBeStartWithString, _ = ast.MayBeStartsWithString(ctx.StringLit().GetSymbol())
}

// ExitMayPassStringPrefix is called when production mayPassStringPrefix is exited.
func (l *Listener) ExitMayPassStringPrefix(ctx *parser.MayPassStringPrefixContext) {}

// EnterMayPassCharPrefix is called when production mayPassCharPrefix is entered.
func (l *Listener) EnterMayPassCharPrefix(ctx *parser.MayPassCharPrefixContext) {
	l.ai.MayBeStartWithChar, _ = ast.MayBeStartsWithChar(ctx.CharLit().GetSymbol())
}

// ExitMayPassCharPrefix is called when production mayPassCharPrefix is exited.
func (l *Listener) ExitMayPassCharPrefix(ctx *parser.MayPassCharPrefixContext) {}

// EnterPassChars is called when production passChars is entered.
func (l *Listener) EnterPassChars(ctx *parser.PassCharsContext) {
	l.ai.PassFirst, _ = ast.PassFirst(ctx.IntLit().GetSymbol())
}

// ExitPassChars is called when production passChars is exited.
func (l *Listener) ExitPassChars(ctx *parser.PassCharsContext) {}

// EnterPassUntil is called when production passUntil is entered.
func (l *Listener) EnterPassUntil(ctx *parser.PassUntilContext) {
	l.ai.Pass, _ = ast.PassUntilTarget()
	l.target = l.ai.Pass.Limit
}

// ExitPassUntil is called when production passUntil is exited.
func (l *Listener) ExitPassUntil(ctx *parser.PassUntilContext) {}

// EnterMayPassUntil is called when production mayPassUntil is entered.
func (l *Listener) EnterMayPassUntil(ctx *parser.MayPassUntilContext) {
	l.ai.PassOrIgnore, _ = ast.PassUntilTargetOrIgnore()
	l.target = l.ai.PassOrIgnore.Limit
}

// ExitMayPassUntil is called when production mayPassUntil is exited.
func (l *Listener) ExitMayPassUntil(ctx *parser.MayPassUntilContext) {}

// EnterTakeUntil is called when production takeUntil is entered.
func (l *Listener) EnterTakeUntil(ctx *parser.TakeUntilContext) {
	checkReserved(ctx.Identifier().GetSymbol())
	l.ai.Take, _ = ast.TakeUntilTarget(ctx.Identifier().GetSymbol(), ctx.FieldType().GetStart())
	l.target = l.ai.Take.Limit
}

// ExitTakeUntil is called when production takeUntil is exited.
func (l *Listener) ExitTakeUntil(ctx *parser.TakeUntilContext) {}

// EnterTakeUntilOrRest is called when production takeUntilOrRest is entered.
func (l *Listener) EnterTakeUntilOrRest(ctx *parser.TakeUntilOrRestContext) {
	checkReserved(ctx.Identifier().GetSymbol())
	l.ai.TakeUntilOrRest, _ = ast.TakeUntilTargetOrRest(
		ctx.Identifier().GetSymbol(), ctx.FieldType().GetStart(),
	)
	l.target = l.ai.TakeUntilOrRest.Limit
}

// ExitTakeUntilOrRest is called when production takeUntilOrRest is exited.
func (l *Listener) ExitTakeUntilOrRest(ctx *parser.TakeUntilOrRestContext) {}

// EnterTakeUntilRest is called when production takeUntilRest is entered.
func (l *Listener) EnterTakeUntilRest(ctx *parser.TakeUntilRestContext) {
	checkReserved(ctx.Identifier().GetSymbol())
	l.ai.TakeRest, _ = ast.TakeTheRest(ctx.Identifier().GetSymbol(), ctx.FieldType().GetStart())
}

// ExitTakeUntilRest is called when production takeUntilRest is exited.
func (l *Listener) ExitTakeUntilRest(ctx *parser.TakeUntilRestContext) {
	l.expectEnd = true
}

// EnterOptionalNamedArea is called when production optionalNamedArea is entered.
func (l *Listener) EnterOptionalNamedArea(ctx *parser.OptionalNamedAreaContext) {
	checkReserved(ctx.Identifier().GetSymbol())
	l.ai.Option, _ = ast.Option(ctx.Identifier().GetSymbol())

	l.actions = append(l.actions, l.ai.Option)
}

// ExitOptionalNamedArea is called when production optionalNamedArea is exited.
func (l *Listener) ExitOptionalNamedArea(ctx *parser.OptionalNamedAreaContext) {
	l.actions = l.actions[:len(l.actions)-1]
}

// EnterOptionalArea is called when production optionalArea is entered.
func (l *Listener) EnterOptionalArea(ctx *parser.OptionalAreaContext) {
	l.ai.Anonymous, _ = ast.Anonymous(ctx.GetStart())
	l.actions = append(l.actions, l.ai.Anonymous)
}

// ExitOptionalArea is called when production optionalArea is exited.
func (l *Listener) ExitOptionalArea(ctx *parser.OptionalAreaContext) {
	l.actions = l.actions[:len(l.actions)-1]
}

// EnterAtEnd is called when production atEnd is entered.
func (l *Listener) EnterAtEnd(ctx *parser.AtEndContext) {
	l.ai.End, _ = ast.AtTheEnd()
}

// ExitAtEnd is called when production atEnd is exited.
func (l *Listener) ExitAtEnd(ctx *parser.AtEndContext) {}

// EnterTarget is called when production target is entered.
func (l *Listener) EnterTarget(ctx *parser.TargetContext) {
	if ctx.Target() != nil {
		l.target.SetClose()
	}
}

// ExitTarget is called when production target is exited.
func (l *Listener) ExitTarget(ctx *parser.TargetContext) {}

// EnterTargetLit is called when production targetLit is entered.
func (l *Listener) EnterTargetLit(ctx *parser.TargetLitContext) {
	if ctx.StringLit() != nil {
		l.target.SetString(ctx.StringLit().GetText())
	} else if ctx.CharLit() != nil {
		l.target.SetChar(ctx.CharLit().GetText())
	} else {
		panic("Integerity error")
	}
}

// ExitTargetLit is called when production targetLit is exited.
func (l *Listener) ExitTargetLit(ctx *parser.TargetLitContext) {}

// EnterBound is called when production bound is entered.
func (l *Listener) EnterBound(ctx *parser.BoundContext) {
	lower, _ := strconv.Atoi(ctx.IntLit(0).GetText())
	upper, _ := strconv.Atoi(ctx.IntLit(1).GetText())
	l.target.SetBound(lower, upper)
}

// ExitBound is called when production bound is exited.
func (l *Listener) ExitBound(ctx *parser.BoundContext) {}

// EnterLimit is called when production limit is entered.
func (l *Listener) EnterLimit(ctx *parser.LimitContext) {
	lower, _ := strconv.Atoi(ctx.IntLit().GetText())
	l.target.SetLimit(lower)
}

// ExitLimit is called when production limit is exited.
func (l *Listener) ExitLimit(ctx *parser.LimitContext) {}

// EnterExact is called when production exact is entered.
func (l *Listener) EnterExact(ctx *parser.ExactContext) {
	index, _ := strconv.Atoi(ctx.IntLit().GetText())
	l.target.SetBound(index, index)
}

// ExitExact is called when production exact is exited.
func (l *Listener) ExitExact(ctx *parser.ExactContext) {}

var acceptablesTypeList string
var acceptableTypesMap = func() map[string]struct{} {
	acceptableTypes := []string{
		"int8", "int16", "int32", "int64",
		"uint8", "uint16", "uint32", "uint64",
		"float32", "float64",
		"string",
	}
	res := map[string]struct{}{}
	for i, typeName := range acceptableTypes {
		res[typeName] = struct{}{}
		acceptableTypes[i] = fmt.Sprintf("\033[1m%s\033[0m", typeName)
	}
	acceptablesTypeList = strings.Join(acceptableTypes, ", ")
	return res
}()

// EnterFieldType is called when production fieldType is entered.
func (l *Listener) EnterFieldType(ctx *parser.FieldTypeContext) {
	typeName := ctx.Identifier().GetText()
	if _, ok := acceptableTypesMap[typeName]; ok {
		return
	}
	panic(fmt.Sprintf(
		"%d:%d: unsupported type `\033[1m%l\033[0m`, must be one of %l",
		ctx.Identifier().GetSymbol().GetLine(),
		ctx.Identifier().GetSymbol().GetColumn()+len(typeName)/2,
		typeName,
		acceptablesTypeList,
	))
}

// ExitFieldType is called when production fieldType is exited.
func (l *Listener) ExitFieldType(ctx *parser.FieldTypeContext) {}
<|endoftext|>


<commit_before>package backend

import (
	"time"
)

type Container interface {
	ID() string
	Handle() string
	GraceTime() time.Duration

	Start() error
	Stop(kill bool) error

	Info() (ContainerInfo, error)

	CopyIn(srcPath, dstPath string) error
	CopyOut(srcPath, dstPath, owner string) error

	LimitBandwidth(limits BandwidthLimits) error
	CurrentBandwidthLimits() (BandwidthLimits, error)

	LimitCPU(limits CPULimits) error
	CurrentCPULimits() (CPULimits, error)

	LimitDisk(limits DiskLimits) error
	CurrentDiskLimits() (DiskLimits, error)

	LimitMemory(limits MemoryLimits) error
	CurrentMemoryLimits() (MemoryLimits, error)

	Run(ProcessSpec) (uint32, <-chan ProcessStream, error)
	Attach(processID uint32) (<-chan ProcessStream, error)

	NetIn(hostPort, containerPort uint32) (uint32, uint32, error)
	NetOut(network string, port uint32) error
}

type ProcessSpec struct {
	Script     string
	Privileged bool
	Limits     ResourceLimits
}

type ProcessStream struct {
	Source     ProcessStreamSource
	Data       []byte
	ExitStatus *uint32
}

type ProcessStreamSource int32

const (
	ProcessStreamSourceInvalid ProcessStreamSource = iota
	ProcessStreamSourceStdin
	ProcessStreamSourceStdout
	ProcessStreamSourceStderr
)

type ContainerInfo struct {
	State         string
	Events        []string
	HostIP        string
	ContainerIP   string
	ContainerPath string
	ProcessIDs    []uint32
	MemoryStat    ContainerMemoryStat
	CPUStat       ContainerCPUStat
	DiskStat      ContainerDiskStat
	BandwidthStat ContainerBandwidthStat
}

type ContainerMemoryStat struct {
	Cache                   uint64
	Rss                     uint64
	MappedFile              uint64
	Pgpgin                  uint64
	Pgpgout                 uint64
	Swap                    uint64
	Pgfault                 uint64
	Pgmajfault              uint64
	InactiveAnon            uint64
	ActiveAnon              uint64
	InactiveFile            uint64
	ActiveFile              uint64
	Unevictable             uint64
	HierarchicalMemoryLimit uint64
	HierarchicalMemswLimit  uint64
	TotalCache              uint64
	TotalRss                uint64
	TotalMappedFile         uint64
	TotalPgpgin             uint64
	TotalPgpgout            uint64
	TotalSwap               uint64
	TotalPgfault            uint64
	TotalPgmajfault         uint64
	TotalInactiveAnon       uint64
	TotalActiveAnon         uint64
	TotalInactiveFile       uint64
	TotalActiveFile         uint64
	TotalUnevictable        uint64
}

type ContainerCPUStat struct {
	Usage  uint64
	User   uint64
	System uint64
}

type ContainerDiskStat struct {
	BytesUsed  uint64
	InodesUsed uint64
}

type ContainerBandwidthStat struct {
	InRate   uint64
	InBurst  uint64
	OutRate  uint64
	OutBurst uint64
}

type BandwidthLimits struct {
	RateInBytesPerSecond      uint64
	BurstRateInBytesPerSecond uint64
}

type DiskLimits struct {
	BlockLimit uint64
	Block      uint64
	BlockSoft  uint64
	BlockHard  uint64

	InodeLimit uint64
	Inode      uint64
	InodeSoft  uint64
	InodeHard  uint64

	ByteLimit uint64
	Byte      uint64
	ByteSoft  uint64
	ByteHard  uint64
}

type MemoryLimits struct {
	LimitInBytes uint64
}

type CPULimits struct {
	LimitInShares uint64
}

type ResourceLimits struct {
	As         *uint64
	Core       *uint64
	Cpu        *uint64
	Data       *uint64
	Fsize      *uint64
	Locks      *uint64
	Memlock    *uint64
	Msgqueue   *uint64
	Nice       *uint64
	Nofile     *uint64
	Nproc      *uint64
	Rss        *uint64
	Rtprio     *uint64
	Sigpending *uint64
	Stack      *uint64
}
<commit_msg>remove Start() from container interface<commit_after>package backend

import (
	"time"
)

type Container interface {
	ID() string
	Handle() string
	GraceTime() time.Duration

	Stop(kill bool) error

	Info() (ContainerInfo, error)

	CopyIn(srcPath, dstPath string) error
	CopyOut(srcPath, dstPath, owner string) error

	LimitBandwidth(limits BandwidthLimits) error
	CurrentBandwidthLimits() (BandwidthLimits, error)

	LimitCPU(limits CPULimits) error
	CurrentCPULimits() (CPULimits, error)

	LimitDisk(limits DiskLimits) error
	CurrentDiskLimits() (DiskLimits, error)

	LimitMemory(limits MemoryLimits) error
	CurrentMemoryLimits() (MemoryLimits, error)

	Run(ProcessSpec) (uint32, <-chan ProcessStream, error)
	Attach(processID uint32) (<-chan ProcessStream, error)

	NetIn(hostPort, containerPort uint32) (uint32, uint32, error)
	NetOut(network string, port uint32) error
}

type ProcessSpec struct {
	Script     string
	Privileged bool
	Limits     ResourceLimits
}

type ProcessStream struct {
	Source     ProcessStreamSource
	Data       []byte
	ExitStatus *uint32
}

type ProcessStreamSource int32

const (
	ProcessStreamSourceInvalid ProcessStreamSource = iota
	ProcessStreamSourceStdin
	ProcessStreamSourceStdout
	ProcessStreamSourceStderr
)

type ContainerInfo struct {
	State         string
	Events        []string
	HostIP        string
	ContainerIP   string
	ContainerPath string
	ProcessIDs    []uint32
	MemoryStat    ContainerMemoryStat
	CPUStat       ContainerCPUStat
	DiskStat      ContainerDiskStat
	BandwidthStat ContainerBandwidthStat
}

type ContainerMemoryStat struct {
	Cache                   uint64
	Rss                     uint64
	MappedFile              uint64
	Pgpgin                  uint64
	Pgpgout                 uint64
	Swap                    uint64
	Pgfault                 uint64
	Pgmajfault              uint64
	InactiveAnon            uint64
	ActiveAnon              uint64
	InactiveFile            uint64
	ActiveFile              uint64
	Unevictable             uint64
	HierarchicalMemoryLimit uint64
	HierarchicalMemswLimit  uint64
	TotalCache              uint64
	TotalRss                uint64
	TotalMappedFile         uint64
	TotalPgpgin             uint64
	TotalPgpgout            uint64
	TotalSwap               uint64
	TotalPgfault            uint64
	TotalPgmajfault         uint64
	TotalInactiveAnon       uint64
	TotalActiveAnon         uint64
	TotalInactiveFile       uint64
	TotalActiveFile         uint64
	TotalUnevictable        uint64
}

type ContainerCPUStat struct {
	Usage  uint64
	User   uint64
	System uint64
}

type ContainerDiskStat struct {
	BytesUsed  uint64
	InodesUsed uint64
}

type ContainerBandwidthStat struct {
	InRate   uint64
	InBurst  uint64
	OutRate  uint64
	OutBurst uint64
}

type BandwidthLimits struct {
	RateInBytesPerSecond      uint64
	BurstRateInBytesPerSecond uint64
}

type DiskLimits struct {
	BlockLimit uint64
	Block      uint64
	BlockSoft  uint64
	BlockHard  uint64

	InodeLimit uint64
	Inode      uint64
	InodeSoft  uint64
	InodeHard  uint64

	ByteLimit uint64
	Byte      uint64
	ByteSoft  uint64
	ByteHard  uint64
}

type MemoryLimits struct {
	LimitInBytes uint64
}

type CPULimits struct {
	LimitInShares uint64
}

type ResourceLimits struct {
	As         *uint64
	Core       *uint64
	Cpu        *uint64
	Data       *uint64
	Fsize      *uint64
	Locks      *uint64
	Memlock    *uint64
	Msgqueue   *uint64
	Nice       *uint64
	Nofile     *uint64
	Nproc      *uint64
	Rss        *uint64
	Rtprio     *uint64
	Sigpending *uint64
	Stack      *uint64
}
<|endoftext|>