<commit_before>package tasker

import (
	"encoding/json"

	"github.com/astaxie/beego"
	"github.com/astaxie/beego/toolbox"
)

// MsgQ is interface for msg, all messages should be implements these interfaces.
type MsgQ interface {
	New() MsgQ
	Topic() string
	TaskSpec() string
	Concurency() int
	Exec(uint64) error
}

// MsgQInitTask add consume task to beego toolbox task, run consumer interval.
func MsgQInitTask(m MsgQ) {
	task := toolbox.NewTask(m.Topic(), m.TaskSpec(), func() error {
		return MsgQConsume(m)
	})
	toolbox.AddTask(m.Topic(), task)
}

// MsgQPublish represents publish a task.
func MsgQPublish(m MsgQ) error {
	input, err := json.Marshal(m)
	if err != nil {
		return err
	}

	return NewSimpleTask(m.Topic(), string(input)).Publish()
}

// MsgQConsume is for consume a message type.
func MsgQConsume(m MsgQ) error {
	num, err := Consume(m.Topic(), func(input string, workerID uint64) (err error) {
		this := m.New()
		if err = json.Unmarshal([]byte(input), this); err != nil {
			return
		}

		return this.Exec(workerID)
	}, m.Concurency())

	beego.BeeLogger.Info("consume for %s exec tasks=%d, err=%v", m.Topic(), num, err)
	return err
}
<commit_msg>add publish with retry and timeout set<commit_after>package tasker

import (
	"encoding/json"
	"time"

	"github.com/astaxie/beego"
	"github.com/astaxie/beego/toolbox"
)

// MsgQ is interface for msg, all messages should be implements these interfaces.
type MsgQ interface {
	New() MsgQ
	Topic() string
	TaskSpec() string
	Concurency() int
	Exec(uint64) error
}

// MsgQInitTask add consume task to beego toolbox task, run consumer interval.
func MsgQInitTask(m MsgQ) {
	task := toolbox.NewTask(m.Topic(), m.TaskSpec(), func() error {
		return MsgQConsume(m)
	})
	toolbox.AddTask(m.Topic(), task)
}

// MsgQPublish represents publish a task.
func MsgQPublish(m MsgQ) error {
	input, err := json.Marshal(m)
	if err != nil {
		return err
	}

	return NewSimpleTask(m.Topic(), string(input)).Publish()
}

// MsgQPublishWithRetry represents publish with retry and timeout set
func MsgQPublishWithRetry(m MsgQ, timeout time.Duration, retry int) error {
	input, err := json.Marshal(m)
	if err != nil {
		return err
	}

	task := &Task{
		Topic:    m.Topic(),
		Status:   "pending",
		Timeout:  int(timeout.Seconds()),
		Retry:    retry,
		Input:    input,
		WorkerId: 0,
	}

	return task.Publish()
}

// MsgQConsume is for consume a message type.
func MsgQConsume(m MsgQ) error {
	num, err := Consume(m.Topic(), func(input string, workerID uint64) (err error) {
		this := m.New()
		if err = json.Unmarshal([]byte(input), this); err != nil {
			return
		}

		return this.Exec(workerID)
	}, m.Concurency())

	beego.BeeLogger.Info("consume for %s exec tasks=%d, err=%v", m.Topic(), num, err)
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"github.com/briandowns/spinner"
	"github.com/mehrdadrad/mylg/cli"
	"github.com/mehrdadrad/mylg/icmp"
	"github.com/mehrdadrad/mylg/lg"
	"net"
	"regexp"
	"strings"
	"time"
)

type Provider interface {
	Set(host, version string)
	GetDefaultNode() string
	GetNodes() map[string]string
	ChangeNode(node string)
	Ping() (string, error)
}

var providers = map[string]Provider{"telia": new(lg.Telia), "level3": new(lg.Level3)}

func validateProvider(p string) (string, error) {
	match, _ := regexp.MatchString("(telia|level3)", p)
	p = strings.ToLower(p)
	if match {
		return p, nil
	} else {
		return "", errors.New("provider not support")
	}
}

func main() {
	var (
		err    error
		cPName string = "local"
	)

	rep := make(chan string, 1)
	cmd := make(chan string, 1)
	nxt := make(chan struct{}, 1)

	c := cli.Init("local")
	go c.Run(cmd, nxt)

	r, _ := regexp.Compile(`(ping|connect|node|local) (.*)`)
	s := spinner.New(spinner.CharSets[26], 220*time.Millisecond)

	for {
		select {
		case req := <-cmd:
			subReq := r.FindStringSubmatch(req)
			if len(subReq) == 0 {
				println("syntax error")
				nxt <- struct{}{}
				continue
			}
			switch {
			case subReq[1] == "ping" && cPName == "local":
				p := icmp.NewPing()
				ra, err := net.ResolveIPAddr("ip", subReq[2])
				if err != nil {
					println("cannot resolve", subReq[2], ": Unknown host")
					nxt <- struct{}{}
					continue
				}
				p.IP(ra.String())
				for n := 0; n < 4; n++ {
					p.Ping(rep)
					println(<-rep)
				}
				nxt <- struct{}{}
			case subReq[1] == "ping":
				s.Prefix = "please wait "
				s.Start()
				providers[cPName].Set(subReq[2], "ipv4")
				m, _ := providers[cPName].Ping()
				s.Stop()
				println(m)
				nxt <- struct{}{}
			case subReq[1] == "node":
				providers[cPName].ChangeNode(subReq[2])
				c.SetPrompt(cPName + "/" + subReq[2])
				nxt <- struct{}{}
			case subReq[1] == "local":
				cPName = "local"
				c.SetPrompt(cPName)
				nxt <- struct{}{}
			case subReq[1] == "connect":
				var pName string
				if pName, err = validateProvider(subReq[2]); err != nil {
					println("provider not available")
					nxt <- struct{}{}
					continue
				}
				cPName = pName
				c.SetPrompt(cPName + "/" + providers[cPName].GetDefaultNode())
				nxt <- struct{}{}
			}
		}
	}
}
<commit_msg>added trim to cmd and args<commit_after>package main

import (
	"errors"
	"github.com/briandowns/spinner"
	"github.com/mehrdadrad/mylg/cli"
	"github.com/mehrdadrad/mylg/icmp"
	"github.com/mehrdadrad/mylg/lg"
	"net"
	"regexp"
	"strings"
	"time"
)

type Provider interface {
	Set(host, version string)
	GetDefaultNode() string
	GetNodes() map[string]string
	ChangeNode(node string)
	Ping() (string, error)
}

var providers = map[string]Provider{"telia": new(lg.Telia), "level3": new(lg.Level3)}

func validateProvider(p string) (string, error) {
	match, _ := regexp.MatchString("(telia|level3)", p)
	p = strings.ToLower(p)
	if match {
		return p, nil
	} else {
		return "", errors.New("provider not support")
	}
}

func main() {
	var (
		err    error
		cPName string = "local"
	)

	rep := make(chan string, 1)
	cmd := make(chan string, 1)
	nxt := make(chan struct{}, 1)

	c := cli.Init("local")
	go c.Run(cmd, nxt)

	r, _ := regexp.Compile(`(ping|connect|node|local) (.*)`)
	s := spinner.New(spinner.CharSets[26], 220*time.Millisecond)

	for {
		select {
		case req := <-cmd:
			subReq := r.FindStringSubmatch(req)
			if len(subReq) == 0 {
				println("syntax error")
				nxt <- struct{}{}
				continue
			}
			cmd := strings.TrimSpace(subReq[1])
			args := strings.TrimSpace(subReq[2])
			switch {
			case cmd == "ping" && cPName == "local":
				p := icmp.NewPing()
				ra, err := net.ResolveIPAddr("ip", args)
				if err != nil {
					println("cannot resolve", args, ": Unknown host")
					nxt <- struct{}{}
					continue
				}
				p.IP(ra.String())
				for n := 0; n < 4; n++ {
					p.Ping(rep)
					println(<-rep)
				}
				nxt <- struct{}{}
			case cmd == "ping":
				s.Prefix = "please wait "
				s.Start()
				providers[cPName].Set(args, "ipv4")
				m, _ := providers[cPName].Ping()
				s.Stop()
				println(m)
				nxt <- struct{}{}
			case cmd == "node":
				providers[cPName].ChangeNode(args)
				c.SetPrompt(cPName + "/" + args)
				nxt <- struct{}{}
			case cmd == "local":
				cPName = "local"
				c.SetPrompt(cPName)
				nxt <- struct{}{}
			case cmd == "connect":
				var pName string
				if pName, err = validateProvider(args); err != nil {
					println("provider not available")
					nxt <- struct{}{}
					continue
				}
				cPName = pName
				c.SetPrompt(cPName + "/" + providers[cPName].GetDefaultNode())
				nxt <- struct{}{}
			}
		}
	}
}
<|endoftext|>


<commit_before>// List the network interfaces with IP address in a platform independent way.
// License: MIT
// Copyright (c) 2016 by Joe Linoff
package main

import (
	"fmt"
	"net"
	"os"
	"path"
	"strings"
)

// NetworkInterfaceForIP contains the network interface information for a single
// IP address.
type NetworkInterfaceForIP struct {
	Interface net.Interface
	IPAddr    string
	Unicast   bool // true == unicast, false == multicast
	IPv4      bool // true == IPv4, false == IPv4
}

// Options contains the command line options.
type Options struct {
	Verbose       int
	ShowMulticast bool
	ShowUnicast   bool
	ShowIPv4s     bool
	ShowIPv6s     bool
	ShowHW        bool // have MAC
	ShowSW        bool // do not have MAC
}

func main() {
	opts := getOpts()
	nifs := LoadNifs()
	ReportNifs(opts, nifs)
	// report(opts, nifs)
}

// LoadNifs loads the network interface information all IP addresses.
func LoadNifs() []NetworkInterfaceForIP {
	recs := []NetworkInterfaceForIP{}

	nifs, _ := net.Interfaces()
	for _, nif := range nifs {
		// unicast
		ifaddrs, _ := nif.Addrs()
		for _, ifaddr := range ifaddrs {
			addr := ifaddr.String()
			//Can't use net.ParseIP() with To4() because it returns false
			// for 127.0.0.1/8.
			ipv4 := strings.Contains(addr, ".")
			rec := NetworkInterfaceForIP{
				Interface: nif,
				IPAddr:    addr,
				Unicast:   true,
				IPv4:      ipv4,
			}
			recs = append(recs, rec)
		}

		// multicast
		ifaddrs, _ = nif.MulticastAddrs()
		for _, ifaddr := range ifaddrs {
			addr := ifaddr.String()
			ipv4 := strings.Contains(addr, ".")
			rec := NetworkInterfaceForIP{
				Interface: nif,
				IPAddr:    addr,
				Unicast:   false,
				IPv4:      ipv4,
			}
			recs = append(recs, rec)
		}
	}
	return recs
}

// ReportNifs reports the NIF information.
func ReportNifs(opts Options, nifs []NetworkInterfaceForIP) {
	for _, nif := range nifs {
		if opts.ShowIPv4s == false && nif.IPv4 == true {
			continue
		}
		if opts.ShowIPv6s == false && nif.IPv4 == false {
			continue
		}
		if opts.ShowUnicast == false && nif.Unicast == true {
			continue
		}
		if opts.ShowMulticast == false && nif.Unicast == false {
			continue
		}
		if opts.ShowHW == false && len(nif.Interface.HardwareAddr) > 0 {
			continue
		}
		if opts.ShowSW == false && len(nif.Interface.HardwareAddr) == 0 {
			continue
		}

		fmt.Printf("%v ", nif.Interface.Name)
		fmt.Printf("%v ", nif.IPAddr)
		if nif.Unicast {
			fmt.Printf("unicast ")
		} else {
			fmt.Printf("multicast ")
		}
		mac := nif.Interface.HardwareAddr.String()
		if len(mac) == 0 {
			mac = "NOMAC"
		}
		fmt.Printf("%v", mac)
		fmt.Printf("\n")
	}
}

