<commit_before>package cmd

import (
	"bufio"
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"unicode"
	"unicode/utf8"

	"github.com/PuerkitoBio/goquery"
	"github.com/fatih/color"
	"github.com/spf13/cobra"
	"golang.org/x/text/encoding/japanese"
	"golang.org/x/text/transform"
)

var (
	errColor   func(string, ...interface{}) string = color.HiYellowString
	countColor func(string, ...interface{}) string = color.HiYellowString
)

type exitCode int

const (
	normal exitCode = iota
	abnormal
)

func (c exitCode) Exit() {
	os.Exit(int(c))
}

func newRootCmd(newOut, newErr io.Writer, args []string) *cobra.Command {

	cmd := &cobra.Command{
		Use:           "kuroneko [flags] 伝票番号",
		Short:         "ヤマト運輸のステータス取得",
		SilenceErrors: true,
		SilenceUsage:  true,

		Args: func(cmd *cobra.Command, args []string) error {
			if len(args) > 1 {
				count := strconv.Itoa(len(args))
				return fmt.Errorf("accepts at most 1 arg(s), received %s", errColor(count))
			}

			if len(args) == 0 {
				return errors.New(errColor("伝票番号を入力してください"))
			}

			return nil
		},

		PreRunE: func(cmd *cobra.Command, args []string) error {
			flagCount := cmd.Flags().NFlag()
			if flagCount > 1 {
				count := strconv.Itoa(flagCount)
				return fmt.Errorf("accepte at most 1 flag(s), received %s", errColor(count))
			}

			serial, err := cmd.Flags().GetInt("serial")
			if err != nil {
				return err
			}

			if serial < 1 || serial > 10 {
				return errors.New(errColor("連番で取得できるのは 1~10件 までです"))
			}

			return nil
		},

		RunE: func(cmd *cobra.Command, args []string) error {
			trackingNumber := args[0]
			tracker := newTracker(cmd)
			return tracker.track(trackingNumber)
		},
	}

	cmd.Flags().IntP("serial", "s", 1, "連番取得(10件まで)")
	cmd.SetArgs(args)
	cmd.SetOut(newOut)
	cmd.SetErr(newErr)

	return cmd
}

func Execute(newOut, newErr io.Writer, args []string) exitCode {
	cmd := newRootCmd(newOut, newErr, args)
	if err := cmd.Execute(); err != nil {
		cmd.PrintErrf("Error: %+v\n", err)
		return abnormal
	}
	return normal
}

func init() {}

func makeSpace(count int) string {
	// 注:全角スペース
	s := "　"
	return strings.Repeat(s, count)
}

type tracker interface {
	track(s string) error
}

func newTracker(cmd *cobra.Command) tracker {
	flagCount := cmd.Flags().NFlag()
	switch flagCount {
	case 0:
		return &trackShipmentsOne{
			cmd: cmd,
		}
	default:
		// PreRunEでエラーチェック済み
		serial, _ := cmd.Flags().GetInt("serial")
		return &trackShipmentsMultiple{
			cmd:    cmd,
			serial: serial,
		}
	}
}

type trackShipmentsOne struct {
	cmd *cobra.Command
}

func (t *trackShipmentsOne) track(s string) error {
	values := url.Values{}
	values.Add("number00", "1")
	values.Add("number01", s)

	contactUrl := "http://toi.kuronekoyamato.co.jp/cgi-bin/tneko"
	resp, err := http.PostForm(contactUrl, values)
	if err != nil {
		return err
	}

	defer resp.Body.Close()

	utfBody := transform.NewReader(bufio.NewReader(resp.Body), japanese.ShiftJIS.NewDecoder())

	doc, err := goquery.NewDocumentFromReader(utfBody)
	if err != nil {
		return err
	}

	w := t.cmd.OutOrStdout()
	doc.Find(".saisin td").Each(func(_ int, args *goquery.Selection) {
		if args.HasClass("bold") || args.HasClass("font14") {
			text := args.Text()
			fmt.Fprintf(w, " %s\n", text)
		}
	})

	fmt.Fprintf(w, "\n")

	doc.Find(".meisai tr").Each(func(i int, args *goquery.Selection) {
		if i != 0 {
			information := args.Find("td").Map(func(_ int, s *goquery.Selection) string {
				text := s.Text()
				return text
			})
			detailInfo := information[1:6]
			statusLength := utf8.RuneCountInString(detailInfo[0])
			whitespace := 15 - statusLength
			space := makeSpace(whitespace)
			status := detailInfo[0] + space
			branchLength := utf8.RuneCountInString(detailInfo[3])
			whitespace = 20 - branchLength
			space = makeSpace(whitespace)
			branch := detailInfo[3] + space
			date, times, code := detailInfo[1], detailInfo[2], detailInfo[4]
			if date == "" {
				date = "     "
			}
			if times == "" {
				times = "     "
			}
			fmt.Fprintf(w, " %s| %s | %s | %s| %s |\n", status, date, times, branch, code)
		}
	})

	underLine := strings.Repeat("-", 99)
	fmt.Fprintf(w, "%s\n", underLine)

	return nil

}

type trackShipmentsMultiple struct {
	cmd    *cobra.Command
	serial int
}

func (t *trackShipmentsMultiple) track(s string) error {
	trackingNumber := removeHyphen(s)
	if !isInt(trackingNumber) {
		return fmt.Errorf("%s", errColor("不正な数値です"))
	}

	if !is12or11Digits(trackingNumber) {
		return fmt.Errorf("%s", errColor("12 or 11桁の伝票番号を入力してください"))
	}

	if !isCorrectNumber(trackingNumber) {
		return fmt.Errorf("%s", errColor("伝票番号に誤りがあります"))
	}

	ctx, cancel := context.WithCancel(context.Background())
	ch := sevenCheckCalculate(ctx, trackingNumber[:len(trackingNumber)-1])
	values := url.Values{}
	values.Add("number00", "1")

	var i int
	for i = 0; i < t.serial; i++ {
		querykey := fmt.Sprintf("number%02d", i+1)
		values.Add(querykey, <-ch)
	}
	cancel()

	contactUrl := "http://toi.kuronekoyamato.co.jp/cgi-bin/tneko"
	resp, err := http.PostForm(contactUrl, values)
	if err != nil {
		return err
	}

	defer resp.Body.Close()

	utfBody := transform.NewReader(bufio.NewReader(resp.Body), japanese.ShiftJIS.NewDecoder())

	doc, err := goquery.NewDocumentFromReader(utfBody)
	if err != nil {
		return err
	}

	w := t.cmd.OutOrStdout()
	doc.Find("center").Each(func(_ int, s *goquery.Selection) {
		hasDetail := false
		s.Find(".saisin td").Each(func(_ int, args *goquery.Selection) {
			if args.HasClass("number") {
				hasDetail = true
				subject := args.Text()
				fmt.Fprintf(w, " %s\n", countColor(subject))
			}

			if args.HasClass("bold") || args.HasClass("font14") {
				text := args.Text()
				fmt.Fprintf(w, " %s\n", text)
			}
		})

		if hasDetail {
			fmt.Fprintf(w, "\n")
		}

		s.Find(".meisai tr").Each(func(i int, args *goquery.Selection) {
			if i != 0 {
				information := args.Find("td").Map(func(_ int, s *goquery.Selection) string {
					text := s.Text()
					return text
				})
				detailInfo := information[1:6]
				statusLength := utf8.RuneCountInString(detailInfo[0])
				whitespace := 15 - statusLength
				space := makeSpace(whitespace)
				status := detailInfo[0] + space
				branchLength := utf8.RuneCountInString(detailInfo[3])
				whitespace = 20 - branchLength
				space = makeSpace(whitespace)
				branch := detailInfo[3] + space
				date, times, code := detailInfo[1], detailInfo[2], detailInfo[4]
				if date == "" {
					date = "     "
				}
				if times == "" {
					times = "     "
				}
				fmt.Fprintf(w, " %s| %s | %s | %s| %s |\n", status, date, times, branch, code)
			}
		})

		if hasDetail {
			underLine := strings.Repeat("-", 99)
			fmt.Fprintf(w, "%s\n", underLine)
		}
	})

	return nil
}

func removeHyphen(s string) string {
	if strings.Contains(s, "-") {
		removed := strings.Replace(s, "-", "", -1)
		return removed
	}
	return s
}

func sevenCheckCalculate(ctx context.Context, n string) <-chan string {
	ch := make(chan string)
	const coef = 7
	var format = "%012s"
	if len(n) == 10 {
		format = "%011s"
	}
	go func() {
		sign, _ := strconv.ParseInt(n, 10, 64)
	LOOP:
		for {
			select {
			case <-ctx.Done():
				break LOOP
			default:
				digit := sign % coef
				digitStr := strconv.FormatInt(digit, 10)
				trackingNumber := strconv.FormatInt(sign, 10) + digitStr
				zeroPaddingNumber := fmt.Sprintf(format, trackingNumber)
				ch <- zeroPaddingNumber
				sign++
			}
		}
		close(ch)
	}()
	return ch
}

func isCorrectNumber(s string) bool {
	const coef = 7
	lastDigits := s[len(s)-1:]
	otherDigits := s[:len(s)-1]
	sign, _ := strconv.ParseInt(otherDigits, 10, 64)
	digit := sign % coef
	return lastDigits == fmt.Sprint(digit)
}

func isInt(s string) bool {
	for _, c := range s {
		if !unicode.IsDigit(c) {
			return false
		}
	}
	return true
}

func is12or11Digits(s string) bool {
	if len(s) == 12 || len(s) == 11 {
		return true
	}
	return false
}
<commit_msg>refactor<commit_after>package cmd

import (
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"unicode"
	"unicode/utf8"

	"github.com/PuerkitoBio/goquery"
	"github.com/fatih/color"
	"github.com/spf13/cobra"
	"golang.org/x/text/encoding/japanese"
	"golang.org/x/text/transform"
)

var (
	errColor   func(string, ...interface{}) string = color.HiYellowString
	countColor func(string, ...interface{}) string = color.HiYellowString
)

type exitCode int

const (
	normal exitCode = iota
	abnormal
)

func (c exitCode) Exit() {
	os.Exit(int(c))
}

func newRootCmd(newOut, newErr io.Writer, args []string) *cobra.Command {

	cmd := &cobra.Command{
		Use:           "kuroneko [flags] 伝票番号",
		Short:         "ヤマト運輸のステータス取得",
		SilenceErrors: true,
		SilenceUsage:  true,

		Args: func(cmd *cobra.Command, args []string) error {
			if len(args) > 1 {
				count := strconv.Itoa(len(args))
				return fmt.Errorf("accepts at most 1 arg(s), received %s", errColor(count))
			}

			if len(args) == 0 {
				return errors.New(errColor("伝票番号を入力してください"))
			}

			return nil
		},

		PreRunE: func(cmd *cobra.Command, args []string) error {
			flagCount := cmd.Flags().NFlag()
			if flagCount > 1 {
				count := strconv.Itoa(flagCount)
				return fmt.Errorf("accepte at most 1 flag(s), received %s", errColor(count))
			}

			serial, err := cmd.Flags().GetInt("serial")
			if err != nil {
				return err
			}

			if serial < 1 || serial > 10 {
				return errors.New(errColor("連番で取得できるのは 1~10件 までです"))
			}

			return nil
		},

		RunE: func(cmd *cobra.Command, args []string) error {
			trackingNumber := args[0]
			tracker := newTracker(cmd)
			return tracker.track(trackingNumber)
		},
	}

	cmd.Flags().IntP("serial", "s", 1, "連番取得(10件まで)")
	cmd.SetArgs(args)
	cmd.SetOut(newOut)
	cmd.SetErr(newErr)

	return cmd
}

