<commit_before>package main

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

	"github.com/spf13/cobra"
)

var newCmd = &cobra.Command{
	Use:   "new [flags] <project name>",
	Short: "creates a project directory of the name supplied as a parameter",
	Long: `Creates aproject  directory of the name supplied as a parameter
immediately following the 'new' option in the $GOPATH/src directory. Note:
'new' depends on the program 'git' and possibly a network connection. If
there is no local repository to clone from at the local machine's $GOPATH,
'new' will attempt to clone the 'github.com/ponzu-cms/ponzu' package from
over the network.`,
	Example: `$ ponzu new github.com/nilslice/proj
> New ponzu project created at $GOPATH/src/github.com/nilslice/proj`,
	RunE: func(cmd *cobra.Command, args []string) error {
		projectName := "ponzu"
		if len(args) > 0 {
			projectName = args[0]
		} else {
			msg := "Please provide a project name."
			msg += "\nThis will create a directory within your $GOPATH/src."
			return fmt.Errorf("%s", msg)
		}
		return newProjectInDir(projectName)
	},
}

// name2path transforns a project name to an absolute path
func name2path(projectName string) (string, error) {
	gopath, err := getGOPATH()
	if err != nil {
		return "", err
	}
	gosrc := filepath.Join(gopath, "src")

	path := projectName
	// support current directory
	if path == "." {
		path, err = os.Getwd()
		if err != nil {
			return "", err
		}
	} else {
		path = filepath.Join(gosrc, path)
	}

	// make sure path is inside $GOPATH/src
	srcrel, err := filepath.Rel(gosrc, path)
	if err != nil {
		return "", err
	}
	if len(srcrel) >= 2 && srcrel[:2] == ".." {
		return "", fmt.Errorf("path '%s' must be inside '%s'", projectName, gosrc)
	}
	if srcrel == "." {
		return "", fmt.Errorf("path '%s' must not be %s", path, filepath.Join("GOPATH", "src"))
	}

	_, err = os.Stat(path)
	if err != nil && !os.IsNotExist(err) {
		return "", err
	}
	if err == nil {
		err = os.ErrExist
	} else if os.IsNotExist(err) {
		err = nil
	}

	return path, err
}

func newProjectInDir(path string) error {
	path, err := name2path(path)
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	// path exists, ask if it should be overwritten
	if os.IsNotExist(err) {
		fmt.Printf("Using '%s' as project directory\n", path)
		fmt.Println("Path exists, overwrite contents? (y/N):")

		answer, err := getAnswer()
		if err != nil {
			return err
		}

		switch answer {
		case "n", "no", "\r\n", "\n", "":
			fmt.Println("")

		case "y", "yes":
			err := os.RemoveAll(path)
			if err != nil {
				return fmt.Errorf("Failed to overwrite %s. \n%s", path, err)
			}

			return createProjectInDir(path)

		default:
			fmt.Println("Input not recognized. No files overwritten. Answer as 'y' or 'n' only.")
		}

		return nil
	}

	return createProjectInDir(path)
}

func createProjectInDir(path string) error {
	gopath, err := getGOPATH()
	if err != nil {
		return err
	}
	repo := ponzuRepo
	local := filepath.Join(gopath, "src", filepath.Join(repo...))
	network := "https://" + strings.Join(repo, "/") + ".git"
	if !strings.HasPrefix(path, gopath) {
		path = filepath.Join(gopath, path)
	}

	// create the directory or overwrite it
	err = os.MkdirAll(path, os.ModeDir|os.ModePerm)
	if err != nil {
		return err
	}

	if dev {
		if fork != "" {
			local = filepath.Join(gopath, "src", fork)
		}

		err = execAndWait("git", "clone", local, "--branch", "ponzu-dev", "--single-branch", path)
		if err != nil {
			return err
		}

		err = vendorCorePackages(path)
		if err != nil {
			return err
		}

		fmt.Println("Dev build cloned from " + local + ":ponzu-dev")
		return nil
	}

	// try to git clone the repository from the local machine's $GOPATH
	err = execAndWait("git", "clone", local, path)
	if err != nil {
		fmt.Println("Couldn't clone from", local, "- trying network...")

		// try to git clone the repository over the network
		networkClone := exec.Command("git", "clone", network, path)
		networkClone.Stdout = os.Stdout
		networkClone.Stderr = os.Stderr

		err = networkClone.Start()
		if err != nil {
			fmt.Println("Network clone failed to start. Try again and make sure you have a network connection.")
			return err
		}
		err = networkClone.Wait()
		if err != nil {
			fmt.Println("Network clone failure.")
			// failed
			return fmt.Errorf("Failed to clone files from local machine [%s] and over the network [%s].\n%s", local, network, err)
		}
	}

	// create an internal vendor directory in ./cmd/ponzu and move content,
	// management and system packages into it
	err = vendorCorePackages(path)
	if err != nil {
		return err
	}

	gitDir := filepath.Join(path, ".git")
	err = os.RemoveAll(gitDir)
	if err != nil {
		fmt.Println("Failed to remove .git directory from your project path. Consider removing it manually.")
	}

	fmt.Println("New ponzu project created at", path)
	return nil
}

func init() {
	newCmd.Flags().StringVar(&fork, "fork", "", "modify repo source for Ponzu core development")
	newCmd.Flags().BoolVar(&dev, "dev", false, "modify environment for Ponzu core development")

	RegisterCmdlineCommand(newCmd)
}
<commit_msg>[cli] add .circleci to paths for post-new removal (#215)<commit_after>package main

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

	"github.com/spf13/cobra"
)

var newCmd = &cobra.Command{
	Use:   "new [flags] <project name>",
	Short: "creates a project directory of the name supplied as a parameter",
	Long: `Creates aproject  directory of the name supplied as a parameter
immediately following the 'new' option in the $GOPATH/src directory. Note:
'new' depends on the program 'git' and possibly a network connection. If
there is no local repository to clone from at the local machine's $GOPATH,
'new' will attempt to clone the 'github.com/ponzu-cms/ponzu' package from
over the network.`,
	Example: `$ ponzu new github.com/nilslice/proj
> New ponzu project created at $GOPATH/src/github.com/nilslice/proj`,
	RunE: func(cmd *cobra.Command, args []string) error {
		projectName := "ponzu"
		if len(args) > 0 {
			projectName = args[0]
		} else {
			msg := "Please provide a project name."
			msg += "\nThis will create a directory within your $GOPATH/src."
			return fmt.Errorf("%s", msg)
		}
		return newProjectInDir(projectName)
	},
}

// name2path transforns a project name to an absolute path
func name2path(projectName string) (string, error) {
	gopath, err := getGOPATH()
	if err != nil {
		return "", err
	}
	gosrc := filepath.Join(gopath, "src")

	path := projectName
	// support current directory
	if path == "." {
		path, err = os.Getwd()
		if err != nil {
			return "", err
		}
	} else {
		path = filepath.Join(gosrc, path)
	}

	// make sure path is inside $GOPATH/src
	srcrel, err := filepath.Rel(gosrc, path)
	if err != nil {
		return "", err
	}
	if len(srcrel) >= 2 && srcrel[:2] == ".." {
		return "", fmt.Errorf("path '%s' must be inside '%s'", projectName, gosrc)
	}
	if srcrel == "." {
		return "", fmt.Errorf("path '%s' must not be %s", path, filepath.Join("GOPATH", "src"))
	}

	_, err = os.Stat(path)
	if err != nil && !os.IsNotExist(err) {
		return "", err
	}
	if err == nil {
		err = os.ErrExist
	} else if os.IsNotExist(err) {
		err = nil
	}

	return path, err
}

func newProjectInDir(path string) error {
	path, err := name2path(path)
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	// path exists, ask if it should be overwritten
	if os.IsNotExist(err) {
		fmt.Printf("Using '%s' as project directory\n", path)
		fmt.Println("Path exists, overwrite contents? (y/N):")

		answer, err := getAnswer()
		if err != nil {
			return err
		}

		switch answer {
		case "n", "no", "\r\n", "\n", "":
			fmt.Println("")

		case "y", "yes":
			err := os.RemoveAll(path)
			if err != nil {
				return fmt.Errorf("Failed to overwrite %s. \n%s", path, err)
			}

			return createProjectInDir(path)

		default:
			fmt.Println("Input not recognized. No files overwritten. Answer as 'y' or 'n' only.")
		}

		return nil
	}

	return createProjectInDir(path)
}

func createProjectInDir(path string) error {
	gopath, err := getGOPATH()
	if err != nil {
		return err
	}
	repo := ponzuRepo
	local := filepath.Join(gopath, "src", filepath.Join(repo...))
	network := "https://" + strings.Join(repo, "/") + ".git"
	if !strings.HasPrefix(path, gopath) {
		path = filepath.Join(gopath, path)
	}

	// create the directory or overwrite it
	err = os.MkdirAll(path, os.ModeDir|os.ModePerm)
	if err != nil {
		return err
	}

	if dev {
		if fork != "" {
			local = filepath.Join(gopath, "src", fork)
		}

		err = execAndWait("git", "clone", local, "--branch", "ponzu-dev", "--single-branch", path)
		if err != nil {
			return err
		}

		err = vendorCorePackages(path)
		if err != nil {
			return err
		}

		fmt.Println("Dev build cloned from " + local + ":ponzu-dev")
		return nil
	}

	// try to git clone the repository from the local machine's $GOPATH
	err = execAndWait("git", "clone", local, path)
	if err != nil {
		fmt.Println("Couldn't clone from", local, "- trying network...")

		// try to git clone the repository over the network
		networkClone := exec.Command("git", "clone", network, path)
		networkClone.Stdout = os.Stdout
		networkClone.Stderr = os.Stderr

		err = networkClone.Start()
		if err != nil {
			fmt.Println("Network clone failed to start. Try again and make sure you have a network connection.")
			return err
		}
		err = networkClone.Wait()
		if err != nil {
			fmt.Println("Network clone failure.")
			// failed
			return fmt.Errorf("Failed to clone files from local machine [%s] and over the network [%s].\n%s", local, network, err)
		}
	}

	// create an internal vendor directory in ./cmd/ponzu and move content,
	// management and system packages into it
	err = vendorCorePackages(path)
	if err != nil {
		return err
	}

	// remove non-project files and directories
	rmPaths := []string{".git", ".circleci"}
	for _, rm := range rmPaths {
		dir := filepath.Join(path, rm)
		err = os.RemoveAll(dir)
		if err != nil {
			fmt.Println("Failed to remove directory from your project path. Consider removing it manually:", dir)
		}
	}

	fmt.Println("New ponzu project created at", path)
	return nil
}

func init() {
	newCmd.Flags().StringVar(&fork, "fork", "", "modify repo source for Ponzu core development")
	newCmd.Flags().BoolVar(&dev, "dev", false, "modify environment for Ponzu core development")

	RegisterCmdlineCommand(newCmd)
}
<|endoftext|>


<commit_before>package cmd

import (
	"github.com/bpicode/fritzctl/logger"
	"github.com/spf13/cobra"
)

var sessionIDCmd = &cobra.Command{
	Use:     "sessionid",
	Short:   "Obtain a session ID",
	Long:    "Obtain a session ID by solving the FRITZ!Box login challenge. The session ID can be used for subsequent requests until it gets invalidated.",
	Example: "fritzctl sessionid",
	RunE:    sessionId,
}

func init() {
	RootCmd.AddCommand(sessionIDCmd)
}

func sessionId(cmd *cobra.Command, args []string) error {
	client := clientLogin()
	logger.Success("Successfully obtained session ID:", client.SessionInfo.SID)
	return nil
}
<commit_msg>CQ: rename sessionid to sessionID<commit_after>package cmd

import (
	"github.com/bpicode/fritzctl/logger"
	"github.com/spf13/cobra"
)

var sessionIDCmd = &cobra.Command{
	Use:     "sessionid",
	Short:   "Obtain a session ID",
	Long:    "Obtain a session ID by solving the FRITZ!Box login challenge. The session ID can be used for subsequent requests until it gets invalidated.",
	Example: "fritzctl sessionid",
	RunE:    sessionID,
}

func init() {
	RootCmd.AddCommand(sessionIDCmd)
}