// Get the command line options.
func getOpts() Options {
	opts := Options{
		ShowUnicast:   false,
		ShowMulticast: false,
		ShowIPv4s:     false,
		ShowIPv6s:     false,
		ShowHW:        false,
		ShowSW:        false,
	}
	for i := 1; i < len(os.Args); i++ {
		opt := os.Args[i]
		switch opt {
		case "-h", "--help":
			help()
			os.Exit(0)
		case "-H", "--hw":
			opts.ShowHW = true
		case "-m", "--multicast":
			opts.ShowMulticast = true
		case "-u", "--unicast":
			opts.ShowUnicast = true
		case "-4", "--ipv4":
			opts.ShowIPv4s = true
		case "-6", "--ipv6":
			opts.ShowIPv6s = true
		case "-s", "--sw":
			opts.ShowSW = true
		case "-V", "--version":
			base := path.Base(os.Args[0])
			fmt.Printf("%s 0.2.0\n", base)
			os.Exit(0)
		default:
			fmt.Printf("ERROR: unrecognized option '%v'\n", opt)
			os.Exit(1)
		}
	}
	if opts.ShowIPv4s == false && opts.ShowIPv6s == false {
		opts.ShowIPv4s = true
		opts.ShowIPv6s = true
	}
	if opts.ShowUnicast == false && opts.ShowMulticast == false {
		opts.ShowUnicast = true
		opts.ShowMulticast = true
	}
	if opts.ShowHW == false && opts.ShowSW == false {
		opts.ShowHW = true
		opts.ShowSW = true
	}

	return opts
}

// Get the next argument.
func getNextArg(i *int) string {
	*i++
	if *i >= len(os.Args) {
		fmt.Printf("ERROR: missing argument for %s", os.Args[*i-1])
		os.Exit(1)
	}
	return os.Args[*i]
}

// help.
func help() {
	base := path.Base(os.Args[0])
	msg := `
USAGE
    %[1]v [OPTIONS]

DESCRIPTION
    Generates a very simple report of the IP addresses associated with the
    network interfaces.

    The report format is very simple. There is one line per interface/ip address
    combination. There are 4 fields on each line:

       1. interface name
       2. IP address (or CIDR)
       3. unicast or multicast
       4. MAC address

OPTIONS
    -4, --ipv4         Report only IPv4 addresses.
                       The default is to report both IPv4 and IPv6 addresses.

    -6, --ipv6         Report only IPv6 addresses.
    The default is to report both IPv4 and IPv6 addresses.

    -h, -help          This help message.

    -H, --hw           Report hardware only interfaces (have a MAC addresses).
                       The default is to report all HW and SW interfaces.

    -m, --multicast    Report only multicast addresses.
                       The default is to report unicast and multicast.

    -s, --sw           Report software only interfaces(no MAC addresses).
                       The default is to report all HW and SW interfaces.

    -u, --unicast      Report only unicast addresses.
                       The default is to report unicast and multicast.

    -V, --version      Print the program version and exit.

EXAMPLES
    $ # Example 1: help
    $ %[1]s -h

    $ # Example 2: Report all IP address
    $ %[1]s

    $ # Example 3: Report only IPv4, unicast addresses.
    $ %[1]s -4 -u

    $ # Example 4: Report only HW, IPv4, unicast addresses
    $ %[1]s -4 -u -H

`
	fmt.Printf(msg, base)
}
<commit_msg>Fixed help typo<commit_after>// List the network interfaces with IP address in a platform independent way.
// License: MIT
// Copyright (c) 2016 by Joe Linoff
package main

import (
	"fmt"
	"net"
	"os"
	"path"
	"strings"
)

// NetworkInterfaceForIP contains the network interface information for a single
// IP address.
type NetworkInterfaceForIP struct {
	Interface net.Interface
	IPAddr    string
	Unicast   bool // true == unicast, false == multicast
	IPv4      bool // true == IPv4, false == IPv4
}

// Options contains the command line options.
type Options struct {
	Verbose       int
	ShowMulticast bool
	ShowUnicast   bool
	ShowIPv4s     bool
	ShowIPv6s     bool
	ShowHW        bool // have MAC
	ShowSW        bool // do not have MAC
}

func main() {
	opts := getOpts()
	nifs := LoadNifs()
	ReportNifs(opts, nifs)
	// report(opts, nifs)
}

// LoadNifs loads the network interface information all IP addresses.
func LoadNifs() []NetworkInterfaceForIP {
	recs := []NetworkInterfaceForIP{}

	nifs, _ := net.Interfaces()
	for _, nif := range nifs {
		// unicast
		ifaddrs, _ := nif.Addrs()
		for _, ifaddr := range ifaddrs {
			addr := ifaddr.String()
			//Can't use net.ParseIP() with To4() because it returns false
			// for 127.0.0.1/8.
			ipv4 := strings.Contains(addr, ".")
			rec := NetworkInterfaceForIP{
				Interface: nif,
				IPAddr:    addr,
				Unicast:   true,
				IPv4:      ipv4,
			}
			recs = append(recs, rec)
		}

		// multicast
		ifaddrs, _ = nif.MulticastAddrs()
		for _, ifaddr := range ifaddrs {
			addr := ifaddr.String()
			ipv4 := strings.Contains(addr, ".")
			rec := NetworkInterfaceForIP{
				Interface: nif,
				IPAddr:    addr,
				Unicast:   false,
				IPv4:      ipv4,
			}
			recs = append(recs, rec)
		}
	}
	return recs
}

// ReportNifs reports the NIF information.
func ReportNifs(opts Options, nifs []NetworkInterfaceForIP) {
	for _, nif := range nifs {
		if opts.ShowIPv4s == false && nif.IPv4 == true {
			continue
		}
		if opts.ShowIPv6s == false && nif.IPv4 == false {
			continue
		}
		if opts.ShowUnicast == false && nif.Unicast == true {
			continue
		}
		if opts.ShowMulticast == false && nif.Unicast == false {
			continue
		}
		if opts.ShowHW == false && len(nif.Interface.HardwareAddr) > 0 {
			continue
		}
		if opts.ShowSW == false && len(nif.Interface.HardwareAddr) == 0 {
			continue
		}

		fmt.Printf("%v ", nif.Interface.Name)
		fmt.Printf("%v ", nif.IPAddr)
		if nif.Unicast {
			fmt.Printf("unicast ")
		} else {
			fmt.Printf("multicast ")
		}
		mac := nif.Interface.HardwareAddr.String()
		if len(mac) == 0 {
			mac = "NOMAC"
		}
		fmt.Printf("%v", mac)
		fmt.Printf("\n")
	}
}

// Get the command line options.
func getOpts() Options {
	opts := Options{
		ShowUnicast:   false,
		ShowMulticast: false,
		ShowIPv4s:     false,
		ShowIPv6s:     false,
		ShowHW:        false,
		ShowSW:        false,
	}
	for i := 1; i < len(os.Args); i++ {
		opt := os.Args[i]
		switch opt {
		case "-h", "--help":
			help()
			os.Exit(0)
		case "-H", "--hw":
			opts.ShowHW = true
		case "-m", "--multicast":
			opts.ShowMulticast = true
		case "-u", "--unicast":
			opts.ShowUnicast = true
		case "-4", "--ipv4":
			opts.ShowIPv4s = true
		case "-6", "--ipv6":
			opts.ShowIPv6s = true
		case "-s", "--sw":
			opts.ShowSW = true
		case "-V", "--version":
			base := path.Base(os.Args[0])
			fmt.Printf("%s 0.2.0\n", base)
			os.Exit(0)
		default:
			fmt.Printf("ERROR: unrecognized option '%v'\n", opt)
			os.Exit(1)
		}
	}
	if opts.ShowIPv4s == false && opts.ShowIPv6s == false {
		opts.ShowIPv4s = true
		opts.ShowIPv6s = true
	}
	if opts.ShowUnicast == false && opts.ShowMulticast == false {
		opts.ShowUnicast = true
		opts.ShowMulticast = true
	}
	if opts.ShowHW == false && opts.ShowSW == false {
		opts.ShowHW = true
		opts.ShowSW = true
	}

	return opts
}

// Get the next argument.
func getNextArg(i *int) string {
	*i++
	if *i >= len(os.Args) {
		fmt.Printf("ERROR: missing argument for %s", os.Args[*i-1])
		os.Exit(1)
	}
	return os.Args[*i]
}

// help.
func help() {
	base := path.Base(os.Args[0])
	msg := `
USAGE
    %[1]v [OPTIONS]

DESCRIPTION
    Generates a very simple report of the IP addresses associated with the
    network interfaces.

    The report format is very simple. There is one line per interface/ip address
    combination. There are 4 fields on each line:

       1. interface name
       2. IP address (or CIDR)
       3. unicast or multicast
       4. MAC address

OPTIONS
    -4, --ipv4         Report only IPv4 addresses.
                       The default is to report both IPv4 and IPv6 addresses.

    -6, --ipv6         Report only IPv6 addresses.
                       The default is to report both IPv4 and IPv6 addresses.

    -h, -help          This help message.

    -H, --hw           Report hardware only interfaces (have a MAC addresses).
                       The default is to report all HW and SW interfaces.

    -m, --multicast    Report only multicast addresses.
                       The default is to report unicast and multicast.

    -s, --sw           Report software only interfaces(no MAC addresses).
                       The default is to report all HW and SW interfaces.

    -u, --unicast      Report only unicast addresses.
                       The default is to report unicast and multicast.

    -V, --version      Print the program version and exit.

EXAMPLES
    $ # Example 1: help
    $ %[1]s -h

    $ # Example 2: Report all IP address
    $ %[1]s

    $ # Example 3: Report only IPv4, unicast addresses.
    $ %[1]s -4 -u

    $ # Example 4: Report only HW, IPv4, unicast addresses
    $ %[1]s -4 -u -H

`
	fmt.Printf(msg, base)
}
<|endoftext|>


<commit_before>package decide

import (
	"fmt"
	"github.com/pkg/errors"
	exp "github.com/sjhitchner/go-decide/expression"
	"log"
)

// Generate syntax parser
//go:generate gocc -a grammar.bnf

// Decision Tree Node
type Node struct {
	Expression exp.Expression
	Payload    []string
	True       *Node
	False      *Node
}

func NewNode(expression exp.Expression) *Node {
	return &Node{
		expression,
		nil,
		nil,
		nil,
	}
}

func (t Node) Evaluate(ctx exp.Context, payloadMap map[string]struct{}) error {
	result, err := toBool(t.Expression.Evaluate(ctx))
	if err != nil {
		return errors.Wrapf(err, "failed to evaluate expression %v", t.Expression)
	}

	if result {
		for _, payload := range t.Payload {
			if _, ok := payloadMap[payload]; !ok {
				payloadMap[payload] = struct{}{}
			}
		}
	}

	log.Printf("EVAL %s Result: %v Payload: %v\n", t.Expression, result, payloadMap)

	if result && t.True != nil {
		return t.True.Evaluate(ctx, payloadMap)
	} else if t.False != nil {
		return t.False.Evaluate(ctx, payloadMap)
	} else if result {
		for _, payload := range t.Payload {
			if _, ok := payloadMap[payload]; !ok {
				payloadMap[payload] = struct{}{}
			}
		}
	}

	return nil
}

func toBool(result interface{}, err error) (bool, error) {
	if err != nil {
		return false, err
	}

	if result == nil {
		return false, nil
	}

	b, ok := result.(bool)
	if !ok {
		return false, errors.Errorf("Expect bool got %v", result)
	}

	return b, nil
}

func (t Node) String() string {
	return fmt.Sprintf("(%s [%s] %s)", t.True, t.Expression, t.False)
}
<commit_msg>CR comments addressed<commit_after>package decide

import (
	"fmt"
	"github.com/pkg/errors"
	exp "github.com/sjhitchner/go-decide/expression"
	"log"
)

// Generate syntax parser
//go:generate gocc -a grammar.bnf

// Decision Tree Node
type Node struct {
	Expression exp.Expression
	Payload    []string
	True       *Node
	False      *Node
}

func NewNode(expression exp.Expression) *Node {
	return &Node{
		expression,
		nil,
		nil,
		nil,
	}
}

