<commit_before>package main

import (
	"errors"
	"fmt"
	. "github.com/3d0c/gmf"
	"log"
	"os"
)

func fatal(err error) {
	log.Fatal(err)
	os.Exit(0)
}

func main() {
	outputfilename := "sample-encoding.mpg"
	dstWidth, dstHeight := 640, 480

	codec, err := NewEncoder(AV_CODEC_ID_MPEG1VIDEO)
	if err != nil {
		fatal(err)
	}

	videoEncCtx := NewCodecCtx(codec)
	if videoEncCtx == nil {
		fatal(err)
	}

	outputCtx, err := NewOutputCtx(outputfilename)
	if err != nil {
		fatal(err)
	}

	videoEncCtx.
		SetBitRate(400000).
		SetWidth(dstWidth).
		SetHeight(dstHeight).
		SetTimeBase(AVR{1, 25}).
		SetPixFmt(AV_PIX_FMT_YUV420P).
		SetProfile(FF_PROFILE_MPEG4_SIMPLE).
		SetMbDecision(FF_MB_DECISION_RD)

	if outputCtx.IsGlobalHeader() {
		videoEncCtx.SetFlag(CODEC_FLAG_GLOBAL_HEADER)
	}

	videoStream := outputCtx.NewStream(codec)
	if videoStream == nil {
		fatal(errors.New(fmt.Sprintf("Unable to create stream for videoEnc [%s]\n", codec.LongName())))
	}

	if err := videoEncCtx.Open(nil); err != nil {
		fatal(err)
	}

	videoStream.SetCodecCtx(videoEncCtx)

	outputCtx.SetStartTime(0)

	if err := outputCtx.WriteHeader(); err != nil {
		fatal(err)
	}

	var frame *Frame
	i := 0

	for frame = range GenSyntVideo(videoEncCtx.Width(), videoEncCtx.Height(), videoEncCtx.PixFmt()) {
		frame.SetPts(i)

		if p, ready, err := frame.Encode(videoStream.CodecCtx()); ready {
			if p.Pts() != AV_NOPTS_VALUE {
				p.SetPts(RescaleQ(p.Pts(), videoStream.CodecCtx().TimeBase(), videoStream.TimeBase()))
			}

			if p.Dts() != AV_NOPTS_VALUE {
				p.SetDts(RescaleQ(p.Dts(), videoStream.CodecCtx().TimeBase(), videoStream.TimeBase()))
			}

			if err := outputCtx.WritePacket(p); err != nil {
				fatal(err)
			}

			log.Printf("Write frame=%d size=%v pts=%v dts=%v\n", i, p.Size(), p.Pts(), p.Dts())

			p.Free();

		} else if err != nil {
			fatal(err)
		}

		i++
	}

	frame.SetPts(i)

	if p, ready, _ := frame.Encode(videoStream.CodecCtx()); ready {
		p.SetPts(RescaleQ(p.Pts(), videoStream.CodecCtx().TimeBase(), videoStream.TimeBase()))

		p.SetDts(RescaleQ(p.Dts(), videoStream.CodecCtx().TimeBase(), videoStream.TimeBase()))

		if err := outputCtx.WritePacket(p); err != nil {
			fatal(err)
		}
		log.Printf("Write frame=%d size=%v pts=%v dts=%v\n", i, p.Size(), p.Pts(), p.Dts())
	}

	frame.Free();

	outputCtx.CloseOutput()

	log.Println(i, "frames written to", outputfilename)
}
<commit_msg>fix some example memory leak<commit_after>package main

import (
	"errors"
	"fmt"
	. "github.com/3d0c/gmf"
	"log"
	"os"
)

func fatal(err error) {
	log.Fatal(err)
	os.Exit(0)
}

func main() {
	outputfilename := "sample-encoding.mpg"
	dstWidth, dstHeight := 640, 480

	codec, err := NewEncoder(AV_CODEC_ID_MPEG1VIDEO)
	if err != nil {
		fatal(err)
	}

	videoEncCtx := NewCodecCtx(codec)
	if videoEncCtx == nil {
		fatal(err)
	}

	outputCtx, err := NewOutputCtx(outputfilename)
	if err != nil {
		fatal(err)
	}

	videoEncCtx.
		SetBitRate(400000).
		SetWidth(dstWidth).
		SetHeight(dstHeight).
		SetTimeBase(AVR{1, 25}).
		SetPixFmt(AV_PIX_FMT_YUV420P).
		SetProfile(FF_PROFILE_MPEG4_SIMPLE).
		SetMbDecision(FF_MB_DECISION_RD)

	if outputCtx.IsGlobalHeader() {
		videoEncCtx.SetFlag(CODEC_FLAG_GLOBAL_HEADER)
	}

	videoStream := outputCtx.NewStream(codec)
	if videoStream == nil {
		fatal(errors.New(fmt.Sprintf("Unable to create stream for videoEnc [%s]\n", codec.LongName())))
	}

	if err := videoEncCtx.Open(nil); err != nil {
		fatal(err)
	}

	videoStream.SetCodecCtx(videoEncCtx)

	outputCtx.SetStartTime(0)

	if err := outputCtx.WriteHeader(); err != nil {
		fatal(err)
	}

	var frame *Frame
	i := 0

	for frame = range GenSyntVideo(videoEncCtx.Width(), videoEncCtx.Height(), videoEncCtx.PixFmt()) {
		frame.SetPts(i)

		if p, ready, err := frame.Encode(videoStream.CodecCtx()); ready {
			if p.Pts() != AV_NOPTS_VALUE {
				p.SetPts(RescaleQ(p.Pts(), videoStream.CodecCtx().TimeBase(), videoStream.TimeBase()))
			}

			if p.Dts() != AV_NOPTS_VALUE {
				p.SetDts(RescaleQ(p.Dts(), videoStream.CodecCtx().TimeBase(), videoStream.TimeBase()))
			}

			if err := outputCtx.WritePacket(p); err != nil {
				fatal(err)
			}

			log.Printf("Write frame=%d size=%v pts=%v dts=%v\n", i, p.Size(), p.Pts(), p.Dts())

			p.Free();

		} else if err != nil {
			fatal(err)
		}

		i++
	}

	frame.SetPts(i)

	if p, ready, _ := frame.Encode(videoStream.CodecCtx()); ready {
		p.SetPts(RescaleQ(p.Pts(), videoStream.CodecCtx().TimeBase(), videoStream.TimeBase()))

		p.SetDts(RescaleQ(p.Dts(), videoStream.CodecCtx().TimeBase(), videoStream.TimeBase()))

		if err := outputCtx.WritePacket(p); err != nil {
			fatal(err)
		}
		p.Free()

		log.Printf("Write frame=%d size=%v pts=%v dts=%v\n", i, p.Size(), p.Pts(), p.Dts())
	}

	frame.Free();

	outputCtx.CloseOutput()

	log.Println(i, "frames written to", outputfilename)
}
<|endoftext|>


<commit_before>package syslog

import (
	"fmt"
	"io"
	"log"
	s1 "log/syslog"
	"net"
	"path/filepath"

	"github.com/hashicorp/nomad/client/allocdir"
	"github.com/hashicorp/nomad/client/driver/logrotator"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/mcuadros/go-syslog"
)

// LogCollectorContext holds context to configure the syslog server
type LogCollectorContext struct {
	// TaskName is the name of the Task
	TaskName string

	// AllocDir is the handle to do operations on the alloc dir of
	// the task
	AllocDir *allocdir.AllocDir

	// LogConfig provides configuration related to log rotation
	LogConfig *structs.LogConfig

	// PortUpperBound is the upper bound of the ports that we can use to start
	// the syslog server
	PortUpperBound uint

	// PortLowerBound is the lower bound of the ports that we can use to start
	// the syslog server
	PortLowerBound uint
}

// SyslogCollectorState holds the address and islation information of a launched
// syslog server
type SyslogCollectorState struct {
	IsolationConfig *IsolationConfig
	Addr            string
}

// LogCollector is an interface which allows a driver to launch a log server
// and update log configuration
type LogCollector interface {
	LaunchCollector(ctx *LogCollectorContext) (*SyslogCollectorState, error)
	Exit() error
	UpdateLogConfig(logConfig *structs.LogConfig) error
}

// IsolationConfig has the cgroup related information of a syslog server
type IsolationConfig struct {
}

// SyslogCollector is a LogCollector which starts a syslog server and does
// rotation to incoming stream
type SyslogCollector struct {
	addr      net.Addr
	logConfig *structs.LogConfig
	ctx       *LogCollectorContext

	lro     *logrotator.LogRotator
	lre     *logrotator.LogRotator
	server  *syslog.Server
	taskDir string

	logger *log.Logger
}

// NewSyslogCollector returns an implementation of the SyslogCollector
func NewSyslogCollector(logger *log.Logger) *SyslogCollector {
	return &SyslogCollector{logger: logger}
}

// LaunchCollector launches a new syslog server and starts writing log lines to
// files and rotates them
func (s *SyslogCollector) LaunchCollector(ctx *LogCollectorContext) (*SyslogCollectorState, error) {
	addr, err := s.getFreePort(ctx.PortLowerBound, ctx.PortUpperBound)
	if err != nil {
		return nil, err
	}
	s.logger.Printf("sylog-server: launching syslog server on addr: %v", addr)
	s.ctx = ctx
	// configuring the task dir
	if err := s.configureTaskDir(); err != nil {
		return nil, err
	}

	channel := make(syslog.LogPartsChannel)
	handler := syslog.NewChannelHandler(channel)

	s.server = syslog.NewServer()
	s.server.SetFormat(&CustomParser{logger: s.logger})
	s.server.SetHandler(handler)
	s.server.ListenTCP(addr.String())
	if err := s.server.Boot(); err != nil {
		return nil, err
	}
	logFileSize := int64(ctx.LogConfig.MaxFileSizeMB * 1024 * 1024)

	ro, wo := io.Pipe()
	lro, err := logrotator.NewLogRotator(filepath.Join(s.taskDir, allocdir.TaskLocal),
		fmt.Sprintf("%v.stdout", ctx.TaskName), ctx.LogConfig.MaxFiles,
		logFileSize, s.logger)
	if err != nil {
		return nil, err
	}
	go lro.Start(ro)

	re, we := io.Pipe()
	lre, err := logrotator.NewLogRotator(filepath.Join(s.taskDir, allocdir.TaskLocal),
		fmt.Sprintf("%v.stderr", ctx.TaskName), ctx.LogConfig.MaxFiles,
		logFileSize, s.logger)
	if err != nil {
		return nil, err
	}
	go lre.Start(re)

	go func(channel syslog.LogPartsChannel) {
		for logParts := range channel {
			s := logParts["severity"].(s1.Priority)
			if s == s1.LOG_ERR {
				we.Write(logParts["content"].([]byte))
			} else {
				wo.Write(logParts["content"].([]byte))
			}
			wo.Write([]byte("\n"))
		}
	}(channel)
	go s.server.Wait()
	return &SyslogCollectorState{Addr: addr.String()}, nil
}

// Exit kills the syslog server
func (s *SyslogCollector) Exit() error {
	return s.server.Kill()
}

// UpdateLogConfig updates the log configuration
func (s *SyslogCollector) UpdateLogConfig(logConfig *structs.LogConfig) error {
	s.ctx.LogConfig = logConfig
	if s.lro == nil {
		return fmt.Errorf("log rotator for stdout doesn't exist")
	}
	s.lro.MaxFiles = logConfig.MaxFiles
	s.lro.FileSize = int64(logConfig.MaxFileSizeMB * 1024 * 1024)

	if s.lre == nil {
		return fmt.Errorf("log rotator for stderr doesn't exist")
	}
	s.lre.MaxFiles = logConfig.MaxFiles
	s.lre.FileSize = int64(logConfig.MaxFileSizeMB * 1024 * 1024)
	return nil

}