func sessionID(cmd *cobra.Command, args []string) error {
	client := clientLogin()
	logger.Success("Successfully obtained session ID:", client.SessionInfo.SID)
	return nil
}
<|endoftext|>


<commit_before>package sign

import (
	"os"
	"time"

	humanize "github.com/dustin/go-humanize"
	"github.com/go-errors/errors"
	"github.com/itchio/butler/comm"
	"github.com/itchio/butler/filtering"
	"github.com/itchio/butler/mansion"
	"github.com/itchio/wharf/pools"
	"github.com/itchio/wharf/pwr"
	"github.com/itchio/wharf/tlc"
	"github.com/itchio/wharf/wire"
	"github.com/itchio/wharf/wsync"
)

var args = struct {
	output    *string
	signature *string
	fixPerms  *bool
}{}

func Register(ctx *mansion.Context) {
	cmd := ctx.App.Command("sign", "(Advanced) Generate a signature file for a given directory. Useful for integrity checks and remote diff generation.")
	args.output = cmd.Arg("dir", "Path of directory to sign").Required().String()
	args.signature = cmd.Arg("signature", "Path to write signature to").Required().String()
	args.fixPerms = cmd.Flag("fix-permissions", "Detect Mac & Linux executables and adjust their permissions automatically").Default("true").Bool()
	ctx.Register(cmd, do)
}

func do(ctx *mansion.Context) {
	ctx.Must(Do(*args.output, *args.signature, ctx.CompressionSettings(), *args.fixPerms))
}

func Do(output string, signature string, compression pwr.CompressionSettings, fixPerms bool) error {
	comm.Opf("Creating signature for %s", output)
	startTime := time.Now()

	container, err := tlc.WalkAny(output, &tlc.WalkOpts{Filter: filtering.FilterPaths})
	if err != nil {
		return errors.Wrap(err, 1)
	}

	pool, err := pools.New(container, output)
	if err != nil {
		return errors.Wrap(err, 1)
	}

	if fixPerms {
		container.FixPermissions(pool)
	}

	signatureWriter, err := os.Create(signature)
	if err != nil {
		return errors.Wrap(err, 1)
	}

	rawSigWire := wire.NewWriteContext(signatureWriter)
	rawSigWire.WriteMagic(pwr.SignatureMagic)

	rawSigWire.WriteMessage(&pwr.SignatureHeader{
		Compression: &compression,
	})

	sigWire, err := pwr.CompressWire(rawSigWire, &compression)
	if err != nil {
		return errors.Wrap(err, 1)
	}
	sigWire.WriteMessage(container)

	comm.StartProgress()
	err = pwr.ComputeSignatureToWriter(container, pool, comm.NewStateConsumer(), func(hash wsync.BlockHash) error {
		return sigWire.WriteMessage(&pwr.BlockHash{
			WeakHash:   hash.WeakHash,
			StrongHash: hash.StrongHash,
		})
	})
	comm.EndProgress()
	if err != nil {
		return errors.Wrap(err, 1)
	}

	err = sigWire.Close()
	if err != nil {
		return errors.Wrap(err, 1)
	}

	prettySize := humanize.IBytes(uint64(container.Size))
	perSecond := humanize.IBytes(uint64(float64(container.Size) / time.Since(startTime).Seconds()))
	comm.Statf("%s (%s) @ %s/s\n", prettySize, container.Stats(), perSecond)

	return nil
}
<commit_msg>Closes #143<commit_after>package sign

import (
	"os"
	"time"

	humanize "github.com/dustin/go-humanize"
	"github.com/go-errors/errors"
	"github.com/itchio/butler/comm"
	"github.com/itchio/butler/filtering"
	"github.com/itchio/butler/mansion"
	"github.com/itchio/wharf/pools"
	"github.com/itchio/wharf/pwr"
	"github.com/itchio/wharf/tlc"
	"github.com/itchio/wharf/wire"
	"github.com/itchio/wharf/wsync"
)

var args = struct {
	output    *string
	signature *string
	fixPerms  *bool
}{}

func Register(ctx *mansion.Context) {
	cmd := ctx.App.Command("sign", "(Advanced) Generate a signature file for a given directory. Useful for integrity checks and remote diff generation.")
	args.output = cmd.Arg("dir", "Path of directory to sign").Required().String()
	args.signature = cmd.Arg("signature", "Path to write signature to").Required().String()
	args.fixPerms = cmd.Flag("fix-permissions", "Detect Mac & Linux executables and adjust their permissions automatically").Default("true").Bool()
	ctx.Register(cmd, do)
}

func do(ctx *mansion.Context) {
	ctx.Must(Do(*args.output, *args.signature, ctx.CompressionSettings(), *args.fixPerms))
}

func Do(output string, signature string, compression pwr.CompressionSettings, fixPerms bool) error {
	comm.Opf("Creating signature for %s", output)
	startTime := time.Now()

	container, err := tlc.WalkAny(output, &tlc.WalkOpts{Filter: filtering.FilterPaths})
	if err != nil {
		return errors.Wrap(err, 1)
	}

	pool, err := pools.New(container, output)
	if err != nil {
		return errors.Wrap(err, 1)
	}

	if fixPerms {
		container.FixPermissions(pool)
	}

	signatureWriter, err := os.Create(signature)
	if err != nil {
		return errors.Wrap(err, 1)
	}
	defer signatureWriter.Close()

	rawSigWire := wire.NewWriteContext(signatureWriter)
	rawSigWire.WriteMagic(pwr.SignatureMagic)

	rawSigWire.WriteMessage(&pwr.SignatureHeader{
		Compression: &compression,
	})

	sigWire, err := pwr.CompressWire(rawSigWire, &compression)
	if err != nil {
		return errors.Wrap(err, 1)
	}
	sigWire.WriteMessage(container)

	comm.StartProgress()
	err = pwr.ComputeSignatureToWriter(container, pool, comm.NewStateConsumer(), func(hash wsync.BlockHash) error {
		return sigWire.WriteMessage(&pwr.BlockHash{
			WeakHash:   hash.WeakHash,
			StrongHash: hash.StrongHash,
		})
	})
	comm.EndProgress()
	if err != nil {
		return errors.Wrap(err, 1)
	}

	err = sigWire.Close()
	if err != nil {
		return errors.Wrap(err, 1)
	}

	prettySize := humanize.IBytes(uint64(container.Size))
	perSecond := humanize.IBytes(uint64(float64(container.Size) / time.Since(startTime).Seconds()))
	comm.Statf("%s (%s) @ %s/s\n", prettySize, container.Stats(), perSecond)

	return nil
}
<|endoftext|>


<commit_before>package term

import (
	"syscall"
)

//#include <termios.h>
import "C"

func tcsetattr(fd uintptr, when int, termios *Termios) {
	var cterm C.struct_termios
	var cc_t [C.NCCS]C.cc_t
	for i, c := range termios.Cc {
		cc_t[i] = C.cc_t(c)
	}
	cterm.c_iflag = C.tcflag_t(termios.Iflag)
	cterm.c_oflag = C.tcflag_t(termios.Oflag)
	cterm.c_cflag = C.tcflag_t(termios.Cflag)
	cterm.c_lflag = C.tcflag_t(termios.Lflag)
	cterm.c_cc = cc_t
	cterm.c_ispeed = C.speed_t(termios.Ispeed)
	cterm.c_ospeed = C.speed_t(termios.Ospeed)
	C.tcsetattr(C.int(fd), C.int(when), &cterm)
}

func GetPassword(fd uintptr) string {
	var termios Termios
	tcgetattr(fd, &termios)
	termios.Lflag &^= syscall.ECHO
	tcsetattr(fd, 0, &termios)
	var buf [16]byte
	var pass []byte
	for {
		n, _ := syscall.Read(int(fd), buf[:])
		if n == 0 {
			break
		}
		for n > 0 && (buf[n-1] == '\n' || buf[n-1] == '\r') {
			n--
		}
		pass = append(pass, buf[:n]...)
		if n < len(buf) {
			break
		}
	}
	return string(pass)
}
<commit_msg>term: returning the terminal to the old state after reading the password<commit_after>package term

import (
	"syscall"
)

//#include <termios.h>
import "C"

func tcsetattr(fd uintptr, when int, termios *Termios) {
	var cterm C.struct_termios
	var cc_t [C.NCCS]C.cc_t
	for i, c := range termios.Cc {
		cc_t[i] = C.cc_t(c)
	}
	cterm.c_iflag = C.tcflag_t(termios.Iflag)
	cterm.c_oflag = C.tcflag_t(termios.Oflag)
	cterm.c_cflag = C.tcflag_t(termios.Cflag)
	cterm.c_lflag = C.tcflag_t(termios.Lflag)
	cterm.c_cc = cc_t
	cterm.c_ispeed = C.speed_t(termios.Ispeed)
	cterm.c_ospeed = C.speed_t(termios.Ospeed)
	C.tcsetattr(C.int(fd), C.int(when), &cterm)
}

func GetPassword(fd uintptr) string {
	var termios, oldState Termios
	tcgetattr(fd, &termios)
	oldState = termios
	termios.Lflag &^= syscall.ECHO
	tcsetattr(fd, 0, &termios)
	defer tcsetattr(fd, 0, &oldState)
	var buf [16]byte
	var pass []byte
	for {
		n, _ := syscall.Read(int(fd), buf[:])
		if n == 0 {
			break
		}
		for n > 0 && (buf[n-1] == '\n' || buf[n-1] == '\r') {
			n--
		}
		pass = append(pass, buf[:n]...)
		if n < len(buf) {
			break
		}
	}
	return string(pass)
}
<|endoftext|>


<commit_before>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
)

type talksBuilder struct {
}

func (b talksBuilder) Signature(heads map[string]string) string {
	return heads["talks"]
}

const talksToolsRev = "ac6d9c1d842f9b6482f39f7a172e0251a0f7cbc0"

func (b talksBuilder) Init(dir, hostport string, heads map[string]string) (*exec.Cmd, error) {
	toolsDir := filepath.Join(dir, "gopath/src/golang.org/x/tools")
	if err := checkout(repoURL+"tools", talksToolsRev, toolsDir); err != nil {
		return nil, err
	}
	talksDir := filepath.Join(dir, "gopath/src/golang.org/x/talks")
	if err := checkout(repoURL+"talks", heads["talks"], talksDir); err != nil {
		return nil, err
	}

	goDir := os.Getenv("GOROOT_BOOTSTRAP")
	if goDir == "" {
		goDir = runtime.GOROOT()
	}
	goBin := filepath.Join(goDir, "bin/go")
	goPath := filepath.Join(dir, "gopath")
	presentPath := "golang.org/x/tools/cmd/present"
	install := exec.Command(goBin, "install", "-tags=appenginevm", presentPath)
	install.Env = []string{"GOROOT=" + goDir, "GOPATH=" + goPath}
	if err := runErr(install); err != nil {
		return nil, err
	}

	talksBin := filepath.Join(goPath, "bin/present")
	presentSrc := filepath.Join(goPath, "src", presentPath)
	present := exec.Command(talksBin, "-http="+hostport, "-base="+presentSrc)
	present.Dir = talksDir
	// TODO(adg): log this somewhere useful
	present.Stdout = os.Stdout
	present.Stderr = os.Stderr
	if err := present.Start(); err != nil {
		return nil, err
	}
	return present, nil
}

var talksMsg = []byte("Talks - The Go Programming Language")

func (b talksBuilder) HealthCheck(hostport string) error {
	body, err := getOK(fmt.Sprintf("http://%v/", hostport))
	if err != nil {
		return err
	}
	if !bytes.Contains(body, talksMsg) {
		return errors.New("couldn't match string")
	}
	return nil
}
<commit_msg>cmd/tip: bump verison serving tip.golang.org to HEAD<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
)

type talksBuilder struct {
}

func (b talksBuilder) Signature(heads map[string]string) string {
	return heads["talks"]
}

const talksToolsRev = "1f1b3322f67af76803c942fd237291538ec68262"