func (t Node) Evaluate(ctx exp.Context, payloadMap map[string]struct{}) error {
	result, err := toBool(t.Expression.Evaluate(ctx))
	if err != nil {
		return errors.Wrapf(err, "failed to evaluate expression %v", t.Expression)
	}

	if result {
		for _, payload := range t.Payload {
			payloadMap[payload] = struct{}{}
		}
	}

	log.Printf("EVAL %s Result: %v Payload: %v\n", t.Expression, result, payloadMap)

	if result && t.True != nil {
		return t.True.Evaluate(ctx, payloadMap)
	} else if t.False != nil {
		return t.False.Evaluate(ctx, payloadMap)
	} else if result {
		for _, payload := range t.Payload {
			payloadMap[payload] = struct{}{}
		}
	}

	return nil
}

func toBool(result interface{}, err error) (bool, error) {
	if err != nil {
		return false, err
	}

	if result == nil {
		return false, nil
	}

	b, ok := result.(bool)
	if !ok {
		return false, errors.Errorf("Expect bool got %v", result)
	}

	return b, nil
}

func (t Node) String() string {
	return fmt.Sprintf("(%s [%s] %s)", t.True, t.Expression, t.False)
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2013-2015 Oryx(ossrs)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// The os defines:
//      bsd: darwin dragonfly freebsd nacl netbsd openbsd solaris
//      unix: bsd linux
//      server: unix plan9
//      posix: bsd linux windows
// All os by go:
//      server windows
//      posix plan9

package main

import (
	"flag"
	"fmt"
	"github.com/ossrs/go-oryx/app"
	"github.com/ossrs/go-oryx/core"
	"os"
)

func serve(svr *app.Server) int {
	if err := svr.PrepareLogger(); err != nil {
		core.Error.Println("prepare logger failed, err is", err)
		return -1
	}

	oryxMain(svr)

	core.Trace.Println(core.OryxSigServer())
	core.Trace.Println(core.OryxSigCopyright)
	core.Trace.Println(core.OryxSigProduct)

	if err := svr.Initialize(); err != nil {
		core.Error.Println("initialize server failed, err is", err)
		return -1
	}

	if err := svr.Run(); err != nil {
		core.Error.Println("run server failed, err is", err)
		return -1
	}

	return 0
}

func main() {
	// the args format:
	//          -c conf/oryx.json
	//          --c conf/oryx.json
	//          -c=conf/oryx.json
	//          --c=conf/oryx.json
	//          --conf=conf/oryx.json
	var confFile string
	if true {
		dv := ""
		ua := "the config file"
		flag.StringVar(&confFile, "c", dv, ua)
		flag.StringVar(&confFile, "conf", dv, ua)
	}

	var showHelp bool
	if true {
		dv := false
		ua := "print version"
		flag.BoolVar(&showHelp, "v", dv, ua)
		flag.BoolVar(&showHelp, "V", dv, ua)
		flag.BoolVar(&showHelp, "version", dv, ua)
	}

	var showSignature bool
	if true {
		dv := false
		ua := "print signature"
		flag.BoolVar(&showSignature, "g", dv, ua)
		flag.BoolVar(&showSignature, "signature", dv, ua)
	}

	flag.Usage = func() {
		fmt.Println(fmt.Sprintf("Usage: %v [-c|--conf <filename>] [-?|-h|--help] [-v|-V|--version] [-g|--signature]", os.Args[0]))
		fmt.Println(fmt.Sprintf("	    -c, --conf filename     : the config file path"))
		fmt.Println(fmt.Sprintf("	    -?, -h, --help          : show this help and exit"))
		fmt.Println(fmt.Sprintf("	    -v, -V, --version       : print version and exit"))
		fmt.Println(fmt.Sprintf("	    -g, --signature         : print server signature and exit"))
		fmt.Println(fmt.Sprintf("For example:"))
		fmt.Println(fmt.Sprintf("	    %v -c conf/oryx.json", os.Args[0]))
	}
	flag.Parse()

	if showHelp {
		fmt.Fprintln(os.Stderr, core.Version())
		os.Exit(0)
	}

	if showSignature {
		fmt.Fprintln(os.Stderr, core.OryxSigServer())
		os.Exit(0)
	}

	if len(confFile) == 0 {
		flag.Usage()
		os.Exit(0)
	}

	fmt.Println(fmt.Sprintf("%v signature is %v", core.OryxSigName, core.OryxSigServer()))
	ret := func() int {
		svr := app.NewServer()
		defer svr.Close()

		if err := svr.ParseConfig(confFile); err != nil {
			core.Error.Println("parse config from", confFile, "failed, err is", err)
			return -1
		}

		return run(svr)
	}()

	os.Exit(ret)
}
<commit_msg>refine help.<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2013-2015 Oryx(ossrs)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// The os defines:
//      bsd: darwin dragonfly freebsd nacl netbsd openbsd solaris
//      unix: bsd linux
//      server: unix plan9
//      posix: bsd linux windows
// All os by go:
//      server windows
//      posix plan9

package main

import (
	"flag"
	"fmt"
	"github.com/ossrs/go-oryx/app"
	"github.com/ossrs/go-oryx/core"
	"os"
)

func serve(svr *app.Server) int {
	if err := svr.PrepareLogger(); err != nil {
		core.Error.Println("prepare logger failed, err is", err)
		return -1
	}

	oryxMain(svr)

	core.Trace.Println(core.OryxSigServer())
	core.Trace.Println(core.OryxSigCopyright)
	core.Trace.Println(core.OryxSigProduct)

	if err := svr.Initialize(); err != nil {
		core.Error.Println("initialize server failed, err is", err)
		return -1
	}

	if err := svr.Run(); err != nil {
		core.Error.Println("run server failed, err is", err)
		return -1
	}

	return 0
}

func main() {
	// the args format:
	//          -c conf/oryx.json
	//          --c conf/oryx.json
	//          -c=conf/oryx.json
	//          --c=conf/oryx.json
	//          --conf=conf/oryx.json
	var confFile string
	if true {
		dv := ""
		ua := "the config file"
		flag.StringVar(&confFile, "c", dv, ua)
		flag.StringVar(&confFile, "conf", dv, ua)
	}

	var showHelp bool
	if true {
		dv := false
		ua := "print version"
		flag.BoolVar(&showHelp, "v", dv, ua)
		flag.BoolVar(&showHelp, "V", dv, ua)
		flag.BoolVar(&showHelp, "version", dv, ua)
	}

	var showSignature bool
	if true {
		dv := false
		ua := "print signature"
		flag.BoolVar(&showSignature, "g", dv, ua)
		flag.BoolVar(&showSignature, "signature", dv, ua)
	}

	flag.Usage = func() {
		fmt.Println(core.OryxSigProduct)
		fmt.Println(fmt.Sprintf("Usage: %v [-c|--conf <filename>] [-?|-h|--help] [-v|-V|--version] [-g|--signature]", os.Args[0]))
		fmt.Println(fmt.Sprintf("	    -c, --conf filename     : the config file path"))
		fmt.Println(fmt.Sprintf("	    -?, -h, --help          : show this help and exit"))
		fmt.Println(fmt.Sprintf("	    -v, -V, --version       : print version and exit"))
		fmt.Println(fmt.Sprintf("	    -g, --signature         : print server signature and exit"))
		fmt.Println(fmt.Sprintf("For example:"))
		fmt.Println(fmt.Sprintf("	    %v -c conf/oryx.json", os.Args[0]))
	}
	flag.Parse()

	if showHelp {
		fmt.Fprintln(os.Stderr, core.Version())
		os.Exit(0)
	}

	if showSignature {
		fmt.Fprintln(os.Stderr, core.OryxSigServer())
		os.Exit(0)
	}

	if len(confFile) == 0 {
		flag.Usage()
		os.Exit(0)
	}

	fmt.Println(fmt.Sprintf("%v signature is %v", core.OryxSigName, core.OryxSigServer()))
	ret := func() int {
		svr := app.NewServer()
		defer svr.Close()

		if err := svr.ParseConfig(confFile); err != nil {
			core.Error.Println("parse config from", confFile, "failed, err is", err)
			return -1
		}

		return run(svr)
	}()

	os.Exit(ret)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path"
	"regexp"
	"strings"
	"time"

	"github.com/schollz/versionedtext"
)

// Page is the basic struct
type Page struct {
	Name                    string
	Text                    versionedtext.VersionedText
	Meta                    string
	RenderedPage            string
	IsLocked                bool
	PassphraseToUnlock      string
	IsEncrypted             bool
	IsPrimedForSelfDestruct bool
	IsPublished             bool
}

func Open(name string) (p *Page) {
	p = new(Page)
	p.Name = name
	p.Text = versionedtext.NewVersionedText("")
	p.Render()
	bJSON, err := ioutil.ReadFile(path.Join(pathToData, encodeToBase32(strings.ToLower(name))+".json"))
	if err != nil {
		return
	}
	err = json.Unmarshal(bJSON, &p)
	if err != nil {
		p = new(Page)
	}
	return p
}

type DirectoryEntry struct {
	Name       string
	Length     int
	Numchanges int
	LastEdited time.Time
}

func (d DirectoryEntry) LastEditTime() string {
	return d.LastEdited.Format("Mon Jan 2 15:04:05 MST 2006")
}

func DirectoryList() []DirectoryEntry {
	files, _ := ioutil.ReadDir(pathToData)
	entries := make([]DirectoryEntry, len(files))
	for i, f := range files {
		name := DecodeFileName(f.Name())
		p := Open(name)
		entries[i] = DirectoryEntry{
			Name:       name,
			Length:     len(p.Text.GetCurrent()),
			Numchanges: p.Text.NumEdits(),
			LastEdited: time.Unix(p.Text.LastEditTime()/1000000000, 0),
		}
	}
	return entries
}

func DecodeFileName(s string) string {
	s2, _ := decodeFromBase32(strings.Split(s, ".")[0])
	return s2
}

// Update cleans the text and updates the versioned text
// and generates a new render
func (p *Page) Update(newText string) error {
	// Trim space from end
	newText = strings.TrimRight(newText, "\n\t ")

	// Update the versioned text
	p.Text.Update(newText)

	// Render the new page
	p.Render()

	return p.Save()
}

var rBracketPage = regexp.MustCompile(`\[\[(.*?)\]\]`)

func (p *Page) Render() {
	if p.IsEncrypted {
		p.RenderedPage = "" + p.Text.GetCurrent() + ""
		return
	}

	// Convert [[page]] to [page](/page/view)
	currentText := p.Text.GetCurrent()
	for _, s := range rBracketPage.FindAllString(currentText, -1) {
		currentText = strings.Replace(currentText, s, "["+s[2:len(s)-2]+"](/"+s[2:len(s)-2]+"/view)", 1)
	}
	p.Text.Update(currentText)
	p.RenderedPage = MarkdownToHtml(p.Text.GetCurrent())
}

func (p *Page) Save() error {
	bJSON, err := json.MarshalIndent(p, "", " ")
	if err != nil {
		return err
	}
	return ioutil.WriteFile(path.Join(pathToData, encodeToBase32(strings.ToLower(p.Name))+".json"), bJSON, 0644)
}

func (p *Page) IsNew() bool {
	return !exists(path.Join(pathToData, encodeToBase32(strings.ToLower(p.Name))+".json"))
}

func (p *Page) Erase() error {
	log.Trace("Erasing " + p.Name)
	return os.Remove(path.Join(pathToData, encodeToBase32(strings.ToLower(p.Name))+".json"))
}

func (p *Page) Published() bool {
	return p.IsPublished
}
<commit_msg>Sort 'ls' page by recent<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path"
	"regexp"
	"sort"
	"strings"
	"time"

	"github.com/schollz/versionedtext"
)

// Page is the basic struct
type Page struct {
	Name                    string
	Text                    versionedtext.VersionedText
	Meta                    string
	RenderedPage            string
	IsLocked                bool
	PassphraseToUnlock      string
	IsEncrypted             bool
	IsPrimedForSelfDestruct bool
	IsPublished             bool
}

func Open(name string) (p *Page) {
	p = new(Page)
	p.Name = name
	p.Text = versionedtext.NewVersionedText("")
	p.Render()
	bJSON, err := ioutil.ReadFile(path.Join(pathToData, encodeToBase32(strings.ToLower(name))+".json"))
	if err != nil {
		return
	}
	err = json.Unmarshal(bJSON, &p)
	if err != nil {
		p = new(Page)
	}
	return p
}

type DirectoryEntry struct {
	Name       string
	Length     int
	Numchanges int
	LastEdited time.Time
}

func (d DirectoryEntry) LastEditTime() string {
	return d.LastEdited.Format("Mon Jan 2 15:04:05 MST 2006")
}