// configureTaskDir sets the task dir in the executor
func (s *SyslogCollector) configureTaskDir() error {
	taskDir, ok := s.ctx.AllocDir.TaskDirs[s.ctx.TaskName]
	if !ok {
		return fmt.Errorf("couldn't find task directory for task %v", s.ctx.TaskName)
	}
	s.taskDir = taskDir
	return nil
}

// getFreePort returns a free port ready to be listened on between upper and
// lower bounds
func (s *SyslogCollector) getFreePort(lowerBound uint, upperBound uint) (net.Addr, error) {
	for i := lowerBound; i <= upperBound; i++ {
		addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("localhost:%v", i))
		if err != nil {
			return nil, err
		}
		l, err := net.ListenTCP("tcp", addr)
		if err != nil {
			continue
		}
		defer l.Close()
		return l.Addr(), nil
	}
	return nil, fmt.Errorf("No free port found")
}
<commit_msg>Sharing the isolationconfig of syslog collector with executor<commit_after>package syslog

import (
	"fmt"
	"io"
	"log"
	s1 "log/syslog"
	"net"
	"path/filepath"

	"github.com/hashicorp/nomad/client/allocdir"
	"github.com/hashicorp/nomad/client/driver/executor"
	"github.com/hashicorp/nomad/client/driver/logrotator"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/mcuadros/go-syslog"
)

// LogCollectorContext holds context to configure the syslog server
type LogCollectorContext struct {
	// TaskName is the name of the Task
	TaskName string

	// AllocDir is the handle to do operations on the alloc dir of
	// the task
	AllocDir *allocdir.AllocDir

	// LogConfig provides configuration related to log rotation
	LogConfig *structs.LogConfig

	// PortUpperBound is the upper bound of the ports that we can use to start
	// the syslog server
	PortUpperBound uint

	// PortLowerBound is the lower bound of the ports that we can use to start
	// the syslog server
	PortLowerBound uint
}

// SyslogCollectorState holds the address and islation information of a launched
// syslog server
type SyslogCollectorState struct {
	IsolationConfig *executor.IsolationConfig
	Addr            string
}

// LogCollector is an interface which allows a driver to launch a log server
// and update log configuration
type LogCollector interface {
	LaunchCollector(ctx *LogCollectorContext) (*SyslogCollectorState, error)
	Exit() error
	UpdateLogConfig(logConfig *structs.LogConfig) error
}

// SyslogCollector is a LogCollector which starts a syslog server and does
// rotation to incoming stream
type SyslogCollector struct {
	addr      net.Addr
	logConfig *structs.LogConfig
	ctx       *LogCollectorContext

	lro     *logrotator.LogRotator
	lre     *logrotator.LogRotator
	server  *syslog.Server
	taskDir string

	logger *log.Logger
}

// NewSyslogCollector returns an implementation of the SyslogCollector
func NewSyslogCollector(logger *log.Logger) *SyslogCollector {
	return &SyslogCollector{logger: logger}
}

// LaunchCollector launches a new syslog server and starts writing log lines to
// files and rotates them
func (s *SyslogCollector) LaunchCollector(ctx *LogCollectorContext) (*SyslogCollectorState, error) {
	addr, err := s.getFreePort(ctx.PortLowerBound, ctx.PortUpperBound)
	if err != nil {
		return nil, err
	}
	s.logger.Printf("sylog-server: launching syslog server on addr: %v", addr)
	s.ctx = ctx
	// configuring the task dir
	if err := s.configureTaskDir(); err != nil {
		return nil, err
	}

	channel := make(syslog.LogPartsChannel)
	handler := syslog.NewChannelHandler(channel)

	s.server = syslog.NewServer()
	s.server.SetFormat(&CustomParser{logger: s.logger})
	s.server.SetHandler(handler)
	s.server.ListenTCP(addr.String())
	if err := s.server.Boot(); err != nil {
		return nil, err
	}
	logFileSize := int64(ctx.LogConfig.MaxFileSizeMB * 1024 * 1024)

	ro, wo := io.Pipe()
	lro, err := logrotator.NewLogRotator(filepath.Join(s.taskDir, allocdir.TaskLocal),
		fmt.Sprintf("%v.stdout", ctx.TaskName), ctx.LogConfig.MaxFiles,
		logFileSize, s.logger)
	if err != nil {
		return nil, err
	}
	go lro.Start(ro)

	re, we := io.Pipe()
	lre, err := logrotator.NewLogRotator(filepath.Join(s.taskDir, allocdir.TaskLocal),
		fmt.Sprintf("%v.stderr", ctx.TaskName), ctx.LogConfig.MaxFiles,
		logFileSize, s.logger)
	if err != nil {
		return nil, err
	}
	go lre.Start(re)

	go func(channel syslog.LogPartsChannel) {
		for logParts := range channel {
			s := logParts["severity"].(s1.Priority)
			if s == s1.LOG_ERR {
				we.Write(logParts["content"].([]byte))
			} else {
				wo.Write(logParts["content"].([]byte))
			}
			wo.Write([]byte("\n"))
		}
	}(channel)
	go s.server.Wait()
	return &SyslogCollectorState{Addr: addr.String()}, nil
}

// Exit kills the syslog server
func (s *SyslogCollector) Exit() error {
	return s.server.Kill()
}

// UpdateLogConfig updates the log configuration
func (s *SyslogCollector) UpdateLogConfig(logConfig *structs.LogConfig) error {
	s.ctx.LogConfig = logConfig
	if s.lro == nil {
		return fmt.Errorf("log rotator for stdout doesn't exist")
	}
	s.lro.MaxFiles = logConfig.MaxFiles
	s.lro.FileSize = int64(logConfig.MaxFileSizeMB * 1024 * 1024)

	if s.lre == nil {
		return fmt.Errorf("log rotator for stderr doesn't exist")
	}
	s.lre.MaxFiles = logConfig.MaxFiles
	s.lre.FileSize = int64(logConfig.MaxFileSizeMB * 1024 * 1024)
	return nil

}

// configureTaskDir sets the task dir in the executor
func (s *SyslogCollector) configureTaskDir() error {
	taskDir, ok := s.ctx.AllocDir.TaskDirs[s.ctx.TaskName]
	if !ok {
		return fmt.Errorf("couldn't find task directory for task %v", s.ctx.TaskName)
	}
	s.taskDir = taskDir
	return nil
}

// getFreePort returns a free port ready to be listened on between upper and
// lower bounds
func (s *SyslogCollector) getFreePort(lowerBound uint, upperBound uint) (net.Addr, error) {
	for i := lowerBound; i <= upperBound; i++ {
		addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("localhost:%v", i))
		if err != nil {
			return nil, err
		}
		l, err := net.ListenTCP("tcp", addr)
		if err != nil {
			continue
		}
		defer l.Close()
		return l.Addr(), nil
	}
	return nil, fmt.Errorf("No free port found")
}
<|endoftext|>


<commit_before>// Copyright 2015 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"math/rand"
	"os"
	"runtime"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/google/syzkaller/pkg/csource"
	"github.com/google/syzkaller/pkg/db"
	"github.com/google/syzkaller/pkg/host"
	"github.com/google/syzkaller/pkg/ipc"
	"github.com/google/syzkaller/pkg/ipc/ipcconfig"
	"github.com/google/syzkaller/pkg/log"
	"github.com/google/syzkaller/pkg/mgrconfig"
	"github.com/google/syzkaller/prog"
	_ "github.com/google/syzkaller/sys"
)

var (
	flagOS       = flag.String("os", runtime.GOOS, "target os")
	flagArch     = flag.String("arch", runtime.GOARCH, "target arch")
	flagCorpus   = flag.String("corpus", "", "corpus database")
	flagOutput   = flag.Bool("output", false, "print executor output to console")
	flagProcs    = flag.Int("procs", 2*runtime.NumCPU(), "number of parallel processes")
	flagLogProg  = flag.Bool("logprog", false, "print programs before execution")
	flagGenerate = flag.Bool("generate", true, "generate new programs, otherwise only mutate corpus")
	flagSyscalls = flag.String("syscalls", "", "comma-separated list of enabled syscalls")
	flagEnable   = flag.String("enable", "none", "enable only listed additional features")
	flagDisable  = flag.String("disable", "none", "enable all additional features except listed")

	statExec uint64
	gate     *ipc.Gate
)

func main() {
	flag.Usage = func() {
		flag.PrintDefaults()
		csource.PrintAvailableFeaturesFlags()
	}
	flag.Parse()
	featuresFlags, err := csource.ParseFeaturesFlags(*flagEnable, *flagDisable, true)
	if err != nil {
		log.Fatalf("%v", err)
	}
	target, err := prog.GetTarget(*flagOS, *flagArch)
	if err != nil {
		log.Fatalf("%v", err)
	}
	corpus, err := db.ReadCorpus(*flagCorpus, target)
	if err != nil {
		log.Fatalf("failed to read corpus: %v", err)
	}
	log.Logf(0, "parsed %v programs", len(corpus))
	if !*flagGenerate && len(corpus) == 0 {
		log.Fatalf("nothing to mutate (-generate=false and no corpus)")
	}

	features, err := host.Check(target)
	if err != nil {
		log.Fatalf("%v", err)
	}

	var syscalls []string
	if *flagSyscalls != "" {
		syscalls = strings.Split(*flagSyscalls, ",")
	}
	calls := buildCallList(target, syscalls)
	ct := target.BuildChoiceTable(corpus, calls)

	config, execOpts, err := createIPCConfig(target, features, featuresFlags)
	if err != nil {
		log.Fatalf("%v", err)
	}
	if err = host.Setup(target, features, featuresFlags, config.Executor); err != nil {
		log.Fatal(err)
	}
	gate = ipc.NewGate(2**flagProcs, nil)
	for pid := 0; pid < *flagProcs; pid++ {
		pid := pid
		go func() {
			env, err := ipc.MakeEnv(config, pid)
			if err != nil {
				log.Fatalf("failed to create execution environment: %v", err)
			}
			rs := rand.NewSource(time.Now().UnixNano() + int64(pid)*1e12)
			rnd := rand.New(rs)
			for i := 0; ; i++ {
				var p *prog.Prog
				if *flagGenerate && len(corpus) == 0 || i%4 != 0 {
					p = target.Generate(rs, prog.RecommendedCalls, ct)
					execute(pid, env, execOpts, p)
					p.Mutate(rs, prog.RecommendedCalls, ct, corpus)
					execute(pid, env, execOpts, p)
				} else {
					p = corpus[rnd.Intn(len(corpus))].Clone()
					p.Mutate(rs, prog.RecommendedCalls, ct, corpus)
					execute(pid, env, execOpts, p)
					p.Mutate(rs, prog.RecommendedCalls, ct, corpus)
					execute(pid, env, execOpts, p)
				}
			}
		}()
	}
	for range time.NewTicker(5 * time.Second).C {
		log.Logf(0, "executed %v programs", atomic.LoadUint64(&statExec))
	}
}

var outMu sync.Mutex