func Execute(newOut, newErr io.Writer, args []string) exitCode {
	cmd := newRootCmd(newOut, newErr, args)
	if err := cmd.Execute(); err != nil {
		cmd.PrintErrf("Error: %+v\n", err)
		return abnormal
	}
	return normal
}

func init() {}

func makeSpace(count int) string {
	// 注:全角スペース
	s := "　"
	return strings.Repeat(s, count)
}

type tracker interface {
	track(s string) error
}

func newTracker(cmd *cobra.Command) tracker {
	flagCount := cmd.Flags().NFlag()
	switch flagCount {
	case 0:
		return &trackShipmentsOne{
			cmd: cmd,
		}
	default:
		// PreRunEでエラーチェック済み
		serial, _ := cmd.Flags().GetInt("serial")
		return &trackShipmentsMultiple{
			cmd:    cmd,
			serial: serial,
		}
	}
}

type trackShipmentsOne struct {
	cmd *cobra.Command
}

func (t *trackShipmentsOne) track(s string) error {
	values := url.Values{}
	values.Add("number00", "1")
	values.Add("number01", s)

	contactUrl := "http://toi.kuronekoyamato.co.jp/cgi-bin/tneko"
	resp, err := http.PostForm(contactUrl, values)
	if err != nil {
		return err
	}

	defer resp.Body.Close()

	utfBody := transform.NewReader(resp.Body, japanese.ShiftJIS.NewDecoder())

	doc, err := goquery.NewDocumentFromReader(utfBody)
	if err != nil {
		return err
	}

	w := t.cmd.OutOrStdout()
	doc.Find(".saisin td").Each(func(_ int, args *goquery.Selection) {
		if args.HasClass("bold") || args.HasClass("font14") {
			text := args.Text()
			fmt.Fprintf(w, " %s\n", text)
		}
	})

	fmt.Fprintf(w, "\n")

	doc.Find(".meisai tr").Each(func(i int, args *goquery.Selection) {
		if i != 0 {
			information := args.Find("td").Map(func(_ int, s *goquery.Selection) string {
				text := s.Text()
				return text
			})
			detailInfo := information[1:6]
			statusLength := utf8.RuneCountInString(detailInfo[0])
			whitespace := 15 - statusLength
			space := makeSpace(whitespace)
			status := detailInfo[0] + space
			branchLength := utf8.RuneCountInString(detailInfo[3])
			whitespace = 20 - branchLength
			space = makeSpace(whitespace)
			branch := detailInfo[3] + space
			date, times, code := detailInfo[1], detailInfo[2], detailInfo[4]
			if date == "" {
				date = "     "
			}
			if times == "" {
				times = "     "
			}
			fmt.Fprintf(w, " %s| %s | %s | %s| %s |\n", status, date, times, branch, code)
		}
	})

	underLine := strings.Repeat("-", 99)
	fmt.Fprintf(w, "%s\n", underLine)

	return nil

}

type trackShipmentsMultiple struct {
	cmd    *cobra.Command
	serial int
}

func (t *trackShipmentsMultiple) track(s string) error {
	trackingNumber := removeHyphen(s)
	if !isInt(trackingNumber) {
		return fmt.Errorf("%s", errColor("不正な数値です"))
	}

	if !is12or11Digits(trackingNumber) {
		return fmt.Errorf("%s", errColor("12 or 11桁の伝票番号を入力してください"))
	}

	if !isCorrectNumber(trackingNumber) {
		return fmt.Errorf("%s", errColor("伝票番号に誤りがあります"))
	}

	ctx, cancel := context.WithCancel(context.Background())
	ch := sevenCheckCalculate(ctx, trackingNumber[:len(trackingNumber)-1])
	values := url.Values{}
	values.Add("number00", "1")

	var i int
	for i = 0; i < t.serial; i++ {
		querykey := fmt.Sprintf("number%02d", i+1)
		values.Add(querykey, <-ch)
	}
	cancel()

	contactUrl := "http://toi.kuronekoyamato.co.jp/cgi-bin/tneko"
	resp, err := http.PostForm(contactUrl, values)
	if err != nil {
		return err
	}

	defer resp.Body.Close()

	utfBody := transform.NewReader(resp.Body, japanese.ShiftJIS.NewDecoder())

	doc, err := goquery.NewDocumentFromReader(utfBody)
	if err != nil {
		return err
	}

	w := t.cmd.OutOrStdout()
	doc.Find("center").Each(func(_ int, s *goquery.Selection) {
		hasDetail := false
		s.Find(".saisin td").Each(func(_ int, args *goquery.Selection) {
			if args.HasClass("number") {
				hasDetail = true
				subject := args.Text()
				fmt.Fprintf(w, " %s\n", countColor(subject))
			}

			if args.HasClass("bold") || args.HasClass("font14") {
				text := args.Text()
				fmt.Fprintf(w, " %s\n", text)
			}
		})

		if hasDetail {
			fmt.Fprintf(w, "\n")
		}

		s.Find(".meisai tr").Each(func(i int, args *goquery.Selection) {
			if i != 0 {
				information := args.Find("td").Map(func(_ int, s *goquery.Selection) string {
					text := s.Text()
					return text
				})
				detailInfo := information[1:6]
				statusLength := utf8.RuneCountInString(detailInfo[0])
				whitespace := 15 - statusLength
				space := makeSpace(whitespace)
				status := detailInfo[0] + space
				branchLength := utf8.RuneCountInString(detailInfo[3])
				whitespace = 20 - branchLength
				space = makeSpace(whitespace)
				branch := detailInfo[3] + space
				date, times, code := detailInfo[1], detailInfo[2], detailInfo[4]
				if date == "" {
					date = "     "
				}
				if times == "" {
					times = "     "
				}
				fmt.Fprintf(w, " %s| %s | %s | %s| %s |\n", status, date, times, branch, code)
			}
		})

		if hasDetail {
			underLine := strings.Repeat("-", 99)
			fmt.Fprintf(w, "%s\n", underLine)
		}
	})

	return nil
}

func removeHyphen(s string) string {
	if strings.Contains(s, "-") {
		removed := strings.Replace(s, "-", "", -1)
		return removed
	}
	return s
}

func sevenCheckCalculate(ctx context.Context, n string) <-chan string {
	ch := make(chan string)
	const coef = 7
	var format = "%012s"
	if len(n) == 10 {
		format = "%011s"
	}
	go func() {
		sign, _ := strconv.ParseInt(n, 10, 64)
	LOOP:
		for {
			select {
			case <-ctx.Done():
				break LOOP
			default:
				digit := sign % coef
				digitStr := strconv.FormatInt(digit, 10)
				trackingNumber := strconv.FormatInt(sign, 10) + digitStr
				zeroPaddingNumber := fmt.Sprintf(format, trackingNumber)
				ch <- zeroPaddingNumber
				sign++
			}
		}
		close(ch)
	}()
	return ch
}

func isCorrectNumber(s string) bool {
	const coef = 7
	lastDigits := s[len(s)-1:]
	otherDigits := s[:len(s)-1]
	sign, _ := strconv.ParseInt(otherDigits, 10, 64)
	digit := sign % coef
	return lastDigits == fmt.Sprint(digit)
}

func isInt(s string) bool {
	for _, c := range s {
		if !unicode.IsDigit(c) {
			return false
		}
	}
	return true
}