func DirectoryList() []DirectoryEntry {
	files, _ := ioutil.ReadDir(pathToData)
	entries := make([]DirectoryEntry, len(files))
	for i, f := range files {
		name := DecodeFileName(f.Name())
		p := Open(name)
		entries[i] = DirectoryEntry{
			Name:       name,
			Length:     len(p.Text.GetCurrent()),
			Numchanges: p.Text.NumEdits(),
			LastEdited: time.Unix(p.Text.LastEditTime()/1000000000, 0),
		}
	}
	sort.Slice(entries, func(i, j int) bool { return entries[i].LastEdited.Before(entries[j].LastEdited) })
	return entries
}

func DecodeFileName(s string) string {
	s2, _ := decodeFromBase32(strings.Split(s, ".")[0])
	return s2
}

// Update cleans the text and updates the versioned text
// and generates a new render
func (p *Page) Update(newText string) error {
	// Trim space from end
	newText = strings.TrimRight(newText, "\n\t ")

	// Update the versioned text
	p.Text.Update(newText)

	// Render the new page
	p.Render()

	return p.Save()
}

var rBracketPage = regexp.MustCompile(`\[\[(.*?)\]\]`)

func (p *Page) Render() {
	if p.IsEncrypted {
		p.RenderedPage = "" + p.Text.GetCurrent() + ""
		return
	}

	// Convert [[page]] to [page](/page/view)
	currentText := p.Text.GetCurrent()
	for _, s := range rBracketPage.FindAllString(currentText, -1) {
		currentText = strings.Replace(currentText, s, "["+s[2:len(s)-2]+"](/"+s[2:len(s)-2]+"/view)", 1)
	}
	p.Text.Update(currentText)
	p.RenderedPage = MarkdownToHtml(p.Text.GetCurrent())
}

func (p *Page) Save() error {
	bJSON, err := json.MarshalIndent(p, "", " ")
	if err != nil {
		return err
	}
	return ioutil.WriteFile(path.Join(pathToData, encodeToBase32(strings.ToLower(p.Name))+".json"), bJSON, 0644)
}

func (p *Page) IsNew() bool {
	return !exists(path.Join(pathToData, encodeToBase32(strings.ToLower(p.Name))+".json"))
}

func (p *Page) Erase() error {
	log.Trace("Erasing " + p.Name)
	return os.Remove(path.Join(pathToData, encodeToBase32(strings.ToLower(p.Name))+".json"))
}

func (p *Page) Published() bool {
	return p.IsPublished
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path"
	"regexp"
	"strings"
	"time"

	"github.com/schollz/versionedtext"
)

// Page is the basic struct
type Page struct {
	Name                    string
	Text                    versionedtext.VersionedText
	Meta                    string
	RenderedPage            string
	IsLocked                bool
	PassphraseToUnlock      string
	IsEncrypted             bool
	IsPrimedForSelfDestruct bool
	IsPublished             bool
}

func Open(name string) (p *Page) {
	p = new(Page)
	p.Name = name
	p.Text = versionedtext.NewVersionedText("")
	p.Render()
	bJSON, err := ioutil.ReadFile(path.Join(pathToData, encodeToBase32(strings.ToLower(name))+".json"))
	if err != nil {
		return
	}
	err = json.Unmarshal(bJSON, &p)
	if err != nil {
		p = new(Page)
	}
	return p
}

type DirectoryEntry struct {
	Name       string
	Length     int
	Numchanges int
	LastEdited time.Time
}

func (d DirectoryEntry) LastEditTime() string {
	return d.LastEdited.Format("Mon Jan 2 15:04:05 MST 2006")
}

func DirectoryList() []DirectoryEntry {
	files, _ := ioutil.ReadDir(pathToData)
	entries := make([]DirectoryEntry, len(files))
	for i, f := range files {
		name := DecodeFileName(f.Name())
		p := Open(name)
		entries[i] = DirectoryEntry{
			Name:       name,
			Length:     len(p.Text.GetCurrent()),
			Numchanges: p.Text.NumEdits(),
			LastEdited: time.Unix(p.Text.LastEditTime()/1000000000, 0),
		}
	}
	return entries
}

func DecodeFileName(s string) string {
	s2, _ := decodeFromBase32(strings.Split(s, ".")[0])
	return s2
}

// Update cleans the text and updates the versioned text
// and generates a new render
func (p *Page) Update(newText string) error {
	// Trim space from end
	newText = strings.TrimRight(newText, "\n\t ")

	// Update the versioned text
	p.Text.Update(newText)

	// Render the new page
	p.Render()

	return p.Save()
}

var rBracketPage = regexp.MustCompile(`\[\[(.*?)\]\]`)

func (p *Page) Render() {
	if p.IsEncrypted {
		p.RenderedPage = "" + p.Text.GetCurrent() + ""
		return
	}

	// Convert [[page]] to [page](/page/view)
	currentText := p.Text.GetCurrent()
	for _, s := range rBracketPage.FindAllString(currentText, -1) {
		currentText = strings.Replace(currentText, s, "["+s[2:len(s)-2]+"](/"+s[2:len(s)-2]+"/view)", 1)
	}
	p.Text.Update(currentText)
	p.RenderedPage = MarkdownToHtml(p.Text.GetCurrent())
}

func (p *Page) Save() error {
	bJSON, err := json.MarshalIndent(p, "", " ")
	if err != nil {
		return err
	}
	return ioutil.WriteFile(path.Join(pathToData, encodeToBase32(strings.ToLower(p.Name))+".json"), bJSON, 0644)
}

func (p *Page) IsNew() bool {
	return !exists(path.Join(pathToData, encodeToBase32(strings.ToLower(p.Name))+".json"))
}

func (p *Page) Erase() error {
	log.Trace("Erasing " + p.Name)
	return os.Remove(path.Join(pathToData, encodeToBase32(strings.ToLower(p.Name))+".json"))
}

func (p *Page) Published() bool {
	return p.IsPublished
}
<commit_msg>Sort 'ls' page by recent<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path"
	"regexp"
	"sort"
	"strings"
	"time"

	"github.com/schollz/versionedtext"
)

// Page is the basic struct
type Page struct {
	Name                    string
	Text                    versionedtext.VersionedText
	Meta                    string
	RenderedPage            string
	IsLocked                bool
	PassphraseToUnlock      string
	IsEncrypted             bool
	IsPrimedForSelfDestruct bool
	IsPublished             bool
}

func Open(name string) (p *Page) {
	p = new(Page)
	p.Name = name
	p.Text = versionedtext.NewVersionedText("")
	p.Render()
	bJSON, err := ioutil.ReadFile(path.Join(pathToData, encodeToBase32(strings.ToLower(name))+".json"))
	if err != nil {
		return
	}
	err = json.Unmarshal(bJSON, &p)
	if err != nil {
		p = new(Page)
	}
	return p
}

type DirectoryEntry struct {
	Name       string
	Length     int
	Numchanges int
	LastEdited time.Time
}

func (d DirectoryEntry) LastEditTime() string {
	return d.LastEdited.Format("Mon Jan 2 15:04:05 MST 2006")
}

func DirectoryList() []DirectoryEntry {
	files, _ := ioutil.ReadDir(pathToData)
	entries := make([]DirectoryEntry, len(files))
	for i, f := range files {
		name := DecodeFileName(f.Name())
		p := Open(name)
		entries[i] = DirectoryEntry{
			Name:       name,
			Length:     len(p.Text.GetCurrent()),
			Numchanges: p.Text.NumEdits(),
			LastEdited: time.Unix(p.Text.LastEditTime()/1000000000, 0),
		}
	}
	sort.Slice(entries, func(i, j int) bool { return entries[i].LastEdited.After(entries[j].LastEdited) })
	return entries
}

func DecodeFileName(s string) string {
	s2, _ := decodeFromBase32(strings.Split(s, ".")[0])
	return s2
}

// Update cleans the text and updates the versioned text
// and generates a new render
func (p *Page) Update(newText string) error {
	// Trim space from end
	newText = strings.TrimRight(newText, "\n\t ")

	// Update the versioned text
	p.Text.Update(newText)

	// Render the new page
	p.Render()

	return p.Save()
}

var rBracketPage = regexp.MustCompile(`\[\[(.*?)\]\]`)

func (p *Page) Render() {
	if p.IsEncrypted {
		p.RenderedPage = "" + p.Text.GetCurrent() + ""
		return
	}

	// Convert [[page]] to [page](/page/view)
	currentText := p.Text.GetCurrent()
	for _, s := range rBracketPage.FindAllString(currentText, -1) {
		currentText = strings.Replace(currentText, s, "["+s[2:len(s)-2]+"](/"+s[2:len(s)-2]+"/view)", 1)
	}
	p.Text.Update(currentText)
	p.RenderedPage = MarkdownToHtml(p.Text.GetCurrent())
}

func (p *Page) Save() error {
	bJSON, err := json.MarshalIndent(p, "", " ")
	if err != nil {
		return err
	}
	return ioutil.WriteFile(path.Join(pathToData, encodeToBase32(strings.ToLower(p.Name))+".json"), bJSON, 0644)
}

func (p *Page) IsNew() bool {
	return !exists(path.Join(pathToData, encodeToBase32(strings.ToLower(p.Name))+".json"))
}

func (p *Page) Erase() error {
	log.Trace("Erasing " + p.Name)
	return os.Remove(path.Join(pathToData, encodeToBase32(strings.ToLower(p.Name))+".json"))
}

func (p *Page) Published() bool {
	return p.IsPublished
}
<|endoftext|>


<commit_before>package villa

import (
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
)

// Path is a wrapper for a path in the OS.
// Some commonly used functions are wrapped as methods of Path,
// and results, if any, are converted back to Path
type Path string

// Join connect elems to the tail of path
func (p Path) Join(elem ...interface{}) Path {
	els := make(StringSlice, 0, len(elem)+1)
	els.Add(p).Add(elem...)
	return Path(filepath.Join(els...))
}

// Exists checks whether the file exists
func (p Path) Exists() bool {
	_, err := p.Stat()
	return err == nil
}

// IsDir returns true only if the path exists and indicates a directory
func (p Path) IsDir() bool {
	info, err := p.Stat()
	if err != nil {
		// the path does not exist
		return false
	}
	return info.Mode().IsDir()
}

// S converts Path back to string. This is sometimes more concise than string(p)
func (p Path) S() string {
	return string(p)
}

// AbsPath returns the absolute path returned by Path.Abs() if no error found,
// panic otherwise.
func (p Path) AbsPath() (ap Path) {
	ap, err := p.Abs()
	if err != nil {
		panic(err)
	}
	return ap
}

/*
	wrappers of path/filepath package
*/

// Abs is a wrapper to filepath.Abs
// It returns an absolute representation of path. If the path is not absolute it
// will be joined with the current working directory to turn it into an absolute
// path. The absolute path name for a given file is not guaranteed to be unique.
func (p Path) Abs() (pth Path, err error) {
	pt, err := filepath.Abs(string(p))
	return Path(pt), err
}

// Base returns the last element of path.
// Trailing path separators are removed before extracting the last element.
// If the path is empty, Base returns ".".
// If the path consists entirely of separators, Base returns a single separator.
func (p Path) Base() Path {
	return Path(filepath.Base(string(p)))
}

// Clean is a wrapper to filepath.Clean.
//
// It returns the shortest path name equivalent to path by purely lexically
// processing.
func (p Path) Clean() Path {
	return Path(filepath.Clean(string(p)))
}

// Dir is a wrapper to filepath.Dir.
// It returns all but the last element of path, typically the path's directory.
// Trailing path separators are removed before processing. If the path is empty,
// Dir returns ".". If the path consists entirely of separators, Dir returns a
// single separator. The returned path does not end in a separator unless it is
// the root directory.
func (p Path) Dir() Path {
	return Path(filepath.Dir(string(p)))
}

// EvalSymlinks is a wrapper to filepath.EvalSymlinks
func (p Path) EvalSymlinks() (Path, error) {
	pt, err := filepath.EvalSymlinks(string(p))
	return Path(pt), err
}

// Ext is a wrapper to filepath.Ext
func (p Path) Ext() string {
	return filepath.Ext(string(p))
}