func execute(pid int, env *ipc.Env, execOpts *ipc.ExecOpts, p *prog.Prog) {
	atomic.AddUint64(&statExec, 1)
	if *flagLogProg {
		ticket := gate.Enter()
		defer gate.Leave(ticket)
		outMu.Lock()
		fmt.Printf("executing program %v\n%s\n", pid, p.Serialize())
		outMu.Unlock()
	}
	output, _, hanged, err := env.Exec(execOpts, p)
	if err != nil {
		fmt.Printf("failed to execute executor: %v\n", err)
	}
	if hanged || err != nil || *flagOutput {
		fmt.Printf("PROGRAM:\n%s\n", p.Serialize())
	}
	if hanged || err != nil || *flagOutput {
		os.Stdout.Write(output)
	}
}

func createIPCConfig(target *prog.Target, features *host.Features, featuresFlags csource.Features) (
	*ipc.Config, *ipc.ExecOpts, error) {
	config, execOpts, err := ipcconfig.Default(target)
	if err != nil {
		return nil, nil, err
	}
	if featuresFlags["tun"].Enabled && features[host.FeatureNetInjection].Enabled {
		config.Flags |= ipc.FlagEnableTun
	}
	if featuresFlags["net_dev"].Enabled && features[host.FeatureNetDevices].Enabled {
		config.Flags |= ipc.FlagEnableNetDev
	}
	if featuresFlags["net_reset"].Enabled {
		config.Flags |= ipc.FlagEnableNetReset
	}
	if featuresFlags["cgroups"].Enabled {
		config.Flags |= ipc.FlagEnableCgroups
	}
	if featuresFlags["close_fds"].Enabled {
		config.Flags |= ipc.FlagEnableCloseFds
	}
	if featuresFlags["devlink_pci"].Enabled && features[host.FeatureDevlinkPCI].Enabled {
		config.Flags |= ipc.FlagEnableDevlinkPCI
	}
	if featuresFlags["vhci"].Enabled && features[host.FeatureVhciInjection].Enabled {
		config.Flags |= ipc.FlagEnableVhciInjection
	}
	if featuresFlags["wifi"].Enabled && features[host.FeatureWifiEmulation].Enabled {
		config.Flags |= ipc.FlagEnableWifi
	}
	return config, execOpts, nil
}

func buildCallList(target *prog.Target, enabled []string) map[*prog.Syscall]bool {
	if *flagOS != runtime.GOOS {
		// This is currently used on akaros, where syz-stress runs on host.
		calls := make(map[*prog.Syscall]bool)
		for _, c := range target.Syscalls {
			calls[c] = true
		}
		return calls
	}
	calls, disabled, err := host.DetectSupportedSyscalls(target, "none")
	if err != nil {
		log.Fatalf("failed to detect host supported syscalls: %v", err)
	}
	if len(enabled) != 0 {
		syscallsIDs, err := mgrconfig.ParseEnabledSyscalls(target, enabled, nil)
		if err != nil {
			log.Fatalf("failed to parse enabled syscalls: %v", err)
		}
		enabledSyscalls := make(map[*prog.Syscall]bool)
		for _, id := range syscallsIDs {
			enabledSyscalls[target.Syscalls[id]] = true
		}
		for c := range calls {
			if !enabledSyscalls[c] {
				delete(calls, c)
			}
		}
		for c := range disabled {
			if !enabledSyscalls[c] {
				delete(disabled, c)
			}
		}
	}
	for c, reason := range disabled {
		log.Logf(0, "unsupported syscall: %v: %v", c.Name, reason)
	}
	calls, disabled = target.TransitivelyEnabledCalls(calls)
	for c, reason := range disabled {
		log.Logf(0, "transitively unsupported: %v: %v", c.Name, reason)
	}
	return calls
}
<commit_msg>tools/syz-stress: add package comment<commit_after>// Copyright 2015 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// syz-stress executes random programs locally.
// A user needs to start a VM manually, copy syz-stress and run it.
// syz-stress will execute random programs infinitely until it's stopped or it crashes the kernel underneath.
// If it's given a corpus of programs, it will alternate between executing random programs and mutated
// programs from the corpus. Running syz-stress can be used as an intermediate step when porting syzkaller
// to a new OS, or to test on a machine that is not supported by the vm package (syz-manager cannot be used).
package main

import (
	"flag"
	"fmt"
	"math/rand"
	"os"
	"runtime"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/google/syzkaller/pkg/csource"
	"github.com/google/syzkaller/pkg/db"
	"github.com/google/syzkaller/pkg/host"
	"github.com/google/syzkaller/pkg/ipc"
	"github.com/google/syzkaller/pkg/ipc/ipcconfig"
	"github.com/google/syzkaller/pkg/log"
	"github.com/google/syzkaller/pkg/mgrconfig"
	"github.com/google/syzkaller/prog"
	_ "github.com/google/syzkaller/sys"
)

var (
	flagOS       = flag.String("os", runtime.GOOS, "target os")
	flagArch     = flag.String("arch", runtime.GOARCH, "target arch")
	flagCorpus   = flag.String("corpus", "", "corpus database")
	flagOutput   = flag.Bool("output", false, "print executor output to console")
	flagProcs    = flag.Int("procs", 2*runtime.NumCPU(), "number of parallel processes")
	flagLogProg  = flag.Bool("logprog", false, "print programs before execution")
	flagGenerate = flag.Bool("generate", true, "generate new programs, otherwise only mutate corpus")
	flagSyscalls = flag.String("syscalls", "", "comma-separated list of enabled syscalls")
	flagEnable   = flag.String("enable", "none", "enable only listed additional features")
	flagDisable  = flag.String("disable", "none", "enable all additional features except listed")

	statExec uint64
	gate     *ipc.Gate
)

func main() {
	flag.Usage = func() {
		flag.PrintDefaults()
		csource.PrintAvailableFeaturesFlags()
	}
	flag.Parse()
	featuresFlags, err := csource.ParseFeaturesFlags(*flagEnable, *flagDisable, true)
	if err != nil {
		log.Fatalf("%v", err)
	}
	target, err := prog.GetTarget(*flagOS, *flagArch)
	if err != nil {
		log.Fatalf("%v", err)
	}
	corpus, err := db.ReadCorpus(*flagCorpus, target)
	if err != nil {
		log.Fatalf("failed to read corpus: %v", err)
	}
	log.Logf(0, "parsed %v programs", len(corpus))
	if !*flagGenerate && len(corpus) == 0 {
		log.Fatalf("nothing to mutate (-generate=false and no corpus)")
	}

	features, err := host.Check(target)
	if err != nil {
		log.Fatalf("%v", err)
	}

	var syscalls []string
	if *flagSyscalls != "" {
		syscalls = strings.Split(*flagSyscalls, ",")
	}
	calls := buildCallList(target, syscalls)
	ct := target.BuildChoiceTable(corpus, calls)

	config, execOpts, err := createIPCConfig(target, features, featuresFlags)
	if err != nil {
		log.Fatalf("%v", err)
	}
	if err = host.Setup(target, features, featuresFlags, config.Executor); err != nil {
		log.Fatal(err)
	}
	gate = ipc.NewGate(2**flagProcs, nil)
	for pid := 0; pid < *flagProcs; pid++ {
		pid := pid
		go func() {
			env, err := ipc.MakeEnv(config, pid)
			if err != nil {
				log.Fatalf("failed to create execution environment: %v", err)
			}
			rs := rand.NewSource(time.Now().UnixNano() + int64(pid)*1e12)
			rnd := rand.New(rs)
			for i := 0; ; i++ {
				var p *prog.Prog
				if *flagGenerate && len(corpus) == 0 || i%4 != 0 {
					p = target.Generate(rs, prog.RecommendedCalls, ct)
					execute(pid, env, execOpts, p)
					p.Mutate(rs, prog.RecommendedCalls, ct, corpus)
					execute(pid, env, execOpts, p)
				} else {
					p = corpus[rnd.Intn(len(corpus))].Clone()
					p.Mutate(rs, prog.RecommendedCalls, ct, corpus)
					execute(pid, env, execOpts, p)
					p.Mutate(rs, prog.RecommendedCalls, ct, corpus)
					execute(pid, env, execOpts, p)
				}
			}
		}()
	}
	for range time.NewTicker(5 * time.Second).C {
		log.Logf(0, "executed %v programs", atomic.LoadUint64(&statExec))
	}
}

var outMu sync.Mutex

func execute(pid int, env *ipc.Env, execOpts *ipc.ExecOpts, p *prog.Prog) {
	atomic.AddUint64(&statExec, 1)
	if *flagLogProg {
		ticket := gate.Enter()
		defer gate.Leave(ticket)
		outMu.Lock()
		fmt.Printf("executing program %v\n%s\n", pid, p.Serialize())
		outMu.Unlock()
	}
	output, _, hanged, err := env.Exec(execOpts, p)
	if err != nil {
		fmt.Printf("failed to execute executor: %v\n", err)
	}
	if hanged || err != nil || *flagOutput {
		fmt.Printf("PROGRAM:\n%s\n", p.Serialize())
	}
	if hanged || err != nil || *flagOutput {
		os.Stdout.Write(output)
	}
}

func createIPCConfig(target *prog.Target, features *host.Features, featuresFlags csource.Features) (
	*ipc.Config, *ipc.ExecOpts, error) {
	config, execOpts, err := ipcconfig.Default(target)
	if err != nil {
		return nil, nil, err
	}
	if featuresFlags["tun"].Enabled && features[host.FeatureNetInjection].Enabled {
		config.Flags |= ipc.FlagEnableTun
	}
	if featuresFlags["net_dev"].Enabled && features[host.FeatureNetDevices].Enabled {
		config.Flags |= ipc.FlagEnableNetDev
	}
	if featuresFlags["net_reset"].Enabled {
		config.Flags |= ipc.FlagEnableNetReset
	}
	if featuresFlags["cgroups"].Enabled {
		config.Flags |= ipc.FlagEnableCgroups
	}
	if featuresFlags["close_fds"].Enabled {
		config.Flags |= ipc.FlagEnableCloseFds
	}
	if featuresFlags["devlink_pci"].Enabled && features[host.FeatureDevlinkPCI].Enabled {
		config.Flags |= ipc.FlagEnableDevlinkPCI
	}
	if featuresFlags["vhci"].Enabled && features[host.FeatureVhciInjection].Enabled {
		config.Flags |= ipc.FlagEnableVhciInjection
	}
	if featuresFlags["wifi"].Enabled && features[host.FeatureWifiEmulation].Enabled {
		config.Flags |= ipc.FlagEnableWifi
	}
	return config, execOpts, nil
}

func buildCallList(target *prog.Target, enabled []string) map[*prog.Syscall]bool {
	if *flagOS != runtime.GOOS {
		// This is currently used on akaros, where syz-stress runs on host.
		calls := make(map[*prog.Syscall]bool)
		for _, c := range target.Syscalls {
			calls[c] = true
		}
		return calls
	}
	calls, disabled, err := host.DetectSupportedSyscalls(target, "none")
	if err != nil {
		log.Fatalf("failed to detect host supported syscalls: %v", err)
	}
	if len(enabled) != 0 {
		syscallsIDs, err := mgrconfig.ParseEnabledSyscalls(target, enabled, nil)
		if err != nil {
			log.Fatalf("failed to parse enabled syscalls: %v", err)
		}
		enabledSyscalls := make(map[*prog.Syscall]bool)
		for _, id := range syscallsIDs {
			enabledSyscalls[target.Syscalls[id]] = true
		}
		for c := range calls {
			if !enabledSyscalls[c] {
				delete(calls, c)
			}
		}
		for c := range disabled {
			if !enabledSyscalls[c] {
				delete(disabled, c)
			}
		}
	}
	for c, reason := range disabled {
		log.Logf(0, "unsupported syscall: %v: %v", c.Name, reason)
	}
	calls, disabled = target.TransitivelyEnabledCalls(calls)
	for c, reason := range disabled {
		log.Logf(0, "transitively unsupported: %v: %v", c.Name, reason)
	}
	return calls
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	tg "github.com/go-telegram-bot-api/telegram-bot-api"
	"log"
	"regexp"
	"strings"
)