func is12or11Digits(s string) bool {
	if len(s) == 12 || len(s) == 11 {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2018 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

// Package ir defines an intermediate representation (IR) for Rego.
//
// The IR specifies an imperative execution model for Rego policies similar to a
// query plan in traditional databases.
package ir

import (
	"fmt"
)

type (
	// Policy represents a planned policy query.
	Policy struct {
		Static Static
		Plan   Plan
	}

	// Static represents a static data segment that is indexed into by the policy.
	Static struct {
		Strings []StringConst
	}

	// Plan represents an ordered series of blocks to execute. All plans contain a
	// final block that returns indicating the plan result was undefined. Plan
	// execution stops when a block returns a value. Blocks are executed in-order.
	Plan struct {
		Blocks []Block
	}

	// Block represents an ordered sequence of statements to execute. Blocks are
	// executed until a return statement is encountered, a statement is undefined,
	// or there are no more statements. If all statements are defined but no return
	// statement is encountered, the block is undefined.
	Block struct {
		Stmts []Stmt
	}

	// Stmt represents an operation (e.g., comparison, loop, dot, etc.) to execute.
	Stmt interface {
	}

	// Local represents a plan-scoped variable.
	Local int

	// NullConst represents a null value.
	NullConst struct{}

	// BooleanConst represents a boolean value.
	BooleanConst struct {
		Value bool
	}

	// StringConst represents a string value.
	StringConst struct {
		Value string
	}

	// IntConst represents an integer constant.
	IntConst struct {
		Value int64
	}

	// FloatConst represents a floating-point constant.
	FloatConst struct {
		Value float64
	}
)

const (
	// Undefined represents an undefined return value. An undefined return value
	// indicates the policy did not return a definitive answer.
	Undefined int32 = iota

	// Defined represents a defined return value.
	Defined

	// Error indicates a runtime error occurred during evaluation.
	Error
)

const (
	// InputRaw refers to the local variable containing the address of the raw
	// (serialized) input data.
	InputRaw Local = 0

	// InputLen refers to the local variable containing the length of the raw input.
	InputLen Local = 1

	// Input refers to the local variable containing the address of the deserialized
	// input value.
	Input Local = 2
)

func (a Policy) String() string {
	return "Policy"
}

func (a Static) String() string {
	return fmt.Sprintf("Static (%d strings)", len(a.Strings))
}

func (a Plan) String() string {
	return fmt.Sprintf("Plan (%d blocks)", len(a.Blocks))
}

func (a Block) String() string {
	return fmt.Sprintf("Block (%d statements)", len(a.Stmts))
}

// Void is a marker indicating that a statement does not produce any output.
type Void struct{}

// ReturnStmt represents a return statement. Return statements halt execution of
// a plan with the given code.
type ReturnStmt struct {
	Void
	Code int32 // 32-bit integer for compatibility with languages like JavaScript.
}

// DotStmt represents a lookup operation on a value (e.g., array, object, etc.)
// The source of a DotStmt may be a scalar value in which case the statement
// will be undefined.
type DotStmt struct {
	Source Local
	Key    Local
	Target Local
}

// LoopStmt represents a loop operation on a composite value. The source of a
// LoopStmt may be a scalar in which case the statement will be undefined.
type LoopStmt struct {
	Void
	Source Local
	Key    Local
	Value  Local
	Cond   Local
	Block  Block
}

// AssignStmt represents an assignment of a local variable.
type AssignStmt struct {
	Void
	Value  interface{}
	Target Local
}

// MakeStringStmt constructs a local variable that refers to a string constant.
type MakeStringStmt struct {
	Index  int
	Target Local
}

// MakeBooleanStmt constructs a local variable that refers to a boolean value.
type MakeBooleanStmt struct {
	Value  bool
	Target Local
}

// MakeNumberIntStmt constructs a local variable that refers to an integer value.
type MakeNumberIntStmt struct {
	Value  int64
	Target Local
}

// EqualStmt represents an value-equality check of two local variables.
type EqualStmt struct {
	Void
	A Local
	B Local
}
<commit_msg>Remove unused Void marker struct<commit_after>// Copyright 2018 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

// Package ir defines an intermediate representation (IR) for Rego.
//
// The IR specifies an imperative execution model for Rego policies similar to a
// query plan in traditional databases.
package ir

import (
	"fmt"
)

type (
	// Policy represents a planned policy query.
	Policy struct {
		Static Static
		Plan   Plan
	}

	// Static represents a static data segment that is indexed into by the policy.
	Static struct {
		Strings []StringConst
	}

	// Plan represents an ordered series of blocks to execute. All plans contain a
	// final block that returns indicating the plan result was undefined. Plan
	// execution stops when a block returns a value. Blocks are executed in-order.
	Plan struct {
		Blocks []Block
	}

	// Block represents an ordered sequence of statements to execute. Blocks are
	// executed until a return statement is encountered, a statement is undefined,
	// or there are no more statements. If all statements are defined but no return
	// statement is encountered, the block is undefined.
	Block struct {
		Stmts []Stmt
	}

	// Stmt represents an operation (e.g., comparison, loop, dot, etc.) to execute.
	Stmt interface {
	}

	// Local represents a plan-scoped variable.
	Local int

	// NullConst represents a null value.
	NullConst struct{}

	// BooleanConst represents a boolean value.
	BooleanConst struct {
		Value bool
	}

	// StringConst represents a string value.
	StringConst struct {
		Value string
	}

	// IntConst represents an integer constant.
	IntConst struct {
		Value int64
	}

	// FloatConst represents a floating-point constant.
	FloatConst struct {
		Value float64
	}
)

const (
	// Undefined represents an undefined return value. An undefined return value
	// indicates the policy did not return a definitive answer.
	Undefined int32 = iota

	// Defined represents a defined return value.
	Defined

	// Error indicates a runtime error occurred during evaluation.
	Error
)

const (
	// InputRaw refers to the local variable containing the address of the raw
	// (serialized) input data.
	InputRaw Local = 0

	// InputLen refers to the local variable containing the length of the raw input.
	InputLen Local = 1

	// Input refers to the local variable containing the address of the deserialized
	// input value.
	Input Local = 2
)

func (a Policy) String() string {
	return "Policy"
}

func (a Static) String() string {
	return fmt.Sprintf("Static (%d strings)", len(a.Strings))
}

func (a Plan) String() string {
	return fmt.Sprintf("Plan (%d blocks)", len(a.Blocks))
}

func (a Block) String() string {
	return fmt.Sprintf("Block (%d statements)", len(a.Stmts))
}

// ReturnStmt represents a return statement. Return statements halt execution of
// a plan with the given code.
type ReturnStmt struct {
	Code int32 // 32-bit integer for compatibility with languages like JavaScript.
}

// DotStmt represents a lookup operation on a value (e.g., array, object, etc.)
// The source of a DotStmt may be a scalar value in which case the statement
// will be undefined.
type DotStmt struct {
	Source Local
	Key    Local
	Target Local
}

// LoopStmt represents a loop operation on a composite value. The source of a
// LoopStmt may be a scalar in which case the statement will be undefined.
type LoopStmt struct {
	Source Local
	Key    Local
	Value  Local
	Cond   Local
	Block  Block
}

// AssignStmt represents an assignment of a local variable.
type AssignStmt struct {
	Value  interface{}
	Target Local
}

// MakeStringStmt constructs a local variable that refers to a string constant.
type MakeStringStmt struct {
	Index  int
	Target Local
}

// MakeBooleanStmt constructs a local variable that refers to a boolean value.
type MakeBooleanStmt struct {
	Value  bool
	Target Local
}

// MakeNumberIntStmt constructs a local variable that refers to an integer value.
type MakeNumberIntStmt struct {
	Value  int64
	Target Local
}

// EqualStmt represents an value-equality check of two local variables.
type EqualStmt struct {
	A Local
	B Local
}
<|endoftext|>


<commit_before>// Package colorine provides a simple feature to print messages to console.
//
// A log line consists of a prefix and a message. The prefix is colored by its
// content (for example below, "create" is green, "exist" is blue, and "error"
// is red, and so on.) and the message is not colored.
//	$ your_program
//	    create path/to/file
//	     exist path/to/another/file
//	     error something went wrong!
//
// By default, no prefix color is defined. You must specify prefix-to-color
// mapping when you create a Logger. See the Logger's example.
package colorine

import (
	"fmt"

	"github.com/daviddengcn/go-colortext"
)

// A Logger handles the printing stuff. You can create one with NewLogger().
type Logger struct {
	// Prefix text colors.
	Prefixes Prefixes
	// Used when the prefix is not found in Prefixes.
	DefaultStyle TextStyle
}

// A TextStyle represents the style that strings are displayed with. Consists
// of a foreground and a background, each of which is one of the text color constants.
type TextStyle struct {
	Foreground textColor
	Background textColor
}

type textColor struct {
	Color  ct.Color
	Bright bool
}

// A Prefixes is a map of prefix string to TextStyle. Prefix strings of log lines are colored according to this mapping.
type Prefixes map[string]TextStyle

// Text color constants. Use these to build a TextStyle.
var (
	None = textColor{ct.None, false}

	Black   = textColor{ct.Black, false}
	Red     = textColor{ct.Red, false}
	Green   = textColor{ct.Green, false}
	Yellow  = textColor{ct.Yellow, false}
	Blue    = textColor{ct.Blue, false}
	Magenta = textColor{ct.Magenta, false}
	Cyan    = textColor{ct.Cyan, false}
	White   = textColor{ct.White, false}

	BrightBlack   = textColor{ct.Black, true}
	BrightRed     = textColor{ct.Red, true}
	BrightGreen   = textColor{ct.Green, true}
	BrightYellow  = textColor{ct.Yellow, true}
	BrightBlue    = textColor{ct.Blue, true}
	BrightMagenta = textColor{ct.Magenta, true}
	BrightCyan    = textColor{ct.Cyan, true}
	BrightWhite   = textColor{ct.White, true}
)

// Predefined TextStyles. Of course you can ignore these.
var (
	Verbose = TextStyle{White, None}
	Info    = TextStyle{Green, None}
	Notice  = TextStyle{Blue, None}
	Warn    = TextStyle{Yellow, None}
	Error   = TextStyle{Red, None}
)

// NewLogger creates a new Logger. prefixes is a prefix-string-to-text-style
// table. The log prefix is colored using this table. If no entry is found in
// prefixes, defaultStyle is used.
//
// By default, no prefix is registered to any text style.
func NewLogger(prefixes Prefixes, defaultStyle TextStyle) *Logger {
	return &Logger{prefixes, defaultStyle}
}

// Log prints messages to console. prefix is colored using the logger.prefixes
// table.
func (logger *Logger) Log(prefix, message string) {
	textColor, ok := logger.Prefixes[prefix]
	if !ok {
		textColor = logger.DefaultStyle
	}

	ct.ChangeColor(
		textColor.Foreground.Color,
		textColor.Foreground.Bright,
		textColor.Background.Color,
		textColor.Background.Bright,
	)

	fmt.Printf("%10s", prefix)

	ct.ResetColor()

	fmt.Printf(" %s\n", message)
}
<commit_msg>Use the empty string for default style<commit_after>// Package colorine provides a simple feature to print messages to console.
//
// A log line consists of a prefix and a message. The prefix is colored by its
// content (for example below, "create" is green, "exist" is blue, and "error"
// is red, and so on.) and the message is not colored.
//	$ your_program
//	    create path/to/file
//	     exist path/to/another/file
//	     error something went wrong!
//
// By default, no prefix color is defined. You must specify prefix-to-color
// mapping when you create a Logger. See the Logger's example.
package colorine

import (
	"fmt"

	"github.com/daviddengcn/go-colortext"
)

// A Logger handles the printing stuff. You can create one with NewLogger().
type Logger struct {
	// Prefix string to TextStyle mapping.
	Prefixes Prefixes
}

// A TextStyle represents the style that strings are displayed with. Consists
// of a foreground and a background, each of which is one of the text color constants.
type TextStyle struct {
	Foreground textColor
	Background textColor
}

type textColor struct {
	Color  ct.Color
	Bright bool
}

// A Prefixes is a map of prefix string to TextStyle. Prefix strings of log lines are colored according to this mapping.
// The TextStyle for an empty prefix ("") is used for default TextStyle.
type Prefixes map[string]TextStyle

// Text color constants. Use these to build a TextStyle.
var (
	None = textColor{ct.None, false}

	Black   = textColor{ct.Black, false}
	Red     = textColor{ct.Red, false}
	Green   = textColor{ct.Green, false}
	Yellow  = textColor{ct.Yellow, false}
	Blue    = textColor{ct.Blue, false}
	Magenta = textColor{ct.Magenta, false}
	Cyan    = textColor{ct.Cyan, false}
	White   = textColor{ct.White, false}

	BrightBlack   = textColor{ct.Black, true}
	BrightRed     = textColor{ct.Red, true}
	BrightGreen   = textColor{ct.Green, true}
	BrightYellow  = textColor{ct.Yellow, true}
	BrightBlue    = textColor{ct.Blue, true}
	BrightMagenta = textColor{ct.Magenta, true}
	BrightCyan    = textColor{ct.Cyan, true}
	BrightWhite   = textColor{ct.White, true}
)

// Predefined TextStyles. Of course you can ignore these.
var (
	Verbose = TextStyle{White, None}
	Info    = TextStyle{Green, None}
	Notice  = TextStyle{Blue, None}
	Warn    = TextStyle{Yellow, None}
	Error   = TextStyle{Red, None}
	Default = TextStyle{Green, None}
)

// NewLogger creates a new Logger. prefixes is a prefix-string-to-text-style
// mapping. The log prefix is colored using this table. If no entry is found in
// prefixes, defaultStyle is used.
//
// By default, no prefix is registered to any text style.
func NewLogger(prefixes Prefixes, defaultStyle TextStyle) *Logger {
	prefixes[""] = defaultStyle
	return &Logger{prefixes}
}

// Log prints messages to console. prefix is colored using the logger.prefixes
// table.
func (logger *Logger) Log(prefix, message string) {
	textStyle, ok := logger.Prefixes[prefix]
	if !ok {
		textStyle, ok = logger.Prefixes[""]
		if !ok {
			textStyle = Default
		}
	}

	ct.ChangeColor(
		textStyle.Foreground.Color,
		textStyle.Foreground.Bright,
		textStyle.Background.Color,
		textStyle.Background.Bright,
	)

	fmt.Printf("%10s", prefix)

	ct.ResetColor()

	fmt.Printf(" %s\n", message)
}
<|endoftext|>


<commit_before>package main

import (
	"eaciit/gdrj/model"
	"eaciit/gdrj/modules"
	"os"

	"strings"
	"time"

	"github.com/eaciit/dbox"
	"github.com/eaciit/orm/v1"
	"github.com/eaciit/toolkit"
)

var conn dbox.IConnection
var count int
var ratioTableName string

var (
	sourcetablename = "salespls-summary"
	calctablename   = "salespls-summary"
	desttablename   = "salespls-summary"
	t0              time.Time
	masters         = toolkit.M{}
	reforsrc        = "ref"
	trxsrc          = "COGSMATERIALADJUST"
	basefield       = "PL8A"
	allocfield      = "PL9"
)

type plalloc struct {
	ID                     string `bson:"_id" json:"_id"`
	Key                    string
	Txt1, Txt2, Txt3       string
	Ref1                   float64
	Current                float64
	Expect                 float64
	Absorbed               float64
	Ratio1, Ratio2, Ratio3 float64
}

type allocmap map[string]*plalloc

var (
	yrtotals = allocmap{}
	ratios   = allocmap{}
	totals   = map[string]float64{
		"2014-2015": -50041697769.24013,
		"2015-2016": -53588372484.758606,
	}
	miles = map[string][]*plalloc{
		"2014-2015": []*plalloc{},
		"2015-2016": []*plalloc{},
	}
)

func main() {
	setinitialconnection()
	conn.NewQuery().From(desttablename).
		Where(dbox.Eq("key.trxsrc", "nakulrd")).
		Delete().
		Exec(nil)

	prepmastercalc()
	buildratio()
	for _, v := range []string{"2015-2016", "2014-2015"} {
		processTable(v)
	}
}

func buildratio() {
	connratio, _ := modules.GetDboxIConnection("db_godrej")
	defer connratio.Close()

	/*
		    ftrx := &dbox.Filter{}
			if reforsrc == "ref" {
				ftrx = dbox.Eq("key.ref", trxsrc)
			} else {
				dbox.Eq("key.trxsrc", trxsrc)
			}
	*/

	csp, _ := connratio.NewQuery().From(calctablename).
		Where(dbox.Eq("key.customer_channelid", "I3"),
		dbox.Ne("key.customer_customergroup", "")).
		Select().Cursor(nil)
	defer csp.Close()

	i := 0
	count := csp.Count()
	t0 := time.Now()
	mstone := 0

	for {
		mr := toolkit.M{}
		if ef := csp.Fetch(&mr, 1, false); ef != nil {
			break
		}
		i++
		makeProgressLog("Disc, SPG & Promo by KA Ratio", i, count, 5, &mstone, t0)
		key := mr.Get("key", toolkit.M{}).(toolkit.M)
		fiscal := key.GetString("fiscal")
		ka := key.GetString("customer_customergroup")
		name := key.GetString("customer_customergroupname")
		if ka != "" {
			basevalue := mr.GetFloat64(basefield)
			keyratio := fiscal + "_" + ka + "_" + name
			adjustAllocs(&ratios, keyratio, 0, 0, 0, basevalue)
			adjustAllocs(&yrtotals, fiscal, 0, 0, 0, basevalue)
		}
	}

	for k, v := range ratios {
		kts := strings.Split(k, "_")
		fiscal := kts[0]
		v.Txt1 = kts[1]
		v.Txt2 = kts[2]
		v.Ratio1 = toolkit.Div(v.Ref1, yrtotals[kts[0]].Ref1)
		v.Expect = v.Ratio1 * totals[fiscal]

		miles[fiscal] = append(miles[fiscal], v)
	}
	toolkit.Printfn("Ratio: %s", toolkit.JsonString(miles))
}

func processTable(fiscal string) {
	connsave, _ := modules.GetDboxIConnection("db_godrej")
	defer connsave.Close()
	qsave := connsave.NewQuery().SetConfig("multiexec", true).From(desttablename).Save()

	connselect, _ := modules.GetDboxIConnection("db_godrej")
	defer connselect.Close()

	cursor, _ := connselect.NewQuery().
		From(calctablename).
		Where(dbox.Eq("key.date_fiscal", fiscal),
		dbox.Eq("key.ref", trxsrc),
		dbox.Eq("key.customer_channelid", "I3")).
		Select().Cursor(nil)
	defer cursor.Close()

	allocs := miles[fiscal]
	allocidx := 0

	absorbed := float64(0)
	group := allocs[0].Txt1
	groupname := allocs[1].Txt2

	i := 0
	count := cursor.Count()
	mstone := 0
	t0 = time.Now()
	for {
		mr := toolkit.M{}
		e := cursor.Fetch(&mr, 1, false)
		if e != nil || i >= count {
			break
		}
		i++
		makeProgressLog("Processing", i, count, 5, &mstone, t0)

		key := mr.Get("key", toolkit.M{}).(toolkit.M)
		key.Set("customer_customergroup", group)
		key.Set("customer_customergroupname", groupname)
		mr.Set("key", key)

		gdrj.CalcSum(mr, masters)
		esave := qsave.Exec(toolkit.M{}.Set("data", mr))
		if esave != nil {
			toolkit.Printfn("Erorr: %s", esave.Error())
			os.Exit(100)
		}

		allocv := mr.GetFloat64(allocfield)
		absorbed += allocv

		if absorbed <= allocs[allocidx].Expect {
			allocidx++
			if allocidx >= len(allocs) {
				allocidx = 0
			}
			absorbed = float64(0)
			group = allocs[0].Txt1
			groupname = allocs[1].Txt2
		}
	}
}

func adjustAllocs(allocsmap *allocmap, key string, current, expect, absorbed, ref1 float64) {
	allocs := *allocsmap
	alloc := allocs[key]
	if alloc == nil {
		alloc = new(plalloc)
		alloc.Key = key
		alloc.ID = key
	}
	alloc.Current += current
	alloc.Expect += expect
	alloc.Ref1 += ref1
	alloc.Absorbed += absorbed
	allocs[key] = alloc
	*allocsmap = allocs
}

func makeProgressLog(reference string, i, count, step int, current *int, tstart time.Time) int {
	perstep := count * step / 100
	icurrent := *current
	if icurrent == 0 {
		icurrent = perstep
	}
	pct := i * 100 / count
	if i >= icurrent {
		toolkit.Printfn("%s, %d of %d [%d pct] in %s",
			reference, i, count, pct, time.Since(tstart).String())
		icurrent += perstep
	}
	*current = icurrent
	return icurrent
}

func isPL(id string) bool {
	if strings.HasPrefix(id, "PL7A") ||
		//strings.HasPrefix(id, "PL28") ||
		strings.HasPrefix(id, "PL29A") ||
		strings.HasPrefix(id, "PL31") {
		return true
	}
	return false
}

func buildmap(holder interface{},
	fnModel func() orm.IModel,
	filter *dbox.Filter,
	fnIter func(holder interface{}, obj interface{})) interface{} {
	crx, ecrx := gdrj.Find(fnModel(), filter, nil)
	if ecrx != nil {
		toolkit.Printfn("Cursor Error: %s", ecrx.Error())
		os.Exit(100)
	}
	defer crx.Close()
	for {
		s := fnModel()
		e := crx.Fetch(s, 1, false)
		if e != nil {
			break
		}
		fnIter(holder, s)
	}
	return holder
}

func prepmastercalc() {
	toolkit.Println("--> PL MODEL")
	masters.Set("plmodel", buildmap(map[string]*gdrj.PLModel{},
		func() orm.IModel {
			return new(gdrj.PLModel)
		},
		nil,
		func(holder, obj interface{}) {
			h := holder.(map[string]*gdrj.PLModel)
			o := obj.(*gdrj.PLModel)
			h[o.ID] = o
		}).(map[string]*gdrj.PLModel))
}

func setinitialconnection() {
	var err error
	conn, err = modules.GetDboxIConnection("db_godrej")

	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}

	err = gdrj.SetDb(conn)
	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}
}
<commit_msg>fisal<commit_after>package main