// FromSlash is a wrapper to filepath.FromSlash
func (p Path) FromSlash() Path {
	return Path(filepath.FromSlash(string(p)))
}

// IsAbs is a wrapper to filepath.IsAbs
//
// IsAbs returns true if the path is absolute.
func (p Path) IsAbs() bool {
	return filepath.IsAbs(string(p))
}

// Rel is a wrapper to filepath.Rel.
// It returns a relative path that is lexically equivalent to targpath when
// joined to basepath with an intervening separator. That is, Join(basepath,
// Rel(basepath, targpath)) is equivalent to targpath itself. On success, the
// returned path will always be relative to basepath, even if basepath and
// targpath share no elements. An error is returned if targpath can't be made
// relative to basepath or if knowing the current working directory would be
// necessary to compute it.
func (p Path) Rel(targetpath Path) (Path, error) {
	rel, err := filepath.Rel(string(p), string(targetpath))
	return Path(rel), err
}

// Split is a wrapper to filepath.Split
func (p Path) Split() (dir, file Path) {
	d, f := filepath.Split(string(p))
	return Path(d), Path(f)
}

// SplitList is a wrapper to filepath.SplitList
func (p Path) SplitList() (lst []Path) {
	l := filepath.SplitList(string(p))
	lst = make([]Path, len(l))
	for i, el := range l {
		lst[i] = Path(el)
	}
	return
}

// ToSlash is a wrapper to filepath.ToSlash
func (p Path) ToSlash() string {
	return filepath.ToSlash(string(p))
}

// VolumeName is a wrapper to filepath.VolumeName
func (p Path) VolumeName() string {
	return filepath.VolumeName(string(p))
}

// WalkFunc is a wrapper to filepath.WalkFunc
// WalkFunc is the type of the function called for each file or directory
// visited by Walk. The path argument contains the argument to Walk as a prefix;
// that is, if Walk is called with "dir", which is a directory containing the
// file "a", the walk function will be called with argument "dir/a". The info
// argument is the os.FileInfo for the named path.
//
// If there was a problem walking to the file or directory named by path, the
// incoming error will describe the problem and the function can decide how to
// handle that error (and Walk will not descend into that directory). If an
// error is returned, processing stops. The sole exception is that if path is a
// directory and the function returns the special value filepath.SkipDir, the
// contents of the directory are skipped and processing continues as usual on
// the next file.
type WalkFunc func(path Path, info os.FileInfo, err error) error

// Walk is a wrapper to filepath.Walk
// Walk walks the file tree rooted at root, calling walkFn for each file or
// directory in the tree, including root. All errors that arise visiting files
// and directories are filtered by walkFn. The files are walked in lexical
// order, which makes the output deterministic but means that for very large
// directories Walk can be inefficient. Walk does not follow symbolic links.
func (p Path) Walk(walkFn WalkFunc) error {
	return filepath.Walk(string(p), func(path string, info os.FileInfo, err error) error {
		return walkFn(Path(path), info, err)
	})
}

/*
	wrappers of os package
*/

// Create is a wrapper to os.Create.
//
// It creates the named file mode 0666 (before umask), truncating it if it
// already exists. If successful, methods on the returned File can be used for
// I/O; the associated file descriptor has mode O_RDWR. If there is an error,
// it will be of type *PathError.
func (p Path) Create() (file *os.File, err error) {
	return os.Create(string(p))
}

// Open is a wrapper to os.Open.
//
// It opens the named file for reading. If successful, methods on the returned
// file can be used for reading; the associated file descriptor has mode O_RDONLY.
// If there is an error, it will be of type *PathError.
func (p Path) Open() (file *os.File, err error) {
	return os.Open(string(p))

}

// OpenFile is a wrapper to os.OpenFile.
//
// It is the generalized open call; most users will use Open or Create instead.
// It opens the named file with specified flag (O_RDONLY etc.) and perm,
// (0666 etc.) if applicable. If successful, methods on the returned File can be
// used for I/O. If there is an error, it will be of type *PathError.
func (p Path) OpenFile(flag int, perm os.FileMode) (file *os.File, err error) {
	return os.OpenFile(string(p), flag, perm)
}

// Mkdir is a wrappter to os.Mkdir.
//
// It creates a new directory with the specified name and permission bits. If
// there is an error, it will be of type *PathError.
func (p Path) Mkdir(perm os.FileMode) error {
	return os.Mkdir(string(p), perm)
}

// MkdirAll is a wrappter to os.MkdirAll.
//
// It creates a directory named path, along with any necessary parents, and
// returns nil, or else returns an error. The permission bits perm are used for
// all directories that MkdirAll creates. If path is already a directory,
// MkdirAll does nothing and returns nil.
func (p Path) MkdirAll(perm os.FileMode) error {
	return os.MkdirAll(string(p), perm)
}

// Remove is a wrappter to os.Remove
//
// Remove removes the named file or directory. If there is an error, it will be
// of type *PathError.
func (p Path) Remove() error {
	return os.Remove(string(p))
}

// RemoveAll is a wrappter to os.RemoveAll
// RemoveAll removes path and any children it contains. It removes everything it
// can but returns the first error it encounters. If the path does not exist,
// RemoveAll returns nil (no error).
func (p Path) RemoveAll() error {
	return os.RemoveAll(string(p))
}

// Rename is a wrappter to os.Rename
func (p Path) Rename(newname Path) error {
	return os.Rename(string(p), string(newname))
}

// Stat is a wrappter to os.Stat
func (p Path) Stat() (fi os.FileInfo, err error) {
	return os.Stat(string(p))
}

// Symlink is a wrappter to os.Symlink
func (p Path) Symlink(dst Path) error {
	return os.Symlink(string(p), string(dst))
}

/*
	wrappers of ioutil package
*/

// ReadDir is a wrappter to ioutil.ReadDir
//
// ReadDir reads the directory named by dirname and returns a list of sorted
// directory entries.
func (p Path) ReadDir() (fi []os.FileInfo, err error) {
	return ioutil.ReadDir(string(p))
}

// ReadFile is a wrappter to ioutil.ReadFile
func (p Path) ReadFile() ([]byte, error) {
	return ioutil.ReadFile(string(p))
}

// WriteFile is a wrappter to ioutil.WriteFile
func (p Path) WriteFile(data []byte, perm os.FileMode) error {
	return ioutil.WriteFile(string(p), data, perm)
}

// TempDir is a wrappter to ioutil.TempDir.
// It creates a new temporary directory in the directory dir with a name
// beginning with prefix and returns the path of the new directory. If dir is
// the empty string, TempDir uses the default directory for temporary files
// (see os.TempDir). Multiple programs calling TempDir simultaneously will not
// choose the same directory. It is the caller's responsibility to remove the
// directory when no longer needed.
func (p Path) TempDir(prefix string) (name Path, err error) {
	nm, err := ioutil.TempDir(string(p), prefix)
	return Path(nm), err
}

/*
	wrapppers of exec package
*/

// Command is a wrappter to exec.Command
func (p Path) Command(arg ...string) *exec.Cmd {
	return exec.Command(string(p), arg...)
}
<commit_msg>ADD Paths<commit_after>package villa

import (
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
)

// Path is a wrapper for a path in the OS.
// Some commonly used functions are wrapped as methods of Path,
// and results, if any, are converted back to Path
type Path string

// Paths returns an array of Path's given a list of strings.
func Paths(strs ...string) (paths []Path) {
	paths = make([]Path, len(strs))
	for i, str := range strs {
		paths[i] = Path(str)
	}
	return
}

// Join connect elems to the tail of path
func (p Path) Join(elem ...interface{}) Path {
	els := make(StringSlice, 0, len(elem)+1)
	els.Add(p).Add(elem...)
	return Path(filepath.Join(els...))
}

// Exists checks whether the file exists
func (p Path) Exists() bool {
	_, err := p.Stat()
	return err == nil
}

// IsDir returns true only if the path exists and indicates a directory
func (p Path) IsDir() bool {
	info, err := p.Stat()
	if err != nil {
		// the path does not exist
		return false
	}
	return info.Mode().IsDir()
}

// S converts Path back to string. This is sometimes more concise than string(p)
func (p Path) S() string {
	return string(p)
}

// AbsPath returns the absolute path returned by Path.Abs() if no error found,
// panic otherwise.
func (p Path) AbsPath() (ap Path) {
	ap, err := p.Abs()
	if err != nil {
		panic(err)
	}
	return ap
}

/*
	wrappers of path/filepath package
*/

// Abs is a wrapper to filepath.Abs
// It returns an absolute representation of path. If the path is not absolute it
// will be joined with the current working directory to turn it into an absolute
// path. The absolute path name for a given file is not guaranteed to be unique.
func (p Path) Abs() (pth Path, err error) {
	pt, err := filepath.Abs(string(p))
	return Path(pt), err
}

// Base returns the last element of path.
// Trailing path separators are removed before extracting the last element.
// If the path is empty, Base returns ".".
// If the path consists entirely of separators, Base returns a single separator.
func (p Path) Base() Path {
	return Path(filepath.Base(string(p)))
}

// Clean is a wrapper to filepath.Clean.
//
// It returns the shortest path name equivalent to path by purely lexically
// processing.
func (p Path) Clean() Path {
	return Path(filepath.Clean(string(p)))
}

// Dir is a wrapper to filepath.Dir.
// It returns all but the last element of path, typically the path's directory.
// Trailing path separators are removed before processing. If the path is empty,
// Dir returns ".". If the path consists entirely of separators, Dir returns a
// single separator. The returned path does not end in a separator unless it is
// the root directory.
func (p Path) Dir() Path {
	return Path(filepath.Dir(string(p)))
}

// EvalSymlinks is a wrapper to filepath.EvalSymlinks
func (p Path) EvalSymlinks() (Path, error) {
	pt, err := filepath.EvalSymlinks(string(p))
	return Path(pt), err
}

// Ext is a wrapper to filepath.Ext
func (p Path) Ext() string {
	return filepath.Ext(string(p))
}

// FromSlash is a wrapper to filepath.FromSlash
func (p Path) FromSlash() Path {
	return Path(filepath.FromSlash(string(p)))
}

// IsAbs is a wrapper to filepath.IsAbs
//
// IsAbs returns true if the path is absolute.
func (p Path) IsAbs() bool {
	return filepath.IsAbs(string(p))
}

// Rel is a wrapper to filepath.Rel.
// It returns a relative path that is lexically equivalent to targpath when
// joined to basepath with an intervening separator. That is, Join(basepath,
// Rel(basepath, targpath)) is equivalent to targpath itself. On success, the
// returned path will always be relative to basepath, even if basepath and
// targpath share no elements. An error is returned if targpath can't be made
// relative to basepath or if knowing the current working directory would be
// necessary to compute it.
func (p Path) Rel(targetpath Path) (Path, error) {
	rel, err := filepath.Rel(string(p), string(targetpath))
	return Path(rel), err
}

// Split is a wrapper to filepath.Split
func (p Path) Split() (dir, file Path) {
	d, f := filepath.Split(string(p))
	return Path(d), Path(f)
}

// SplitList is a wrapper to filepath.SplitList
func (p Path) SplitList() (lst []Path) {
	l := filepath.SplitList(string(p))
	lst = make([]Path, len(l))
	for i, el := range l {
		lst[i] = Path(el)
	}
	return
}

// ToSlash is a wrapper to filepath.ToSlash
func (p Path) ToSlash() string {
	return filepath.ToSlash(string(p))
}

// VolumeName is a wrapper to filepath.VolumeName
func (p Path) VolumeName() string {
	return filepath.VolumeName(string(p))
}

// WalkFunc is a wrapper to filepath.WalkFunc
// WalkFunc is the type of the function called for each file or directory
// visited by Walk. The path argument contains the argument to Walk as a prefix;
// that is, if Walk is called with "dir", which is a directory containing the
// file "a", the walk function will be called with argument "dir/a". The info
// argument is the os.FileInfo for the named path.
//
// If there was a problem walking to the file or directory named by path, the
// incoming error will describe the problem and the function can decide how to
// handle that error (and Walk will not descend into that directory). If an
// error is returned, processing stops. The sole exception is that if path is a
// directory and the function returns the special value filepath.SkipDir, the
// contents of the directory are skipped and processing continues as usual on
// the next file.
type WalkFunc func(path Path, info os.FileInfo, err error) error