/*
Following is the command menu for constructing the bot with @BotFather.
Use the /setcommands command and reply with the following list of commands.
---------------------
newgame - Start a new game with a fresh word list.
current - Show the current word.
challenge - Challenge the word that was entered.
history - Show the words that have been used in the game.
scores - Show the current scores.
nick - Set your nickname.
help - Display game rules and other instructions.
shutdown - Shutdown the bot (DEBUG ONLY)
*/

var torigemubot = botEventHandlers{
	onInitialize: torigemubotOnInitialize,
	onDispose:    torigemubotOnDispose,
	onMessage:    torigemubotOnMessage,
}

const wordPts = 3
const challengePenaltyPts = 5
const lostGamePts = 7

// Track players in each game
type playerEntry struct {
	user     *tg.User
	nickname string
	score    int
	numWords int
}
type playerMap map[int64][]*playerEntry

var players playerMap

// Track the words used for each game.
type wordEntry struct {
	word   string
	player *playerEntry
	points int
}
type wordHistoryMap map[int64][]*wordEntry

var usedWords wordHistoryMap

// Initialize global data
func torigemubotOnInitialize(bot *tg.BotAPI) bool {
	usedWords = make(wordHistoryMap)
	players = make(playerMap)
	return true
}

func torigemubotOnDispose(bot *tg.BotAPI) {
	// TODO: Any cleanup of external resources.
}

var newgameCmd = regexp.MustCompile(`(?i)^/?newgame(@torigemubot)?`)
var currentCmd = regexp.MustCompile(`(?i)^/?current(@torigemubot)?`)
var challengeCmd = regexp.MustCompile(`(?i)^/?challenge(@torigemubot)?`)
var historyCmd = regexp.MustCompile(`(?i)^/?history(@torigemubot)?`)
var scoresCmd = regexp.MustCompile(`(?i)^/?scores(@torigemubot)?`)
var nicknameCmd = regexp.MustCompile(`(?i)^/?nick(@torigemubot)?[ \t]*`)
var helpCmd = regexp.MustCompile(`(?i)^/?help(@torigemubot)?`)
var shutdownCmd = regexp.MustCompile(`(?i)^/?shutdown(@torigemubot)?[ \t]+now`)

func torigemubotOnMessage(bot *tg.BotAPI, msg *tg.Message) bool {
	log.Printf("MsgFrom: Chat %s, User %s %s", getGameName(msg.Chat), getUserDisplayName(msg.From), msg.Text)
	switch {
	case newgameCmd.MatchString(msg.Text):
		doNewGame(bot, msg)
	case currentCmd.MatchString(msg.Text):
		doShowCurrentWord(bot, msg, true)
	case challengeCmd.MatchString(msg.Text):
		doChallenge(bot, msg)
	case historyCmd.MatchString(msg.Text):
		doShowHistory(bot, msg)
	case scoresCmd.MatchString(msg.Text):
		doShowScores(bot, msg.Chat)
	case nicknameCmd.MatchString(msg.Text):
		doSetNickname(bot, msg, nicknameCmd.ReplaceAllString(msg.Text, ""))
	case helpCmd.MatchString(msg.Text):
		doHelp(bot, msg)
	case shutdownCmd.MatchString(msg.Text):
		doShutdown(bot, msg)
		return false
	default:
		doWordEntry(bot, msg)
	}
	return true
}

func doNewGame(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received newgame command.")
	// TODO: Add some safety checks so that one other person must agree. Give a lazy consensus time.
	// If no one objects within 1 minute, then the game starts new. If someone agrees, it starts new right away.
	// If someone objects, then the reset is canceled.
	newGame(bot, msg.Chat, false)
	joinGame(bot, msg.From, msg.Chat, false)
}

func doShowCurrentWord(bot *tg.BotAPI, msg *tg.Message, showUserInfo bool) {
	var reply string
	entry := getLastEntry(msg.Chat)
	if entry == nil {
		reply = "現在の言葉はありません。"
	} else {
		var wordDisplay string
		if showUserInfo {
			wordDisplay = getWordEntryDisplay(entry)
		} else {
			wordDisplay = entry.word
		}

		reply = fmt.Sprintf("》%s", wordDisplay)
	}
	bot.Send(tg.NewMessage(msg.Chat.ID, reply))
}

func doShowScores(bot *tg.BotAPI, chat *tg.Chat) {
	log.Println("Received showscores command.")
	scores := "ゲームの得点は\n＿＿＿＿＿＿＿＿＿＿＿"
	for _, player := range players[chat.ID] {
		scores += fmt.Sprintf("\n%s 「%d」", getPlayerDisplayName(player), player.score)
	}
	bot.Send(tg.NewMessage(chat.ID, scores))
}

func doShowHistory(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received showhistory command.")
	wordHistory := "使用された言葉:"
	for _, entry := range usedWords[msg.Chat.ID] {
		wordHistory += "\n" + getWordEntryDisplay(entry)
	}
	bot.Send(tg.NewMessage(msg.Chat.ID, wordHistory))
}

func doChallenge(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received challenge command.")
	entry := getLastEntry(msg.Chat)
	if entry == nil {
		bot.Send(tg.NewMessage(msg.Chat.ID, "言葉はありません。"))
		return
	}

	if entry.player.user.ID == msg.From.ID {
		// Player is challenging their own word, so remove it.
		currentWords := usedWords[msg.Chat.ID]
		currentEntry := currentWords[len(currentWords)]
		// Remove points for this word. Also add penalty points.
		currentEntry.player.score -= currentEntry.points + challengePenaltyPts
		usedWords[msg.Chat.ID] = currentWords[:len(currentWords)-1]
		bot.Send(tg.NewMessage(msg.Chat.ID, fmt.Sprintf("%sを消しました", currentEntry.word)))
		doShowCurrentWord(bot, msg, true)
	} else {
		// Auto-join the game.
		player := joinGame(bot, msg.From, msg.Chat, true)
		// TODO: Check tanslation
		bot.Send(tg.NewMessage(msg.Chat.ID,
			fmt.Sprintf("%sは%sに挑戦します。\n準備をして。。。戦う!!!",
				getPlayerDisplayName(player), getWordEntryDisplay(entry))))
	}
}

func doWordEntry(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received a word submission.")
	theWord := msg.Text
	// Auto-create the game.
	createGame(bot, msg.Chat)
	// Auto-join the game.
	player := joinGame(bot, msg.From, msg.Chat, true)
	if userSubmittedLastWord(msg) {
		bot.Send(tg.NewMessage(msg.Chat.ID, fmt.Sprintf("%s様お待ちください。他の人が最初に行くようにしましょう。", msg.From.FirstName)))
		doShowCurrentWord(bot, msg, false)
		return
	}
	if alreadyUsedWord(msg.Chat, theWord) {
		userLostGame(bot, player, msg, fmt.Sprintf("すでに使用されている言葉: %s", theWord))
		newGame(bot, msg.Chat, false)
		return
	}
	if !isValidWord(theWord) {
		userLostGame(bot, player, msg, fmt.Sprintf("無効言葉: %s", theWord))
		newGame(bot, msg.Chat, false)
		return
	}

	// Calculate points. If the first word, then no points awarded.
	entryPts := 0
	if len(usedWords[msg.Chat.ID]) > 1 {
		entryPts = wordPts
	}
	player.score += entryPts
	submission := &wordEntry{
		word:   theWord,
		player: player,
		points: entryPts}
	usedWords[msg.Chat.ID] = append(usedWords[msg.Chat.ID], submission)
	// TODO: Display the amount of points won/lost for this word entry.
	doShowCurrentWord(bot, msg, false)
}

func doSetNickname(bot *tg.BotAPI, msg *tg.Message, newNickname string) {
	player, _ := findPlayer(msg.Chat.ID, msg.From)
	if player != nil {
		oldName := getPlayerDisplayName(player)
		player.nickname = newNickname
		bot.Send(tg.NewMessage(msg.Chat.ID, fmt.Sprintf("%sは今から%sとよんでます。", oldName, newNickname)))
	}
}

func doHelp(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received help command.")
	bot.Send(tg.NewMessage(msg.Chat.ID,
		`Game Rules
＿＿＿＿＿＿＿＿＿＿＿
① Two or more people take turns to play.
② Only nouns are permitted.
③ A player who plays a word ending in the mora N 「ん」 loses the game, as no Japanese word begins with that character.
④ Words may not be repeated.
⑤ Phrases connected by no 「の」 are permitted, but only in those cases where the phrase is sufficiently fossilized to be considered a "word".
⑥ When a word ends in a small kana, such as 「じてんしゃ」 (bicycle), continue with the しゃ combination, such as 「しゃこ」 (garage).

Example: sakura 「さくら」 → rajio 「ラジオ」 → onigiri 「おにぎり」 → risu 「りす」 → sumou 「すもう」 → udon 「うどん」

The player who used the word udon lost this game.`))
}

func doShutdown(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received shutdown command.")
	bot.Send(tg.NewMessage(msg.Chat.ID, "シャットダウン。。。"))
}

// TODO: Do a new game if the bot is kicked out of chat.
func newGame(bot *tg.BotAPI, chat *tg.Chat, withNewPlayers bool) {
	delete(usedWords, chat.ID)
	if withNewPlayers {
		delete(players, chat.ID)
	}
	bot.Send(tg.NewMessage(chat.ID, "新しいゲームを開始します。\n誰が最初に行きたいですか？"))
}

func createGame(bot *tg.BotAPI, chat *tg.Chat) {
	if len(players[chat.ID]) == 0 {
		newGame(bot, chat, true)
	}
}

func joinGame(bot *tg.BotAPI, user *tg.User, chat *tg.Chat, announce bool) *playerEntry {
	player, _ := findPlayer(chat.ID, user)
	if player == nil {
		player = &playerEntry{user: user}
		playerName := getPlayerDisplayName(player)
		log.Printf("Adding %s to game %s.", playerName, getGameName(chat))
		players[chat.ID] = append(players[chat.ID], player)
		// TODO: Temporarily commented out to lower the chat volume.
		if false && announce {
			bot.Send(tg.NewMessage(chat.ID, fmt.Sprintf("%sはゲームに参加しました。", playerName)))
		}
	}
	return player
}

// For when a user leaves the chat.
func leaveGame(bot *tg.BotAPI, msg *tg.Message) {
	player, index := findPlayer(msg.Chat.ID, msg.From)
	if player == nil {
		return
	}

	currentPlayers := players[msg.Chat.ID]
	// Remove the player
	players[msg.Chat.ID] = append(currentPlayers[:index], currentPlayers[index+1:]...)
	bot.Send(tg.NewMessage(msg.Chat.ID, fmt.Sprintf("%sはゲームを去った。", getPlayerDisplayName(player))))
	if len(players[msg.Chat.ID]) < 2 {
		// Game over.
		newGame(bot, msg.Chat, true)
	}
}

func getWordEntryDisplay(entry *wordEntry) string {
	//【】『』「」
	return fmt.Sprintf("%s 「%s」", entry.word, getPlayerDisplayName(entry.player))
}

func getLastEntry(chat *tg.Chat) *wordEntry {
	numWords := len(usedWords[chat.ID])
	if numWords == 0 {
		return nil
	}

	return usedWords[chat.ID][numWords-1]
}