import (
	"eaciit/gdrj/model"
	"eaciit/gdrj/modules"
	"os"

	"strings"
	"time"

	"github.com/eaciit/dbox"
	"github.com/eaciit/orm/v1"
	"github.com/eaciit/toolkit"
)

var conn dbox.IConnection
var count int
var ratioTableName string

var (
	sourcetablename = "salespls-summary"
	calctablename   = "salespls-summary"
	desttablename   = "salespls-summary"
	t0              time.Time
	masters         = toolkit.M{}
	reforsrc        = "ref"
	trxsrc          = "COGSMATERIALADJUST"
	basefield       = "PL8A"
	allocfield      = "PL9"
)

type plalloc struct {
	ID                     string `bson:"_id" json:"_id"`
	Key                    string
	Txt1, Txt2, Txt3       string
	Ref1                   float64
	Current                float64
	Expect                 float64
	Absorbed               float64
	Ratio1, Ratio2, Ratio3 float64
}

type allocmap map[string]*plalloc

var (
	yrtotals = allocmap{}
	ratios   = allocmap{}
	totals   = map[string]float64{
		"2014-2015": -50041697769.24013,
		"2015-2016": -53588372484.758606,
	}
	miles = map[string][]*plalloc{
		"2014-2015": []*plalloc{},
		"2015-2016": []*plalloc{},
	}
)

func main() {
	setinitialconnection()
	conn.NewQuery().From(desttablename).
		Where(dbox.Eq("key.trxsrc", "nakulrd")).
		Delete().
		Exec(nil)

	prepmastercalc()
	buildratio()
	for _, v := range []string{"2015-2016", "2014-2015"} {
		processTable(v)
	}
}

func buildratio() {
	connratio, _ := modules.GetDboxIConnection("db_godrej")
	defer connratio.Close()

	/*
		    ftrx := &dbox.Filter{}
			if reforsrc == "ref" {
				ftrx = dbox.Eq("key.ref", trxsrc)
			} else {
				dbox.Eq("key.trxsrc", trxsrc)
			}
	*/

	csp, _ := connratio.NewQuery().From(calctablename).
		Where(dbox.Eq("key.customer_channelid", "I3"),
		dbox.Ne("key.customer_customergroup", "")).
		Select().Cursor(nil)
	defer csp.Close()

	i := 0
	count := csp.Count()
	t0 := time.Now()
	mstone := 0

	for {
		mr := toolkit.M{}
		if ef := csp.Fetch(&mr, 1, false); ef != nil {
			break
		}
		i++
		makeProgressLog("Disc, SPG & Promo by KA Ratio", i, count, 5, &mstone, t0)
		key := mr.Get("key", toolkit.M{}).(toolkit.M)
		fiscal := key.GetString("date_fiscal")
		ka := key.GetString("customer_customergroup")
		name := key.GetString("customer_customergroupname")
		if ka != "" {
			basevalue := mr.GetFloat64(basefield)
			keyratio := fiscal + "_" + ka + "_" + name
			adjustAllocs(&ratios, keyratio, 0, 0, 0, basevalue)
			adjustAllocs(&yrtotals, fiscal, 0, 0, 0, basevalue)
		}
	}

	for k, v := range ratios {
		kts := strings.Split(k, "_")
		fiscal := kts[0]
		v.Txt1 = kts[1]
		v.Txt2 = kts[2]
		v.Ratio1 = toolkit.Div(v.Ref1, yrtotals[kts[0]].Ref1)
		v.Expect = v.Ratio1 * totals[fiscal]

		miles[fiscal] = append(miles[fiscal], v)
	}
	toolkit.Printfn("Ratio: %s", toolkit.JsonString(miles))
}