func (b talksBuilder) Init(dir, hostport string, heads map[string]string) (*exec.Cmd, error) {
	toolsDir := filepath.Join(dir, "gopath/src/golang.org/x/tools")
	if err := checkout(repoURL+"tools", talksToolsRev, toolsDir); err != nil {
		return nil, err
	}
	talksDir := filepath.Join(dir, "gopath/src/golang.org/x/talks")
	if err := checkout(repoURL+"talks", heads["talks"], talksDir); err != nil {
		return nil, err
	}

	goDir := os.Getenv("GOROOT_BOOTSTRAP")
	if goDir == "" {
		goDir = runtime.GOROOT()
	}
	goBin := filepath.Join(goDir, "bin/go")
	goPath := filepath.Join(dir, "gopath")
	presentPath := "golang.org/x/tools/cmd/present"
	install := exec.Command(goBin, "install", "-tags=appenginevm", presentPath)
	install.Env = []string{"GOROOT=" + goDir, "GOPATH=" + goPath}
	if err := runErr(install); err != nil {
		return nil, err
	}

	talksBin := filepath.Join(goPath, "bin/present")
	presentSrc := filepath.Join(goPath, "src", presentPath)
	present := exec.Command(talksBin, "-http="+hostport, "-base="+presentSrc)
	present.Dir = talksDir
	// TODO(adg): log this somewhere useful
	present.Stdout = os.Stdout
	present.Stderr = os.Stderr
	if err := present.Start(); err != nil {
		return nil, err
	}
	return present, nil
}

var talksMsg = []byte("Talks - The Go Programming Language")

func (b talksBuilder) HealthCheck(hostport string) error {
	body, err := getOK(fmt.Sprintf("http://%v/", hostport))
	if err != nil {
		return err
	}
	if !bytes.Contains(body, talksMsg) {
		return errors.New("couldn't match string")
	}
	return nil
}
<|endoftext|>