func userSubmittedLastWord(msg *tg.Message) bool {
	entry := getLastEntry(msg.Chat)
	if entry == nil {
		return false
	}

	return entry.player.user.ID == msg.From.ID
}

func userLostGame(bot *tg.BotAPI, player *playerEntry, msg *tg.Message, reason string) {
	player.score -= lostGamePts
	bot.Send(tg.NewMessage(msg.Chat.ID, fmt.Sprintf("❌%sはゲームを負けました！\n%s", getPlayerDisplayName(player), reason)))
	doShowScores(bot, msg.Chat)
}

func findPlayer(chatID int64, user *tg.User) (*playerEntry, int) {
	for i, player := range players[chatID] {
		if player.user.FirstName == user.FirstName &&
			player.user.LastName == user.LastName &&
			player.user.UserName == user.UserName {
			return player, i
		}
	}
	return nil, -1
}

func alreadyUsedWord(chat *tg.Chat, theWord string) bool {
	wordCheck := strings.ToLower(theWord)
	for _, usedWord := range usedWords[chat.ID] {
		if wordCheck == strings.ToLower(usedWord.word) {
			return true
		}
	}
	return false
}

func isValidWord(theWord string) bool {
	// TODO: Do database lookup of the noun word.
	return true
}

func getGameName(chat *tg.Chat) string {
	switch chat.Type {
	case "group":
		return fmt.Sprintf("%s [%d]", chat.Title, chat.ID)
	default:
		gameName := chat.FirstName
		if len(chat.LastName) != 0 {
			gameName += fmt.Sprintf(" %s", chat.LastName)
		}
		if len(chat.UserName) != 0 {
			gameName += fmt.Sprintf(" (@%s)", chat.UserName)
		}
		return fmt.Sprintf("%s [%d]", gameName, chat.ID)
	}
}

func getPlayerDisplayName(player *playerEntry) string {
	if len(player.nickname) == 0 {
		player.nickname = getUserDisplayName(player.user)
	}
	return player.nickname
}

func getUserDisplayName(user *tg.User) string {
	displayname := user.FirstName
	if len(user.LastName) != 0 {
		displayname += fmt.Sprintf(" %s", user.LastName)
	}
	if len(user.UserName) != 0 {
		displayname += fmt.Sprintf(" (@%s)", user.UserName)
	}
	return displayname
}
<commit_msg>Improve game point display.<commit_after>package main

import (
	"fmt"
	tg "github.com/go-telegram-bot-api/telegram-bot-api"
	"log"
	"regexp"
	"strings"
)

/*
Following is the command menu for constructing the bot with @BotFather.
Use the /setcommands command and reply with the following list of commands.
---------------------
newgame - Start a new game with a fresh word list.
current - Show the current word.
challenge - Challenge the word that was entered.
history - Show the words that have been used in the game.
scores - Show the current scores.
nick - Set your nickname.
help - Display game rules and other instructions.
*/

var torigemubot = botEventHandlers{
	onInitialize: torigemubotOnInitialize,
	onDispose:    torigemubotOnDispose,
	onMessage:    torigemubotOnMessage,
}

const wordPts = 3
const challengePenaltyPts = 5
const lostGamePts = 7

// Track players in each game
type playerEntry struct {
	user     *tg.User
	nickname string
	score    int
	numWords int
}
type playerMap map[int64][]*playerEntry

var players playerMap

// Track the words used for each game.
type wordEntry struct {
	word   string
	player *playerEntry
	points int
}
type wordHistoryMap map[int64][]*wordEntry

var usedWords wordHistoryMap

// Initialize global data
func torigemubotOnInitialize(bot *tg.BotAPI) bool {
	usedWords = make(wordHistoryMap)
	players = make(playerMap)
	return true
}

func torigemubotOnDispose(bot *tg.BotAPI) {
	// TODO: Any cleanup of external resources.
}

var newgameCmd = regexp.MustCompile(`(?i)^/?newgame(@torigemubot)?`)
var currentCmd = regexp.MustCompile(`(?i)^/?current(@torigemubot)?`)
var challengeCmd = regexp.MustCompile(`(?i)^/?challenge(@torigemubot)?`)
var historyCmd = regexp.MustCompile(`(?i)^/?history(@torigemubot)?`)
var scoresCmd = regexp.MustCompile(`(?i)^/?scores(@torigemubot)?`)
var nicknameCmd = regexp.MustCompile(`(?i)^/?nick(@torigemubot)?[ \t]*`)
var helpCmd = regexp.MustCompile(`(?i)^/?help(@torigemubot)?`)
var shutdownCmd = regexp.MustCompile(`(?i)^/?shutdown(@torigemubot)?[ \t]+now`)

func torigemubotOnMessage(bot *tg.BotAPI, msg *tg.Message) bool {
	log.Printf("MsgFrom: Chat %s, User %s %s", getGameName(msg.Chat), getUserDisplayName(msg.From), msg.Text)
	switch {
	case newgameCmd.MatchString(msg.Text):
		doNewGame(bot, msg)
	case currentCmd.MatchString(msg.Text):
		doShowCurrentWord(bot, msg, true)
	case challengeCmd.MatchString(msg.Text):
		doChallenge(bot, msg)
	case historyCmd.MatchString(msg.Text):
		doShowHistory(bot, msg)
	case scoresCmd.MatchString(msg.Text):
		doShowScores(bot, msg.Chat)
	case nicknameCmd.MatchString(msg.Text):
		doSetNickname(bot, msg, nicknameCmd.ReplaceAllString(msg.Text, ""))
	case helpCmd.MatchString(msg.Text):
		doHelp(bot, msg)
	case shutdownCmd.MatchString(msg.Text):
		doShutdown(bot, msg)
		return false
	default:
		doWordEntry(bot, msg)
	}
	return true
}

func doNewGame(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received newgame command.")
	// TODO: Add some safety checks so that one other person must agree. Give a lazy consensus time.
	// If no one objects within 1 minute, then the game starts new. If someone agrees, it starts new right away.
	// If someone objects, then the reset is canceled.
	newGame(bot, msg.Chat, false)
	joinGame(bot, msg.From, msg.Chat, false)
}

func doShowCurrentWord(bot *tg.BotAPI, msg *tg.Message, showUserInfo bool) {
	var reply string
	entry := getLastEntry(msg.Chat)
	if entry == nil {
		reply = "現在の言葉はありません。"
	} else {
		var wordDisplay string
		if showUserInfo {
			wordDisplay = getWordEntryDisplay(entry)
		} else {
			wordDisplay = entry.word
		}

		reply = fmt.Sprintf("》%s", wordDisplay)
	}
	bot.Send(tg.NewMessage(msg.Chat.ID, reply))
}

func doShowScores(bot *tg.BotAPI, chat *tg.Chat) {
	log.Println("Received showscores command.")
	scores := "ゲームの得点は\n＿＿＿＿＿＿＿＿＿＿＿"
	for _, player := range players[chat.ID] {
		scores += fmt.Sprintf("\n%s 「%d」 %d言葉", getPlayerDisplayName(player), player.score, player.numWords)
	}
	bot.Send(tg.NewMessage(chat.ID, scores))
}

func doShowHistory(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received showhistory command.")
	wordHistory := "使用された言葉:"
	for _, entry := range usedWords[msg.Chat.ID] {
		wordHistory += "\n" + getWordEntryDisplay(entry)
	}
	bot.Send(tg.NewMessage(msg.Chat.ID, wordHistory))
}

func doChallenge(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received challenge command.")
	entry := getLastEntry(msg.Chat)
	if entry == nil {
		bot.Send(tg.NewMessage(msg.Chat.ID, "言葉はありません。"))
		return
	}

	if entry.player.user.ID == msg.From.ID {
		// Player is challenging their own word, so remove it.
		currentWords := usedWords[msg.Chat.ID]
		currentEntry := currentWords[len(currentWords)]
		// Remove points for this word. Also add penalty points.
		currentEntry.player.score -= currentEntry.points + challengePenaltyPts
		usedWords[msg.Chat.ID] = currentWords[:len(currentWords)-1]
		bot.Send(tg.NewMessage(msg.Chat.ID, fmt.Sprintf("%sを消しました", currentEntry.word)))
		doShowCurrentWord(bot, msg, true)
	} else {
		// Auto-join the game.
		player := joinGame(bot, msg.From, msg.Chat, true)
		// TODO: Check tanslation
		bot.Send(tg.NewMessage(msg.Chat.ID,
			fmt.Sprintf("%sは%sに挑戦します。\n準備をして。。。戦う!!!",
				getPlayerDisplayName(player), getWordEntryDisplay(entry))))
	}
}

func doWordEntry(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received a word submission.")
	theWord := msg.Text
	// Auto-create the game.
	createGame(bot, msg.Chat)
	// Auto-join the game.
	player := joinGame(bot, msg.From, msg.Chat, true)
	if userSubmittedLastWord(msg) {
		bot.Send(tg.NewMessage(msg.Chat.ID, fmt.Sprintf("%s様お待ちください。他の人が最初に行くようにしましょう。", msg.From.FirstName)))
		doShowCurrentWord(bot, msg, false)
		return
	}
	if alreadyUsedWord(msg.Chat, theWord) {
		userLostGame(bot, player, msg, fmt.Sprintf("すでに使用されている言葉: %s", theWord))
		newGame(bot, msg.Chat, false)
		return
	}
	if !isValidWord(theWord) {
		userLostGame(bot, player, msg, fmt.Sprintf("無効言葉: %s", theWord))
		newGame(bot, msg.Chat, false)
		return
	}

	// Calculate points. If the first word, then no points awarded.
	entryPts := 0
	if len(usedWords[msg.Chat.ID]) > 0 {
		entryPts = wordPts
	}
	player.score += entryPts
	submission := &wordEntry{
		word:   theWord,
		player: player,
		points: entryPts}
	usedWords[msg.Chat.ID] = append(usedWords[msg.Chat.ID], submission)
	// TODO: Display the amount of points won/lost for this word entry.
	doShowCurrentWord(bot, msg, false)
}

func doSetNickname(bot *tg.BotAPI, msg *tg.Message, newNickname string) {
	// Auto-join the game.
	player := joinGame(bot, msg.From, msg.Chat, false)
	oldName := getPlayerDisplayName(player)
	player.nickname = newNickname
	bot.Send(tg.NewMessage(msg.Chat.ID, fmt.Sprintf("%sは今から%sとよんでます。", oldName, newNickname)))
}

func doHelp(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received help command.")
	bot.Send(tg.NewMessage(msg.Chat.ID,
		`Game Rules
＿＿＿＿＿＿＿＿＿＿＿
① Two or more people take turns to play.
② Only nouns are permitted.
③ A player who plays a word ending in the mora N 「ん」 loses the game, as no Japanese word begins with that character.
④ Words may not be repeated.
⑤ Phrases connected by no 「の」 are permitted, but only in those cases where the phrase is sufficiently fossilized to be considered a "word".
⑥ When a word ends in a small kana, such as 「じてんしゃ」 (bicycle), continue with the しゃ combination, such as 「しゃこ」 (garage).

Example: sakura 「さくら」 → rajio 「ラジオ」 → onigiri 「おにぎり」 → risu 「りす」 → sumou 「すもう」 → udon 「うどん」

The player who used the word udon lost this game.`))
}

func doShutdown(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received shutdown command.")
	bot.Send(tg.NewMessage(msg.Chat.ID, "シャットダウン。。。"))
}