func processTable(fiscal string) {
	connsave, _ := modules.GetDboxIConnection("db_godrej")
	defer connsave.Close()
	qsave := connsave.NewQuery().SetConfig("multiexec", true).From(desttablename).Save()

	connselect, _ := modules.GetDboxIConnection("db_godrej")
	defer connselect.Close()

	cursor, _ := connselect.NewQuery().
		From(calctablename).
		Where(dbox.Eq("key.date_fiscal", fiscal),
		dbox.Eq("key.ref", trxsrc),
		dbox.Eq("key.customer_channelid", "I3")).
		Select().Cursor(nil)
	defer cursor.Close()

	allocs := miles[fiscal]
	allocidx := 0

	absorbed := float64(0)
	group := allocs[0].Txt1
	groupname := allocs[1].Txt2

	i := 0
	count := cursor.Count()
	mstone := 0
	t0 = time.Now()
	for {
		mr := toolkit.M{}
		e := cursor.Fetch(&mr, 1, false)
		if e != nil || i >= count {
			break
		}
		i++
		makeProgressLog("Processing", i, count, 5, &mstone, t0)

		key := mr.Get("key", toolkit.M{}).(toolkit.M)
		key.Set("customer_customergroup", group)
		key.Set("customer_customergroupname", groupname)
		mr.Set("key", key)

		gdrj.CalcSum(mr, masters)
		esave := qsave.Exec(toolkit.M{}.Set("data", mr))
		if esave != nil {
			toolkit.Printfn("Erorr: %s", esave.Error())
			os.Exit(100)
		}

		allocv := mr.GetFloat64(allocfield)
		absorbed += allocv

		if absorbed <= allocs[allocidx].Expect {
			allocidx++
			if allocidx >= len(allocs) {
				allocidx = 0
			}
			absorbed = float64(0)
			group = allocs[0].Txt1
			groupname = allocs[1].Txt2
		}
	}
}

func adjustAllocs(allocsmap *allocmap, key string, current, expect, absorbed, ref1 float64) {
	allocs := *allocsmap
	alloc := allocs[key]
	if alloc == nil {
		alloc = new(plalloc)
		alloc.Key = key
		alloc.ID = key
	}
	alloc.Current += current
	alloc.Expect += expect
	alloc.Ref1 += ref1
	alloc.Absorbed += absorbed
	allocs[key] = alloc
	*allocsmap = allocs
}

func makeProgressLog(reference string, i, count, step int, current *int, tstart time.Time) int {
	perstep := count * step / 100
	icurrent := *current
	if icurrent == 0 {
		icurrent = perstep
	}
	pct := i * 100 / count
	if i >= icurrent {
		toolkit.Printfn("%s, %d of %d [%d pct] in %s",
			reference, i, count, pct, time.Since(tstart).String())
		icurrent += perstep
	}
	*current = icurrent
	return icurrent
}

func isPL(id string) bool {
	if strings.HasPrefix(id, "PL7A") ||
		//strings.HasPrefix(id, "PL28") ||
		strings.HasPrefix(id, "PL29A") ||
		strings.HasPrefix(id, "PL31") {
		return true
	}
	return false
}

func buildmap(holder interface{},
	fnModel func() orm.IModel,
	filter *dbox.Filter,
	fnIter func(holder interface{}, obj interface{})) interface{} {
	crx, ecrx := gdrj.Find(fnModel(), filter, nil)
	if ecrx != nil {
		toolkit.Printfn("Cursor Error: %s", ecrx.Error())
		os.Exit(100)
	}
	defer crx.Close()
	for {
		s := fnModel()
		e := crx.Fetch(s, 1, false)
		if e != nil {
			break
		}
		fnIter(holder, s)
	}
	return holder
}

func prepmastercalc() {
	toolkit.Println("--> PL MODEL")
	masters.Set("plmodel", buildmap(map[string]*gdrj.PLModel{},
		func() orm.IModel {
			return new(gdrj.PLModel)
		},
		nil,
		func(holder, obj interface{}) {
			h := holder.(map[string]*gdrj.PLModel)
			o := obj.(*gdrj.PLModel)
			h[o.ID] = o
		}).(map[string]*gdrj.PLModel))
}

func setinitialconnection() {
	var err error
	conn, err = modules.GetDboxIConnection("db_godrej")

	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}

	err = gdrj.SetDb(conn)
	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"

	"github.com/Syfaro/telegram-bot-api"
)

// Ctx - context for bot command function (users, command, args, ...)
type Ctx struct {
	bot         *tgbotapi.BotAPI
	appConfig   Config   // configuration
	commands    Commands // all chat commands
	users       Users    // all users
	userID      int      // current user
	allowExec   bool     // is user authorized
	messageCmd  string   // command name
	messageArgs string   // command arguments
}

// /auth and /authroot - authorize users
func cmdAuth(ctx Ctx) (replayMsg string) {
	forRoot := ctx.messageCmd == "/authroot"

	if ctx.messageArgs == "" {

		replayMsg = "See code in terminal with shell2telegram or ask code from root user and type:\n" + ctx.messageCmd + " code"
		authCode := ctx.users.DoLogin(ctx.userID, forRoot)

		rootRoleStr := ""
		if forRoot {
			rootRoleStr = "root "
		}
		secretCodeMsg := fmt.Sprintf("Request %saccess for %s. Code: %s\n", rootRoleStr, ctx.users.String(ctx.userID), authCode)
		fmt.Print(secretCodeMsg)
		ctx.users.broadcastForRoots(ctx.bot, secretCodeMsg)

	} else {
		if ctx.users.IsValidCode(ctx.userID, ctx.messageArgs, forRoot) {
			ctx.users.list[ctx.userID].IsAuthorized = true
			if forRoot {
				ctx.users.list[ctx.userID].IsRoot = true
				replayMsg = fmt.Sprintf("You (%s) authorized as root.", ctx.users.String(ctx.userID))
				log.Print("root authorized: ", ctx.users.String(ctx.userID))
			} else {
				replayMsg = fmt.Sprintf("You (%s) authorized.", ctx.users.String(ctx.userID))
				log.Print("authorized: ", ctx.users.String(ctx.userID))
			}
		} else {
			replayMsg = fmt.Sprintf("Code is not valid.")
		}
	}

	return replayMsg
}

// /help
func cmdHelp(ctx Ctx) (replayMsg string) {
	helpMsg := []string{
		"/auth [code] → authorize user",
		"/authroot [code] → authorize user as root",
	}

	if ctx.allowExec {
		for cmd, shellCmd := range ctx.commands {
			helpMsg = append(helpMsg, cmd+" → "+shellCmd)
		}
		if ctx.users.IsRoot(ctx.userID) {
			helpMsg = append(helpMsg,
				"/shell2telegram stat → get stat about users",
				"/shell2telegram ban <user_id|username> → ban user")
			if ctx.appConfig.addExit {
				helpMsg = append(helpMsg, "/shell2telegram exit → terminate bot")
			}
		}
	}

	helpMsg = append(helpMsg, "/shell2telegram version → show version")

	if ctx.appConfig.description != "" {
		replayMsg = ctx.appConfig.description
	} else {
		replayMsg = "This bot created with shell2telegram"
	}
	replayMsg += "\n\n" +
		"available commands:\n" +
		strings.Join(helpMsg, "\n")

	return replayMsg
}

// /shell2telegram stat
func cmdShell2telegramStat(ctx Ctx) (replayMsg string) {
	for userID, user := range ctx.users.list {
		replayMsg += fmt.Sprintf("%s: id: %d, auth: %v, root: %v, count: %d, last: %v\n",
			ctx.users.String(userID),
			userID,
			user.IsAuthorized,
			user.IsRoot,
			user.Counter,
			user.LastAccessTime.Format("2006-01-02 15:04:05"),
		)
	}

	return replayMsg
}

// /shell2telegram ban
func cmdShell2telegramBan(ctx Ctx) (replayMsg string) {
	_, userName := splitStringHalfBySpace(ctx.messageArgs)

	if userName == "" {
		return "Please set user_id or login"
	}

	userID, err := strconv.Atoi(userName)
	if err != nil {
		userName = regexp.MustCompile("@").ReplaceAllLiteralString(userName, "")
		userID = ctx.users.getUserIDByName(userName)
	}

	if userID > 0 && ctx.users.banUser(userID) {
		replayMsg = fmt.Sprintf("User %s banned", ctx.users.String(userID))
	} else {
		replayMsg = "User not found"
	}

	return replayMsg
}

// all commands from command-line
func cmdUser(ctx Ctx) (replayMsg string) {
	if cmd, found := ctx.commands[ctx.messageCmd]; found {

		shell, params := "sh", []string{"-c", cmd}
		osExecCommand := exec.Command(shell, params...)
		osExecCommand.Stderr = os.Stderr

		// write all arguments to STDIN
		if ctx.messageArgs != "" {
			stdin, err := osExecCommand.StdinPipe()
			if err == nil {
				io.WriteString(stdin, ctx.messageArgs)
				stdin.Close()
			} else {
				log.Print("get STDIN error: ", err)
			}
		}

		shellOut, err := osExecCommand.Output()
		if err != nil {
			log.Print("exec error: ", err)
			replayMsg = fmt.Sprintf("exec error: %s", err)
		} else {
			replayMsg = string(shellOut)
		}
	}

	return replayMsg
}
<commit_msg>Reformat /help out<commit_after>package main

import (
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"

	"github.com/Syfaro/telegram-bot-api"
)

// Ctx - context for bot command function (users, command, args, ...)
type Ctx struct {
	bot         *tgbotapi.BotAPI
	appConfig   Config   // configuration
	commands    Commands // all chat commands
	users       Users    // all users
	userID      int      // current user
	allowExec   bool     // is user authorized
	messageCmd  string   // command name
	messageArgs string   // command arguments
}

// /auth and /authroot - authorize users
func cmdAuth(ctx Ctx) (replayMsg string) {
	forRoot := ctx.messageCmd == "/authroot"

	if ctx.messageArgs == "" {

		replayMsg = "See code in terminal with shell2telegram or ask code from root user and type:\n" + ctx.messageCmd + " code"
		authCode := ctx.users.DoLogin(ctx.userID, forRoot)

		rootRoleStr := ""
		if forRoot {
			rootRoleStr = "root "
		}
		secretCodeMsg := fmt.Sprintf("Request %saccess for %s. Code: %s\n", rootRoleStr, ctx.users.String(ctx.userID), authCode)
		fmt.Print(secretCodeMsg)
		ctx.users.broadcastForRoots(ctx.bot, secretCodeMsg)

	} else {
		if ctx.users.IsValidCode(ctx.userID, ctx.messageArgs, forRoot) {
			ctx.users.list[ctx.userID].IsAuthorized = true
			if forRoot {
				ctx.users.list[ctx.userID].IsRoot = true
				replayMsg = fmt.Sprintf("You (%s) authorized as root.", ctx.users.String(ctx.userID))
				log.Print("root authorized: ", ctx.users.String(ctx.userID))
			} else {
				replayMsg = fmt.Sprintf("You (%s) authorized.", ctx.users.String(ctx.userID))
				log.Print("authorized: ", ctx.users.String(ctx.userID))
			}
		} else {
			replayMsg = fmt.Sprintf("Code is not valid.")
		}
	}

	return replayMsg
}

// /help
func cmdHelp(ctx Ctx) (replayMsg string) {
	helpMsg := []string{}

	if ctx.allowExec {
		for cmd, shellCmd := range ctx.commands {
			helpMsg = append(helpMsg, cmd+" → "+shellCmd)
		}
		helpMsg = append(helpMsg,
			"/auth [code] → authorize user",
			"/authroot [code] → authorize user as root",
		)
		if ctx.users.IsRoot(ctx.userID) {
			helpMsg = append(helpMsg,
				"/shell2telegram stat → get stat about users",
				"/shell2telegram ban <user_id|username> → ban user",
			)
			if ctx.appConfig.addExit {
				helpMsg = append(helpMsg, "/shell2telegram exit → terminate bot")
			}
		}
	}

	helpMsg = append(helpMsg, "/shell2telegram version → show version")

	if ctx.appConfig.description != "" {
		replayMsg = ctx.appConfig.description
	} else {
		replayMsg = "This bot created with shell2telegram"
	}
	replayMsg += "\n\n" +
		"available commands:\n" +
		strings.Join(helpMsg, "\n")

	return replayMsg
}