// Walk is a wrapper to filepath.Walk
// Walk walks the file tree rooted at root, calling walkFn for each file or
// directory in the tree, including root. All errors that arise visiting files
// and directories are filtered by walkFn. The files are walked in lexical
// order, which makes the output deterministic but means that for very large
// directories Walk can be inefficient. Walk does not follow symbolic links.
func (p Path) Walk(walkFn WalkFunc) error {
	return filepath.Walk(string(p), func(path string, info os.FileInfo, err error) error {
		return walkFn(Path(path), info, err)
	})
}

/*
	wrappers of os package
*/

// Create is a wrapper to os.Create.
//
// It creates the named file mode 0666 (before umask), truncating it if it
// already exists. If successful, methods on the returned File can be used for
// I/O; the associated file descriptor has mode O_RDWR. If there is an error,
// it will be of type *PathError.
func (p Path) Create() (file *os.File, err error) {
	return os.Create(string(p))
}

// Open is a wrapper to os.Open.
//
// It opens the named file for reading. If successful, methods on the returned
// file can be used for reading; the associated file descriptor has mode O_RDONLY.
// If there is an error, it will be of type *PathError.
func (p Path) Open() (file *os.File, err error) {
	return os.Open(string(p))

}

// OpenFile is a wrapper to os.OpenFile.
//
// It is the generalized open call; most users will use Open or Create instead.
// It opens the named file with specified flag (O_RDONLY etc.) and perm,
// (0666 etc.) if applicable. If successful, methods on the returned File can be
// used for I/O. If there is an error, it will be of type *PathError.
func (p Path) OpenFile(flag int, perm os.FileMode) (file *os.File, err error) {
	return os.OpenFile(string(p), flag, perm)
}

// Mkdir is a wrappter to os.Mkdir.
//
// It creates a new directory with the specified name and permission bits. If
// there is an error, it will be of type *PathError.
func (p Path) Mkdir(perm os.FileMode) error {
	return os.Mkdir(string(p), perm)
}

// MkdirAll is a wrappter to os.MkdirAll.
//
// It creates a directory named path, along with any necessary parents, and
// returns nil, or else returns an error. The permission bits perm are used for
// all directories that MkdirAll creates. If path is already a directory,
// MkdirAll does nothing and returns nil.
func (p Path) MkdirAll(perm os.FileMode) error {
	return os.MkdirAll(string(p), perm)
}

// Remove is a wrappter to os.Remove
//
// Remove removes the named file or directory. If there is an error, it will be
// of type *PathError.
func (p Path) Remove() error {
	return os.Remove(string(p))
}

// RemoveAll is a wrappter to os.RemoveAll
// RemoveAll removes path and any children it contains. It removes everything it
// can but returns the first error it encounters. If the path does not exist,
// RemoveAll returns nil (no error).
func (p Path) RemoveAll() error {
	return os.RemoveAll(string(p))
}

// Rename is a wrappter to os.Rename
func (p Path) Rename(newname Path) error {
	return os.Rename(string(p), string(newname))
}

// Stat is a wrappter to os.Stat
func (p Path) Stat() (fi os.FileInfo, err error) {
	return os.Stat(string(p))
}

// Symlink is a wrappter to os.Symlink
func (p Path) Symlink(dst Path) error {
	return os.Symlink(string(p), string(dst))
}

/*
	wrappers of ioutil package
*/

// ReadDir is a wrappter to ioutil.ReadDir
//
// ReadDir reads the directory named by dirname and returns a list of sorted
// directory entries.
func (p Path) ReadDir() (fi []os.FileInfo, err error) {
	return ioutil.ReadDir(string(p))
}

// ReadFile is a wrappter to ioutil.ReadFile
func (p Path) ReadFile() ([]byte, error) {
	return ioutil.ReadFile(string(p))
}

// WriteFile is a wrappter to ioutil.WriteFile
func (p Path) WriteFile(data []byte, perm os.FileMode) error {
	return ioutil.WriteFile(string(p), data, perm)
}

// TempDir is a wrappter to ioutil.TempDir.
// It creates a new temporary directory in the directory dir with a name
// beginning with prefix and returns the path of the new directory. If dir is
// the empty string, TempDir uses the default directory for temporary files
// (see os.TempDir). Multiple programs calling TempDir simultaneously will not
// choose the same directory. It is the caller's responsibility to remove the
// directory when no longer needed.
func (p Path) TempDir(prefix string) (name Path, err error) {
	nm, err := ioutil.TempDir(string(p), prefix)
	return Path(nm), err
}

/*
	wrapppers of exec package
*/

// Command is a wrappter to exec.Command
func (p Path) Command(arg ...string) *exec.Cmd {
	return exec.Command(string(p), arg...)
}
<|endoftext|>


<commit_before>/*
* Copyright (c) 2014 Mark Samman <https://github.com/marksamman/gotorrent>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
 */

package main

import (
	"fmt"
	"log"
	"net"
)

type Peer struct {
	IP        uint32
	Port      uint16
	torrent   *Torrent
	handshake []byte

	am_choking      bool
	am_interested   bool
	peer_choking    bool
	peer_interested bool
}

func NewPeer(ip uint32, port uint16, torrent *Torrent) Peer {
	peer := Peer{}
	peer.IP = ip
	peer.Port = port
	peer.torrent = torrent

	peer.am_choking = true
	peer.am_interested = false
	peer.peer_choking = true
	peer.peer_interested = false
	return peer
}

func (peer *Peer) getStringIP() string {
	return fmt.Sprintf("%d.%d.%d.%d",
		peer.IP>>24, (peer.IP>>16)&255, (peer.IP>>8)&255, peer.IP&255)
}

func (peer *Peer) readN(n int, conn net.Conn) ([]byte, error) {
	buf := make([]byte, n)
	for pos := 0; pos < n; {
		count, err := conn.Read(buf[pos:])
		if err != nil {
			return nil, err
		}
		pos += count
	}
	return buf, nil
}

func (peer *Peer) connect() {
	addr := fmt.Sprintf("%s:%d", peer.getStringIP(), peer.Port)
	log.Println("connecting to:", addr)

	conn, err := net.Dial("tcp4", addr)
	if err != nil {
		log.Printf("failed to connect to peer: %s\n", err)
		return
	}
	defer conn.Close()

	log.Printf("connected to peer: %s\n", addr)

	// Send handshake
	if _, err := conn.Write(peer.torrent.Handshake); err != nil {
		log.Printf("failed to send handshake to peer: %s\n", err)
		return
	}

	// Receive handshake
	peer.handshake, err = peer.readN(68, conn)
	if err != nil {
		log.Printf("failed to read handshake from peer: %s\n", err)
		return
	}
	log.Printf("received handshake from peer: %s\n", peer.handshake)
}
<commit_msg>Validate info hash<commit_after>/*
* Copyright (c) 2014 Mark Samman <https://github.com/marksamman/gotorrent>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
 */

package main

import (
	"bytes"
	"fmt"
	"log"
	"net"
)

type Peer struct {
	IP        uint32
	Port      uint16
	torrent   *Torrent
	handshake []byte

	am_choking      bool
	am_interested   bool
	peer_choking    bool
	peer_interested bool
}

func NewPeer(ip uint32, port uint16, torrent *Torrent) Peer {
	peer := Peer{}
	peer.IP = ip
	peer.Port = port
	peer.torrent = torrent

	peer.am_choking = true
	peer.am_interested = false
	peer.peer_choking = true
	peer.peer_interested = false
	return peer
}

func (peer *Peer) getStringIP() string {
	return fmt.Sprintf("%d.%d.%d.%d",
		peer.IP>>24, (peer.IP>>16)&255, (peer.IP>>8)&255, peer.IP&255)
}

func (peer *Peer) readN(n int, conn net.Conn) ([]byte, error) {
	buf := make([]byte, n)
	for pos := 0; pos < n; {
		count, err := conn.Read(buf[pos:])
		if err != nil {
			return nil, err
		}
		pos += count
	}
	return buf, nil
}

func (peer *Peer) connect() {
	addr := fmt.Sprintf("%s:%d", peer.getStringIP(), peer.Port)
	log.Println("connecting to:", addr)

	conn, err := net.Dial("tcp4", addr)
	if err != nil {
		log.Printf("failed to connect to peer: %s\n", err)
		return
	}
	defer conn.Close()

	log.Printf("connected to peer: %s\n", addr)

	// Send handshake
	if _, err := conn.Write(peer.torrent.Handshake); err != nil {
		log.Printf("failed to send handshake to peer: %s\n", err)
		return
	}

	// Receive handshake
	peer.handshake, err = peer.readN(68, conn)
	if err != nil {
		log.Printf("failed to read handshake from peer: %s\n", err)
		return
	}

	// Validate info hash
	if !bytes.Equal(peer.handshake[28:48], peer.torrent.InfoHash) {
		log.Printf("info hash mismatch from peer: %s", addr)
		return
	}

	// TODO: Validate peer id if provided by tracker

	log.Printf("successfully exchanged handshake with peer: %s\n", addr)
}
<|endoftext|>


<commit_before>package pino

import (
	"fmt"

	irc "github.com/fluffle/goirc/client"
)

// Pino is the central orchestrator
type Pino struct {
	config                   *Config
	ircProxy                 *ircProxy
	slackProxy               *slackProxy
	slackChannelToIRCChannel map[SlackChannel]IRCChannel
	ircChannelToSlackChannel map[IRCChannel]SlackChannel
}

// NewPino creates a new Pino instance
func NewPino(config *Config) (*Pino, error) {
	pino := &Pino{
		config: config,
	}

	ircProxy, err := newIRCProxy(&config.IRC)
	if err != nil {
		return pino, fmt.Errorf("Could not create IRC client: %v", err)
	}
	pino.ircProxy = ircProxy

	slackProxy, err := newSlackProxy(&config.Slack)
	if err != nil {
		return pino, fmt.Errorf("Could not create Slack client: %v", err)
	}
	pino.slackProxy = slackProxy

	pino.slackChannelToIRCChannel = make(map[SlackChannel]IRCChannel)
	pino.ircChannelToSlackChannel = make(map[IRCChannel]SlackChannel)
	// Set up the Slack channel -> IRC channel name mappings, and vice versa
	for slackChannel, ircChannel := range pino.config.ChannelMapping {
		pino.slackChannelToIRCChannel[slackChannel] = ircChannel
		pino.ircChannelToSlackChannel[ircChannel] = slackChannel
	}

	return pino, nil
}

// Run connects to IRC and Slack and runs the main loop
func (pino *Pino) Run() error {
	if err := pino.ircProxy.connect(); err != nil {
		return fmt.Errorf("IRC connection error: %s\n", err.Error())
	}
	if err := pino.slackProxy.connect(); err != nil {
		return fmt.Errorf("Slack connection error: %s\n", err.Error())
	}

	// Channel to signal that the program should stop running
	quit := make(chan bool)

	go pino.handleIRCEvents(quit)

	<-quit

	return nil
}