// TODO: Do a new game if the bot is kicked out of chat.
func newGame(bot *tg.BotAPI, chat *tg.Chat, withNewPlayers bool) {
	delete(usedWords, chat.ID)
	if withNewPlayers {
		delete(players, chat.ID)
	}
	bot.Send(tg.NewMessage(chat.ID, "新しいゲームを開始します。\n誰が最初に行きたいですか？"))
}

func createGame(bot *tg.BotAPI, chat *tg.Chat) {
	if len(players[chat.ID]) == 0 {
		newGame(bot, chat, true)
	}
}

func joinGame(bot *tg.BotAPI, user *tg.User, chat *tg.Chat, announce bool) *playerEntry {
	player, _ := findPlayer(chat.ID, user)
	if player == nil {
		player = &playerEntry{user: user}
		playerName := getPlayerDisplayName(player)
		log.Printf("Adding %s to game %s.", playerName, getGameName(chat))
		players[chat.ID] = append(players[chat.ID], player)
		// TODO: Temporarily commented out to lower the chat volume.
		if false && announce {
			bot.Send(tg.NewMessage(chat.ID, fmt.Sprintf("%sはゲームに参加しました。", playerName)))
		}
	}
	return player
}

// For when a user leaves the chat.
func leaveGame(bot *tg.BotAPI, msg *tg.Message) {
	player, index := findPlayer(msg.Chat.ID, msg.From)
	if player == nil {
		return
	}

	currentPlayers := players[msg.Chat.ID]
	// Remove the player
	players[msg.Chat.ID] = append(currentPlayers[:index], currentPlayers[index+1:]...)
	bot.Send(tg.NewMessage(msg.Chat.ID, fmt.Sprintf("%sはゲームを去った。", getPlayerDisplayName(player))))
	if len(players[msg.Chat.ID]) < 2 {
		// Game over.
		newGame(bot, msg.Chat, true)
	}
}

func getWordEntryDisplay(entry *wordEntry) string {
	//【】『』「」
	return fmt.Sprintf("%s 【%d】「%s」", entry.word, entry.points, getPlayerDisplayName(entry.player))
}

func getLastEntry(chat *tg.Chat) *wordEntry {
	numWords := len(usedWords[chat.ID])
	if numWords == 0 {
		return nil
	}

	return usedWords[chat.ID][numWords-1]
}

func userSubmittedLastWord(msg *tg.Message) bool {
	entry := getLastEntry(msg.Chat)
	if entry == nil {
		return false
	}

	return entry.player.user.ID == msg.From.ID
}

func userLostGame(bot *tg.BotAPI, player *playerEntry, msg *tg.Message, reason string) {
	player.score -= lostGamePts
	bot.Send(tg.NewMessage(msg.Chat.ID, fmt.Sprintf("❌%sはゲームを負けました！\n%s", getPlayerDisplayName(player), reason)))
	doShowScores(bot, msg.Chat)
}

func findPlayer(chatID int64, user *tg.User) (*playerEntry, int) {
	for i, player := range players[chatID] {
		if player.user.FirstName == user.FirstName &&
			player.user.LastName == user.LastName &&
			player.user.UserName == user.UserName {
			return player, i
		}
	}
	return nil, -1
}

func alreadyUsedWord(chat *tg.Chat, theWord string) bool {
	wordCheck := strings.ToLower(theWord)
	for _, usedWord := range usedWords[chat.ID] {
		if wordCheck == strings.ToLower(usedWord.word) {
			return true
		}
	}
	return false
}

func isValidWord(theWord string) bool {
	// TODO: Do database lookup of the noun word.
	return true
}

func getGameName(chat *tg.Chat) string {
	switch chat.Type {
	case "group":
		return fmt.Sprintf("%s [%d]", chat.Title, chat.ID)
	default:
		gameName := chat.FirstName
		if len(chat.LastName) != 0 {
			gameName += fmt.Sprintf(" %s", chat.LastName)
		}
		if len(chat.UserName) != 0 {
			gameName += fmt.Sprintf(" (@%s)", chat.UserName)
		}
		return fmt.Sprintf("%s [%d]", gameName, chat.ID)
	}
}

func getPlayerDisplayName(player *playerEntry) string {
	if len(player.nickname) == 0 {
		player.nickname = getUserDisplayName(player.user)
	}
	return player.nickname
}

func getUserDisplayName(user *tg.User) string {
	displayname := user.FirstName
	if len(user.LastName) != 0 {
		displayname += fmt.Sprintf(" %s", user.LastName)
	}
	if len(user.UserName) != 0 {
		displayname += fmt.Sprintf(" (@%s)", user.UserName)
	}
	return displayname
}
<|endoftext|>


<commit_before>// EXAMPLE FROM: https://github.com/GoogleCloudPlatform/appengine-angular-gotodos
//
// Copyright 2013 Google Inc. All Rights Reserved.
//
// 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.
//

// gotodos is an App Engine JSON backend for managing a todo list.
//
// It supports the following commands:
//
// - Create a new todo
// POST /todos
// > {"text": "do this"}
// < {"id": 1, "text": "do this", "created": 1356724843.0, "done": false}
//
// - Update an existing todo
// POST /todos
// > {"id": 1, "text": "do this", "created": 1356724843.0, "done": true}
// < {"id": 1, "text": "do this", "created": 1356724843.0, "done": true}
//
// - List existing todos:
// GET /todos
// >
// < [{"id": 1, "text": "do this", "created": 1356724843.0, "done": true},
//    {"id": 2, "text": "do that", "created": 1356724849.0, "done": false}]
//
// - Delete 'done' todos:
// DELETE /todos
// >
// <

package controllers

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"regexp"

	"models"

	"appengine/datastore"
	"appengine/urlfetch"

	"github.com/PuerkitoBio/goquery"
	"github.com/astaxie/beegae"
)

type IOSAppController struct {
	beegae.Controller
}

func (this *IOSAppController) Get() {
	iosapps := []models.IOSApp{}
	_, err := datastore.NewQuery("IOSApp").Order("-UpdatedAt").GetAll(this.AppEngineCtx, &iosapps)
	if err != nil {
		this.Data["json"] = err
		return
	}
	listDataSet := map[string]interface{}{"items": iosapps}
	this.Data["json"] = listDataSet
}

func (this *IOSAppController) Post() {
	iosapp, err := decodeIOSApp(this.Ctx.Input.Request.Body)
	if err != nil {
		log.Println("decode err")
		this.Data["json"] = err
		return
	}
	i, err := iosapp.Create(this.AppEngineCtx)
	if err != nil {
		this.Data["json"] = err
	} else {
		this.Data["json"] = &i
	}
}

func (this *IOSAppController) GetEntity() {
	keyName := this.Ctx.Input.Param(":key_name")
	key := datastore.NewKey(this.AppEngineCtx, "IOSApp", keyName, 0, nil)
	var iosapp models.IOSApp
	err := datastore.Get(this.AppEngineCtx, key, &iosapp)
	if err != nil {
		this.Data["json"] = err
		return
	} else {
		this.Data["json"] = &iosapp
	}
}
func (this *IOSAppController) UpdateEntity() {
	keyName := this.Ctx.Input.Param(":key_name")
	key := datastore.NewKey(this.AppEngineCtx, "IOSApp", keyName, 0, nil)
	var iosapp models.IOSApp
	err := datastore.Get(this.AppEngineCtx, key, &iosapp)
	if err != nil {
		this.Data["json"] = err
		return
	}
	err = json.NewDecoder(this.Ctx.Input.Request.Body).Decode(&iosapp)
	if err != nil {
		this.Data["json"] = err
		return
	}
	i, err := iosapp.Update(this.AppEngineCtx)
	if err != nil {
		this.Data["json"] = err
	} else {
		this.Data["json"] = &i
	}
}

func (this *IOSAppController) DeleteEntity() {
	keyName := this.Ctx.Input.Param(":key_name")
	key := datastore.NewKey(this.AppEngineCtx, "IOSApp", keyName, 0, nil)
	err := datastore.Delete(this.AppEngineCtx, key)
	if err == nil {
		this.Data["json"] = nil
	} else {
		this.Data["json"] = err
	}
}

func (this *IOSAppController) GetAppReview() {
	appID := this.Ctx.Input.Param(":app_id")
	client := urlfetch.Client(this.AppEngineCtx)
	req, err := http.NewRequest("GET", "https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?pageNumber=0&sortOrdering=4&onlyLatestVersion=false&type=Purple+Software&id="+appID, nil)
	req.Header.Add("X-Apple-Store-Front", "143462")
	req.Header.Add("User-Agent", "iTunes/9.2 (Macintosh; U; Mac OS X 10.6)")
	resp, err := client.Do(req)
	if err != nil {
		this.Data["json"] = err
		return
	}
	defer resp.Body.Close()
	doc, _ := goquery.NewDocumentFromResponse(resp)
	doc.Find("Document View VBoxView View MatrixView VBoxView:nth-child(1) VBoxView VBoxView VBoxView").Each(func(_ int, s *goquery.Selection) {
		title_node := s.Find("HBoxView>TextView>SetFontStyle>b").First()
		title := title_node.Text()
		if title != "" {
			reviewIDURL, idExists := s.Find("HBoxView VBoxView GotoURL").First().Attr("url")
			if idExists {
				regex_str := "([0-9]{4,}$)"
				re, err := regexp.Compile(regex_str)
				if err != nil {
					panic(err)
				}
				reviewID := re.FindString(reviewIDURL)
				var content string
				if len(reviewID) > 4 {
					num := 0
					log.Println(title)
					log.Println(reviewID)
					s.Find("TextView SetFontStyle").Each(func(_ int, sc *goquery.Selection) {
						num = num + 1
						if num == 4 {
							content = sc.Text()
						}
					})
					var appreview models.AppReview
					appreview.AppID = appID
					appreview.ReviewID = reviewID
					appreview.Title = title
					appreview.Content = content
					_, err = appreview.Create(this.AppEngineCtx)
					if err != nil {
						this.Data["json"] = err
						return
					}
				}

			}
		}

	})
}

func (this *IOSAppController) GetReviews() {
	iosapps := []models.IOSApp{}
	_, err := datastore.NewQuery("IOSApp").Order("-updated_at").GetAll(this.AppEngineCtx, &iosapps)
	if err != nil {
		this.Data["json"] = err
		return
	}
	for i := 0; i < len(iosapps); i++ {
		log.Println(iosapps[i].AppID)
	}
	listDataSet := map[string]interface{}{"items": iosapps}
	this.Data["json"] = listDataSet
	// TODO set taskque to get app reviews
}

func (this *IOSAppController) Render() error {
	if _, ok := this.Data["json"].(error); ok {
		this.AppEngineCtx.Errorf("iosapp error: %v", this.Data["json"])
	}
	this.ServeJson()
	return nil
}

func decodeIOSApp(r io.ReadCloser) (*models.IOSApp, error) {
	defer r.Close()
	var iosapp models.IOSApp
	err := json.NewDecoder(r).Decode(&iosapp)
	return &iosapp, err
}
<commit_msg>post to taskque on /admin/task/iosapp/getreviews<commit_after>// EXAMPLE FROM: https://github.com/GoogleCloudPlatform/appengine-angular-gotodos
//
// Copyright 2013 Google Inc. All Rights Reserved.
//
// 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.
//

// gotodos is an App Engine JSON backend for managing a todo list.
//
// It supports the following commands:
//
// - Create a new todo
// POST /todos
// > {"text": "do this"}
// < {"id": 1, "text": "do this", "created": 1356724843.0, "done": false}
//
// - Update an existing todo
// POST /todos
// > {"id": 1, "text": "do this", "created": 1356724843.0, "done": true}
// < {"id": 1, "text": "do this", "created": 1356724843.0, "done": true}
//
// - List existing todos:
// GET /todos
// >
// < [{"id": 1, "text": "do this", "created": 1356724843.0, "done": true},
//    {"id": 2, "text": "do that", "created": 1356724849.0, "done": false}]
//
// - Delete 'done' todos:
// DELETE /todos
// >
// <