// /shell2telegram stat
func cmdShell2telegramStat(ctx Ctx) (replayMsg string) {
	for userID, user := range ctx.users.list {
		replayMsg += fmt.Sprintf("%s: id: %d, auth: %v, root: %v, count: %d, last: %v\n",
			ctx.users.String(userID),
			userID,
			user.IsAuthorized,
			user.IsRoot,
			user.Counter,
			user.LastAccessTime.Format("2006-01-02 15:04:05"),
		)
	}

	return replayMsg
}

// /shell2telegram ban
func cmdShell2telegramBan(ctx Ctx) (replayMsg string) {
	_, userName := splitStringHalfBySpace(ctx.messageArgs)

	if userName == "" {
		return "Please set user_id or login"
	}

	userID, err := strconv.Atoi(userName)
	if err != nil {
		userName = regexp.MustCompile("@").ReplaceAllLiteralString(userName, "")
		userID = ctx.users.getUserIDByName(userName)
	}

	if userID > 0 && ctx.users.banUser(userID) {
		replayMsg = fmt.Sprintf("User %s banned", ctx.users.String(userID))
	} else {
		replayMsg = "User not found"
	}

	return replayMsg
}

// all commands from command-line
func cmdUser(ctx Ctx) (replayMsg string) {
	if cmd, found := ctx.commands[ctx.messageCmd]; found {

		shell, params := "sh", []string{"-c", cmd}
		osExecCommand := exec.Command(shell, params...)
		osExecCommand.Stderr = os.Stderr

		// write all arguments to STDIN
		if ctx.messageArgs != "" {
			stdin, err := osExecCommand.StdinPipe()
			if err == nil {
				io.WriteString(stdin, ctx.messageArgs)
				stdin.Close()
			} else {
				log.Print("get STDIN error: ", err)
			}
		}

		shellOut, err := osExecCommand.Output()
		if err != nil {
			log.Print("exec error: ", err)
			replayMsg = fmt.Sprintf("exec error: %s", err)
		} else {
			replayMsg = string(shellOut)
		}
	}

	return replayMsg
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/fzzy/radix/redis"
	"math/rand"
	"os/exec"
	"strings"
)

var cmdDb *redis.Client

//used for calling functions using string variable contents
type command func(chan string, string, string, string, []string)

func initMap() map[string]command {
	return map[string]command{
		"source":   command(source),
		"botsnack": command(botsnack),
		"register": command(register),
		"uptime":   command(uptime),
		"web":      command(web),
		"login":    command(login),
		"verify":   command(verify),
		"verified": command(verified),
		"help":     command(help),
		"commands": command(commands),
		"kick":     command(kick),
	}
}

func initCmdRedis() {
	cmdDb, _ = redis.Dial("tcp", "127.0.0.1:6379")
}

func source(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :https://github.com/heydabop/yaircb"
	fmt.Println(message)
	srvChan <- message
}

func botsnack(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :Kisses commend. Perplexities deprave."
	fmt.Println(message)
	srvChan <- message
}

func register(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :https://anex.us/register/"
	fmt.Println(message)
	srvChan <- message
}

func uptime(srvChan chan string, channel, nick, hostname string, args []string) {
	out, err := exec.Command("uptime").Output()
	message := "PRIVMSG " + channel + " :" + strings.TrimSpace(string(out))
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(message)
	srvChan <- message
}

func web(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :https://anex.us/"
	fmt.Println(message)
	srvChan <- message
}

func login(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :https://anex.us/login/"
	fmt.Println(message)
	srvChan <- message
}

func verify(srvChan chan string, channel, nick, hostname string, args []string) {
	var message string
	if len(args) != 2 {
		message = "PRIVMSG " + channel + " :ERROR: Invalid number of arguments"
	} else {
		uname := args[0]
		pin := args[1]
		reply := cmdDb.Cmd("get", uname+"Pin")
		pinDb, _ := (reply.Bytes())
		if string(pinDb) == pin {
			message = "PRIVMSG " + channel + " :You are now verified as " + uname
			cmdDb.Cmd("set", uname+"Host", hostname)
			cmdDb.Cmd("set", uname+"Pin", fmt.Sprintf("%06d", rand.Intn(1000000)))
		} else {
			message = "PRIVMSG " + channel + " :PIN does not match that of " + uname
		}
	}
	fmt.Println(message)
	srvChan <- message
}

func verified(srvChan chan string, channel, nick, hostname string, args []string) {
	var message string
	if len(args) != 1 {
		message = "PRIVMSG " + channel + " :ERROR: Invalid number of arguments"
	} else {
		uname := args[0]
		reply := cmdDb.Cmd("get", uname+"Host")
		hostnameDb, _ := reply.Bytes()
		if hostname == string(hostnameDb) {
			message = "PRIVMSG " + channel + " :You are " + uname + " at " + hostname
		} else {
			message = "PRIVMSG " + channel + " :You are not " + uname
		}
	}
	fmt.Println(message)
	srvChan <- message
}

func help(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :8)"
	fmt.Println(message)
	srvChan <- message
}

func commands(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :"
	for command := range funcMap {
		message += command + " "
	}
	fmt.Println(message)
	srvChan <- message
}

func kick(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "KICK " + channel + " " + nick + " :You don't tell me what to do."
	fmt.Println(message)
	srvChan <- message

	message = "KICK " + channel
	if len(args) < 1 {
		message = "PRIVMSG " + channel + " :ERROR: Invalid number of arguments"
	} else {
		if args[0] == config.Nick {
			return
		}
		message += " " + args[0]
	}
	if len(args) >= 2 {
		message += " :" + strings.Join(args[1:], " ")
	}
	fmt.Println(message)
	srvChan <- message
}
<commit_msg>added wc command<commit_after>package main

import (
	"fmt"
	"github.com/fzzy/radix/redis"
	"math/rand"
	"os"
	"os/exec"
	"regexp"
	"strings"
)

var cmdDb *redis.Client

//used for calling functions using string variable contents
type command func(chan string, string, string, string, []string)

func initMap() map[string]command {
	return map[string]command{
		"source":   command(source),
		"botsnack": command(botsnack),
		"register": command(register),
		"uptime":   command(uptime),
		"web":      command(web),
		"login":    command(login),
		"verify":   command(verify),
		"verified": command(verified),
		"help":     command(help),
		"commands": command(commands),
		"kick":     command(kick),
		"wc":       command(wc),
	}
}

func initCmdRedis() {
	cmdDb, _ = redis.Dial("tcp", "127.0.0.1:6379")
}

func source(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :https://github.com/heydabop/yaircb"
	fmt.Println(message)
	srvChan <- message
}

func botsnack(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :Kisses commend. Perplexities deprave."
	fmt.Println(message)
	srvChan <- message
}

func register(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :https://anex.us/register/"
	fmt.Println(message)
	srvChan <- message
}

func uptime(srvChan chan string, channel, nick, hostname string, args []string) {
	out, err := exec.Command("uptime").Output()
	message := "PRIVMSG " + channel + " :" + strings.TrimSpace(string(out))
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(message)
	srvChan <- message
}

func web(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :https://anex.us/"
	fmt.Println(message)
	srvChan <- message
}

func login(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :https://anex.us/login/"
	fmt.Println(message)
	srvChan <- message
}

func verify(srvChan chan string, channel, nick, hostname string, args []string) {
	var message string
	if len(args) != 2 {
		message = "PRIVMSG " + channel + " :ERROR: Invalid number of arguments"
	} else {
		uname := args[0]
		pin := args[1]
		reply := cmdDb.Cmd("get", uname+"Pin")
		pinDb, _ := (reply.Bytes())
		if string(pinDb) == pin {
			message = "PRIVMSG " + channel + " :You are now verified as " + uname
			cmdDb.Cmd("set", uname+"Host", hostname)
			cmdDb.Cmd("set", uname+"Pin", fmt.Sprintf("%06d", rand.Intn(1000000)))
		} else {
			message = "PRIVMSG " + channel + " :PIN does not match that of " + uname
		}
	}
	fmt.Println(message)
	srvChan <- message
}

func verified(srvChan chan string, channel, nick, hostname string, args []string) {
	var message string
	if len(args) != 1 {
		message = "PRIVMSG " + channel + " :ERROR: Invalid number of arguments"
	} else {
		uname := args[0]
		reply := cmdDb.Cmd("get", uname+"Host")
		hostnameDb, _ := reply.Bytes()
		if hostname == string(hostnameDb) {
			message = "PRIVMSG " + channel + " :You are " + uname + " at " + hostname
		} else {
			message = "PRIVMSG " + channel + " :You are not " + uname
		}
	}
	fmt.Println(message)
	srvChan <- message
}

func help(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :8)"
	fmt.Println(message)
	srvChan <- message
}

func commands(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "PRIVMSG " + channel + " :"
	for command := range funcMap {
		message += command + " "
	}
	fmt.Println(message)
	srvChan <- message
}

func kick(srvChan chan string, channel, nick, hostname string, args []string) {
	message := "KICK " + channel + " " + nick + " :You don't tell me what to do."
	fmt.Println(message)
	srvChan <- message

	message = "KICK " + channel
	if len(args) < 1 {
		message = "PRIVMSG " + channel + " :ERROR: Invalid number of arguments"
	} else {
		if args[0] == config.Nick {
			return
		}
		message += " " + args[0]
	}
	if len(args) >= 2 {
		message += " :" + strings.Join(args[1:], " ")
	}
	fmt.Println(message)
	srvChan <- message
}

func wc(srvChan chan string, channel, nick, hostnam string, args []string) {
	message := "PRIVMSG " + channel + " :"
	if len(args) != 1 {
		message += "ERROR: Invalid number of arguments"
	} else {
		logFile, err := os.Open(`/home/ross/irclogs/freenode/` + channel + `.log`)
		if err != nil {
			message += fmt.Sprintf("%s", err)
		} else {
			fileStat, err := logFile.Stat()
			log := make([]byte, fileStat.Size())
			_, err = logFile.Read(log)
			if err != nil {
				message += fmt.Sprintf("%s", err)
			} else {
				logLines := strings.Split(string(log),"\n")
				nickLine := regexp.MustCompile(`^\d\d:\d\d <[@\+\s]?` + args[0] + `>`)
				matches := 0
				for _, line := range logLines {
					if match := nickLine.FindStringSubmatch(line); match != nil {
						matches++
					}
				}
				message += args[0] + ": " + fmt.Sprintf("%d", matches) + " lines"
			}
		}
	}
	fmt.Println(message)
	srvChan <- message
}
<|endoftext|>


<commit_before>package selenium

import (
	"bytes"
	"template"
)

type Params struct {
	Id, Name, Other, PropertyName, SessionId string
}

type Command struct {
	Method string
	url *template.Template
}

func (cmd *Command) URL(params *Params) string, os.Error {
	buf := new(bytes.Buffer)
	if err := command.url.Execute(buf, Params); err != nil {
		return "", err
	}

	return buf.String(), nil
}