// Consumes incoming IRC events in a loop
func (pino *Pino) handleIRCEvents(quit chan bool) {
	for {
		select {
		case line := <-pino.ircProxy.incomingEvents:
			switch line.Cmd {
			case irc.CONNECTED:
				fmt.Printf("Connected to IRC!\n")
				ircChannels := pino.config.getUsedIRCChannels()
				for _, ircChannel := range ircChannels {
					fmt.Printf("Joining IRC channel: %v\n", ircChannel)
					pino.ircProxy.join(ircChannel)
				}

			case irc.DISCONNECTED:
				fmt.Printf("Disconnected from IRC!")

			case irc.ACTION:
				channel := IRCChannel(line.Target())
				action := line.Text()
				username := line.Nick

				fmt.Printf("ACTION: %v %s\n", username, action)
				message := fmt.Sprintf("```%v %v```", username, action)
				pino.slackProxy.sendMessageAsUser(username, message, pino.ircChannelToSlackChannel[channel])

			case irc.JOIN:
				channel := IRCChannel(line.Text())
				username := line.Nick
				usermask := line.Src

				fmt.Printf("JOIN: %v(%v) has joined %v\n", line.Nick, line.Src, channel)
				message := fmt.Sprintf("```%v(%v) has joined```", username, usermask)
				pino.slackProxy.sendMessageAsBot(message, pino.ircChannelToSlackChannel[channel])

			case irc.INVITE:
				// Actually doing anything with invites has not been implemented yet.
				channel := line.Args[1]
				fmt.Printf("INVITE: %v(%v) invited you to %v\n", line.Nick, line.Src, channel)

			case irc.KICK:
				kickee := line.Args[1]
				reason := line.Args[2:]
				fmt.Printf("KICK: (%v) %v has kicked %v (%v)\n", line.Target(), line.Nick, kickee, reason)

			case irc.MODE:
				username := line.Nick
				mode := line.Args[1]

				if len(line.Args) == 2 {
					// This was a User mode command
					destination := line.Args[0]
					fmt.Printf("MODE: %v has set mode %v on %v\n", username, mode, destination)
				} else {
					// This was a Channel mode command
					channel := IRCChannel(line.Args[0])
					destination := line.Args[2]
					fmt.Printf("MODE: (%v) %v sets %v %v\n", channel, username, mode, destination)

					message := fmt.Sprintf("```%v sets %v %v```", username, mode, destination)
					pino.slackProxy.sendMessageAsBot(message, pino.ircChannelToSlackChannel[channel])
				}

			case irc.NICK:
				newNick := line.Text()
				fmt.Printf("NICK: %v is now known as %v\n", line.Nick, newNick)

			case irc.PART:
				reason := line.Text()
				fmt.Printf("PART: (%v) %v(%v) has left (%s)\n", line.Target(), line.Nick, line.Src, reason)

			case irc.PRIVMSG:
				fmt.Printf("PRIVMSG: (%v) <%v> %v\n", line.Target(), line.Nick, line.Text())

			case irc.QUIT:
				fmt.Printf("QUIT: %v(%v) has quit\n", line.Nick, line.Src)

			case irc.TOPIC:
				newTopic := line.Text()
				fmt.Printf("TOPIC: (%v) %v has changed the topic to \"%v\"\n", line.Target(), line.Nick, newTopic)

			default:
				fmt.Printf("Received unrecognized line: %#v\n", line)
			}
		default:
			// No message was received
		}
	}
}
<commit_msg>implement sending nick change messages to Slack<commit_after>package pino

import (
	"fmt"

	irc "github.com/fluffle/goirc/client"
)

// Pino is the central orchestrator
type Pino struct {
	config                   *Config
	ircProxy                 *ircProxy
	slackProxy               *slackProxy
	slackChannelToIRCChannel map[SlackChannel]IRCChannel
	ircChannelToSlackChannel map[IRCChannel]SlackChannel
}

// NewPino creates a new Pino instance
func NewPino(config *Config) (*Pino, error) {
	pino := &Pino{
		config: config,
	}

	ircProxy, err := newIRCProxy(&config.IRC)
	if err != nil {
		return pino, fmt.Errorf("Could not create IRC client: %v", err)
	}
	pino.ircProxy = ircProxy

	slackProxy, err := newSlackProxy(&config.Slack)
	if err != nil {
		return pino, fmt.Errorf("Could not create Slack client: %v", err)
	}
	pino.slackProxy = slackProxy

	pino.slackChannelToIRCChannel = make(map[SlackChannel]IRCChannel)
	pino.ircChannelToSlackChannel = make(map[IRCChannel]SlackChannel)
	// Set up the Slack channel -> IRC channel name mappings, and vice versa
	for slackChannel, ircChannel := range pino.config.ChannelMapping {
		pino.slackChannelToIRCChannel[slackChannel] = ircChannel
		pino.ircChannelToSlackChannel[ircChannel] = slackChannel
	}

	return pino, nil
}

// Run connects to IRC and Slack and runs the main loop
func (pino *Pino) Run() error {
	if err := pino.ircProxy.connect(); err != nil {
		return fmt.Errorf("IRC connection error: %s\n", err.Error())
	}
	if err := pino.slackProxy.connect(); err != nil {
		return fmt.Errorf("Slack connection error: %s\n", err.Error())
	}

	// Channel to signal that the program should stop running
	quit := make(chan bool)

	go pino.handleIRCEvents(quit)

	<-quit

	return nil
}

// Consumes incoming IRC events in a loop
func (pino *Pino) handleIRCEvents(quit chan bool) {
	for {
		select {
		case line := <-pino.ircProxy.incomingEvents:
			switch line.Cmd {
			case irc.CONNECTED:
				fmt.Printf("Connected to IRC!\n")
				ircChannels := pino.config.getUsedIRCChannels()
				for _, ircChannel := range ircChannels {
					fmt.Printf("Joining IRC channel: %v\n", ircChannel)
					pino.ircProxy.join(ircChannel)
				}

			case irc.DISCONNECTED:
				fmt.Printf("Disconnected from IRC!")

			case irc.ACTION:
				channel := IRCChannel(line.Target())
				action := line.Text()
				username := line.Nick

				fmt.Printf("ACTION: %v %s\n", username, action)
				message := fmt.Sprintf("```%v %v```", username, action)
				pino.slackProxy.sendMessageAsUser(username, message, pino.ircChannelToSlackChannel[channel])

			case irc.JOIN:
				channel := IRCChannel(line.Text())
				username := line.Nick
				usermask := line.Src

				fmt.Printf("JOIN: %v(%v) has joined %v\n", line.Nick, line.Src, channel)
				message := fmt.Sprintf("```%v(%v) has joined```", username, usermask)
				pino.slackProxy.sendMessageAsBot(message, pino.ircChannelToSlackChannel[channel])

			case irc.INVITE:
				// Actually doing anything with invites has not been implemented yet.
				channel := line.Args[1]
				fmt.Printf("INVITE: %v(%v) invited you to %v\n", line.Nick, line.Src, channel)

			case irc.KICK:
				kickee := line.Args[1]
				reason := line.Args[2:]
				fmt.Printf("KICK: (%v) %v has kicked %v (%v)\n", line.Target(), line.Nick, kickee, reason)

			case irc.MODE:
				username := line.Nick
				mode := line.Args[1]

				if len(line.Args) == 2 {
					// This was a User mode command
					destination := line.Args[0]
					fmt.Printf("MODE: %v has set mode %v on %v\n", username, mode, destination)
				} else {
					// This was a Channel mode command
					channel := IRCChannel(line.Args[0])
					destination := line.Args[2]
					fmt.Printf("MODE: (%v) %v sets %v %v\n", channel, username, mode, destination)

					message := fmt.Sprintf("```%v sets %v %v```", username, mode, destination)
					pino.slackProxy.sendMessageAsBot(message, pino.ircChannelToSlackChannel[channel])
				}

			case irc.NICK:
				oldNick := line.Nick
				newNick := line.Text()
				fmt.Printf("NICK: %v is now known as %v\n", oldNick, newNick)

				message := fmt.Sprintf("```%v is now known as %v```", oldNick, newNick)
				stateTracker := pino.ircProxy.client.StateTracker()
				for ircChannel, slackChannel := range pino.ircChannelToSlackChannel {
					// The state tracker has already registered the nick change, so check for the new nick
					if _, ok := stateTracker.IsOn(string(ircChannel), newNick); ok != false {
						pino.slackProxy.sendMessageAsBot(message, slackChannel)
					}
				}

			case irc.PART:
				reason := line.Text()
				fmt.Printf("PART: (%v) %v(%v) has left (%s)\n", line.Target(), line.Nick, line.Src, reason)

			case irc.PRIVMSG:
				fmt.Printf("PRIVMSG: (%v) <%v> %v\n", line.Target(), line.Nick, line.Text())

			case irc.QUIT:
				fmt.Printf("QUIT: %v(%v) has quit\n", line.Nick, line.Src)

			case irc.TOPIC:
				newTopic := line.Text()
				fmt.Printf("TOPIC: (%v) %v has changed the topic to \"%v\"\n", line.Target(), line.Nick, newTopic)

			default:
				fmt.Printf("Received unrecognized line: %#v\n", line)
			}
		default:
			// No message was received
		}
	}
}
<|endoftext|>


<commit_before>/*
Package pipe provides filters that can be chained together in a manner
similar to Unix pipelines.

Each filter is a function that takes as input a sequence of
strings (read from a channel) and produces as output a sequence of
strings (written to a channel).

Filters can be chained together (e.g., via the Run function), the
output of one filter is fed as input to the next filter.  The empty
input is passed to the first filter. The following sequence will
print two lines to standard output:

	Run(
		Echo("hello", "world"),
		Reverse(),
		Tee(os.Stdout),
	)

An application can implement its own filters easily. For example,
Repeat(n) returns a filter that repeats every input n times:

	func Repeat(n int) Filter {
		return func(arg Arg) {
			for s := range arg.In {
				for i := 0; i < n; i++ {
					arg.Out <- s
			}
		}
	}

	Run(
		Echo("hello"),
		Repeat(10),
	)
*/
package pipe

import (
	"bufio"
	"fmt"
	"io"
	"regexp"
	"sync"
)

// filterErrors records errors accumulated during the execution of a filter.
type filterErrors struct {
	mu     sync.Mutex
	errors []error
}

// Arg contains the data passed to a Filter. Arg.In is a channel that
// produces the input to the filter, and Arg.Out is a channel that
// receives the output from the filter.
type Arg struct {
	In     <-chan string
	Out    chan<- string
	errors *filterErrors
}

// ReportError records an error encountered during an execution of a filter.
// This error will be reported by whatever facility (e.g., ForEach or Run)
// was being used to execute the filters.
func (a *Arg) ReportError(err error) {
	a.errors.mu.Lock()
	defer a.errors.mu.Unlock()
	a.errors.errors = append(a.errors.errors, err)
}

// Filter reads a sequence of strings from a channel and produces a
// sequence on another channel.
type Filter func(Arg)

// Sequence returns a filter that is the concatenation of all filter arguments.
// The output of a filter is fed as input to the next filter.
func Sequence(filters ...Filter) Filter {
	return func(arg Arg) {
		in := arg.In
		for _, f := range filters {
			c := make(chan string, 10000)
			go runAndClose(f, Arg{in, c, arg.errors})
			in = c
		}
		passThrough(Arg{in, arg.Out, arg.errors})
	}
}

// Run() executes the sequence of filters and discards all output.
// It returns either nil, an error if any filter reported an error.
func Run(filters ...Filter) error {
	return ForEach(Sequence(filters...), func(s string) {})
}

// ForEach() calls fn(s) for every item s in the output of filter and
// returns either nil, or any error reported by the execution of the filter.
func ForEach(filter Filter, fn func(s string)) error {
	in := make(chan string, 0)
	close(in)
	out := make(chan string, 10000)
	e := &filterErrors{}
	go runAndClose(filter, Arg{in, out, e})
	for s := range out {
		fn(s)
	}

	e.mu.Lock()
	defer e.mu.Unlock()
	switch len(e.errors) {
	case 0:
		return nil
	case 1:
		return e.errors[0]
	default:
		return fmt.Errorf("Filter errors: %s", e.errors)
	}
}

func runAndClose(f Filter, arg Arg) {
	f(arg)
	close(arg.Out)
}

// passThrough copies all items read from in to out.
func passThrough(arg Arg) {
	for s := range arg.In {
		arg.Out <- s
	}
}

func splitIntoLines(rd io.Reader, arg Arg) {
	scanner := bufio.NewScanner(rd)
	for scanner.Scan() {
		arg.Out <- scanner.Text()
	}
}

// Echo copies its input and then emits items.
func Echo(items ...string) Filter {
	return func(arg Arg) {
		passThrough(arg)
		for _, s := range items {
			arg.Out <- s
		}
	}
}

// Numbers copies its input and then emits the integers x..y
func Numbers(x, y int) Filter {
	return func(arg Arg) {
		passThrough(arg)
		for i := x; i <= y; i++ {
			arg.Out <- fmt.Sprintf("%d", i)
		}
	}
}

// Map calls fn(x) for every item x and yields the outputs of the fn calls.
func Map(fn func(string) string) Filter {
	return func(arg Arg) {
		for s := range arg.In {
			arg.Out <- fn(s)
		}
	}
}

// If emits every input x for which fn(x) is true.
func If(fn func(string) bool) Filter {
	return func(arg Arg) {
		for s := range arg.In {
			if fn(s) {
				arg.Out <- s
			}
		}
	}
}

// Grep emits every input x that matches the regular expression r.
func Grep(r string) Filter {
	re := regexp.MustCompile(r)
	return If(re.MatchString)
}