package controllers

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"regexp"

	"models"

	"appengine/datastore"
	"appengine/taskqueue"
	"appengine/urlfetch"

	"github.com/PuerkitoBio/goquery"
	"github.com/astaxie/beegae"
)

type IOSAppController struct {
	beegae.Controller
}

func (this *IOSAppController) Get() {
	iosapps := []models.IOSApp{}
	_, err := datastore.NewQuery("IOSApp").Order("-UpdatedAt").GetAll(this.AppEngineCtx, &iosapps)
	if err != nil {
		this.Data["json"] = err
		return
	}
	listDataSet := map[string]interface{}{"items": iosapps}
	this.Data["json"] = listDataSet
}

func (this *IOSAppController) Post() {
	iosapp, err := decodeIOSApp(this.Ctx.Input.Request.Body)
	if err != nil {
		log.Println("decode err")
		this.Data["json"] = err
		return
	}
	i, err := iosapp.Create(this.AppEngineCtx)
	if err != nil {
		this.Data["json"] = err
	} else {
		this.Data["json"] = &i
	}
}

func (this *IOSAppController) GetEntity() {
	keyName := this.Ctx.Input.Param(":key_name")
	key := datastore.NewKey(this.AppEngineCtx, "IOSApp", keyName, 0, nil)
	var iosapp models.IOSApp
	err := datastore.Get(this.AppEngineCtx, key, &iosapp)
	if err != nil {
		this.Data["json"] = err
		return
	} else {
		this.Data["json"] = &iosapp
	}
}
func (this *IOSAppController) UpdateEntity() {
	keyName := this.Ctx.Input.Param(":key_name")
	key := datastore.NewKey(this.AppEngineCtx, "IOSApp", keyName, 0, nil)
	var iosapp models.IOSApp
	err := datastore.Get(this.AppEngineCtx, key, &iosapp)
	if err != nil {
		this.Data["json"] = err
		return
	}
	err = json.NewDecoder(this.Ctx.Input.Request.Body).Decode(&iosapp)
	if err != nil {
		this.Data["json"] = err
		return
	}
	i, err := iosapp.Update(this.AppEngineCtx)
	if err != nil {
		this.Data["json"] = err
	} else {
		this.Data["json"] = &i
	}
}

func (this *IOSAppController) DeleteEntity() {
	keyName := this.Ctx.Input.Param(":key_name")
	key := datastore.NewKey(this.AppEngineCtx, "IOSApp", keyName, 0, nil)
	err := datastore.Delete(this.AppEngineCtx, key)
	if err == nil {
		this.Data["json"] = nil
	} else {
		this.Data["json"] = err
	}
}

func (this *IOSAppController) GetAppReview() {
	appID := this.Ctx.Input.Param(":app_id")
	client := urlfetch.Client(this.AppEngineCtx)
	req, err := http.NewRequest("GET", "https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?pageNumber=0&sortOrdering=4&onlyLatestVersion=false&type=Purple+Software&id="+appID, nil)
	req.Header.Add("X-Apple-Store-Front", "143462")
	req.Header.Add("User-Agent", "iTunes/9.2 (Macintosh; U; Mac OS X 10.6)")
	resp, err := client.Do(req)
	if err != nil {
		this.Data["json"] = err
		return
	}
	defer resp.Body.Close()
	doc, _ := goquery.NewDocumentFromResponse(resp)
	doc.Find("Document View VBoxView View MatrixView VBoxView:nth-child(1) VBoxView VBoxView VBoxView").Each(func(_ int, s *goquery.Selection) {
		title_node := s.Find("HBoxView>TextView>SetFontStyle>b").First()
		title := title_node.Text()
		if title != "" {
			reviewIDURL, idExists := s.Find("HBoxView VBoxView GotoURL").First().Attr("url")
			if idExists {
				regex_str := "([0-9]{4,}$)"
				re, err := regexp.Compile(regex_str)
				if err != nil {
					panic(err)
				}
				reviewID := re.FindString(reviewIDURL)
				var content string
				if len(reviewID) > 4 {
					num := 0
					log.Println(title)
					log.Println(reviewID)
					s.Find("TextView SetFontStyle").Each(func(_ int, sc *goquery.Selection) {
						num = num + 1
						if num == 4 {
							content = sc.Text()
						}
					})
					var appreview models.AppReview
					appreview.AppID = appID
					appreview.ReviewID = reviewID
					appreview.Title = title
					appreview.Content = content
					_, err = appreview.Create(this.AppEngineCtx)
					if err != nil {
						this.Data["json"] = err
						return
					}
				}

			}
		}

	})
}

func (this *IOSAppController) GetReviews() {
	iosapps := []models.IOSApp{}
	_, err := datastore.NewQuery("IOSApp").Order("-UpdatedAt").GetAll(this.AppEngineCtx, &iosapps)
	if err != nil {
		this.Data["json"] = err
		return
	}
	for i := 0; i < len(iosapps); i++ {
		log.Println(iosapps[i].AppID)
		t := taskqueue.NewPOSTTask("/admin/task/iosapp/getappreview/"+iosapps[i].AppID, nil)
		if _, err := taskqueue.Add(this.AppEngineCtx, t, ""); err != nil {
			this.Data["json"] = err
			return
		}
	}
	listDataSet := map[string]interface{}{"items": iosapps}
	this.Data["json"] = listDataSet
	// TODO set taskque to get app reviews
}

func (this *IOSAppController) Render() error {
	if _, ok := this.Data["json"].(error); ok {
		this.AppEngineCtx.Errorf("iosapp error: %v", this.Data["json"])
	}
	this.ServeJson()
	return nil
}

func decodeIOSApp(r io.ReadCloser) (*models.IOSApp, error) {
	defer r.Close()
	var iosapp models.IOSApp
	err := json.NewDecoder(r).Decode(&iosapp)
	return &iosapp, err
}
<|endoftext|>


<commit_before>package controllers

import (
	"fmt"
	"log"
	"net/http"

	"encoding/json"

	"github.com/gorilla/mux"
	"github.com/nuveo/prest/adapters/postgres"
	"github.com/nuveo/prest/api"
	"github.com/nuveo/prest/statements"
)

// GetTables list all (or filter) tables
func GetTables(w http.ResponseWriter, r *http.Request) {
	requestWhere := postgres.WhereByRequest(r)
	sqlTables := statements.Tables
	if requestWhere != "" {
		sqlTables = fmt.Sprint(
			statements.TablesSelect,
			statements.TablesWhere,
			" AND ",
			requestWhere,
			statements.TablesOrderBy)
	}

	object, err := postgres.Query(sqlTables)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}

// GetTablesByDatabaseAndSchema list all (or filter) tables based on database and schema
func GetTablesByDatabaseAndSchema(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	database, ok := vars["database"]
	if !ok {
		log.Println("Unable to parse database in URI")
		http.Error(w, "Unable to parse database in URI", http.StatusInternalServerError)
		return
	}
	schema, ok := vars["schema"]
	if !ok {
		log.Println("Unable to parse schema in URI")
		http.Error(w, "Unable to parse schema in URI", http.StatusInternalServerError)
		return
	}
	requestWhere := postgres.WhereByRequest(r)
	sqlSchemaTables := statements.SchemaTables
	if requestWhere != "" {
		sqlSchemaTables = fmt.Sprint(
			statements.SchemaTablesSelect,
			statements.SchemaTablesWhere,
			" AND ",
			requestWhere,
			statements.SchemaTablesOrderBy)
	}
	sqlSchemaTables = fmt.Sprint(sqlSchemaTables, " ", postgres.PaginateIfPossible(r))

	object, err := postgres.Query(sqlSchemaTables, database, schema)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}

// SelectFromTables perform select in database
func SelectFromTables(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	database, ok := vars["database"]
	if !ok {
		log.Println("Unable to parse database in URI")
		http.Error(w, "Unable to parse database in URI", http.StatusInternalServerError)
		return
	}
	schema, ok := vars["schema"]
	if !ok {
		log.Println("Unable to parse schema in URI")
		http.Error(w, "Unable to parse schema in URI", http.StatusInternalServerError)
		return
	}
	table, ok := vars["table"]
	if !ok {
		log.Println("Unable to parse table in URI")
		http.Error(w, "Unable to parse table in URI", http.StatusInternalServerError)
		return
	}

	query := fmt.Sprintf("%s %s.%s.%s", statements.SelectInTable, database, schema, table)
	requestWhere := postgres.WhereByRequest(r)
	sqlSelect := query
	if requestWhere != "" {
		sqlSelect = fmt.Sprint(
			query,
			" WHERE ",
			requestWhere)
	}
	sqlSelect = fmt.Sprint(sqlSelect, " ", postgres.PaginateIfPossible(r))

	object, err := postgres.Query(sqlSelect)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}

// InsertInTables perform insert in specific table
func InsertInTables(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	database, ok := vars["database"]
	if !ok {
		log.Println("Unable to parse database in URI")
		http.Error(w, "Unable to parse database in URI", http.StatusInternalServerError)
		return
	}
	schema, ok := vars["schema"]
	if !ok {
		log.Println("Unable to parse schema in URI")
		http.Error(w, "Unable to parse schema in URI", http.StatusInternalServerError)
		return
	}
	table, ok := vars["table"]
	if !ok {
		log.Println("Unable to parse table in URI")
		http.Error(w, "Unable to parse table in URI", http.StatusInternalServerError)
		return
	}
	req := api.Request{}
	err := json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	object, err := postgres.Insert(database, schema, table, req)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}
<commit_msg>delete controller implementation<commit_after>package controllers

import (
	"fmt"
	"log"
	"net/http"

	"encoding/json"

	"github.com/gorilla/mux"
	"github.com/nuveo/prest/adapters/postgres"
	"github.com/nuveo/prest/api"
	"github.com/nuveo/prest/statements"
)

// GetTables list all (or filter) tables
func GetTables(w http.ResponseWriter, r *http.Request) {
	requestWhere := postgres.WhereByRequest(r)
	sqlTables := statements.Tables
	if requestWhere != "" {
		sqlTables = fmt.Sprint(
			statements.TablesSelect,
			statements.TablesWhere,
			" AND ",
			requestWhere,
			statements.TablesOrderBy)
	}

	object, err := postgres.Query(sqlTables)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}

// GetTablesByDatabaseAndSchema list all (or filter) tables based on database and schema
func GetTablesByDatabaseAndSchema(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	database, ok := vars["database"]
	if !ok {
		log.Println("Unable to parse database in URI")
		http.Error(w, "Unable to parse database in URI", http.StatusInternalServerError)
		return
	}
	schema, ok := vars["schema"]
	if !ok {
		log.Println("Unable to parse schema in URI")
		http.Error(w, "Unable to parse schema in URI", http.StatusInternalServerError)
		return
	}
	requestWhere := postgres.WhereByRequest(r)
	sqlSchemaTables := statements.SchemaTables
	if requestWhere != "" {
		sqlSchemaTables = fmt.Sprint(
			statements.SchemaTablesSelect,
			statements.SchemaTablesWhere,
			" AND ",
			requestWhere,
			statements.SchemaTablesOrderBy)
	}
	sqlSchemaTables = fmt.Sprint(sqlSchemaTables, " ", postgres.PaginateIfPossible(r))

	object, err := postgres.Query(sqlSchemaTables, database, schema)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}