var CMD_NEW_SESSION = &Command{"POST", "/session"}
var CMD_QUIT = &Command{"DELETE", template.MustCompile("/session/{SessionId}", nil)}
var CMD_GET_CURRENT_WINDOW_HANDLE = &Command{"GET", template.MustCompile("/session/{SessionId}/window_handle", nil)}
var CMD_GET_WINDOW_HANDLES = &Command{"GET", template.MustCompile("/session/{SessionId}/window_handles", nil)}
var CMD_GET = &Command{"POST", template.MustCompile("/session/{SessionId}/url", nil)}
var CMD_GO_FORWARD = &Command{"POST", template.MustCompile("/session/{SessionId}/forward", nil)}
var CMD_GO_BACK = &Command{"POST", template.MustCompile("/session/{SessionId}/back", nil)}
var CMD_REFRESH = &Command{"POST", template.MustCompile("/session/{SessionId}/refresh", nil)}
var CMD_EXECUTE_SCRIPT = &Command{"POST", template.MustCompile("/session/{SessionId}/execute", nil)}
var CMD_GET_CURRENT_URL = &Command{"GET", template.MustCompile("/session/{SessionId}/url", nil)}
var CMD_GET_TITLE = &Command{"GET", template.MustCompile("/session/{SessionId}/title", nil)}
var CMD_GET_PAGE_SOURCE = &Command{"GET", template.MustCompile("/session/{SessionId}/source", nil)}
var CMD_SCREENSHOT = &Command{"GET", template.MustCompile("/session/{SessionId}/screenshot", nil)}
var CMD_SET_BROWSER_VISIBLE = &Command{"POST", template.MustCompile("/session/{SessionId}/visible", nil)}
var CMD_IS_BROWSER_VISIBLE = &Command{"GET", template.MustCompile("/session/{SessionId}/visible", nil)}
var CMD_FIND_ELEMENT = &Command{"POST", template.MustCompile("/session/{SessionId}/element", nil)}
var CMD_FIND_ELEMENTS = &Command{"POST", template.MustCompile("/session/{SessionId}/elements", nil)}
var CMD_GET_ACTIVE_ELEMENT = &Command{"POST", template.MustCompile("/session/{SessionId}/element/active", nil)}
var CMD_FIND_CHILD_ELEMENT = &Command{"POST", template.MustCompile("/session/{SessionId}/element/{Id}/element", nil)}
var CMD_FIND_CHILD_ELEMENTS = &Command{"POST", template.MustCompile("/session/{SessionId}/element/{Id}/elements", nil)}
var CMD_CLICK_ELEMENT = &Command{"POST", template.MustCompile("/session/{SessionId}/element/{Id}/click", nil)}
var CMD_CLEAR_ELEMENT = &Command{"POST", template.MustCompile("/session/{SessionId}/element/{Id}/clear", nil)}
var CMD_SUBMIT_ELEMENT = &Command{"POST", template.MustCompile("/session/{SessionId}/element/{Id}/submit", nil)}
var CMD_GET_ELEMENT_TEXT = &Command{"GET", template.MustCompile("/session/{SessionId}/element/{Id}/text", nil)}
var CMD_SEND_KEYS_TO_ELEMENT = &Command{"POST", template.MustCompile("/session/{SessionId}/element/{Id}/value", nil)}
var CMD_SEND_MODIFIER_KEY_TO_ACTIVE_ELEMENT = &Command{"POST", template.MustCompile("/session/{SessionId}/modifier", nil)}
var CMD_GET_ELEMENT_VALUE = &Command{"GET", template.MustCompile("/session/{SessionId}/element/{Id}/value", nil)}
var CMD_GET_ELEMENT_TAG_NAME = &Command{"GET", template.MustCompile("/session/{SessionId}/element/{Id}/name", nil)}
var CMD_IS_ELEMENT_SELECTED = &Command{"GET", template.MustCompile("/session/{SessionId}/element/{Id}/selected", nil)}
var CMD_SET_ELEMENT_SELECTED = &Command{"POST", template.MustCompile("/session/{SessionId}/element/{Id}/selected", nil)}
var CMD_TOGGLE_ELEMENT = &Command{"POST", template.MustCompile("/session/{SessionId}/element/{Id}/toggle", nil)}
var CMD_IS_ELEMENT_ENABLED = &Command{"GET", template.MustCompile("/session/{SessionId}/element/{Id}/enabled", nil)}
var CMD_IS_ELEMENT_DISPLAYED = &Command{"GET", template.MustCompile("/session/{SessionId}/element/{Id}/displayed", nil)}
var CMD_HOVER_OVER_ELEMENT = &Command{"POST", template.MustCompile("/session/{SessionId}/element/{Id}/hover", nil)}
var CMD_GET_ELEMENT_LOCATION = &Command{"GET", template.MustCompile("/session/{SessionId}/element/{Id}/location", nil)}
var CMD_GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW = &Command{"GET", template.MustCompile("/session/{SessionId}/element/{Id}/location_in_view", nil)}
var CMD_GET_ELEMENT_SIZE = &Command{"GET", template.MustCompile("/session/{SessionId}/element/{Id}/size", nil)}
var CMD_GET_ELEMENT_ATTRIBUTE = &Command{"GET", template.MustCompile("/session/{SessionId}/element/{Id}/attribute/{Name}", nil)}
var CMD_ELEMENT_EQUALS = &Command{"GET", template.MustCompile("/session/{SessionId}/element/{Id}/equals/{Other}", nil)}
var CMD_GET_ALL_COOKIES = &Command{"GET", template.MustCompile("/session/{SessionId}/cookie", nil)}
var CMD_ADD_COOKIE = &Command{"POST", template.MustCompile("/session/{SessionId}/cookie", nil)}
var CMD_DELETE_ALL_COOKIES = &Command{"DELETE", template.MustCompile("/session/{SessionId}/cookie", nil)}
var CMD_DELETE_COOKIE = &Command{"DELETE", template.MustCompile("/session/{SessionId}/cookie/{Name}", nil)}
var CMD_SWITCH_TO_FRAME = &Command{"POST", template.MustCompile("/session/{SessionId}/frame", nil)}
var CMD_SWITCH_TO_WINDOW = &Command{"POST", template.MustCompile("/session/{SessionId}/window", nil)}
var CMD_CLOSE = &Command{"DELETE", template.MustCompile("/session/{SessionId}/window", nil)}
var CMD_DRAG_ELEMENT = &Command{"POST", template.MustCompile("/session/{SessionId}/element/{Id}/drag", nil)}
var CMD_GET_SPEED = &Command{"GET", template.MustCompile("/session/{SessionId}/speed", nil)}
var CMD_SET_SPEED = &Command{"POST", template.MustCompile("/session/{SessionId}/speed", nil)}
var CMD_GET_ELEMENT_VALUE_OF_CSS_PROPERTY = &Command{"GET", template.MustCompile("/session/{SessionId}/element/{Id}/css/{PropertyName}", nil}
var CMD_IMPLICIT_WAIT = &Command{"POST", template.MustCompile("/session/{SessionId}/timeouts/implicit_wait", nil)}
var CMD_EXECUTE_ASYNC_SCRIPT = &Command{"POST", template.MustCompile("/session/{SessionId}/execute_async", nil)}
var CMD_SET_SCRIPT_TIMEOUT = &Command{"POST", template.MustCompile("/session/{SessionId}/timeouts/async_script", nil)}
var CMD_GET_ELEMENT_VALUE_OF_CSS_PROPERTY = &Command{"GET", template.MustCompile("/session/{SessionId}/element/{Id}/css/{PropertyName}", nil)}
var CMD_DISMISS_ALERT = &Command{"POST", template.MustCompile("/session/{SessionId}/dismiss_alert", nil)}
var CMD_ACCEPT_ALERT = &Command{"POST", template.MustCompile("/session/{SessionId}/accept_alert", nil)}
var CMD_SET_ALERT_VALUE = &Command{"POST", template.MustCompile("/session/{SessionId}/alert_text", nil)}
var CMD_GET_ALERT_TEXT = &Command{"GET", template.MustCompile("/session/{SessionId}/alert_text", nil)}
var CMD_CLICK = &Command{"POST", template.MustCompile("/session/{SessionId}/click", nil)}
var CMD_DOUBLE_CLICK = &Command{"POST", template.MustCompile("/session/{SessionId}/doubleclick", nil)}
var CMD_MOUSE_DOWN = &Command{"POST", template.MustCompile("/session/{SessionId}/buttondown", nil)}
var CMD_MOUSE_UP = &Command{"POST", template.MustCompile("/session/{SessionId}/buttonup", nil)}
var CMD_MOVE_TO = &Command{"POST", template.MustCompile("/session/{SessionId}/moveto", nil)}

<commit_msg>Commands and URLs<commit_after>package selenium

import (
	"bytes"
	"os"
	"template"
)

type Params struct {
	Id, Name, Other, PropertyName, SessionId string
}

type Command struct {
	Method string
	url *template.Template
}

func (cmd *Command) URL(params *Params) (string, os.Error) {
	var buf bytes.Buffer
	if err := cmd.url.Execute(&buf, params); err != nil {
		return "", err
	}

	return string(buf.String()), nil
}

var CMD_NEW_SESSION = &Command{"POST", template.MustParse("/session", nil)}
var CMD_QUIT = &Command{"DELETE", template.MustParse("/session/{SessionId}", nil)}
var CMD_GET_CURRENT_WINDOW_HANDLE = &Command{"GET", template.MustParse("/session/{SessionId}/window_handle", nil)}
var CMD_GET_WINDOW_HANDLES = &Command{"GET", template.MustParse("/session/{SessionId}/window_handles", nil)}
var CMD_GET = &Command{"POST", template.MustParse("/session/{SessionId}/url", nil)}
var CMD_GO_FORWARD = &Command{"POST", template.MustParse("/session/{SessionId}/forward", nil)}
var CMD_GO_BACK = &Command{"POST", template.MustParse("/session/{SessionId}/back", nil)}
var CMD_REFRESH = &Command{"POST", template.MustParse("/session/{SessionId}/refresh", nil)}
var CMD_EXECUTE_SCRIPT = &Command{"POST", template.MustParse("/session/{SessionId}/execute", nil)}
var CMD_GET_CURRENT_URL = &Command{"GET", template.MustParse("/session/{SessionId}/url", nil)}
var CMD_GET_TITLE = &Command{"GET", template.MustParse("/session/{SessionId}/title", nil)}
var CMD_GET_PAGE_SOURCE = &Command{"GET", template.MustParse("/session/{SessionId}/source", nil)}
var CMD_SCREENSHOT = &Command{"GET", template.MustParse("/session/{SessionId}/screenshot", nil)}
var CMD_SET_BROWSER_VISIBLE = &Command{"POST", template.MustParse("/session/{SessionId}/visible", nil)}
var CMD_IS_BROWSER_VISIBLE = &Command{"GET", template.MustParse("/session/{SessionId}/visible", nil)}
var CMD_FIND_ELEMENT = &Command{"POST", template.MustParse("/session/{SessionId}/element", nil)}
var CMD_FIND_ELEMENTS = &Command{"POST", template.MustParse("/session/{SessionId}/elements", nil)}
var CMD_GET_ACTIVE_ELEMENT = &Command{"POST", template.MustParse("/session/{SessionId}/element/active", nil)}
var CMD_FIND_CHILD_ELEMENT = &Command{"POST", template.MustParse("/session/{SessionId}/element/{Id}/element", nil)}
var CMD_FIND_CHILD_ELEMENTS = &Command{"POST", template.MustParse("/session/{SessionId}/element/{Id}/elements", nil)}
var CMD_CLICK_ELEMENT = &Command{"POST", template.MustParse("/session/{SessionId}/element/{Id}/click", nil)}
var CMD_CLEAR_ELEMENT = &Command{"POST", template.MustParse("/session/{SessionId}/element/{Id}/clear", nil)}
var CMD_SUBMIT_ELEMENT = &Command{"POST", template.MustParse("/session/{SessionId}/element/{Id}/submit", nil)}
var CMD_GET_ELEMENT_TEXT = &Command{"GET", template.MustParse("/session/{SessionId}/element/{Id}/text", nil)}
var CMD_SEND_KEYS_TO_ELEMENT = &Command{"POST", template.MustParse("/session/{SessionId}/element/{Id}/value", nil)}
var CMD_SEND_MODIFIER_KEY_TO_ACTIVE_ELEMENT = &Command{"POST", template.MustParse("/session/{SessionId}/modifier", nil)}
var CMD_GET_ELEMENT_VALUE = &Command{"GET", template.MustParse("/session/{SessionId}/element/{Id}/value", nil)}
var CMD_GET_ELEMENT_TAG_NAME = &Command{"GET", template.MustParse("/session/{SessionId}/element/{Id}/name", nil)}
var CMD_IS_ELEMENT_SELECTED = &Command{"GET", template.MustParse("/session/{SessionId}/element/{Id}/selected", nil)}
var CMD_SET_ELEMENT_SELECTED = &Command{"POST", template.MustParse("/session/{SessionId}/element/{Id}/selected", nil)}
var CMD_TOGGLE_ELEMENT = &Command{"POST", template.MustParse("/session/{SessionId}/element/{Id}/toggle", nil)}
var CMD_IS_ELEMENT_ENABLED = &Command{"GET", template.MustParse("/session/{SessionId}/element/{Id}/enabled", nil)}
var CMD_IS_ELEMENT_DISPLAYED = &Command{"GET", template.MustParse("/session/{SessionId}/element/{Id}/displayed", nil)}
var CMD_HOVER_OVER_ELEMENT = &Command{"POST", template.MustParse("/session/{SessionId}/element/{Id}/hover", nil)}
var CMD_GET_ELEMENT_LOCATION = &Command{"GET", template.MustParse("/session/{SessionId}/element/{Id}/location", nil)}
var CMD_GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW = &Command{"GET", template.MustParse("/session/{SessionId}/element/{Id}/location_in_view", nil)}
var CMD_GET_ELEMENT_SIZE = &Command{"GET", template.MustParse("/session/{SessionId}/element/{Id}/size", nil)}
var CMD_GET_ELEMENT_ATTRIBUTE = &Command{"GET", template.MustParse("/session/{SessionId}/element/{Id}/attribute/{Name}", nil)}
var CMD_ELEMENT_EQUALS = &Command{"GET", template.MustParse("/session/{SessionId}/element/{Id}/equals/{Other}", nil)}
var CMD_GET_ALL_COOKIES = &Command{"GET", template.MustParse("/session/{SessionId}/cookie", nil)}
var CMD_ADD_COOKIE = &Command{"POST", template.MustParse("/session/{SessionId}/cookie", nil)}
var CMD_DELETE_ALL_COOKIES = &Command{"DELETE", template.MustParse("/session/{SessionId}/cookie", nil)}
var CMD_DELETE_COOKIE = &Command{"DELETE", template.MustParse("/session/{SessionId}/cookie/{Name}", nil)}
var CMD_SWITCH_TO_FRAME = &Command{"POST", template.MustParse("/session/{SessionId}/frame", nil)}
var CMD_SWITCH_TO_WINDOW = &Command{"POST", template.MustParse("/session/{SessionId}/window", nil)}
var CMD_CLOSE = &Command{"DELETE", template.MustParse("/session/{SessionId}/window", nil)}
var CMD_DRAG_ELEMENT = &Command{"POST", template.MustParse("/session/{SessionId}/element/{Id}/drag", nil)}
var CMD_GET_SPEED = &Command{"GET", template.MustParse("/session/{SessionId}/speed", nil)}
var CMD_SET_SPEED = &Command{"POST", template.MustParse("/session/{SessionId}/speed", nil)}
var CMD_GET_ELEMENT_VALUE_OF_CSS_PROPERTY = &Command{"GET", template.MustParse("/session/{SessionId}/element/{Id}/css/{PropertyName}", nil)}
var CMD_IMPLICIT_WAIT = &Command{"POST", template.MustParse("/session/{SessionId}/timeouts/implicit_wait", nil)}
var CMD_EXECUTE_ASYNC_SCRIPT = &Command{"POST", template.MustParse("/session/{SessionId}/execute_async", nil)}
var CMD_SET_SCRIPT_TIMEOUT = &Command{"POST", template.MustParse("/session/{SessionId}/timeouts/async_script", nil)}
var CMD_DISMISS_ALERT = &Command{"POST", template.MustParse("/session/{SessionId}/dismiss_alert", nil)}
var CMD_ACCEPT_ALERT = &Command{"POST", template.MustParse("/session/{SessionId}/accept_alert", nil)}
var CMD_SET_ALERT_VALUE = &Command{"POST", template.MustParse("/session/{SessionId}/alert_text", nil)}
var CMD_GET_ALERT_TEXT = &Command{"GET", template.MustParse("/session/{SessionId}/alert_text", nil)}
var CMD_CLICK = &Command{"POST", template.MustParse("/session/{SessionId}/click", nil)}
var CMD_DOUBLE_CLICK = &Command{"POST", template.MustParse("/session/{SessionId}/doubleclick", nil)}
var CMD_MOUSE_DOWN = &Command{"POST", template.MustParse("/session/{SessionId}/buttondown", nil)}
var CMD_MOUSE_UP = &Command{"POST", template.MustParse("/session/{SessionId}/buttonup", nil)}
var CMD_MOVE_TO = &Command{"POST", template.MustParse("/session/{SessionId}/moveto", nil)}

<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"
)