// GrepNot emits every input x that does not match the regular expression r.
func GrepNot(r string) Filter {
	re := regexp.MustCompile(r)
	return If(func(s string) bool { return !re.MatchString(s) })
}

// Uniq squashes adjacent identical items in arg.In into a single output.
func Uniq() Filter {
	return func(arg Arg) {
		first := true
		last := ""
		for s := range arg.In {
			if first || last != s {
				arg.Out <- s
			}
			last = s
			first = false
		}
	}
}

// UniqWithCount squashes adjacent identical items in arg.In into a single
// output prefixed with the count of identical items.
func UniqWithCount() Filter {
	return func(arg Arg) {
		current := ""
		count := 0
		for s := range arg.In {
			if s != current {
				if count > 0 {
					arg.Out <- fmt.Sprintf("%d %s", count, current)
				}
				count = 0
				current = s
			}
			count++
		}
		if count > 0 {
			arg.Out <- fmt.Sprintf("%d %s", count, current)
		}
	}
}

// Substitute replaces all occurrences of the regular expression r in
// an input item with replacement.  The replacement string can contain
// $1, $2, etc. which represent submatches of r.
func Substitute(r, replacement string) Filter {
	re := regexp.MustCompile(r)
	return func(arg Arg) {
		for s := range arg.In {
			arg.Out <- re.ReplaceAllString(s, replacement)
		}
	}
}

// Reverse yields items in the reverse of the order it received them.
func Reverse() Filter {
	return func(arg Arg) {
		var data []string
		for s := range arg.In {
			data = append(data, s)
		}
		for i := len(data) - 1; i >= 0; i-- {
			arg.Out <- data[i]
		}
	}
}

// First yields the first n items that it receives.
func First(n int) Filter {
	return func(arg Arg) {
		emitted := 0
		for s := range arg.In {
			if emitted < n {
				arg.Out <- s
				emitted++
			}
		}
	}
}

// DropFirst yields all items except for the first n items that it receives.
func DropFirst(n int) Filter {
	return func(arg Arg) {
		emitted := 0
		for s := range arg.In {
			if emitted >= n {
				arg.Out <- s
			}
			emitted++
		}
	}
}

// Last yields the last n items that it receives.
func Last(n int) Filter {
	return func(arg Arg) {
		var buf []string
		for s := range arg.In {
			buf = append(buf, s)
			if len(buf) > n {
				buf = buf[1:]
			}
		}
		for _, s := range buf {
			arg.Out <- s
		}
	}
}

// DropFirst yields all items except for the last n items that it receives.
func DropLast(n int) Filter {
	return func(arg Arg) {
		var buf []string
		for s := range arg.In {
			buf = append(buf, s)
			if len(buf) > n {
				arg.Out <- buf[0]
				buf = buf[1:]
			}
		}
	}
}

// NumberLines prefixes its item with its index in the input sequence
// (starting at 1).
func NumberLines() Filter {
	return func(arg Arg) {
		line := 1
		for s := range arg.In {
			arg.Out <- fmt.Sprintf("%5d %s", line, s)
			line++
		}
	}
}

// Cut emits just the bytes indexed [start..end] of each input item.
func Cut(start, end int) Filter {
	return func(arg Arg) {
		for s := range arg.In {
			if len(s) > end {
				s = s[:end+1]
			}
			if len(s) < start {
				s = ""
			} else {
				s = s[start:]
			}
			arg.Out <- s
		}
	}
}

// Select splits each item into columns and yields the concatenation
// of the columns numbers passed as arguments to Select.  Columns are
// numbered starting at 1. A column number of 0 is interpreted as the
// full string.
func Select(columns ...int) Filter {
	return func(arg Arg) {
		for s := range arg.In {
			result := ""
			for _, col := range columns {
				if _, c := column(s, col); c != "" {
					if result != "" {
						result = result + " "
					}
					result = result + c
				}
			}
			arg.Out <- result
		}
	}
}
<commit_msg>fixed typo in comment<commit_after>/*
Package pipe provides filters that can be chained together in a manner
similar to Unix pipelines.

Each filter is a function that takes as input a sequence of
strings (read from a channel) and produces as output a sequence of
strings (written to a channel).

Filters can be chained together (e.g., via the Run function), the
output of one filter is fed as input to the next filter.  The empty
input is passed to the first filter. The following sequence will
print two lines to standard output:

	Run(
		Echo("hello", "world"),
		Reverse(),
		Tee(os.Stdout),
	)

An application can implement its own filters easily. For example,
Repeat(n) returns a filter that repeats every input n times:

	func Repeat(n int) Filter {
		return func(arg Arg) {
			for s := range arg.In {
				for i := 0; i < n; i++ {
					arg.Out <- s
				}
			}
		}
	}

	Run(
		Echo("hello"),
		Repeat(10),
	)
*/
package pipe

import (
	"bufio"
	"fmt"
	"io"
	"regexp"
	"sync"
)

// filterErrors records errors accumulated during the execution of a filter.
type filterErrors struct {
	mu     sync.Mutex
	errors []error
}

// Arg contains the data passed to a Filter. Arg.In is a channel that
// produces the input to the filter, and Arg.Out is a channel that
// receives the output from the filter.
type Arg struct {
	In     <-chan string
	Out    chan<- string
	errors *filterErrors
}

// ReportError records an error encountered during an execution of a filter.
// This error will be reported by whatever facility (e.g., ForEach or Run)
// was being used to execute the filters.
func (a *Arg) ReportError(err error) {
	a.errors.mu.Lock()
	defer a.errors.mu.Unlock()
	a.errors.errors = append(a.errors.errors, err)
}

// Filter reads a sequence of strings from a channel and produces a
// sequence on another channel.
type Filter func(Arg)

// Sequence returns a filter that is the concatenation of all filter arguments.
// The output of a filter is fed as input to the next filter.
func Sequence(filters ...Filter) Filter {
	return func(arg Arg) {
		in := arg.In
		for _, f := range filters {
			c := make(chan string, 10000)
			go runAndClose(f, Arg{in, c, arg.errors})
			in = c
		}
		passThrough(Arg{in, arg.Out, arg.errors})
	}
}

// Run() executes the sequence of filters and discards all output.
// It returns either nil, an error if any filter reported an error.
func Run(filters ...Filter) error {
	return ForEach(Sequence(filters...), func(s string) {})
}

// ForEach() calls fn(s) for every item s in the output of filter and
// returns either nil, or any error reported by the execution of the filter.
func ForEach(filter Filter, fn func(s string)) error {
	in := make(chan string, 0)
	close(in)
	out := make(chan string, 10000)
	e := &filterErrors{}
	go runAndClose(filter, Arg{in, out, e})
	for s := range out {
		fn(s)
	}

	e.mu.Lock()
	defer e.mu.Unlock()
	switch len(e.errors) {
	case 0:
		return nil
	case 1:
		return e.errors[0]
	default:
		return fmt.Errorf("Filter errors: %s", e.errors)
	}
}

func runAndClose(f Filter, arg Arg) {
	f(arg)
	close(arg.Out)
}

// passThrough copies all items read from in to out.
func passThrough(arg Arg) {
	for s := range arg.In {
		arg.Out <- s
	}
}

func splitIntoLines(rd io.Reader, arg Arg) {
	scanner := bufio.NewScanner(rd)
	for scanner.Scan() {
		arg.Out <- scanner.Text()
	}
}

// Echo copies its input and then emits items.
func Echo(items ...string) Filter {
	return func(arg Arg) {
		passThrough(arg)
		for _, s := range items {
			arg.Out <- s
		}
	}
}

// Numbers copies its input and then emits the integers x..y
func Numbers(x, y int) Filter {
	return func(arg Arg) {
		passThrough(arg)
		for i := x; i <= y; i++ {
			arg.Out <- fmt.Sprintf("%d", i)
		}
	}
}

// Map calls fn(x) for every item x and yields the outputs of the fn calls.
func Map(fn func(string) string) Filter {
	return func(arg Arg) {
		for s := range arg.In {
			arg.Out <- fn(s)
		}
	}
}

// If emits every input x for which fn(x) is true.
func If(fn func(string) bool) Filter {
	return func(arg Arg) {
		for s := range arg.In {
			if fn(s) {
				arg.Out <- s
			}
		}
	}
}

// Grep emits every input x that matches the regular expression r.
func Grep(r string) Filter {
	re := regexp.MustCompile(r)
	return If(re.MatchString)
}

// GrepNot emits every input x that does not match the regular expression r.
func GrepNot(r string) Filter {
	re := regexp.MustCompile(r)
	return If(func(s string) bool { return !re.MatchString(s) })
}

// Uniq squashes adjacent identical items in arg.In into a single output.
func Uniq() Filter {
	return func(arg Arg) {
		first := true
		last := ""
		for s := range arg.In {
			if first || last != s {
				arg.Out <- s
			}
			last = s
			first = false
		}
	}
}

// UniqWithCount squashes adjacent identical items in arg.In into a single
// output prefixed with the count of identical items.
func UniqWithCount() Filter {
	return func(arg Arg) {
		current := ""
		count := 0
		for s := range arg.In {
			if s != current {
				if count > 0 {
					arg.Out <- fmt.Sprintf("%d %s", count, current)
				}
				count = 0
				current = s
			}
			count++
		}
		if count > 0 {
			arg.Out <- fmt.Sprintf("%d %s", count, current)
		}
	}
}

// Substitute replaces all occurrences of the regular expression r in
// an input item with replacement.  The replacement string can contain
// $1, $2, etc. which represent submatches of r.
func Substitute(r, replacement string) Filter {
	re := regexp.MustCompile(r)
	return func(arg Arg) {
		for s := range arg.In {
			arg.Out <- re.ReplaceAllString(s, replacement)
		}
	}
}

// Reverse yields items in the reverse of the order it received them.
func Reverse() Filter {
	return func(arg Arg) {
		var data []string
		for s := range arg.In {
			data = append(data, s)
		}
		for i := len(data) - 1; i >= 0; i-- {
			arg.Out <- data[i]
		}
	}
}

// First yields the first n items that it receives.
func First(n int) Filter {
	return func(arg Arg) {
		emitted := 0
		for s := range arg.In {
			if emitted < n {
				arg.Out <- s
				emitted++
			}
		}
	}
}

// DropFirst yields all items except for the first n items that it receives.
func DropFirst(n int) Filter {
	return func(arg Arg) {
		emitted := 0
		for s := range arg.In {
			if emitted >= n {
				arg.Out <- s
			}
			emitted++
		}
	}
}

// Last yields the last n items that it receives.
func Last(n int) Filter {
	return func(arg Arg) {
		var buf []string
		for s := range arg.In {
			buf = append(buf, s)
			if len(buf) > n {
				buf = buf[1:]
			}
		}
		for _, s := range buf {
			arg.Out <- s
		}
	}
}

// DropFirst yields all items except for the last n items that it receives.
func DropLast(n int) Filter {
	return func(arg Arg) {
		var buf []string
		for s := range arg.In {
			buf = append(buf, s)
			if len(buf) > n {
				arg.Out <- buf[0]
				buf = buf[1:]
			}
		}
	}
}

// NumberLines prefixes its item with its index in the input sequence
// (starting at 1).
func NumberLines() Filter {
	return func(arg Arg) {
		line := 1
		for s := range arg.In {
			arg.Out <- fmt.Sprintf("%5d %s", line, s)
			line++
		}
	}
}

// Cut emits just the bytes indexed [start..end] of each input item.
func Cut(start, end int) Filter {
	return func(arg Arg) {
		for s := range arg.In {
			if len(s) > end {
				s = s[:end+1]
			}
			if len(s) < start {
				s = ""
			} else {
				s = s[start:]
			}
			arg.Out <- s
		}
	}
}

// Select splits each item into columns and yields the concatenation
// of the columns numbers passed as arguments to Select.  Columns are
// numbered starting at 1. A column number of 0 is interpreted as the
// full string.
func Select(columns ...int) Filter {
	return func(arg Arg) {
		for s := range arg.In {
			result := ""
			for _, col := range columns {
				if _, c := column(s, col); c != "" {
					if result != "" {
						result = result + " "
					}
					result = result + c
				}
			}
			arg.Out <- result
		}
	}
}
<|endoftext|>