// SelectFromTables perform select in database
func SelectFromTables(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	database, ok := vars["database"]
	if !ok {
		log.Println("Unable to parse database in URI")
		http.Error(w, "Unable to parse database in URI", http.StatusInternalServerError)
		return
	}
	schema, ok := vars["schema"]
	if !ok {
		log.Println("Unable to parse schema in URI")
		http.Error(w, "Unable to parse schema in URI", http.StatusInternalServerError)
		return
	}
	table, ok := vars["table"]
	if !ok {
		log.Println("Unable to parse table in URI")
		http.Error(w, "Unable to parse table in URI", http.StatusInternalServerError)
		return
	}

	query := fmt.Sprintf("%s %s.%s.%s", statements.SelectInTable, database, schema, table)
	requestWhere := postgres.WhereByRequest(r)
	sqlSelect := query
	if requestWhere != "" {
		sqlSelect = fmt.Sprint(
			query,
			" WHERE ",
			requestWhere)
	}
	sqlSelect = fmt.Sprint(sqlSelect, " ", postgres.PaginateIfPossible(r))

	object, err := postgres.Query(sqlSelect)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}

// InsertInTables perform insert in specific table
func InsertInTables(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	database, ok := vars["database"]
	if !ok {
		log.Println("Unable to parse database in URI")
		http.Error(w, "Unable to parse database in URI", http.StatusInternalServerError)
		return
	}
	schema, ok := vars["schema"]
	if !ok {
		log.Println("Unable to parse schema in URI")
		http.Error(w, "Unable to parse schema in URI", http.StatusInternalServerError)
		return
	}
	table, ok := vars["table"]
	if !ok {
		log.Println("Unable to parse table in URI")
		http.Error(w, "Unable to parse table in URI", http.StatusInternalServerError)
		return
	}
	req := api.Request{}
	err := json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	object, err := postgres.Insert(database, schema, table, req)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}

// DeleteFromTable perform delete sql
func DeleteFromTable(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	database, ok := vars["database"]
	if !ok {
		log.Println("Unable to parse database in URI")
		http.Error(w, "Unable to parse database in URI", http.StatusInternalServerError)
		return
	}
	schema, ok := vars["schema"]
	if !ok {
		log.Println("Unable to parse schema in URI")
		http.Error(w, "Unable to parse schema in URI", http.StatusInternalServerError)
		return
	}
	table, ok := vars["table"]
	if !ok {
		log.Println("Unable to parse table in URI")
		http.Error(w, "Unable to parse table in URI", http.StatusInternalServerError)
		return
	}

	where := postgres.WhereByRequest(r)

	object, err := postgres.Delete(database, schema, table, where)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}
<|endoftext|>


<commit_before>//
//  Lazy Pirate server.
//  Binds REQ socket to tcp://*:5555
//  Like hwserver except:
//   - echoes request as-is
//   - randomly runs slowly, or exits to simulate a crash.
//

package main

import (
	zmq "github.com/pebbe/zmq3"

	"fmt"
	"math/rand"
	"time"
)

func main() {
	rand.Seed(time.Now().UnixNano())

	server, _ := zmq.NewSocket(zmq.REP)
	defer server.Close()
	server.Bind("tcp://*:5555")

	for cycles := 0; true; {
		request, _ := server.RecvMessage(0)
		cycles++

		//  Simulate various problems, after a few cycles
		if cycles > 3 && rand.Intn(3) == 0 {
			fmt.Println("I: simulating a crash")
			break
		} else if cycles > 3 && rand.Intn(3) == 0 {
			fmt.Println("I: simulating CPU overload")
			time.Sleep(2 * time.Second)
		}
		fmt.Printf("I: normal request (%s)\n", request)
		time.Sleep(time.Second) //  Do some heavy work
		server.SendMessage(request)
	}
}
<commit_msg>small adjustment in examples/lpserver.go<commit_after>//
//  Lazy Pirate server.
//  Binds REQ socket to tcp://*:5555
//  Like hwserver except:
//   - echoes request as-is
//   - randomly runs slowly, or exits to simulate a crash.
//

package main

import (
	zmq "github.com/pebbe/zmq3"

	"fmt"
	"math/rand"
	"time"
)

func main() {
	rand.Seed(time.Now().UnixNano())

	server, _ := zmq.NewSocket(zmq.REP)
	defer server.Close()
	server.Bind("tcp://*:5555")

	for cycles := 0; true; {
		cycles++

		//  Simulate various problems, after a few cycles
		if cycles > 3 && rand.Intn(3) == 0 {
			fmt.Println("I: simulating a crash")
			break
		} else if cycles > 3 && rand.Intn(3) == 0 {
			fmt.Println("I: simulating CPU overload")
			time.Sleep(2 * time.Second)
		}

		request, _ := server.RecvMessage(0)
		fmt.Printf("I: normal request (%s)\n", request)
		time.Sleep(time.Second) //  Do some heavy work
		server.SendMessage(request)
	}
}
<|endoftext|>


<commit_before>package auth

import (
	"net/http"
)

const CookieName = "ATC-Authorization"

type CookieSetHandler struct {
	Handler http.Handler
}

func (handler CookieSetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	cookie, err := r.Cookie(CookieName)
	if err == nil && r.Header.Get("Authorization") == "" {
		r.Header.Set("Authorization", cookie.Value)
	}

	handler.Handler.ServeHTTP(w, r)
}
<commit_msg>Add X- headers for security<commit_after>package auth

import (
	"net/http"
)

const CookieName = "ATC-Authorization"

type CookieSetHandler struct {
	Handler http.Handler
}

func (handler CookieSetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	cookie, err := r.Cookie(CookieName)
	if err == nil && r.Header.Get("Authorization") == "" {
		r.Header.Set("Authorization", cookie.Value)

	}

	handler.Handler.ServeHTTP(w, r)
}
<|endoftext|>


<commit_before>package executor

import (
	"fmt"
	"log"
	"reflect"

	"github.com/tmc/graphql"
	"github.com/tmc/graphql/schema"
)

type Executor struct {
	schema *schema.Schema
}

func New(schema *schema.Schema) *Executor {
	return &Executor{
		schema: schema,
	}
}

func (e *Executor) HandleOperation(o *graphql.Operation) (interface{}, error) {
	rootSelections := o.Selections
	rootCalls := e.schema.RootCalls()
	result := make([]interface{}, 0)

	for _, selection := range rootSelections {
		rootCallHandler, ok := rootCalls[selection.Field.Name]
		if !ok {
			return nil, fmt.Errorf("Root call '%s' is not registered", selection.Field.Name)
		}
		partial, err := rootCallHandler.Func(e, selection.Field)
		if err != nil {
			return nil, err
		}
		resolved, err := e.Resolve(partial, selection.Field)
		if err != nil {
			return nil, err
		}
		result = append(result, resolved)
	}
	return result, nil
}

func isSlice(value interface{}) bool {
	return reflect.TypeOf(value).Kind() == reflect.Slice
}

func (e *Executor) Resolve(partial interface{}, field *graphql.Field) (interface{}, error) {
	if isSlice(partial) {
		return e.resolveSlice(partial, field)
	}
	graphQLValue, ok := partial.(schema.GraphQLType)
	// if we have a scalar we're done
	if !ok {
		log.Printf("returning scalar %T: %v\n", partial, partial)
		return partial, nil
	}
	// check against returning object as non-leaf
	if len(field.Selections) == 0 {
		return nil, fmt.Errorf("Cannot return a '%T' as a leaf", graphQLValue)
	}

	result := map[string]interface{}{}
	typeInfo := schema.WithIntrospectionField(graphQLValue.GraphQLTypeInfo())
	for _, selection := range field.Selections {
		fieldName := selection.Field.Name
		fieldHandler, ok := typeInfo.Fields[fieldName]
		if !ok {
			return nil, fmt.Errorf("No handler for field '%s' on type '%T'", fieldName, graphQLValue)
		}
		partial, err := fieldHandler.Func(e, selection.Field)
		if err != nil {
			return nil, err // TODO(tmc) decorate error
		}
		resolved, err := e.Resolve(partial, selection.Field)
		if err != nil {
			return nil, err
		}
		result[fieldName] = resolved
	}
	return result, nil
}

func (e *Executor) resolveSlice(partials interface{}, field *graphql.Field) (interface{}, error) {
	v := reflect.ValueOf(partials)
	results := make([]interface{}, 0, v.Len())
	for i := 0; i < v.Len(); i++ {
		result, err := e.Resolve(v.Index(i).Interface(), field)
		if err != nil {
			return nil, err
		}
		results = append(results, result)
	}
	return results, nil
}
<commit_msg>fix nil partial case<commit_after>package executor

import (
	"fmt"
	"log"
	"reflect"

	"github.com/tmc/graphql"
	"github.com/tmc/graphql/schema"
)

type Executor struct {
	schema *schema.Schema
}

func New(schema *schema.Schema) *Executor {
	return &Executor{
		schema: schema,
	}
}

func (e *Executor) HandleOperation(o *graphql.Operation) (interface{}, error) {
	rootSelections := o.Selections
	rootCalls := e.schema.RootCalls()
	result := make([]interface{}, 0)

	for _, selection := range rootSelections {
		rootCallHandler, ok := rootCalls[selection.Field.Name]
		if !ok {
			return nil, fmt.Errorf("Root call '%s' is not registered", selection.Field.Name)
		}
		partial, err := rootCallHandler.Func(e, selection.Field)
		if err != nil {
			return nil, err
		}
		resolved, err := e.Resolve(partial, selection.Field)
		if err != nil {
			return nil, err
		}
		result = append(result, resolved)
	}
	return result, nil
}

func isSlice(value interface{}) bool {
	if value == nil {
		return false
	}
	return reflect.TypeOf(value).Kind() == reflect.Slice
}

func (e *Executor) Resolve(partial interface{}, field *graphql.Field) (interface{}, error) {
	if partial != nil && isSlice(partial) {
		return e.resolveSlice(partial, field)
	}
	graphQLValue, ok := partial.(schema.GraphQLType)
	// if we have a scalar we're done
	if !ok {
		log.Printf("returning scalar %T: %v\n", partial, partial)
		return partial, nil
	}
	// check against returning object as non-leaf
	if len(field.Selections) == 0 {
		return nil, fmt.Errorf("Cannot return a '%T' as a leaf", graphQLValue)
	}

	result := map[string]interface{}{}
	typeInfo := schema.WithIntrospectionField(graphQLValue.GraphQLTypeInfo())
	for _, selection := range field.Selections {
		fieldName := selection.Field.Name
		fieldHandler, ok := typeInfo.Fields[fieldName]
		if !ok {
			return nil, fmt.Errorf("No handler for field '%s' on type '%T'", fieldName, graphQLValue)
		}
		partial, err := fieldHandler.Func(e, selection.Field)
		if err != nil {
			return nil, err // TODO(tmc) decorate error
		}
		resolved, err := e.Resolve(partial, selection.Field)
		if err != nil {
			return nil, err
		}
		result[fieldName] = resolved
	}
	return result, nil
}

func (e *Executor) resolveSlice(partials interface{}, field *graphql.Field) (interface{}, error) {
	v := reflect.ValueOf(partials)
	results := make([]interface{}, 0, v.Len())
	for i := 0; i < v.Len(); i++ {
		result, err := e.Resolve(v.Index(i).Interface(), field)
		if err != nil {
			return nil, err
		}
		results = append(results, result)
	}
	return results, nil
}
<|endoftext|>