type model interface {
	incr(key string) error //increment the given key, setting it to zero if it doesn't exist
	getInt(key string) int //get a key as an int, defaulting to 0 if it doesn't exist
}

// a dabopobo command, consisting of a regex to match against and a commandHandler to run if it matches
type cmd struct {
	regex   string
	handler commandHandler
}

/*
A commandHandler is a function that handles a dabopobo command and returns a slice of bytes to respond with and possibly an error.

m is the data model for this process.
submatches is the output of FindAllStringSubmatch() when running the message text on the corresponding cmd's regex.
username is the username of the user who sent the message.
response is the response to be sent back to slack.
err is non-nil if an error is produced. response should be empty in this case.
*/
type commandHandler func(m model, submatches [][]string, username string) (response string, err error)

var mutateKarmaCmd = cmd{"(\\(.+\\)|[^ ]+?)(\\+\\++|--+|\\+-|-\\+)", mutateKarma}

//handles identifier++
func mutateKarma(m model, mutations [][]string, username string) (s string, err error) {
	if username == "slackbot" { // ignore if message is from the bot
		return
	}
	for _, mutation := range mutations {
		identifier := maybeRemoveParens(mutation[1])
		op := mutation[2]
		if identifier != "" && identifier != username { // users may not mutate themselves
			suffix := canonicalizeSuffix(op)
			key := strings.ToLower(identifier) + suffix // canonicalize identifier as lowercase to prevent confusion
			err = m.incr(key)
			if err != nil {
				err = nil
				return
			}
			fmt.Println(key)
		}
	}
	return
}

var getKarmaCmd = cmd{"^!karma +([^ ].+)", getKarma}

//handles !karma identifier
func getKarma(m model, identifier [][]string, username string) (text string, err error) {
	name := identifier[0][1] //since the regex has a beginning of string hook, there should only be one match, so we only care about index 0.
	karmaset := getKarmaSet(m, name)
	text = fmt.Sprintf("%v's karma is %v %v", name, karmaset.value(), karmaset)
	fmt.Println(text)
	return
}

var helpCmd = cmd{"^!karma(|help)$", help}

func help(m model, s [][]string, u string) (string, error) {
	fmt.Println("help message")
	return strings.Join(
		[]string{
			"\"!karma thing\" displays things karma. It can be anything, including with spaces.",
			"thing++ (with at least 2 pluses) gives positive karma",
			"thing-- (with at least 2 minuses) gives negative karma",
			"thing+- (either order) gives neutral karma",
			"(thing with spaces)++ (with any of the above) gives karma to a thing with spaces in it.",
		},
		"\n",
	), nil
}

// getKarmaSet loads the karma for a given key
func getKarmaSet(m model, name string) (k karmaSet) {
	name = strings.ToLower(name)
	k.plusplus = m.getInt(name + "++")
	k.minusminus = m.getInt(name + "--")
	k.plusminus = m.getInt(name + "+-")
	return
}
<commit_msg>Added help and tabes to help output.<commit_after>package main

import (
	"fmt"
	"strings"
)

type model interface {
	incr(key string) error //increment the given key, setting it to zero if it doesn't exist
	getInt(key string) int //get a key as an int, defaulting to 0 if it doesn't exist
}

// a dabopobo command, consisting of a regex to match against and a commandHandler to run if it matches
type cmd struct {
	regex   string
	handler commandHandler
}

/*
A commandHandler is a function that handles a dabopobo command and returns a slice of bytes to respond with and possibly an error.

m is the data model for this process.
submatches is the output of FindAllStringSubmatch() when running the message text on the corresponding cmd's regex.
username is the username of the user who sent the message.
response is the response to be sent back to slack.
err is non-nil if an error is produced. response should be empty in this case.
*/
type commandHandler func(m model, submatches [][]string, username string) (response string, err error)

var mutateKarmaCmd = cmd{"(\\(.+\\)|[^ ]+?)(\\+\\++|--+|\\+-|-\\+)", mutateKarma}

//handles identifier++
func mutateKarma(m model, mutations [][]string, username string) (s string, err error) {
	if username == "slackbot" { // ignore if message is from the bot
		return
	}
	for _, mutation := range mutations {
		identifier := maybeRemoveParens(mutation[1])
		op := mutation[2]
		if identifier != "" && identifier != username { // users may not mutate themselves
			suffix := canonicalizeSuffix(op)
			key := strings.ToLower(identifier) + suffix // canonicalize identifier as lowercase to prevent confusion
			err = m.incr(key)
			if err != nil {
				err = nil
				return
			}
			fmt.Println(key)
		}
	}
	return
}

var getKarmaCmd = cmd{"^!karma +([^ ].+)", getKarma}

//handles !karma identifier
func getKarma(m model, identifier [][]string, username string) (text string, err error) {
	name := identifier[0][1] //since the regex has a beginning of string hook, there should only be one match, so we only care about index 0.
	karmaset := getKarmaSet(m, name)
	text = fmt.Sprintf("%v's karma is %v %v", name, karmaset.value(), karmaset)
	fmt.Println(text)
	return
}

var helpCmd = cmd{"^!karma(|help)$", help}

func help(m model, s [][]string, u string) (string, error) {
	fmt.Println("help message")
	return strings.Join(
		[]string{
			"!karma thing\tdisplays things karma. It can be anything, including with spaces.",
			"thing++\t(with at least 2 pluses) gives positive karma",
			"thing--\t(with at least 2 minuses) gives negative karma",
			"thing+-\t(either order) gives neutral karma",
			"(thing with spaces)++\t(with any of the above) gives karma to a thing with spaces in it.",
			"!karma or !karmahelp\tdisplays this help",
		},
		"\n",
	), nil
}

// getKarmaSet loads the karma for a given key
func getKarmaSet(m model, name string) (k karmaSet) {
	name = strings.ToLower(name)
	k.plusplus = m.getInt(name + "++")
	k.minusminus = m.getInt(name + "--")
	k.plusminus = m.getInt(name + "+-")
	return
}
<|endoftext|>