<commit_before>/**
 * Copyright (C) 2015 Red Hat, 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 cmds

import (
	"github.com/fabric8io/gofabric8/client"
	"github.com/fabric8io/gofabric8/util"
	oclient "github.com/openshift/origin/pkg/client"
	"github.com/spf13/cobra"
	"k8s.io/kubernetes/pkg/api"
	k8sclient "k8s.io/kubernetes/pkg/client/unversioned"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"time"
)

const (
	allFlag = "all"
)

func NewCmdWaitFor(f *cmdutil.Factory) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "wait-for",
		Short: "Waits for the listed deployments to be ready - useful for automation and testing",
		Long:  `Waits for the listed deployments to be ready - useful for automation and testing`,
		PreRun: func(cmd *cobra.Command, args []string) {
			showBanner()
		},
		Run: func(cmd *cobra.Command, args []string) {

			waitAll := cmd.Flags().Lookup(allFlag).Value.String() == "true"

			if !waitAll && len(args) == 0 {
				util.Infof("Please specify one or more names of Deployment or DeploymentConfig resources or use the --%s flag to match all Deployments and DeploymentConfigs\n", allFlag)
				return
			}
			c, cfg := client.NewClient(f)
			oc, _ := client.NewOpenShiftClient(cfg)

			initSchema()

			fromNamespace := cmd.Flags().Lookup(fromNamespaceFlag).Value.String()
			if len(fromNamespace) == 0 {
				ns, _, err := f.DefaultNamespace()
				if err != nil {
					util.Fatal("No default namespace")
				}
				fromNamespace = ns
			}

			sleepMillis := 1 * time.Second

			util.Infof("Waiting for Deployments to be ready in namespace %s\n", fromNamespace)

			typeOfMaster := util.TypeOfMaster(c)

			for i := 0; i < 2; i++ {
				waitForDeployments(c, fromNamespace, waitAll, args, sleepMillis)
				if typeOfMaster == util.OpenShift {
					waitForDeploymentConfigs(oc, fromNamespace, waitAll, args, sleepMillis)
				}
			}
			util.Infof("Deployments are ready now!\n")
		},
	}
	cmd.PersistentFlags().Bool(allFlag, false, "waits for all the Deployments or DeploymentConfigs to be ready")
	cmd.PersistentFlags().StringP(fromNamespaceFlag, "f", "", "the source namespace or uses the default namespace")
	return cmd
}

func waitForDeployments(c *k8sclient.Client, ns string, waitAll bool, names []string, sleepMillis time.Duration) error {
	if waitAll {
		deployments, err := c.Extensions().Deployments(ns).List(api.ListOptions{})
		if err != nil {
			return err
		}
		for _, deployment := range deployments.Items {
			name := deployment.Name
			err = waitForDeployment(c, ns, name, sleepMillis)
			if err != nil {
				return err
			}
		}
	} else {
		for _, name := range names {
			err := waitForDeployment(c, ns, name, sleepMillis)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func waitForDeploymentConfigs(c *oclient.Client, ns string, waitAll bool, names []string, sleepMillis time.Duration) error {
	if waitAll {
		deployments, err := c.DeploymentConfigs(ns).List(api.ListOptions{})
		if err != nil {
			return err
		}
		for _, deployment := range deployments.Items {
			name := deployment.Name
			err = waitForDeploymentConfig(c, ns, name, sleepMillis)
			if err != nil {
				return err
			}
		}
	} else {
		for _, name := range names {
			err := waitForDeploymentConfig(c, ns, name, sleepMillis)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func waitForDeployment(c *k8sclient.Client, ns string, name string, sleepMillis time.Duration) error {
	util.Infof("Deployment %s waiting for it to be ready...\n", name)
	for {
		deployment, err := c.Extensions().Deployments(ns).Get(name)
		if err != nil {
			return err
		}
		available := deployment.Status.AvailableReplicas
		unavailable := deployment.Status.UnavailableReplicas
		if unavailable == 0 && available > 0 {
			util.Infof("DeploymentConfig %s now has %d available replicas\n", name, available)
			return nil
		}
		time.Sleep(sleepMillis)
	}
}

func waitForDeploymentConfig(c *oclient.Client, ns string, name string, sleepMillis time.Duration) error {
	util.Infof("DeploymentConfig %s waiting for it to be ready...\n", name)
	for {
		deployment, err := c.DeploymentConfigs(ns).Get(name)
		if err != nil {
			return err
		}
		available := deployment.Status.AvailableReplicas
		unavailable := deployment.Status.UnavailableReplicas
		if unavailable == 0 && available > 0 {
			util.Infof("DeploymentConfig %s now has %d available replicas\n", name, available)
			return nil
		}
		time.Sleep(sleepMillis)
	}
}
<commit_msg>lets add a configurable timeout and poll period #301<commit_after>/**
 * Copyright (C) 2015 Red Hat, 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 cmds

import (
	"github.com/fabric8io/gofabric8/client"
	"github.com/fabric8io/gofabric8/util"
	oclient "github.com/openshift/origin/pkg/client"
	"github.com/spf13/cobra"
	"k8s.io/kubernetes/pkg/api"
	k8sclient "k8s.io/kubernetes/pkg/client/unversioned"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"time"
)

const (
	allFlag         = "all"
	timeoutFlag     = "timeout"
	sleepPeriodFlag = "sleep"
)

func NewCmdWaitFor(f *cmdutil.Factory) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "wait-for",
		Short: "Waits for the listed deployments to be ready - useful for automation and testing",
		Long:  `Waits for the listed deployments to be ready - useful for automation and testing`,
		PreRun: func(cmd *cobra.Command, args []string) {
			showBanner()
		},
		Run: func(cmd *cobra.Command, args []string) {

			waitAll := cmd.Flags().Lookup(allFlag).Value.String() == "true"

			durationText := cmd.Flags().Lookup(timeoutFlag).Value.String()
			maxDuration, err := time.ParseDuration(durationText)
			if err != nil {
				util.Fatalf("Could not parse duration `%s` from flag --%s. Error %v\n", durationText, timeoutFlag, err)
			}
			durationText = cmd.Flags().Lookup(sleepPeriodFlag).Value.String()
			sleepMillis, err := time.ParseDuration(durationText)
			if err != nil {
				util.Fatalf("Could not parse duration `%s` from flag --%s. Error %v\n", durationText, sleepPeriodFlag, err)
			}

			if !waitAll && len(args) == 0 {
				util.Infof("Please specify one or more names of Deployment or DeploymentConfig resources or use the --%s flag to match all Deployments and DeploymentConfigs\n", allFlag)
				return
			}
			c, cfg := client.NewClient(f)
			oc, _ := client.NewOpenShiftClient(cfg)

			initSchema()

			fromNamespace := cmd.Flags().Lookup(fromNamespaceFlag).Value.String()
			if len(fromNamespace) == 0 {
				ns, _, err := f.DefaultNamespace()
				if err != nil {
					util.Fatal("No default namespace")
				}
				fromNamespace = ns
			}

			timer := time.NewTimer(maxDuration)
			go func() {
				<-timer.C
				util.Fatalf("Timed out waiting for Deployments. Waited: %v\n", maxDuration)
			}()

			util.Infof("Waiting for Deployments to be ready in namespace %s\n", fromNamespace)

			typeOfMaster := util.TypeOfMaster(c)

			for i := 0; i < 2; i++ {
				handleError(waitForDeployments(c, fromNamespace, waitAll, args, sleepMillis))
				if typeOfMaster == util.OpenShift {
					handleError(waitForDeploymentConfigs(oc, fromNamespace, waitAll, args, sleepMillis))
				}
			}
			timer.Stop()
			util.Infof("Deployments are ready now!\n")

		},
	}
	cmd.PersistentFlags().Bool(allFlag, false, "waits for all the Deployments or DeploymentConfigs to be ready")
	cmd.PersistentFlags().StringP(fromNamespaceFlag, "f", "", "the source namespace or uses the default namespace")
	cmd.PersistentFlags().String(timeoutFlag, "60m", "the maximum amount of time to wait for the Deployemnts to be ready before failing. e.g. an expression like: 1.5h, 12m, 10s")
	cmd.PersistentFlags().String(sleepPeriodFlag, "1s", "the sleep period while polling for Deployment status (e.g. 1s)")
	return cmd
}

func handleError(err error) {
	if err != nil {
		util.Fatalf("Failed to wait %v\n", err)
	}
}

func waitForDeployments(c *k8sclient.Client, ns string, waitAll bool, names []string, sleepMillis time.Duration) error {
	if waitAll {
		deployments, err := c.Extensions().Deployments(ns).List(api.ListOptions{})
		if err != nil {
			return err
		}
		for _, deployment := range deployments.Items {
			name := deployment.Name
			err = waitForDeployment(c, ns, name, sleepMillis)
			if err != nil {
				return err
			}
		}
	} else {
		for _, name := range names {
			err := waitForDeployment(c, ns, name, sleepMillis)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func waitForDeploymentConfigs(c *oclient.Client, ns string, waitAll bool, names []string, sleepMillis time.Duration) error {
	if waitAll {
		deployments, err := c.DeploymentConfigs(ns).List(api.ListOptions{})
		if err != nil {
			return err
		}
		for _, deployment := range deployments.Items {
			name := deployment.Name
			err = waitForDeploymentConfig(c, ns, name, sleepMillis)
			if err != nil {
				return err
			}
		}
	} else {
		for _, name := range names {
			err := waitForDeploymentConfig(c, ns, name, sleepMillis)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func waitForDeployment(c *k8sclient.Client, ns string, name string, sleepMillis time.Duration) error {
	util.Infof("Deployment %s waiting for it to be ready...\n", name)
	for {
		deployment, err := c.Extensions().Deployments(ns).Get(name)
		if err != nil {
			return err
		}
		available := deployment.Status.AvailableReplicas
		unavailable := deployment.Status.UnavailableReplicas
		if unavailable == 0 && available > 0 {
			util.Infof("DeploymentConfig %s now has %d available replicas\n", name, available)
			return nil
		}
		time.Sleep(sleepMillis)
	}
}

func waitForDeploymentConfig(c *oclient.Client, ns string, name string, sleepMillis time.Duration) error {
	util.Infof("DeploymentConfig %s waiting for it to be ready...\n", name)
	for {
		deployment, err := c.DeploymentConfigs(ns).Get(name)
		if err != nil {
			return err
		}
		available := deployment.Status.AvailableReplicas
		unavailable := deployment.Status.UnavailableReplicas
		if unavailable == 0 && available > 0 {
			util.Infof("DeploymentConfig %s now has %d available replicas\n", name, available)
			return nil
		}
		time.Sleep(sleepMillis)
	}
}
<|endoftext|>


<commit_before>package goworld

// GoWorld是一个分布式的游戏服务器，提供

import (
	"time"

	"github.com/xiaonanln/goTimer"
	"github.com/xiaonanln/goworld/components/game"
	"github.com/xiaonanln/goworld/engine/common"
	"github.com/xiaonanln/goworld/engine/config"
	"github.com/xiaonanln/goworld/engine/entity"
	"github.com/xiaonanln/goworld/engine/gwlog"
	"github.com/xiaonanln/goworld/engine/kvdb"
	"github.com/xiaonanln/goworld/engine/post"
	"github.com/xiaonanln/goworld/engine/service"
	"github.com/xiaonanln/goworld/engine/storage"
)

type GameID = uint16
type GateID = uint16
type DispatcherID uint16

// Export useful types
type Vector3 = entity.Vector3

// Entity 类型代表游戏服务器中的一个对象
type Entity = entity.Entity

// Space 类型代表一个游戏服务器中的一个场景。一个场景中可以包含多个Entity。Space和其中的Entity都存在于一个game进程中。
type Space = entity.Space
type EntityID = common.EntityID

// Run runs the server endless loop
//
// This is the main routine for the server and all entity logic,
// and this function never quit
func Run() {
	game.Run()
}

// RegisterEntity registers the entity type so that entities can be created or loaded
//
// returns the entity type description object which can be used to define more properties
// of entity type
func RegisterEntity(typeName string, entityPtr entity.IEntity) *entity.EntityTypeDesc {
	return entity.RegisterEntity(typeName, entityPtr, false)
}

// RegisterService registeres an service type
// After registeration, the service entity will be created automatically on some game
func RegisterService(typeName string, entityPtr entity.IEntity) {
	service.RegisterService(typeName, entityPtr)
}

// CreateSpaceAnywhere creates a space with specified kind in any game server
func CreateSpaceAnywhere(kind int) EntityID {
	if kind == 0 {
		gwlog.Panicf("Can not create nil space with kind=0. Game will create 1 nil space automatically.")
	}
	return entity.CreateSpaceAnywhere(kind)
}

// CreateSpaceLocally creates a space with specified kind in the local game server
//
// returns the space EntityID
func CreateSpaceLocally(kind int) *Space {
	if kind == 0 {
		gwlog.Panicf("Can not create nil space with kind=0. Game will create 1 nil space automatically.")
	}
	return entity.CreateSpaceLocally(kind)
}

// CreateEntityLocally creates a entity on the local server
//
// returns EntityID
func CreateEntityLocally(typeName string) *Entity {
	return entity.CreateEntityLocally(typeName, nil)
}

// CreateEntityAnywhere creates a entity on any server
func CreateEntityAnywhere(typeName string) EntityID {
	return entity.CreateEntityAnywhere(typeName)
}

// LoadEntityAnywhere loads the specified entity from entity storage
func LoadEntityAnywhere(typeName string, entityID EntityID) {
	entity.LoadEntityAnywhere(typeName, entityID)
}

// LoadEntityOnGame loads entity in the specified game
// If the entity already exists on any server, LoadEntityOnGame will do nothing
func LoadEntityOnGame(typeName string, entityID EntityID, gameid GameID) {
	entity.LoadEntityOnGame(typeName, entityID, gameid)
}

// LoadEntityLocally load entity in the local game
// If the entity already exists on any server, LoadEntityLocally will do nothing
func LoadEntityLocally(typeName string, entityID EntityID) {
	entity.LoadEntityOnGame(typeName, entityID, GetGameID())
}

// ListEntityIDs gets all saved entity ids in storage, may take long time and block the main routine
//
// returns result in callback
func ListEntityIDs(typeName string, callback storage.ListCallbackFunc) {
	storage.ListEntityIDs(typeName, callback)
}

// Exists checks if entityID exists in entity storage
//
// returns result in callback
func Exists(typeName string, entityID EntityID, callback storage.ExistsCallbackFunc) {
	storage.Exists(typeName, entityID, callback)
}

// GetEntity gets the entity by EntityID
func GetEntity(id EntityID) *Entity {
	return entity.GetEntity(id)
}

// GetSpace gets the space by ID
func GetSpace(id EntityID) *Space {
	return entity.GetSpace(id)
}

// GetGameID gets the local server ID
//
// server ID is a uint16 number starts from 1, which should be different for each servers
// server ID is also in the game config section name of goworld.ini
func GetGameID() uint16 {
	return game.GetGameID()
}

// MapAttr creates a new MapAttr
func MapAttr() *entity.MapAttr {
	return entity.NewMapAttr()
}

// ListAttr creates a new ListAttr
func ListAttr() *entity.ListAttr {
	return entity.NewListAttr()
}

// RegisterSpace registers the space entity type.
//
// All spaces will be created as an instance of this type
func RegisterSpace(spacePtr entity.ISpace) {
	entity.RegisterSpace(spacePtr)
}

// Entities gets all entities as an EntityMap (do not modify it!)
func Entities() entity.EntityMap {
	return entity.Entities()
}

// Call other entities
func Call(id EntityID, method string, args ...interface{}) {
	entity.Call(id, method, args)
}

// CallService calls a service entity
func CallService(serviceName string, method string, args ...interface{}) {
	service.CallService(serviceName, method, args)
}

// GetServiceEntityID returns the entityid of the service
func GetServiceEntityID(serviceName string) common.EntityID {
	return service.GetServiceEntityID(serviceName)
}

// CallNilSpaces calls methods of all nil spaces on all games
func CallNilSpaces(method string, args ...interface{}) {
	entity.CallNilSpaces(method, args, game.GetGameID())
}

// GetNilSpaceID returns the Entity ID of nil space on the specified game
func GetNilSpaceID(gameid GameID) EntityID {
	return entity.GetNilSpaceID(gameid)
}

// GetNilSpace returns the nil space on this game
// Nil space is a special space with Kind = 0. Nil space is the default space for all created entities.
// Each game has one nil space with fixed EntityID for each game, which can be acquired by calling `GetNilSpaceID`
//
// Since nil game exists on each game with fixed EntityID, an entity can migrate to target game by calling `e.EnterSpace(GetNilSpaceID(gameid), Vector3{})`
func GetNilSpace() *Space {
	return entity.GetNilSpace()
}

// GetKVDB gets value of key from KVDB
func GetKVDB(key string, callback kvdb.KVDBGetCallback) {
	kvdb.Get(key, callback)
}

// PutKVDB puts key-value to KVDB
func PutKVDB(key string, val string, callback kvdb.KVDBPutCallback) {
	kvdb.Put(key, val, callback)
}

// GetOrPut gets value of key from KVDB, if val not exists or is "", put key-value to KVDB.
func GetOrPutKVDB(key string, val string, callback kvdb.KVDBGetOrPutCallback) {
	kvdb.GetOrPut(key, val, callback)
}

// ListGameIDs returns all game IDs
func ListGameIDs() []uint16 {
	return config.GetGameIDs()
}

// AddTimer adds a timer to be executed after specified duration
func AddCallback(d time.Duration, callback func()) {
	timer.AddCallback(d, callback)
}

// AddTimer adds a repeat timer to be executed every specified duration
func AddTimer(d time.Duration, callback func()) {
	timer.AddTimer(d, callback)
}

// Post posts a callback to be executed
// It is almost same as AddCallback(0, callback)
func Post(callback post.PostCallback) {
	post.Post(callback)
}
<commit_msg>CN DOC<commit_after>package goworld

// GoWorld是一个分布式的游戏服务器，提供

import (
	"time"

	"github.com/xiaonanln/goTimer"
	"github.com/xiaonanln/goworld/components/game"
	"github.com/xiaonanln/goworld/engine/common"
	"github.com/xiaonanln/goworld/engine/config"
	"github.com/xiaonanln/goworld/engine/entity"
	"github.com/xiaonanln/goworld/engine/gwlog"
	"github.com/xiaonanln/goworld/engine/kvdb"
	"github.com/xiaonanln/goworld/engine/post"
	"github.com/xiaonanln/goworld/engine/service"
	"github.com/xiaonanln/goworld/engine/storage"
)

type GameID = uint16
type GateID = uint16
type DispatcherID uint16

// EntityID 唯一代表
type EntityID = common.EntityID

// Entity 类型代表游戏服务器中的一个对象。开发者可以使用GoWorld提供的接口进行对象创建、载入。对象载入之后，GoWorld提供定时的对象数据存盘。
// 同一个game进程中的Entity之间可以拿到相互的引用（指针）并直接进行相关的函数调用。不同game进程中的Entity之间可以使用RPC进行相互通信。
type Entity = entity.Entity

// Space 类型代表一个游戏服务器中的一个场景。一个场景中可以包含多个Entity。Space和其中的Entity都存在于一个game进程中。
type Space = entity.Space

// Vector3 是服务端用于存储Entity位置的类型，包含X, Y, Z三个字段。
// GoWorld使用X轴和Z轴坐标进行AOI管理，无视Y轴坐标值。
type Vector3 = entity.Vector3

// Run 开始运行game服务。开发者需要为自己的游戏服务器提供一个main模块和main函数，并在main函数里正确初始化GoWorld服务器并启动服务器。
// 一般来说，开发者需要在main函数中注册相应的Space类型、Service类型、Entity类型，然后调用`goworld.Run`启动GoWorld服务器即可
// goworld.RegisterSpace(&MySpace{}) // 注册自定义的Space类型
// goworld.RegisterService("OnlineService", &OnlineService{})
// goworld.RegisterService("SpaceService", &SpaceService{})
// goworld.RegisterEntity("Account", &Account{})
// goworld.RegisterEntity("Monster", &Monster{})
// goworld.RegisterEntity("Player", &Player{})
//
// goworld.Run()
func Run() {
	game.Run()
}

// RegisterEntity registers the entity type so that entities can be created or loaded
//
// returns the entity type description object which can be used to define more properties
// of entity type
func RegisterEntity(typeName string, entityPtr entity.IEntity) *entity.EntityTypeDesc {
	return entity.RegisterEntity(typeName, entityPtr, false)
}

// RegisterService registeres an service type
// After registeration, the service entity will be created automatically on some game
func RegisterService(typeName string, entityPtr entity.IEntity) {
	service.RegisterService(typeName, entityPtr)
}

// CreateSpaceAnywhere creates a space with specified kind in any game server
func CreateSpaceAnywhere(kind int) EntityID {
	if kind == 0 {
		gwlog.Panicf("Can not create nil space with kind=0. Game will create 1 nil space automatically.")
	}
	return entity.CreateSpaceAnywhere(kind)
}

// CreateSpaceLocally creates a space with specified kind in the local game server
//
// returns the space EntityID
func CreateSpaceLocally(kind int) *Space {
	if kind == 0 {
		gwlog.Panicf("Can not create nil space with kind=0. Game will create 1 nil space automatically.")
	}
	return entity.CreateSpaceLocally(kind)
}

// CreateEntityLocally creates a entity on the local server
//
// returns EntityID
func CreateEntityLocally(typeName string) *Entity {
	return entity.CreateEntityLocally(typeName, nil)
}

// CreateEntityAnywhere creates a entity on any server
func CreateEntityAnywhere(typeName string) EntityID {
	return entity.CreateEntityAnywhere(typeName)
}

// LoadEntityAnywhere loads the specified entity from entity storage
func LoadEntityAnywhere(typeName string, entityID EntityID) {
	entity.LoadEntityAnywhere(typeName, entityID)
}

// LoadEntityOnGame loads entity in the specified game
// If the entity already exists on any server, LoadEntityOnGame will do nothing
func LoadEntityOnGame(typeName string, entityID EntityID, gameid GameID) {
	entity.LoadEntityOnGame(typeName, entityID, gameid)
}

// LoadEntityLocally load entity in the local game
// If the entity already exists on any server, LoadEntityLocally will do nothing
func LoadEntityLocally(typeName string, entityID EntityID) {
	entity.LoadEntityOnGame(typeName, entityID, GetGameID())
}

// ListEntityIDs gets all saved entity ids in storage, may take long time and block the main routine
//
// returns result in callback
func ListEntityIDs(typeName string, callback storage.ListCallbackFunc) {
	storage.ListEntityIDs(typeName, callback)
}

// Exists checks if entityID exists in entity storage
//
// returns result in callback
func Exists(typeName string, entityID EntityID, callback storage.ExistsCallbackFunc) {
	storage.Exists(typeName, entityID, callback)
}

// GetEntity gets the entity by EntityID
func GetEntity(id EntityID) *Entity {
	return entity.GetEntity(id)
}

// GetSpace gets the space by ID
func GetSpace(id EntityID) *Space {
	return entity.GetSpace(id)
}

// GetGameID gets the local server ID
//
// server ID is a uint16 number starts from 1, which should be different for each servers
// server ID is also in the game config section name of goworld.ini
func GetGameID() uint16 {
	return game.GetGameID()
}

// MapAttr creates a new MapAttr
func MapAttr() *entity.MapAttr {
	return entity.NewMapAttr()
}

// ListAttr creates a new ListAttr
func ListAttr() *entity.ListAttr {
	return entity.NewListAttr()
}

// RegisterSpace registers the space entity type.
//
// All spaces will be created as an instance of this type
func RegisterSpace(spacePtr entity.ISpace) {
	entity.RegisterSpace(spacePtr)
}

// Entities gets all entities as an EntityMap (do not modify it!)
func Entities() entity.EntityMap {
	return entity.Entities()
}

// Call other entities
func Call(id EntityID, method string, args ...interface{}) {
	entity.Call(id, method, args)
}

// CallService calls a service entity
func CallService(serviceName string, method string, args ...interface{}) {
	service.CallService(serviceName, method, args)
}

// GetServiceEntityID returns the entityid of the service
func GetServiceEntityID(serviceName string) common.EntityID {
	return service.GetServiceEntityID(serviceName)
}

// CallNilSpaces calls methods of all nil spaces on all games
func CallNilSpaces(method string, args ...interface{}) {
	entity.CallNilSpaces(method, args, game.GetGameID())
}

// GetNilSpaceID returns the Entity ID of nil space on the specified game
func GetNilSpaceID(gameid GameID) EntityID {
	return entity.GetNilSpaceID(gameid)
}

// GetNilSpace returns the nil space on this game
// Nil space is a special space with Kind = 0. Nil space is the default space for all created entities.
// Each game has one nil space with fixed EntityID for each game, which can be acquired by calling `GetNilSpaceID`
//
// Since nil game exists on each game with fixed EntityID, an entity can migrate to target game by calling `e.EnterSpace(GetNilSpaceID(gameid), Vector3{})`
func GetNilSpace() *Space {
	return entity.GetNilSpace()
}

// GetKVDB gets value of key from KVDB
func GetKVDB(key string, callback kvdb.KVDBGetCallback) {
	kvdb.Get(key, callback)
}

// PutKVDB puts key-value to KVDB
func PutKVDB(key string, val string, callback kvdb.KVDBPutCallback) {
	kvdb.Put(key, val, callback)
}

// GetOrPut gets value of key from KVDB, if val not exists or is "", put key-value to KVDB.
func GetOrPutKVDB(key string, val string, callback kvdb.KVDBGetOrPutCallback) {
	kvdb.GetOrPut(key, val, callback)
}

// ListGameIDs returns all game IDs
func ListGameIDs() []uint16 {
	return config.GetGameIDs()
}

// AddTimer adds a timer to be executed after specified duration
func AddCallback(d time.Duration, callback func()) {
	timer.AddCallback(d, callback)
}

// AddTimer adds a repeat timer to be executed every specified duration
func AddTimer(d time.Duration, callback func()) {
	timer.AddTimer(d, callback)
}

// Post posts a callback to be executed
// It is almost same as AddCallback(0, callback)
func Post(callback post.PostCallback) {
	post.Post(callback)
}
<|endoftext|>


<commit_before>package ls

import (
	flag "../../appletflag"
	"fmt"
	"io/ioutil"
	"log"
	"math"
	"os"
	"text/tabwriter"
)

var (
	longFlag      = flag.Bool("l", false, "Long, detailed listing")
	recursiveFlag = flag.Bool("r", false, "Recurse into directories")
	humanFlag     = flag.Bool("h", false, "Output sizes in a human readable format")
	helpFlag      = flag.Bool("help", false, "Show this help")
	out           = tabwriter.NewWriter(os.Stdout, 4, 4, 1, ' ', 0)
)

func Main() {
	flag.Parse()

	if *helpFlag {
		println("`ls` [options] [dirs...]")
		flag.PrintDefaults()
		return
	}

	dirs, e := getDirList()
	if e != nil {
		log.Fatalf("Could not get cwd: %s\n", e)
	}

	for _, dir := range dirs {
		e := list(dir, "")
		if e != nil {
			log.Printf("Error while listing directory: %s\n", e)
		}
	}
	out.Flush()
	return
}

func getDirList() ([]string, error) {
	if flag.NArg() <= 0 {
		cwd, e := os.Getwd()
		return []string{cwd}, e
	}
	return flag.Args(), nil
}

func list(dir, prefix string) error {
	entries, e := ioutil.ReadDir(dir)
	if e != nil {
		return e
	}

	for _, entry := range entries {
		printEntry(entry)
		if entry.IsDir() && *recursiveFlag {
			folder := prefix + "/" + entry.Name()
			fmt.Fprintf(out, "%s:\n", folder)
			e := list(dir+"/"+entry.Name(), folder)
			if e != nil {
				log.Printf("Failed listing %s: %s", entry.Name(), e)
				continue
			}
		}
	}
	return nil
}

func printEntry(e os.FileInfo) {
	fmt.Fprintf(out, "%s%s\t", e.Name(), getEntryTypeString(e))
	if *longFlag {
		fmt.Fprintf(out, "%s\t", getModeString(e.Mode().Perm()))
		fmt.Fprintf(out, "%s\t", getSizeString(e.Size()))
		fmt.Fprintf(out, "%s\t", getUserString(e.Uid))
	}
	fmt.Fprintln(out, "")
}

var accessSymbols = "xwr"

func getModeString(mode os.FileMode) (s string) {
	for i := 8; i >= 0; i-- {
		if uint32(mode)&(1<<uint(i)) == 0 {
			s += "-"
		} else {
			char := i % 3
			s += accessSymbols[char : char+1]
		}
	}
	return
}

var sizeSymbols = "BkMGT"

func getSizeString(size int64) (s string) {
	if !*humanFlag {
		return fmt.Sprintf("%9dB", size)
	}
	var power int
	if size == 0 {
		power = 0
	} else {
		power = int(math.Log(float64(size)) / math.Log(1024.0))
	}
	if power > len(sizeSymbols)-1 {
		power = len(sizeSymbols) - 1
	}
	rSize := float64(size) / math.Pow(1024, float64(power))
	return fmt.Sprintf("%7.3f%s", rSize, sizeSymbols[power:power+1])
}

func getEntryTypeString(e os.FileInfo) string {
	if e.IsDir() {
		return "/"
	} else if e.IsBlock() {
		return "<>"
	} else if e.Mode()&os.ModeNamedPipe != 0 {
		return ">>"
	} else if e.Mode()&os.ModeSymlink != 0 {
		return "@"
	} else if e.Mode()&os.ModeSocket != 0 {
		return "&"
	} else if e.Mode().IsRegular() && (e.Mode()&0001 == 0001) {
		return "*"
	}
	return ""
}

func getUserString(id int) string {
	return fmt.Sprintf("%03d", id)
}
<commit_msg>Fix up ls output<commit_after>package ls

import (
	flag "../../appletflag"
	"fmt"
	"io/ioutil"
	"log"
	"math"
	"os"
	"text/tabwriter"
	"time"
)

var (
	longFlag      = flag.Bool("l", false, "Long, detailed listing")
	recursiveFlag = flag.Bool("r", false, "Recurse into directories")
	humanFlag     = flag.Bool("h", false, "Output sizes in a human readable format")
	helpFlag      = flag.Bool("help", false, "Show this help")
	out           = tabwriter.NewWriter(os.Stdout, 4, 4, 1, ' ', 0)
)

func Main() {
	flag.Parse()

	if *helpFlag {
		println("`ls` [options] [dirs...]")
		flag.PrintDefaults()
		return
	}

	dirs, e := getDirList()
	if e != nil {
		log.Fatalf("Could not get cwd: %s\n", e)
	}

	for _, dir := range dirs {
		e := list(dir, "")
		if e != nil {
			log.Printf("Error while listing directory: %s\n", e)
		}
	}
	out.Flush()
	return
}

func getDirList() ([]string, error) {
	if flag.NArg() <= 0 {
		cwd, e := os.Getwd()
		return []string{cwd}, e
	}
	return flag.Args(), nil
}

func list(dir, prefix string) error {
	entries, e := ioutil.ReadDir(dir)
	if e != nil {
		return e
	}

	for _, entry := range entries {
		printEntry(entry)
		if entry.IsDir() && *recursiveFlag {
			folder := prefix + "/" + entry.Name()
			fmt.Fprintf(out, "%s:\n", folder)
			e := list(dir+"/"+entry.Name(), folder)
			if e != nil {
				log.Printf("Failed listing %s: %s", entry.Name(), e)
				continue
			}
		}
	}
	return nil
}

func printEntry(e os.FileInfo) {
	if *longFlag {
		if e.IsDir() {
			fmt.Print("d")
		} else {
			fmt.Print("-")
		}
		fmt.Fprintf(out, "%s ", getModeString(e.Mode()))
		fmt.Fprintf(out, "%s ", getSizeString(e.Size()))
		fmt.Fprintf(out, "%16s ", getTimeString(e.ModTime()))
	}
	fmt.Fprintf(out, "%s%s", e.Name(), getEntryTypeString(e))
	fmt.Fprintln(out, "")
}

func getTimeString(mtime time.Time) (s string) {
	return mtime.Format("2006-01-02 15:04")
}

var accessSymbols = "xwr"

func getModeString(mode os.FileMode) (s string) {
	for i := 8; i >= 0; i-- {
		if uint32(mode)&(1<<uint(i)) == 0 {
			s += "-"
		} else {
			char := i % 3
			s += accessSymbols[char : char+1]
		}
	}
	return
}

var sizeSymbols = "BkMGT"

func getSizeString(size int64) (s string) {
	if !*humanFlag {
		return fmt.Sprintf("%6dB", size)
	}
	var power int
	if size == 0 {
		power = 0
	} else {
		power = int(math.Log(float64(size)) / math.Log(1024.0))
	}
	if power > len(sizeSymbols)-1 {
		power = len(sizeSymbols) - 1
	}
	rSize := float64(size) / math.Pow(1024, float64(power))
	return fmt.Sprintf("% 6.1f%s", rSize, sizeSymbols[power:power+1])
}

func getEntryTypeString(e os.FileInfo) string {
	if e.IsDir() {
		return "/"
	} else if e.IsBlock() {
		return "<>"
	} else if e.Mode()&os.ModeNamedPipe != 0 {
		return ">>"
	} else if e.Mode()&os.ModeSymlink != 0 {
		return "@"
	} else if e.Mode()&os.ModeSocket != 0 {
		return "&"
	} else if e.Mode().IsRegular() && (e.Mode()&0001 == 0001) {
		return "*"
	}
	return ""
}

func getUserString(id int) string {
	return fmt.Sprintf("%03d", id)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/golang/protobuf/jsonpb"
	"github.com/tmc/grpc-websocket-proxy/examples/cmd/wsechoserver/echoserver"
)

type Server struct{}

func (s *Server) Stream(_ *echoserver.Empty, stream echoserver.EchoService_StreamServer) error {
	start := time.Now()
	for i := 0; i < 5; i++ {
		time.Sleep(time.Second)
		if err := stream.Send(&echoserver.EchoResponse{
			Message: "hello there!" + fmt.Sprint(time.Now().Sub(start)),
		}); err != nil {
			return err
		}
	}
	return nil
}

func (s *Server) Echo(srv echoserver.EchoService_EchoServer) error {
	for {
		req, err := srv.Recv()
		if err != nil {
			return err
		}
		if err := srv.Send(&echoserver.EchoResponse{
			Message: req.Message + "!",
		}); err != nil {
			return err
		}
	}
}

func (s *Server) Heartbeats(srv echoserver.EchoService_HeartbeatsServer) error {
	go func() {
		for {
			_, err := srv.Recv()
			if err != nil {
				log.Println("Recv() err:", err)
				return
			}
			log.Println("got hb from client")
		}
	}()
	t := time.NewTicker(time.Second * 1)
	for {
		log.Println("sending hb")
		hb := &echoserver.Heartbeat{
			Status: echoserver.Heartbeat_OK,
		}
		b := new(bytes.Buffer)
		if err := (&jsonpb.Marshaler{}).Marshal(b, hb); err != nil {
			log.Println("marshal err:", err)
		}
		log.Println(string(b.Bytes()))
		if err := srv.Send(hb); err != nil {
			return err
		}
		<-t.C
	}
	return nil
}
<commit_msg>logrus: use new import path<commit_after>package main

import (
	"bytes"
	"fmt"
	"time"

	"github.com/golang/protobuf/jsonpb"
	log "github.com/sirupsen/logrus"
	"github.com/tmc/grpc-websocket-proxy/examples/cmd/wsechoserver/echoserver"
)

type Server struct{}

func (s *Server) Stream(_ *echoserver.Empty, stream echoserver.EchoService_StreamServer) error {
	start := time.Now()
	for i := 0; i < 5; i++ {
		time.Sleep(time.Second)
		if err := stream.Send(&echoserver.EchoResponse{
			Message: "hello there!" + fmt.Sprint(time.Now().Sub(start)),
		}); err != nil {
			return err
		}
	}
	return nil
}

func (s *Server) Echo(srv echoserver.EchoService_EchoServer) error {
	for {
		req, err := srv.Recv()
		if err != nil {
			return err
		}
		if err := srv.Send(&echoserver.EchoResponse{
			Message: req.Message + "!",
		}); err != nil {
			return err
		}
	}
}

func (s *Server) Heartbeats(srv echoserver.EchoService_HeartbeatsServer) error {
	go func() {
		for {
			_, err := srv.Recv()
			if err != nil {
				log.Println("Recv() err:", err)
				return
			}
			log.Println("got hb from client")
		}
	}()
	t := time.NewTicker(time.Second * 1)
	for {
		log.Println("sending hb")
		hb := &echoserver.Heartbeat{
			Status: echoserver.Heartbeat_OK,
		}
		b := new(bytes.Buffer)
		if err := (&jsonpb.Marshaler{}).Marshal(b, hb); err != nil {
			log.Println("marshal err:", err)
		}
		log.Println(string(b.Bytes()))
		if err := srv.Send(hb); err != nil {
			return err
		}
		<-t.C
	}
	return nil
}
<|endoftext|>


<commit_before><commit_msg>added: change topic<commit_after><|endoftext|>


<commit_before><commit_msg>Make integration/v7/push/path_flag_test understand Mac paths<commit_after><|endoftext|>


<commit_before>package srnd

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"path/filepath"
	"strconv"
	"strings"
)

type varnishHandler struct {
	cache *VarnishCache
}

func (self *varnishHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	path := r.URL.Path
	_, file := filepath.Split(path)

	isjson := strings.HasSuffix(path, "/json") || strings.HasSuffix(path, "/json/")

	if strings.HasPrefix(path, "/t/") {
		// thread handler
		parts := strings.Split(path[3:], "/")
		hash := parts[0]
		msg, err := self.cache.database.GetMessageIDByHash(hash)
		if err == nil {
			template.genThread(self.cache.attachments, msg, self.cache.prefix, self.cache.name, w, self.cache.database, isjson)
			return
		} else {
			goto notfound
		}
	}
	if strings.Trim(path, "/") == "overboard" {
		// generate ukko aka overboard
		template.genUkko(self.cache.prefix, self.cache.name, w, self.cache.database, isjson)
		return
	}

	if strings.HasPrefix(path, "/b/") {
		// board handler
		parts := strings.Split(path[3:], "/")
		page := 0
		group := parts[0]
		if len(parts) > 1 && parts[1] != "" && parts[1] != "json" {
			var err error
			page, err = strconv.Atoi(parts[1])
			if err != nil {
				goto notfound
			}
		}
		hasgroup := self.cache.database.HasNewsgroup(group)
		if !hasgroup {
			goto notfound
		}
		pages := self.cache.database.GetGroupPageCount(group)
		if page >= int(pages) {
			goto notfound
		}
		template.genBoardPage(self.cache.attachments, self.cache.prefix, self.cache.name, group, page, w, self.cache.database, isjson)
		return
	}

	if strings.HasPrefix(path, "/o/") {
		page := 0
		parts := strings.Split(path, "/")
		if len(parts) > 1 {
			if parts[1] != "json" {
				var err error
				page, err = strconv.Atoi(parts[1])
				if err != nil {
					goto notfound
				}

			}
		}
		template.genUkkoPaginated(self.cache.prefix, self.cache.name, w, self.cache.database, page, isjson)
		return
	}

	if len(file) == 0 || file == "index.html" {
		template.genFrontPage(10, self.cache.prefix, self.cache.name, w, ioutil.Discard, self.cache.database)
		return
	}

	if file == "index.json" {
		// TODO: index.json
		goto notfound
	}
	if strings.HasPrefix(file, "history.html") {
		template.genGraphs(self.cache.prefix, w, self.cache.database)
		return
	}
	if strings.HasPrefix(file, "boards.html") {
		template.genFrontPage(10, self.cache.prefix, self.cache.name, ioutil.Discard, w, self.cache.database)
		return
	}

	if strings.HasPrefix(file, "boards.json") {
		b := self.cache.database.GetAllNewsgroups()
		json.NewEncoder(w).Encode(b)
		return
	}

	if strings.HasPrefix(file, "ukko.html") {
		template.genUkko(self.cache.prefix, self.cache.name, w, self.cache.database, false)
		return
	}
	if strings.HasPrefix(file, "ukko.json") {
		template.genUkko(self.cache.prefix, self.cache.name, w, self.cache.database, true)
		return
	}

	if strings.HasPrefix(file, "ukko-") {
		page := getUkkoPage(file)
		template.genUkkoPaginated(self.cache.prefix, self.cache.name, w, self.cache.database, page, isjson)
		return
	}
	if strings.HasPrefix(file, "thread-") {
		hash := getThreadHash(file)
		if len(hash) == 0 {
			goto notfound
		}
		msg, err := self.cache.database.GetMessageIDByHash(hash)
		if err != nil {
			goto notfound
		}
		template.genThread(self.cache.attachments, msg, self.cache.prefix, self.cache.name, w, self.cache.database, isjson)
		return
	}
	if strings.HasPrefix(file, "catalog-") {
		group := getGroupForCatalog(file)
		if len(group) == 0 {
			goto notfound
		}
		hasgroup := self.cache.database.HasNewsgroup(group)
		if !hasgroup {
			goto notfound
		}
		template.genCatalog(self.cache.prefix, self.cache.name, group, w, self.cache.database)
		return
	} else {
		group, page := getGroupAndPage(file)
		if len(group) == 0 || page < 0 {
			goto notfound
		}
		hasgroup := self.cache.database.HasNewsgroup(group)
		if !hasgroup {
			goto notfound
		}
		pages := self.cache.database.GetGroupPageCount(group)
		if page >= int(pages) {
			goto notfound
		}
		template.genBoardPage(self.cache.attachments, self.cache.prefix, self.cache.name, group, page, w, self.cache.database, isjson)
		return
	}

notfound:
	template.renderNotFound(w, r, self.cache.prefix, self.cache.name)
}

type VarnishCache struct {
	database Database
	store    ArticleStore

	webroot_dir string
	name        string

	regen_threads int
	attachments   bool

	prefix          string
	varnish_url     string
	client          *http.Client
	regenThreadChan chan ArticleEntry
	regenGroupChan  chan groupRegenRequest
}

func (self *VarnishCache) invalidate(r string) {
	u, _ := url.Parse(r)
	resp, err := self.client.Do(&http.Request{
		Method: "PURGE",
		URL:    u,
	})
	if err == nil {
		resp.Body.Close()
	} else {
		log.Println("varnish cache error", err)
	}
}

func (self *VarnishCache) DeleteBoardMarkup(group string) {
	n, _ := self.database.GetPagesPerBoard(group)
	for n > 0 {
		go self.invalidate(fmt.Sprintf("%s%s%s-%d.html", self.varnish_url, self.prefix, group, n))
		go self.invalidate(fmt.Sprintf("%s%sb/%s/%d/", self.varnish_url, self.prefix, group, n))
		n--
	}
	self.invalidate(fmt.Sprintf("%s%sb/%s/", self.varnish_url, self.prefix, group))
}

// try to delete root post's page
func (self *VarnishCache) DeleteThreadMarkup(root_post_id string) {
	self.invalidate(fmt.Sprintf("%s%sthread-%s.html", self.varnish_url, self.prefix, HashMessageID(root_post_id)))
	self.invalidate(fmt.Sprintf("%s%st/%s/", self.varnish_url, self.prefix, HashMessageID(root_post_id)))
}

// regen every newsgroup
func (self *VarnishCache) RegenAll() {
	// we will do this as it's used by rengen on start for frontend
	groups := self.database.GetAllNewsgroups()
	for _, group := range groups {
		self.database.GetGroupThreads(group, self.regenThreadChan)
	}
}

func (self *VarnishCache) RegenFrontPage() {
	self.invalidate(fmt.Sprintf("%s%s", self.varnish_url, self.prefix))
}

func (self *VarnishCache) invalidateUkko() {
	// TODO: invalidate paginated ukko
	self.invalidate(fmt.Sprintf("%s%sukko.html", self.varnish_url, self.prefix))
	self.invalidate(fmt.Sprintf("%s%soverboard/", self.varnish_url, self.prefix))
}

func (self *VarnishCache) pollRegen() {
	for {
		select {
		// consume regen requests
		case ev := <-self.regenGroupChan:
			{
				self.invalidate(fmt.Sprintf("%s%s%s-%d.html", self.varnish_url, self.prefix, ev.group, ev.page))
				self.invalidate(fmt.Sprintf("%s%sb/%s/%d/", self.varnish_url, self.prefix, ev.group, ev.page))
				if ev.page == 0 {
					self.invalidate(fmt.Sprintf("%s%sb/%s/", self.varnish_url, self.prefix, ev.group))
				}
			}
		case ev := <-self.regenThreadChan:
			{
				self.Regen(ev)
			}
		}
	}
}

// regen every page of the board
func (self *VarnishCache) RegenerateBoard(group string) {
	n, _ := self.database.GetPagesPerBoard(group)
	for n > 0 {
		go self.invalidate(fmt.Sprintf("%s%s%s-%d.html", self.varnish_url, self.prefix, group, n))
		go self.invalidate(fmt.Sprintf("%s%s%s/%d/", self.varnish_url, self.prefix, group, n))
		n--
	}
	self.invalidate(fmt.Sprintf("%s%sb/%s/", self.varnish_url, self.prefix, group))
}

// regenerate pages after a mod event
func (self *VarnishCache) RegenOnModEvent(newsgroup, msgid, root string, page int) {
	self.regenGroupChan <- groupRegenRequest{newsgroup, page}
	self.regenThreadChan <- ArticleEntry{newsgroup, root}
}

func (self *VarnishCache) Start() {
	go self.pollRegen()
}

func (self *VarnishCache) Regen(msg ArticleEntry) {
	go self.invalidate(fmt.Sprintf("%s%s%s-%d.html", self.varnish_url, self.prefix, msg.Newsgroup(), 0))
	go self.invalidate(fmt.Sprintf("%s%s%s/%d/", self.varnish_url, self.prefix, msg.Newsgroup(), 0))
	go self.invalidate(fmt.Sprintf("%s%sthread-%s.html", self.varnish_url, self.prefix, HashMessageID(msg.MessageID())))
	go self.invalidate(fmt.Sprintf("%s%st/%s/", self.varnish_url, self.prefix, HashMessageID(msg.MessageID())))
	self.invalidateUkko()
}

func (self *VarnishCache) GetThreadChan() chan ArticleEntry {
	return self.regenThreadChan
}

func (self *VarnishCache) GetGroupChan() chan groupRegenRequest {
	return self.regenGroupChan
}

func (self *VarnishCache) GetHandler() http.Handler {
	return &varnishHandler{self}
}

func (self *VarnishCache) Close() {
	//nothig to do
}

func NewVarnishCache(varnish_url, bind_addr, prefix, webroot, name string, attachments bool, db Database, store ArticleStore) CacheInterface {
	cache := new(VarnishCache)
	cache.regenThreadChan = make(chan ArticleEntry, 16)
	cache.regenGroupChan = make(chan groupRegenRequest, 8)
	local_addr, err := net.ResolveTCPAddr("tcp", bind_addr)
	if err != nil {
		log.Fatalf("failed to resolve %s for varnish cache: %s", bind_addr, err)
	}
	cache.client = &http.Client{
		Transport: &http.Transport{
			Dial: func(network, addr string) (c net.Conn, err error) {
				var remote_addr *net.TCPAddr
				remote_addr, err = net.ResolveTCPAddr(network, addr)
				if err == nil {
					c, err = net.DialTCP(network, local_addr, remote_addr)
				}
				return
			},
		},
	}
	cache.prefix = prefix
	cache.webroot_dir = webroot
	cache.name = name
	cache.attachments = attachments
	cache.database = db
	cache.store = store
	cache.varnish_url = varnish_url
	return cache
}
<commit_msg>fix json<commit_after>package srnd

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"path/filepath"
	"strconv"
	"strings"
)

type varnishHandler struct {
	cache *VarnishCache
}

func (self *varnishHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	path := r.URL.Path
	_, file := filepath.Split(path)

	isjson := strings.HasSuffix(path, "/json") || strings.HasSuffix(path, "/json/")

	if strings.HasPrefix(path, "/t/") {
		// thread handler
		parts := strings.Split(path[3:], "/")
		hash := parts[0]
		msg, err := self.cache.database.GetMessageIDByHash(hash)
		if err == nil {
			template.genThread(self.cache.attachments, msg, self.cache.prefix, self.cache.name, w, self.cache.database, isjson)
			return
		} else {
			goto notfound
		}
	}
	if strings.Trim(path, "/") == "overboard" {
		// generate ukko aka overboard
		template.genUkko(self.cache.prefix, self.cache.name, w, self.cache.database, isjson)
		return
	}

	if strings.HasPrefix(path, "/b/") {
		// board handler
		parts := strings.Split(path[3:], "/")
		page := 0
		group := parts[0]
		if len(parts) > 1 && parts[1] != "" && parts[1] != "json" {
			var err error
			page, err = strconv.Atoi(parts[1])
			if err != nil {
				goto notfound
			}
		}
		hasgroup := self.cache.database.HasNewsgroup(group)
		if !hasgroup {
			goto notfound
		}
		pages := self.cache.database.GetGroupPageCount(group)
		if page >= int(pages) {
			goto notfound
		}
		template.genBoardPage(self.cache.attachments, self.cache.prefix, self.cache.name, group, page, w, self.cache.database, isjson)
		return
	}

	if strings.HasPrefix(path, "/o/") {
		page := 0
		parts := strings.Split(path[3:], "/")
		if parts[0] != "json" {
			var err error
			page, err = strconv.Atoi(parts[0])
			if err != nil {
				goto notfound
			}
		}
		template.genUkkoPaginated(self.cache.prefix, self.cache.name, w, self.cache.database, page, isjson)
		return
	}

	if len(file) == 0 || file == "index.html" {
		template.genFrontPage(10, self.cache.prefix, self.cache.name, w, ioutil.Discard, self.cache.database)
		return
	}

	if file == "index.json" {
		// TODO: index.json
		goto notfound
	}
	if strings.HasPrefix(file, "history.html") {
		template.genGraphs(self.cache.prefix, w, self.cache.database)
		return
	}
	if strings.HasPrefix(file, "boards.html") {
		template.genFrontPage(10, self.cache.prefix, self.cache.name, ioutil.Discard, w, self.cache.database)
		return
	}

	if strings.HasPrefix(file, "boards.json") {
		b := self.cache.database.GetAllNewsgroups()
		json.NewEncoder(w).Encode(b)
		return
	}

	if strings.HasPrefix(file, "ukko.html") {
		template.genUkko(self.cache.prefix, self.cache.name, w, self.cache.database, false)
		return
	}
	if strings.HasPrefix(file, "ukko.json") {
		template.genUkko(self.cache.prefix, self.cache.name, w, self.cache.database, true)
		return
	}

	if strings.HasPrefix(file, "ukko-") {
		page := getUkkoPage(file)
		template.genUkkoPaginated(self.cache.prefix, self.cache.name, w, self.cache.database, page, isjson)
		return
	}
	if strings.HasPrefix(file, "thread-") {
		hash := getThreadHash(file)
		if len(hash) == 0 {
			goto notfound
		}
		msg, err := self.cache.database.GetMessageIDByHash(hash)
		if err != nil {
			goto notfound
		}
		template.genThread(self.cache.attachments, msg, self.cache.prefix, self.cache.name, w, self.cache.database, isjson)
		return
	}
	if strings.HasPrefix(file, "catalog-") {
		group := getGroupForCatalog(file)
		if len(group) == 0 {
			goto notfound
		}
		hasgroup := self.cache.database.HasNewsgroup(group)
		if !hasgroup {
			goto notfound
		}
		template.genCatalog(self.cache.prefix, self.cache.name, group, w, self.cache.database)
		return
	} else {
		group, page := getGroupAndPage(file)
		if len(group) == 0 || page < 0 {
			goto notfound
		}
		hasgroup := self.cache.database.HasNewsgroup(group)
		if !hasgroup {
			goto notfound
		}
		pages := self.cache.database.GetGroupPageCount(group)
		if page >= int(pages) {
			goto notfound
		}
		template.genBoardPage(self.cache.attachments, self.cache.prefix, self.cache.name, group, page, w, self.cache.database, isjson)
		return
	}

notfound:
	template.renderNotFound(w, r, self.cache.prefix, self.cache.name)
}

type VarnishCache struct {
	database Database
	store    ArticleStore

	webroot_dir string
	name        string

	regen_threads int
	attachments   bool

	prefix          string
	varnish_url     string
	client          *http.Client
	regenThreadChan chan ArticleEntry
	regenGroupChan  chan groupRegenRequest
}

func (self *VarnishCache) invalidate(r string) {
	u, _ := url.Parse(r)
	resp, err := self.client.Do(&http.Request{
		Method: "PURGE",
		URL:    u,
	})
	if err == nil {
		resp.Body.Close()
	} else {
		log.Println("varnish cache error", err)
	}
}

func (self *VarnishCache) DeleteBoardMarkup(group string) {
	n, _ := self.database.GetPagesPerBoard(group)
	for n > 0 {
		go self.invalidate(fmt.Sprintf("%s%s%s-%d.html", self.varnish_url, self.prefix, group, n))
		go self.invalidate(fmt.Sprintf("%s%sb/%s/%d/", self.varnish_url, self.prefix, group, n))
		n--
	}
	self.invalidate(fmt.Sprintf("%s%sb/%s/", self.varnish_url, self.prefix, group))
}

// try to delete root post's page
func (self *VarnishCache) DeleteThreadMarkup(root_post_id string) {
	self.invalidate(fmt.Sprintf("%s%sthread-%s.html", self.varnish_url, self.prefix, HashMessageID(root_post_id)))
	self.invalidate(fmt.Sprintf("%s%st/%s/", self.varnish_url, self.prefix, HashMessageID(root_post_id)))
}

// regen every newsgroup
func (self *VarnishCache) RegenAll() {
	// we will do this as it's used by rengen on start for frontend
	groups := self.database.GetAllNewsgroups()
	for _, group := range groups {
		self.database.GetGroupThreads(group, self.regenThreadChan)
	}
}

func (self *VarnishCache) RegenFrontPage() {
	self.invalidate(fmt.Sprintf("%s%s", self.varnish_url, self.prefix))
}

func (self *VarnishCache) invalidateUkko() {
	// TODO: invalidate paginated ukko
	self.invalidate(fmt.Sprintf("%s%sukko.html", self.varnish_url, self.prefix))
	self.invalidate(fmt.Sprintf("%s%soverboard/", self.varnish_url, self.prefix))
}

func (self *VarnishCache) pollRegen() {
	for {
		select {
		// consume regen requests
		case ev := <-self.regenGroupChan:
			{
				self.invalidate(fmt.Sprintf("%s%s%s-%d.html", self.varnish_url, self.prefix, ev.group, ev.page))
				self.invalidate(fmt.Sprintf("%s%sb/%s/%d/", self.varnish_url, self.prefix, ev.group, ev.page))
				if ev.page == 0 {
					self.invalidate(fmt.Sprintf("%s%sb/%s/", self.varnish_url, self.prefix, ev.group))
				}
			}
		case ev := <-self.regenThreadChan:
			{
				self.Regen(ev)
			}
		}
	}
}

// regen every page of the board
func (self *VarnishCache) RegenerateBoard(group string) {
	n, _ := self.database.GetPagesPerBoard(group)
	for n > 0 {
		go self.invalidate(fmt.Sprintf("%s%s%s-%d.html", self.varnish_url, self.prefix, group, n))
		go self.invalidate(fmt.Sprintf("%s%s%s/%d/", self.varnish_url, self.prefix, group, n))
		n--
	}
	self.invalidate(fmt.Sprintf("%s%sb/%s/", self.varnish_url, self.prefix, group))
}

// regenerate pages after a mod event
func (self *VarnishCache) RegenOnModEvent(newsgroup, msgid, root string, page int) {
	self.regenGroupChan <- groupRegenRequest{newsgroup, page}
	self.regenThreadChan <- ArticleEntry{newsgroup, root}
}

func (self *VarnishCache) Start() {
	go self.pollRegen()
}

func (self *VarnishCache) Regen(msg ArticleEntry) {
	go self.invalidate(fmt.Sprintf("%s%s%s-%d.html", self.varnish_url, self.prefix, msg.Newsgroup(), 0))
	go self.invalidate(fmt.Sprintf("%s%s%s/%d/", self.varnish_url, self.prefix, msg.Newsgroup(), 0))
	go self.invalidate(fmt.Sprintf("%s%sthread-%s.html", self.varnish_url, self.prefix, HashMessageID(msg.MessageID())))
	go self.invalidate(fmt.Sprintf("%s%st/%s/", self.varnish_url, self.prefix, HashMessageID(msg.MessageID())))
	self.invalidateUkko()
}

func (self *VarnishCache) GetThreadChan() chan ArticleEntry {
	return self.regenThreadChan
}

func (self *VarnishCache) GetGroupChan() chan groupRegenRequest {
	return self.regenGroupChan
}

func (self *VarnishCache) GetHandler() http.Handler {
	return &varnishHandler{self}
}

func (self *VarnishCache) Close() {
	//nothig to do
}

func NewVarnishCache(varnish_url, bind_addr, prefix, webroot, name string, attachments bool, db Database, store ArticleStore) CacheInterface {
	cache := new(VarnishCache)
	cache.regenThreadChan = make(chan ArticleEntry, 16)
	cache.regenGroupChan = make(chan groupRegenRequest, 8)
	local_addr, err := net.ResolveTCPAddr("tcp", bind_addr)
	if err != nil {
		log.Fatalf("failed to resolve %s for varnish cache: %s", bind_addr, err)
	}
	cache.client = &http.Client{
		Transport: &http.Transport{
			Dial: func(network, addr string) (c net.Conn, err error) {
				var remote_addr *net.TCPAddr
				remote_addr, err = net.ResolveTCPAddr(network, addr)
				if err == nil {
					c, err = net.DialTCP(network, local_addr, remote_addr)
				}
				return
			},
		},
	}
	cache.prefix = prefix
	cache.webroot_dir = webroot
	cache.name = name
	cache.attachments = attachments
	cache.database = db
	cache.store = store
	cache.varnish_url = varnish_url
	return cache
}
<|endoftext|>


<commit_before>package command

import (
	"flag"
	"fmt"
	"github.com/hashicorp/serf/cli"
	"strings"
)

// EventCommand is a Command implementation that queries a running
// Serf agent what members are part of the cluster currently.
type EventCommand struct{}

func (c *EventCommand) Help() string {
	helpText := `
Usage: serf event [options] name payload

  Dispatches a custom event across the Serf cluster.

Options:

  -rpc-addr=127.0.0.1:7373  RPC address of the Serf agent.
`
	return strings.TrimSpace(helpText)
}

func (c *EventCommand) Run(args []string, ui cli.Ui) int {
	cmdFlags := flag.NewFlagSet("event", flag.ContinueOnError)
	cmdFlags.Usage = func() { ui.Output(c.Help()) }
	rpcAddr := RPCAddrFlag(cmdFlags)
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	args = cmdFlags.Args()
	if len(args) < 1 {
		ui.Error("An event name must be specified.")
		ui.Error("")
		ui.Error(c.Help())
		return 1
	} else if len(args) > 2 {
		ui.Error("Too many command line arguments. Only a name and payload must be specified.")
		ui.Error("")
		ui.Error(c.Help())
		return 1
	}

	event := args[0]
	var payload []byte
	if len(args) == 2 {
		payload = []byte(args[1])
	}

	client, err := RPCClient(*rpcAddr)
	if err != nil {
		ui.Error(fmt.Sprintf("Error connecting to Serf agent: %s", err))
		return 1
	}
	defer client.Close()

	if err := client.UserEvent(event, payload); err != nil {
		ui.Error(fmt.Sprintf("Error sending event: %s", err))
		return 1
	}

	return 0
}

func (c *EventCommand) Synopsis() string {
	return "Send a custom event through the Serf cluster"
}
<commit_msg>command: event command takes a `-coalesce` flag<commit_after>package command

import (
	"flag"
	"fmt"
	"github.com/hashicorp/serf/cli"
	"strings"
)

// EventCommand is a Command implementation that queries a running
// Serf agent what members are part of the cluster currently.
type EventCommand struct{}

func (c *EventCommand) Help() string {
	helpText := `
Usage: serf event [options] name payload

  Dispatches a custom event across the Serf cluster.

Options:

  -coalesce=true/false      If set, this event can be coalesced. This means
                            that repeated events of the same name within a
                            short period of time are ignored, except the last
                            one received.
  -rpc-addr=127.0.0.1:7373  RPC address of the Serf agent.
`
	return strings.TrimSpace(helpText)
}

func (c *EventCommand) Run(args []string, ui cli.Ui) int {
	var coalesce bool

	cmdFlags := flag.NewFlagSet("event", flag.ContinueOnError)
	cmdFlags.Usage = func() { ui.Output(c.Help()) }
	cmdFlags.BoolVar(&coalesce, "coalesce", false, "coalesce")
	rpcAddr := RPCAddrFlag(cmdFlags)
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	args = cmdFlags.Args()
	if len(args) < 1 {
		ui.Error("An event name must be specified.")
		ui.Error("")
		ui.Error(c.Help())
		return 1
	} else if len(args) > 2 {
		ui.Error("Too many command line arguments. Only a name and payload must be specified.")
		ui.Error("")
		ui.Error(c.Help())
		return 1
	}

	event := args[0]
	var payload []byte
	if len(args) == 2 {
		payload = []byte(args[1])
	}

	client, err := RPCClient(*rpcAddr)
	if err != nil {
		ui.Error(fmt.Sprintf("Error connecting to Serf agent: %s", err))
		return 1
	}
	defer client.Close()

	if err := client.UserEvent(event, payload, coalesce); err != nil {
		ui.Error(fmt.Sprintf("Error sending event: %s", err))
		return 1
	}

	return 0
}

func (c *EventCommand) Synopsis() string {
	return "Send a custom event through the Serf cluster"
}
<|endoftext|>


<commit_before>package test

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"testing"
	"time"

	"github.com/coreos/etcd/tests"
	"github.com/coreos/etcd/third_party/github.com/stretchr/testify/assert"
)

// Ensure that we can start a v2 node from the log of a v1 node.
func TestV1SoloMigration(t *testing.T) {
	path, _ := ioutil.TempDir("", "etcd-")
	os.MkdirAll(path, 0777)
	defer os.RemoveAll(path)

	nodepath := filepath.Join(path, "node0")
	fixturepath, _ := filepath.Abs("../fixtures/v1.solo/node0")
	fmt.Println("DATA_DIR =", nodepath)

	// Copy over fixture files.
	c := exec.Command("cp", "-rf", fixturepath, nodepath)
	if out, err := c.CombinedOutput(); err != nil {
		fmt.Println(">>>>>>\n", string(out), "<<<<<<")
		panic("Fixture initialization error:" + err.Error())
	}

	procAttr := new(os.ProcAttr)
	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}

	args := []string{"etcd", fmt.Sprintf("-data-dir=%s", nodepath)}
	args = append(args, "-addr", "127.0.0.1:4001")
	args = append(args, "-peer-addr", "127.0.0.1:7001")
	process, err := os.StartProcess(EtcdBinPath, args, procAttr)
	if err != nil {
		t.Fatal("start process failed:" + err.Error())
		return
	}
	defer process.Kill()
	time.Sleep(time.Second)

	// Ensure deleted message is removed.
	resp, err := tests.Get("http://localhost:4001/v2/keys/message")
	tests.ReadBody(resp)
	assert.Nil(t, err, "")
	assert.Equal(t, resp.StatusCode, 200, "")
}

// Ensure that we can start a v2 cluster from the logs of a v1 cluster.
func TestV1ClusterMigration(t *testing.T) {
	path, _ := ioutil.TempDir("", "etcd-")
	os.RemoveAll(path)
	defer os.RemoveAll(path)

	nodes := []string{"node0", "node2"}
	for i, node := range nodes {
		nodepath := filepath.Join(path, node)
		fixturepath, _ := filepath.Abs(filepath.Join("../fixtures/v1.cluster/", node))
		fmt.Println("FIXPATH  =", fixturepath)
		fmt.Println("NODEPATH =", nodepath)
		os.MkdirAll(filepath.Dir(nodepath), 0777)

		// Copy over fixture files.
		c := exec.Command("cp", "-rf", fixturepath, nodepath)
		if out, err := c.CombinedOutput(); err != nil {
			fmt.Println(">>>>>>\n", string(out), "<<<<<<")
			panic("Fixture initialization error:" + err.Error())
		}

		procAttr := new(os.ProcAttr)
		procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}

		args := []string{"etcd", fmt.Sprintf("-data-dir=%s", nodepath)}
		args = append(args, "-addr", fmt.Sprintf("127.0.0.1:%d", 4001+i))
		args = append(args, "-peer-addr", fmt.Sprintf("127.0.0.1:%d", 7001+i))
		process, err := os.StartProcess(EtcdBinPath, args, procAttr)
		if err != nil {
			t.Fatal("start process failed:" + err.Error())
			return
		}
		defer process.Kill()
		time.Sleep(time.Second)
	}

	// Ensure deleted message is removed.
	resp, err := tests.Get("http://localhost:4001/v2/keys/message")
	body := tests.ReadBody(resp)
	assert.Nil(t, err, "")
	assert.Equal(t, resp.StatusCode, http.StatusNotFound)
	assert.Equal(t, string(body), `{"errorCode":100,"message":"Key not found","cause":"/message","index":11}`+"\n")

	// Ensure TTL'd message is removed.
	resp, err = tests.Get("http://localhost:4001/v2/keys/foo")
	body = tests.ReadBody(resp)
	assert.Nil(t, err, "")
	assert.Equal(t, resp.StatusCode, 200, "")
	assert.Equal(t, string(body), `{"action":"get","node":{"key":"/foo","value":"one","modifiedIndex":9,"createdIndex":9}}`)
}
<commit_msg>fix(tests/v1_migration): add a -name flag<commit_after>package test

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"testing"
	"time"

	"github.com/coreos/etcd/tests"
	"github.com/coreos/etcd/third_party/github.com/stretchr/testify/assert"
)

// Ensure that we can start a v2 node from the log of a v1 node.
func TestV1SoloMigration(t *testing.T) {
	path, _ := ioutil.TempDir("", "etcd-")
	os.MkdirAll(path, 0777)
	defer os.RemoveAll(path)

	nodepath := filepath.Join(path, "node0")
	fixturepath, _ := filepath.Abs("../fixtures/v1.solo/node0")
	fmt.Println("DATA_DIR =", nodepath)

	// Copy over fixture files.
	c := exec.Command("cp", "-rf", fixturepath, nodepath)
	if out, err := c.CombinedOutput(); err != nil {
		fmt.Println(">>>>>>\n", string(out), "<<<<<<")
		panic("Fixture initialization error:" + err.Error())
	}

	procAttr := new(os.ProcAttr)
	procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}

	args := []string{"etcd", fmt.Sprintf("-data-dir=%s", nodepath)}
	args = append(args, "-addr", "127.0.0.1:4001")
	args = append(args, "-peer-addr", "127.0.0.1:7001")
	args = append(args, "-name", "v1")
	process, err := os.StartProcess(EtcdBinPath, args, procAttr)
	if err != nil {
		t.Fatal("start process failed:" + err.Error())
		return
	}
	defer process.Kill()
	time.Sleep(time.Second)

	// Ensure deleted message is removed.
	resp, err := tests.Get("http://localhost:4001/v2/keys/message")
	tests.ReadBody(resp)
	assert.Nil(t, err, "")
	assert.Equal(t, resp.StatusCode, 200, "")
}

// Ensure that we can start a v2 cluster from the logs of a v1 cluster.
func TestV1ClusterMigration(t *testing.T) {
	path, _ := ioutil.TempDir("", "etcd-")
	os.RemoveAll(path)
	defer os.RemoveAll(path)

	nodes := []string{"node0", "node2"}
	for i, node := range nodes {
		nodepath := filepath.Join(path, node)
		fixturepath, _ := filepath.Abs(filepath.Join("../fixtures/v1.cluster/", node))
		fmt.Println("FIXPATH  =", fixturepath)
		fmt.Println("NODEPATH =", nodepath)
		os.MkdirAll(filepath.Dir(nodepath), 0777)

		// Copy over fixture files.
		c := exec.Command("cp", "-rf", fixturepath, nodepath)
		if out, err := c.CombinedOutput(); err != nil {
			fmt.Println(">>>>>>\n", string(out), "<<<<<<")
			panic("Fixture initialization error:" + err.Error())
		}

		procAttr := new(os.ProcAttr)
		procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}

		args := []string{"etcd", fmt.Sprintf("-data-dir=%s", nodepath)}
		args = append(args, "-addr", fmt.Sprintf("127.0.0.1:%d", 4001+i))
		args = append(args, "-peer-addr", fmt.Sprintf("127.0.0.1:%d", 7001+i))
		args = append(args, "-name", node)
		process, err := os.StartProcess(EtcdBinPath, args, procAttr)
		if err != nil {
			t.Fatal("start process failed:" + err.Error())
			return
		}
		defer process.Kill()
		time.Sleep(time.Second)
	}

	// Ensure deleted message is removed.
	resp, err := tests.Get("http://localhost:4001/v2/keys/message")
	body := tests.ReadBody(resp)
	assert.Nil(t, err, "")
	assert.Equal(t, resp.StatusCode, http.StatusNotFound)
	assert.Equal(t, string(body), `{"errorCode":100,"message":"Key not found","cause":"/message","index":11}`+"\n")

	// Ensure TTL'd message is removed.
	resp, err = tests.Get("http://localhost:4001/v2/keys/foo")
	body = tests.ReadBody(resp)
	assert.Nil(t, err, "")
	assert.Equal(t, resp.StatusCode, 200, "")
	assert.Equal(t, string(body), `{"action":"get","node":{"key":"/foo","value":"one","modifiedIndex":9,"createdIndex":9}}`)
}
<|endoftext|>