<commit_before>// comment this out // // + build testing

// Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.

package codec

import (
	"strconv"
	"strings"
	"time"
)

const teststrucflexChanCap = 64

// This file contains values used by tests alone.
// This is where we may try out different things,
// that other engines may not support or may barf upon
// e.g. custom extensions for wrapped types, maps with non-string keys, etc.

// some funky types to test codecgen

type codecgenA struct {
	ZZ []byte
}
type codecgenB struct {
	AA codecgenA
}
type codecgenC struct {
	_struct struct{} `codec:",omitempty"`
	BB      codecgenB
}

type TestCodecgenG struct {
	TestCodecgenG int
}
type codecgenH struct {
	TestCodecgenG
}
type codecgenI struct {
	codecgenH
}

type codecgenK struct {
	X int
	Y string
}
type codecgenL struct {
	X int
	Y uint32
}
type codecgenM struct {
	codecgenK
	codecgenL
}

// some types to test struct keytype

type testStrucKeyTypeT0 struct {
	_struct struct{}
	F       int
}
type testStrucKeyTypeT1 struct {
	_struct struct{} `codec:",string"`
	F       int      `codec:"FFFF"`
}
type testStrucKeyTypeT2 struct {
	_struct struct{} `codec:",int"`
	F       int      `codec:"-1"`
}
type testStrucKeyTypeT3 struct {
	_struct struct{} `codec:",uint"`
	F       int      `codec:"1"`
}
type testStrucKeyTypeT4 struct {
	_struct struct{} `codec:",float"`
	F       int      `codec:"2.5"`
}

// Some unused types just stored here

type Bbool bool
type Aarray [1]string
type Sstring string
type Sstructsmall struct {
	A int
}

type Sstructbig struct {
	A int
	B bool
	c string
	// Sval Sstruct
	Ssmallptr *Sstructsmall
	Ssmall    *Sstructsmall
	Sptr      *Sstructbig
}

type SstructbigMapBySlice struct {
	_struct struct{} `codec:",toarray"`
	A       int
	B       bool
	c       string
	// Sval Sstruct
	Ssmallptr *Sstructsmall
	Ssmall    *Sstructsmall
	Sptr      *Sstructbig
}

// small struct for testing that codecgen works for unexported types
type tLowerFirstLetter struct {
	I int
	u uint64
	S string
	b []byte
}

// Some used types
type wrapInt64 int64
type wrapUint8 uint8
type wrapBytes []byte

type AnonInTestStrucIntf struct {
	Islice []interface{}
	Ms     map[string]interface{}
	Nintf  interface{} //don't set this, so we can test for nil
	T      time.Time
	Tptr   *time.Time
}

type missingFielderT1 struct {
	S string
	B bool
	f float64
	i int64
}

func (t *missingFielderT1) CodecMissingField(field []byte, value interface{}) bool {
	switch string(field) {
	case "F":
		t.f = value.(float64)
	case "I":
		t.i = value.(int64)
	default:
		return false
	}
	return true
}

func (t *missingFielderT1) CodecMissingFields() map[string]interface{} {
	return map[string]interface{}{"F": t.f, "I": t.i}
}

type missingFielderT2 struct {
	S string
	B bool
	F float64
	I int64
}

type testSelfExtHelper struct {
	S string
	I int64
	B bool
}

type TestSelfExtImpl struct {
	testSelfExtHelper
}

type TestSelfExtImpl2 struct {
	M string
	O bool
}

type TestTwoNakedInterfaces struct {
	A interface{}
	B interface{}
}

var testWRepeated512 wrapBytes
var testStrucTime = time.Date(2012, 2, 2, 2, 2, 2, 2000, time.UTC).UTC()

func init() {
	var testARepeated512 [512]byte
	for i := range testARepeated512 {
		testARepeated512[i] = 'A'
	}
	testWRepeated512 = wrapBytes(testARepeated512[:])
}

type TestStrucFlex struct {
	_struct struct{} `codec:",omitempty"` //set omitempty for every field
	TestStrucCommon

	Chstr chan string

	Mis     map[int]string
	Mbu64   map[bool]struct{}
	Miwu64s map[int]wrapUint64Slice
	Mfwss   map[float64]wrapStringSlice
	Mf32wss map[float32]wrapStringSlice
	Mui2wss map[uint64]wrapStringSlice

	// DecodeNaked bombs because stringUint64T is decoded as a map,
	// and a map cannot be the key type of a map.
	// Ensure this is set to nil if decoding into a nil interface{}.
	Msu2wss map[stringUint64T]wrapStringSlice

	Ci64       wrapInt64
	Swrapbytes []wrapBytes
	Swrapuint8 []wrapUint8

	ArrStrUi64T [4]stringUint64T

	Ui64array      [4]uint64
	Ui64slicearray []*[4]uint64

	SintfAarray []interface{}

	// Ensure this is set to nil if decoding into a nil interface{}.
	MstrUi64TSelf map[stringUint64T]*stringUint64T

	Ttime    time.Time
	Ttimeptr *time.Time

	// make this a ptr, so that it could be set or not.
	// for comparison (e.g. with msgp), give it a struct tag (so it is not inlined),
	// make this one omitempty (so it is excluded if nil).
	*AnonInTestStrucIntf `json:",omitempty"`

	//M map[interface{}]interface{}  `json:"-",bson:"-"`
	Mtsptr     map[string]*TestStrucFlex
	Mts        map[string]TestStrucFlex
	Its        []*TestStrucFlex
	Nteststruc *TestStrucFlex

	Ffunc       func() error // expect this to be skipped/ignored
	Bboolignore bool         `codec:"-"` // expect this to be skipped/ignored
}

func emptyTestStrucFlex() *TestStrucFlex {
	var ts TestStrucFlex
	// we initialize and start draining the chan, so that we can decode into it without it blocking due to no consumer
	ts.Chstr = make(chan string, teststrucflexChanCap)
	go func() {
		for range ts.Chstr {
		}
	}() // drain it
	return &ts
}

func newTestStrucFlex(depth, n int, bench, useInterface, useStringKeyOnly bool) (ts *TestStrucFlex) {
	ts = &TestStrucFlex{
		Chstr: make(chan string, teststrucflexChanCap),

		Miwu64s: map[int]wrapUint64Slice{
			5: []wrapUint64{1, 2, 3, 4, 5},
			3: []wrapUint64{1, 2, 3},
		},

		Mf32wss: map[float32]wrapStringSlice{
			5.0: []wrapString{"1.0", "2.0", "3.0", "4.0", "5.0"},
			3.0: []wrapString{"1.0", "2.0", "3.0"},
		},

		Mui2wss: map[uint64]wrapStringSlice{
			5: []wrapString{"1.0", "2.0", "3.0", "4.0", "5.0"},
			3: []wrapString{"1.0", "2.0", "3.0"},
		},

		Mfwss: map[float64]wrapStringSlice{
			5.0: []wrapString{"1.0", "2.0", "3.0", "4.0", "5.0"},
			3.0: []wrapString{"1.0", "2.0", "3.0"},
		},

		// DecodeNaked bombs here, because the stringUint64T is decoded as a map,
		// and a map cannot be the key type of a map.
		// Ensure this is set to nil if decoding into a nil interface{}.
		Msu2wss: map[stringUint64T]wrapStringSlice{
			stringUint64T{"5", 5}: []wrapString{"1", "2", "3", "4", "5"},
			stringUint64T{"3", 3}: []wrapString{"1", "2", "3"},
		},

		Mis: map[int]string{
			1:   "one",
			22:  "twenty two",
			-44: "minus forty four",
		},
		Mbu64: map[bool]struct{}{false: {}, true: {}},

		Ci64: -22,
		Swrapbytes: []wrapBytes{ // lengths of 1, 2, 4, 8, 16, 32, 64, 128, 256,
			testWRepeated512[:1],
			testWRepeated512[:2],
			testWRepeated512[:4],
			testWRepeated512[:8],
			testWRepeated512[:16],
			testWRepeated512[:32],
			testWRepeated512[:64],
			testWRepeated512[:128],
			testWRepeated512[:256],
			testWRepeated512[:512],
		},
		Swrapuint8: []wrapUint8{
			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
		},
		Ui64array:     [4]uint64{4, 16, 64, 256},
		ArrStrUi64T:   [4]stringUint64T{{"4", 4}, {"3", 3}, {"2", 2}, {"1", 1}},
		SintfAarray:   []interface{}{Aarray{"s"}},
		MstrUi64TSelf: make(map[stringUint64T]*stringUint64T, numStrUi64T),

		Ttime:    testStrucTime,
		Ttimeptr: &testStrucTime,
	}

	for i := uint64(0); i < numStrUi64T; i++ {
		ss := stringUint64T{S: strings.Repeat(strconv.FormatUint(i, 10), 4), U: i}
		// Ensure this is set to nil if decoding into a nil interface{}.
		ts.MstrUi64TSelf[ss] = &ss
	}

	numChanSend := cap(ts.Chstr) / 4 // 8
	for i := 0; i < numChanSend; i++ {
		ts.Chstr <- strings.Repeat("A", i+1)
	}

	ts.Ui64slicearray = []*[4]uint64{&ts.Ui64array, &ts.Ui64array}

	if useInterface {
		ts.AnonInTestStrucIntf = &AnonInTestStrucIntf{
			Islice: []interface{}{strRpt(n, "true"), true, strRpt(n, "no"), false, uint64(288), float64(0.4)},
			Ms: map[string]interface{}{
				strRpt(n, "true"):     strRpt(n, "true"),
				strRpt(n, "int64(9)"): false,
			},
			T:    testStrucTime,
			Tptr: &testStrucTime,
		}
	}

	populateTestStrucCommon(&ts.TestStrucCommon, n, bench, useInterface, useStringKeyOnly)
	if depth > 0 {
		depth--
		if ts.Mtsptr == nil {
			ts.Mtsptr = make(map[string]*TestStrucFlex)
		}
		if ts.Mts == nil {
			ts.Mts = make(map[string]TestStrucFlex)
		}
		ts.Mtsptr["0"] = newTestStrucFlex(depth, n, bench, useInterface, useStringKeyOnly)
		ts.Mts["0"] = *(ts.Mtsptr["0"])
		ts.Its = append(ts.Its, ts.Mtsptr["0"])
	}
	return
}
<commit_msg>codec: test types that implement Binary, Text and JSON Marshaling<commit_after>// comment this out // // + build testing

// Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.

package codec

import (
	"fmt"
	"strconv"
	"strings"
	"time"
)

const teststrucflexChanCap = 64

// This file contains values used by tests alone.
// This is where we may try out different things,
// that other engines may not support or may barf upon
// e.g. custom extensions for wrapped types, maps with non-string keys, etc.

// some funky types to test codecgen

type codecgenA struct {
	ZZ []byte
}
type codecgenB struct {
	AA codecgenA
}
type codecgenC struct {
	_struct struct{} `codec:",omitempty"`
	BB      codecgenB
}

type TestCodecgenG struct {
	TestCodecgenG int
}
type codecgenH struct {
	TestCodecgenG
}
type codecgenI struct {
	codecgenH
}

type codecgenK struct {
	X int
	Y string
}
type codecgenL struct {
	X int
	Y uint32
}
type codecgenM struct {
	codecgenK
	codecgenL
}

// some types to test struct keytype

type testStrucKeyTypeT0 struct {
	_struct struct{}
	F       int
}
type testStrucKeyTypeT1 struct {
	_struct struct{} `codec:",string"`
	F       int      `codec:"FFFF"`
}
type testStrucKeyTypeT2 struct {
	_struct struct{} `codec:",int"`
	F       int      `codec:"-1"`
}
type testStrucKeyTypeT3 struct {
	_struct struct{} `codec:",uint"`
	F       int      `codec:"1"`
}
type testStrucKeyTypeT4 struct {
	_struct struct{} `codec:",float"`
	F       int      `codec:"2.5"`
}

// Some unused types just stored here

type Bbool bool
type Aarray [1]string
type Sstring string
type Sstructsmall struct {
	A int
}

type Sstructbig struct {
	A int
	B bool
	c string
	// Sval Sstruct
	Ssmallptr *Sstructsmall
	Ssmall    *Sstructsmall
	Sptr      *Sstructbig
}

type SstructbigMapBySlice struct {
	_struct struct{} `codec:",toarray"`
	A       int
	B       bool
	c       string
	// Sval Sstruct
	Ssmallptr *Sstructsmall
	Ssmall    *Sstructsmall
	Sptr      *Sstructbig
}

// small struct for testing that codecgen works for unexported types
type tLowerFirstLetter struct {
	I int
	u uint64
	S string
	b []byte
}

// Some wrapped types which are used as extensions
type wrapInt64 int64
type wrapUint8 uint8
type wrapBytes []byte

// some types that define how to marshal themselves
type testMarshalAsJSON bool
type testMarshalAsBinary []byte
type testMarshalAsText string

func (x testMarshalAsJSON) MarshalJSON() (data []byte, err error) {
	if x {
		data = []byte("true")
	} else {
		data = []byte("false")
	}
	return
}
func (x *testMarshalAsJSON) UnmarshalJSON(data []byte) (err error) {
	switch string(data) {
	case "true":
		*x = true
	case "false":
		*x = false
	default:
		err = fmt.Errorf("testMarshalAsJSON failed to decode as bool: %s", data)
	}
	return
}

func (x testMarshalAsBinary) MarshalBinary() (data []byte, err error) {
	data = []byte(x)
	return
}
func (x *testMarshalAsBinary) UnmarshalBinary(data []byte) (err error) {
	*x = data
	return
}

func (x testMarshalAsText) MarshalText() (text []byte, err error) {
	text = []byte(x)
	return
}
func (x *testMarshalAsText) UnmarshalText(text []byte) (err error) {
	*x = testMarshalAsText(string(text))
	return
}

type AnonInTestStrucIntf struct {
	Islice []interface{}
	Ms     map[string]interface{}
	Nintf  interface{} //don't set this, so we can test for nil
	T      time.Time
	Tptr   *time.Time
}

type missingFielderT1 struct {
	S string
	B bool
	f float64
	i int64
}

func (t *missingFielderT1) CodecMissingField(field []byte, value interface{}) bool {
	switch string(field) {
	case "F":
		t.f = value.(float64)
	case "I":
		t.i = value.(int64)
	default:
		return false
	}
	return true
}

func (t *missingFielderT1) CodecMissingFields() map[string]interface{} {
	return map[string]interface{}{"F": t.f, "I": t.i}
}

type missingFielderT2 struct {
	S string
	B bool
	F float64
	I int64
}

type testSelfExtHelper struct {
	S string
	I int64
	B bool
}

type TestSelfExtImpl struct {
	testSelfExtHelper
}

type TestSelfExtImpl2 struct {
	M string
	O bool
}

type TestTwoNakedInterfaces struct {
	A interface{}
	B interface{}
}

var testWRepeated512 wrapBytes
var testStrucTime = time.Date(2012, 2, 2, 2, 2, 2, 2000, time.UTC).UTC()

func init() {
	var testARepeated512 [512]byte
	for i := range testARepeated512 {
		testARepeated512[i] = 'A'
	}
	testWRepeated512 = wrapBytes(testARepeated512[:])
}

type TestStrucFlex struct {
	_struct struct{} `codec:",omitempty"` //set omitempty for every field
	TestStrucCommon

	Chstr chan string

	Mis     map[int]string
	Mbu64   map[bool]struct{}
	Miwu64s map[int]wrapUint64Slice
	Mfwss   map[float64]wrapStringSlice
	Mf32wss map[float32]wrapStringSlice
	Mui2wss map[uint64]wrapStringSlice

	// DecodeNaked bombs because stringUint64T is decoded as a map,
	// and a map cannot be the key type of a map.
	// Ensure this is set to nil if decoding into a nil interface{}.
	Msu2wss map[stringUint64T]wrapStringSlice

	Ci64       wrapInt64
	Swrapbytes []wrapBytes
	Swrapuint8 []wrapUint8

	ArrStrUi64T [4]stringUint64T

	Ui64array      [4]uint64
	Ui64slicearray []*[4]uint64

	SintfAarray []interface{}

	// Ensure this is set to nil if decoding into a nil interface{}.
	MstrUi64TSelf map[stringUint64T]*stringUint64T

	Ttime    time.Time
	Ttimeptr *time.Time

	// make this a ptr, so that it could be set or not.
	// for comparison (e.g. with msgp), give it a struct tag (so it is not inlined),
	// make this one omitempty (so it is excluded if nil).
	*AnonInTestStrucIntf `json:",omitempty"`

	//M map[interface{}]interface{}  `json:"-",bson:"-"`
	Mtsptr     map[string]*TestStrucFlex
	Mts        map[string]TestStrucFlex
	Its        []*TestStrucFlex
	Nteststruc *TestStrucFlex

	MarJ testMarshalAsJSON
	MarT testMarshalAsText
	MarB testMarshalAsBinary

	Ffunc       func() error // expect this to be skipped/ignored
	Bboolignore bool         `codec:"-"` // expect this to be skipped/ignored
}

func emptyTestStrucFlex() *TestStrucFlex {
	var ts TestStrucFlex
	// we initialize and start draining the chan, so that we can decode into it without it blocking due to no consumer
	ts.Chstr = make(chan string, teststrucflexChanCap)
	go func() {
		for range ts.Chstr {
		}
	}() // drain it
	return &ts
}

func newTestStrucFlex(depth, n int, bench, useInterface, useStringKeyOnly bool) (ts *TestStrucFlex) {
	ts = &TestStrucFlex{
		Chstr: make(chan string, teststrucflexChanCap),

		Miwu64s: map[int]wrapUint64Slice{
			5: []wrapUint64{1, 2, 3, 4, 5},
			3: []wrapUint64{1, 2, 3},
		},

		Mf32wss: map[float32]wrapStringSlice{
			5.0: []wrapString{"1.0", "2.0", "3.0", "4.0", "5.0"},
			3.0: []wrapString{"1.0", "2.0", "3.0"},
		},

		Mui2wss: map[uint64]wrapStringSlice{
			5: []wrapString{"1.0", "2.0", "3.0", "4.0", "5.0"},
			3: []wrapString{"1.0", "2.0", "3.0"},
		},

		Mfwss: map[float64]wrapStringSlice{
			5.0: []wrapString{"1.0", "2.0", "3.0", "4.0", "5.0"},
			3.0: []wrapString{"1.0", "2.0", "3.0"},
		},

		// DecodeNaked bombs here, because the stringUint64T is decoded as a map,
		// and a map cannot be the key type of a map.
		// Ensure this is set to nil if decoding into a nil interface{}.
		Msu2wss: map[stringUint64T]wrapStringSlice{
			stringUint64T{"5", 5}: []wrapString{"1", "2", "3", "4", "5"},
			stringUint64T{"3", 3}: []wrapString{"1", "2", "3"},
		},

		Mis: map[int]string{
			1:   "one",
			22:  "twenty two",
			-44: "minus forty four",
		},
		Mbu64: map[bool]struct{}{false: {}, true: {}},

		Ci64: -22,
		Swrapbytes: []wrapBytes{ // lengths of 1, 2, 4, 8, 16, 32, 64, 128, 256,
			testWRepeated512[:1],
			testWRepeated512[:2],
			testWRepeated512[:4],
			testWRepeated512[:8],
			testWRepeated512[:16],
			testWRepeated512[:32],
			testWRepeated512[:64],
			testWRepeated512[:128],
			testWRepeated512[:256],
			testWRepeated512[:512],
		},
		Swrapuint8: []wrapUint8{
			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
		},
		Ui64array:     [4]uint64{4, 16, 64, 256},
		ArrStrUi64T:   [4]stringUint64T{{"4", 4}, {"3", 3}, {"2", 2}, {"1", 1}},
		SintfAarray:   []interface{}{Aarray{"s"}},
		MstrUi64TSelf: make(map[stringUint64T]*stringUint64T, numStrUi64T),

		Ttime:    testStrucTime,
		Ttimeptr: &testStrucTime,

		MarJ: true,
		MarT: "hello string",
		MarB: []byte("hello bytes"),
	}

	for i := uint64(0); i < numStrUi64T; i++ {
		ss := stringUint64T{S: strings.Repeat(strconv.FormatUint(i, 10), 4), U: i}
		// Ensure this is set to nil if decoding into a nil interface{}.
		ts.MstrUi64TSelf[ss] = &ss
	}

	numChanSend := cap(ts.Chstr) / 4 // 8
	for i := 0; i < numChanSend; i++ {
		ts.Chstr <- strings.Repeat("A", i+1)
	}

	ts.Ui64slicearray = []*[4]uint64{&ts.Ui64array, &ts.Ui64array}

	if useInterface {
		ts.AnonInTestStrucIntf = &AnonInTestStrucIntf{
			Islice: []interface{}{strRpt(n, "true"), true, strRpt(n, "no"), false, uint64(288), float64(0.4)},
			Ms: map[string]interface{}{
				strRpt(n, "true"):     strRpt(n, "true"),
				strRpt(n, "int64(9)"): false,
			},
			T:    testStrucTime,
			Tptr: &testStrucTime,
		}
	}

	populateTestStrucCommon(&ts.TestStrucCommon, n, bench, useInterface, useStringKeyOnly)
	if depth > 0 {
		depth--
		if ts.Mtsptr == nil {
			ts.Mtsptr = make(map[string]*TestStrucFlex)
		}
		if ts.Mts == nil {
			ts.Mts = make(map[string]TestStrucFlex)
		}
		ts.Mtsptr["0"] = newTestStrucFlex(depth, n, bench, useInterface, useStringKeyOnly)
		ts.Mts["0"] = *(ts.Mtsptr["0"])
		ts.Its = append(ts.Its, ts.Mtsptr["0"])
	}
	return
}
<|endoftext|>


<commit_before>package main

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

/* A Simple function to verify error */
func CheckError(err error) {
    if err  != nil {
        fmt.Println("Error: " , err)
        os.Exit(0)
    }
}

func main() {
    /* Lets prepare a address at any address at port 10001*/
    ServerAddr,err := net.ResolveUDPAddr("udp",":1234")
    CheckError(err)

    /* Now listen at selected port */
    ServerConn, err := net.ListenUDP("udp", ServerAddr)
    CheckError(err)
    defer ServerConn.Close()

    buf := make([]byte, 1024)

    for {
        n,addr,err := ServerConn.ReadFromUDP(buf)
        if err != nil {
            fmt.Println("Error: ",err)
        }

        scanner := bufio.NewScanner(strings.NewReader(string(buf[0:n])))
        if err := scanner.Err(); err != nil {
            fmt.Fprintln(os.Stderr, "error:", err)
            os.Exit(1)
        }

        scanner.Scan()

        ucl := strings.SplitAfter(scanner.Text(), "]")

        fmt.Println(ucl, addr)
    }
}<commit_msg>prototype is done<commit_after>package main

import (
    "fmt"
    "net"
    "os"
    "bufio"
    "strings"
    "time"
    "encoding/json"
    "strconv"
)

type Response struct {
    Timestamp string `json:timestamp`
    Message string `json:message`
}

/* A Simple function to verify error */
func CheckError(err error) {
    if err  != nil {
        fmt.Println("Error: " , err)
        os.Exit(0)
    }
}

func main() {
    /* Lets prepare a address at any address at port 10001*/
    ServerAddr,err := net.ResolveUDPAddr("udp",":1234")
    CheckError(err)

    /* Now listen at selected port */
    ServerConn, err := net.ListenUDP("udp", ServerAddr)
    CheckError(err)
    defer ServerConn.Close()

    buf := make([]byte, 1024)

    for {
        n,addr,err := ServerConn.ReadFromUDP(buf)
        if err != nil {
            fmt.Println("ERROR: ", err)
        }

        scanner := bufio.NewScanner(strings.NewReader(string(buf[0:n])))
        if err != nil {
            fmt.Println("ERROR: ", err)
        }

        scanner.Scan()
        if err != nil {
            fmt.Println("ERROR: ", err)
        }

        ucl := strings.SplitAfter(scanner.Text(), "]")

        t, err := time.Parse("[02/01/2006 15:04]", ucl[0])
        if err != nil {
            fmt.Println("ERROR: ", err)
        }

        g, _ := json.Marshal(Response{
            Timestamp: strconv.FormatInt(t.Unix(), 10),
            Message: ucl[1],
        })
        if err != nil {
            fmt.Println("ERROR: ", err)
        }

        fmt.Println(string(g), addr)
    }
}<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "net"
    "os"
)

/* A Simple function to verify error */
func CheckError(err error) {
    if err  != nil {
        fmt.Println("Error: " , err)
        os.Exit(0)
    }
}

func main() {
    /* Lets prepare a address at any address at port 10001*/
    ServerAddr,err := net.ResolveUDPAddr("udp",":10001")
    CheckError(err)

    /* Now listen at selected port */
    ServerConn, err := net.ListenUDP("udp", ServerAddr)
    CheckError(err)
    defer ServerConn.Close()

    buf := make([]byte, 1024)

    for {
        n,addr,err := ServerConn.ReadFromUDP(buf)
        fmt.Println("Received ",string(buf[0:n]), " from ",addr)

        if err != nil {
            fmt.Println("Error: ",err)
        }
    }
}<commit_msg>split message https://gobyexample.com/line-filters<commit_after>package main

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

/* A Simple function to verify error */
func CheckError(err error) {
    if err  != nil {
        fmt.Println("Error: " , err)
        os.Exit(0)
    }
}

func main() {
    /* Lets prepare a address at any address at port 10001*/
    ServerAddr,err := net.ResolveUDPAddr("udp",":1234")
    CheckError(err)

    /* Now listen at selected port */
    ServerConn, err := net.ListenUDP("udp", ServerAddr)
    CheckError(err)
    defer ServerConn.Close()

    buf := make([]byte, 1024)

    for {
        n,addr,err := ServerConn.ReadFromUDP(buf)
        if err != nil {
            fmt.Println("Error: ",err)
        }

        scanner := bufio.NewScanner(strings.NewReader(string(buf[0:n])))
        if err := scanner.Err(); err != nil {
            fmt.Fprintln(os.Stderr, "error:", err)
            os.Exit(1)
        }

        scanner.Scan()

        ucl := strings.SplitAfter(scanner.Text(), "]")

        fmt.Println(ucl, addr)
    }
}<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package webpush provides helper functions for sending encrpyted payloads
// using the Web Push protocol.
//
// Sending a message:
//   import (
//     "strings"
//     "github.com/googlechrome/push-encryption-go/webpush"
//   )
//
//   func main() {
//     // The values that make up the Subscription struct come from the browser
//     sub := &webpush.Subscription{endpoint, key, auth}
//     webpush.Send(nil, sub, "Yay! Web Push!", nil)
//   }
//
// You can turn a JSON string representation of a PushSubscription object you
// collected from the browser into a Subscription struct with a helper function.
//
//   var exampleJSON = []byte(`{"endpoint": "...", "keys": {"p256dh": "...", "auth": "..."}}`)
//   sub, err := SubscriptionFromJSON(exampleJSON)
//
// If the push service requires an authentication header (notably Google Cloud
// Messaging, used by Chrome) then you can add that as a fourth parameter:
//
//   if strings.Contains(sub.Endpoint, "https://android.googleapis.com/gcm/send/") {
//     webpush.Send(nil, sub, "A message for Chrome", myGCMKey)
//   }
package webpush

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/elliptic"
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"strings"
)

const (
	maxPayloadLength = 4078
)

var (
	authInfo = []byte("Content-Encoding: auth\x00")
	curve    = elliptic.P256()

	// Generate a random key pair to be used for the encryption. Overridable for
	// testing.
	randomKey = func() (priv []byte, pub []byte, err error) {
		priv, x, y, err := elliptic.GenerateKey(curve, rand.Reader)
		if err != nil {
			return nil, nil, err
		}

		return priv, elliptic.Marshal(curve, x, y), nil
	}

	// Generate a random salt for the encryption. Overridable for testing.
	randomSalt = func() ([]byte, error) {
		salt := make([]byte, 16)
		_, err := rand.Read(salt)
		if err != nil {
			return nil, err
		}
		return salt, nil
	}
)

// Subscription holds the useful values from a PushSubscription object acquired
// from the browser
type Subscription struct {
	// Endpoint is the URL to send the Web Push message to. Comes from the
	// endpoint field of the PushSubscription.
	Endpoint string
	// Key is the client's public key. From the keys.p256dh field.
	Key []byte
	// Auth is a value used by the client to validate the encryption. From the
	// keys.auth field.
	Auth []byte
}

// SubscriptionFromJSON is a convenience function that takes a JSON encoded
// PushSubscription object acquired from the browser and returns a pointer to a
// Subscription
func SubscriptionFromJSON(b []byte) (*Subscription, error) {
	var sub struct {
		Endpoint string
		Keys     struct {
			P256dh string
			Auth   string
		}
	}
	if err := json.Unmarshal(b, &sub); err != nil {
		return nil, err
	}

	b64 := base64.URLEncoding.WithPadding(base64.NoPadding)

	// Chrome < 52 incorrectly adds padding when Base64 encoding the values, so
	// we need to strip that out
	key, err := b64.DecodeString(strings.TrimRight(sub.Keys.P256dh, "="))
	if err != nil {
		return nil, err
	}

	auth, err := b64.DecodeString(strings.TrimRight(sub.Keys.Auth, "="))
	if err != nil {
		return nil, err
	}

	return &Subscription{sub.Endpoint, key, auth}, nil
}

// EncryptionResult stores the result of encrypting a message. The ciphertext is
// the actual encrypted message, while the salt and server public key are
// required to be sent to the client so that the message can be decrypted.
type EncryptionResult struct {
	Ciphertext      []byte
	Salt            []byte
	ServerPublicKey []byte
}

// Encrypt a message such that it can be sent using the Web Push protocol.
// You can find out more about the various pieces:
//    - https://tools.ietf.org/html/draft-ietf-httpbis-encryption-encoding
//    - https://en.wikipedia.org/wiki/Elliptic_curve_Diffie%E2%80%93Hellman
//    - https://tools.ietf.org/html/draft-ietf-webpush-encryption
func Encrypt(sub *Subscription, message string) (*EncryptionResult, error) {
	plaintext := []byte(message)
	if len(plaintext) > maxPayloadLength {
		return nil, fmt.Errorf("Payload is too large. The max number of bytes is %d, input is %d bytes.", maxPayloadLength, len(plaintext))
	}

	if len(sub.Key) == 0 {
		return nil, fmt.Errorf("Subscription must include the client's public key")
	}

	if len(sub.Auth) == 0 {
		return nil, fmt.Errorf("Subscription must include the client's auth value")
	}

	salt, err := randomSalt()
	if err != nil {
		return nil, err
	}

	// Use ECDH to derive a shared secret between us and the client. We generate
	// a fresh private/public key pair at random every time we encrypt.
	serverPrivateKey, serverPublicKey, err := randomKey()
	if err != nil {
		return nil, err
	}
	secret, err := sharedSecret(curve, sub.Key, serverPrivateKey)
	if err != nil {
		return nil, err
	}

	// Derive a Pseudo-Random Key (prk) that can be used to further derive our
	// other encryption parameters. These derivations are described in
	// https://tools.ietf.org/html/draft-ietf-httpbis-encryption-encoding-00
	prk := hkdf(sub.Auth, secret, authInfo, 32)

	// Derive the Content Encryption Key and nonce
	ctx := newContext(sub.Key, serverPublicKey)
	cek := newCEK(ctx, salt, prk)
	nonce := newNonce(ctx, salt, prk)

	// Do the actual encryption
	ciphertext, err := encrypt(plaintext, cek, nonce)
	if err != nil {
		return nil, err
	}

	// Return all of the values needed to construct a Web Push HTTP request.
	return &EncryptionResult{ciphertext, salt, serverPublicKey}, nil
}

func newCEK(ctx, salt, prk []byte) []byte {
	info := newInfo("aesgcm", ctx)
	return hkdf(salt, prk, info, 16)
}

func newNonce(ctx, salt, prk []byte) []byte {
	info := newInfo("nonce", ctx)
	return hkdf(salt, prk, info, 12)
}

// Creates a context for deriving encyption parameters, as described in
// https://tools.ietf.org/html/draft-ietf-httpbis-encryption-encoding-00.
// The 'context' in this case is just the public keys of both client and server.
// The keys should always be 65 bytes each. The format of the keys is
// described in section 4.3.6 of the (sadly not freely linkable) ANSI X9.62
// specification.
func newContext(clientPublicKey, serverPublicKey []byte) []byte {
	// The context format is:
	// 0x00 || length(clientPublicKey) || clientPublicKey ||
	//         length(serverPublicKey) || serverPublicKey
	// The lengths are 16-bit, Big Endian, unsigned integers so take 2 bytes each.
	cplen := uint16(len(clientPublicKey))
	cplenbuf := make([]byte, 2)
	binary.BigEndian.PutUint16(cplenbuf, cplen)

	splen := uint16(len(serverPublicKey))
	splenbuf := make([]byte, 2)
	binary.BigEndian.PutUint16(splenbuf, splen)

	var ctx []byte
	ctx = append(ctx, 0)
	ctx = append(ctx, cplenbuf...)
	ctx = append(ctx, []byte(clientPublicKey)...)
	ctx = append(ctx, splenbuf...)
	ctx = append(ctx, []byte(serverPublicKey)...)

	return ctx
}

// Returns an info record. See sections 3.2 and 3.3 of
// https://tools.ietf.org/html/draft-ietf-httpbis-encryption-encoding-00.
// The context argument should match what newContext creates
func newInfo(infoType string, context []byte) []byte {
	var info []byte
	info = append(info, []byte("Content-Encoding: ")...)
	info = append(info, []byte(infoType)...)
	info = append(info, 0)
	info = append(info, []byte("P-256")...)
	info = append(info, context...)
	return info
}

// HMAC-based Extract-and-Expand Key Derivation Function (HKDF)
//
// This is used to derive a secure encryption key from a mostly-secure shared
// secret.
//
// This is a partial implementation of HKDF tailored to our specific purposes.
// In particular, for us the value of N will always be 1, and thus T always
// equals HMAC-Hash(PRK, info | 0x01). This is true because the maximum output
// length we need/allow is 32.
//
// See https://www.rfc-editor.org/rfc/rfc5869.txt
func hkdf(salt, ikm, info []byte, length int) []byte {
	// HMAC length for SHA256 is 32 bytes, so that is the maximum result length.
	if length > 32 {
		panic("Can only produce HKDF outputs up to 32 bytes long")
	}

	// Extract
	mac := hmac.New(sha256.New, salt)
	mac.Write(ikm)
	prk := mac.Sum(nil)

	// Expand
	mac = hmac.New(sha256.New, prk)
	mac.Write(info)
	mac.Write([]byte{1})
	return mac.Sum(nil)[0:length]
}

// Encrypt the plaintext message using AES128/GCM
func encrypt(plaintext, key, nonce []byte) ([]byte, error) {
	// Add padding. There is a uint16 size followed by that number of bytes of
	// padding.
	// TODO: Right now we leave the size at zero. We should add a padding option
	// that allows the payload size to be obscured.
	padding := make([]byte, 2)
	data := append(padding, plaintext...)

	c, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	gcm, err := cipher.NewGCM(c)
	if err != nil {
		return nil, err
	}

	return gcm.Seal([]byte{}, nonce, data, nil), nil
}

// Given the coordinates of a party A's public key and the bytes of party B's
// private key, compute a shared secret.
func sharedSecret(curve elliptic.Curve, pub, priv []byte) ([]byte, error) {
	publicX, publicY := elliptic.Unmarshal(curve, pub)
	if publicX == nil {
		return nil, fmt.Errorf("Couldn't unmarshal public key. Not a valid point on the curve.")
	}
	x, _ := curve.ScalarMult(publicX, publicY, priv)
	return x.Bytes(), nil
}
<commit_msg>Fixing linting errors<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package webpush provides helper functions for sending encrpyted payloads
// using the Web Push protocol.
//
// Sending a message:
//   import (
//     "strings"
//     "github.com/googlechrome/push-encryption-go/webpush"
//   )
//
//   func main() {
//     // The values that make up the Subscription struct come from the browser
//     sub := &webpush.Subscription{endpoint, key, auth}
//     webpush.Send(nil, sub, "Yay! Web Push!", nil)
//   }
//
// You can turn a JSON string representation of a PushSubscription object you
// collected from the browser into a Subscription struct with a helper function.
//
//   var exampleJSON = []byte(`{"endpoint": "...", "keys": {"p256dh": "...", "auth": "..."}}`)
//   sub, err := SubscriptionFromJSON(exampleJSON)
//
// If the push service requires an authentication header (notably Google Cloud
// Messaging, used by Chrome) then you can add that as a fourth parameter:
//
//   if strings.Contains(sub.Endpoint, "https://android.googleapis.com/gcm/send/") {
//     webpush.Send(nil, sub, "A message for Chrome", myGCMKey)
//   }
package webpush

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/elliptic"
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"strings"
)

const (
	maxPayloadLength = 4078
)

var (
	authInfo = []byte("Content-Encoding: auth\x00")
	curve    = elliptic.P256()

	// Generate a random key pair to be used for the encryption. Overridable for
	// testing.
	randomKey = func() (priv []byte, pub []byte, err error) {
		priv, x, y, err := elliptic.GenerateKey(curve, rand.Reader)
		if err != nil {
			return nil, nil, err
		}

		return priv, elliptic.Marshal(curve, x, y), nil
	}

	// Generate a random salt for the encryption. Overridable for testing.
	randomSalt = func() ([]byte, error) {
		salt := make([]byte, 16)
		_, err := rand.Read(salt)
		if err != nil {
			return nil, err
		}
		return salt, nil
	}
)

// Subscription holds the useful values from a PushSubscription object acquired
// from the browser
type Subscription struct {
	// Endpoint is the URL to send the Web Push message to. Comes from the
	// endpoint field of the PushSubscription.
	Endpoint string
	// Key is the client's public key. From the keys.p256dh field.
	Key []byte
	// Auth is a value used by the client to validate the encryption. From the
	// keys.auth field.
	Auth []byte
}

// SubscriptionFromJSON is a convenience function that takes a JSON encoded
// PushSubscription object acquired from the browser and returns a pointer to a
// Subscription
func SubscriptionFromJSON(b []byte) (*Subscription, error) {
	var sub struct {
		Endpoint string
		Keys     struct {
			P256dh string
			Auth   string
		}
	}
	if err := json.Unmarshal(b, &sub); err != nil {
		return nil, err
	}

	b64 := base64.URLEncoding.WithPadding(base64.NoPadding)

	// Chrome < 52 incorrectly adds padding when Base64 encoding the values, so
	// we need to strip that out
	key, err := b64.DecodeString(strings.TrimRight(sub.Keys.P256dh, "="))
	if err != nil {
		return nil, err
	}

	auth, err := b64.DecodeString(strings.TrimRight(sub.Keys.Auth, "="))
	if err != nil {
		return nil, err
	}

	return &Subscription{sub.Endpoint, key, auth}, nil
}

// EncryptionResult stores the result of encrypting a message. The ciphertext is
// the actual encrypted message, while the salt and server public key are
// required to be sent to the client so that the message can be decrypted.
type EncryptionResult struct {
	Ciphertext      []byte
	Salt            []byte
	ServerPublicKey []byte
}

// Encrypt a message such that it can be sent using the Web Push protocol.
// You can find out more about the various pieces:
//    - https://tools.ietf.org/html/draft-ietf-httpbis-encryption-encoding
//    - https://en.wikipedia.org/wiki/Elliptic_curve_Diffie%E2%80%93Hellman
//    - https://tools.ietf.org/html/draft-ietf-webpush-encryption
func Encrypt(sub *Subscription, message string) (*EncryptionResult, error) {
	plaintext := []byte(message)
	if len(plaintext) > maxPayloadLength {
		return nil, fmt.Errorf("Payload is too large. The max number of bytes is %d, input is %d bytes", maxPayloadLength, len(plaintext))
	}

	if len(sub.Key) == 0 {
		return nil, fmt.Errorf("Subscription must include the client's public key")
	}

	if len(sub.Auth) == 0 {
		return nil, fmt.Errorf("Subscription must include the client's auth value")
	}

	salt, err := randomSalt()
	if err != nil {
		return nil, err
	}

	// Use ECDH to derive a shared secret between us and the client. We generate
	// a fresh private/public key pair at random every time we encrypt.
	serverPrivateKey, serverPublicKey, err := randomKey()
	if err != nil {
		return nil, err
	}
	secret, err := sharedSecret(curve, sub.Key, serverPrivateKey)
	if err != nil {
		return nil, err
	}

	// Derive a Pseudo-Random Key (prk) that can be used to further derive our
	// other encryption parameters. These derivations are described in
	// https://tools.ietf.org/html/draft-ietf-httpbis-encryption-encoding-00
	prk := hkdf(sub.Auth, secret, authInfo, 32)

	// Derive the Content Encryption Key and nonce
	ctx := newContext(sub.Key, serverPublicKey)
	cek := newCEK(ctx, salt, prk)
	nonce := newNonce(ctx, salt, prk)

	// Do the actual encryption
	ciphertext, err := encrypt(plaintext, cek, nonce)
	if err != nil {
		return nil, err
	}

	// Return all of the values needed to construct a Web Push HTTP request.
	return &EncryptionResult{ciphertext, salt, serverPublicKey}, nil
}

func newCEK(ctx, salt, prk []byte) []byte {
	info := newInfo("aesgcm", ctx)
	return hkdf(salt, prk, info, 16)
}

func newNonce(ctx, salt, prk []byte) []byte {
	info := newInfo("nonce", ctx)
	return hkdf(salt, prk, info, 12)
}

// Creates a context for deriving encyption parameters, as described in
// https://tools.ietf.org/html/draft-ietf-httpbis-encryption-encoding-00.
// The 'context' in this case is just the public keys of both client and server.
// The keys should always be 65 bytes each. The format of the keys is
// described in section 4.3.6 of the (sadly not freely linkable) ANSI X9.62
// specification.
func newContext(clientPublicKey, serverPublicKey []byte) []byte {
	// The context format is:
	// 0x00 || length(clientPublicKey) || clientPublicKey ||
	//         length(serverPublicKey) || serverPublicKey
	// The lengths are 16-bit, Big Endian, unsigned integers so take 2 bytes each.
	cplen := uint16(len(clientPublicKey))
	cplenbuf := make([]byte, 2)
	binary.BigEndian.PutUint16(cplenbuf, cplen)

	splen := uint16(len(serverPublicKey))
	splenbuf := make([]byte, 2)
	binary.BigEndian.PutUint16(splenbuf, splen)

	var ctx []byte
	ctx = append(ctx, 0)
	ctx = append(ctx, cplenbuf...)
	ctx = append(ctx, []byte(clientPublicKey)...)
	ctx = append(ctx, splenbuf...)
	ctx = append(ctx, []byte(serverPublicKey)...)

	return ctx
}

// Returns an info record. See sections 3.2 and 3.3 of
// https://tools.ietf.org/html/draft-ietf-httpbis-encryption-encoding-00.
// The context argument should match what newContext creates
func newInfo(infoType string, context []byte) []byte {
	var info []byte
	info = append(info, []byte("Content-Encoding: ")...)
	info = append(info, []byte(infoType)...)
	info = append(info, 0)
	info = append(info, []byte("P-256")...)
	info = append(info, context...)
	return info
}

// HMAC-based Extract-and-Expand Key Derivation Function (HKDF)
//
// This is used to derive a secure encryption key from a mostly-secure shared
// secret.
//
// This is a partial implementation of HKDF tailored to our specific purposes.
// In particular, for us the value of N will always be 1, and thus T always
// equals HMAC-Hash(PRK, info | 0x01). This is true because the maximum output
// length we need/allow is 32.
//
// See https://www.rfc-editor.org/rfc/rfc5869.txt
func hkdf(salt, ikm, info []byte, length int) []byte {
	// HMAC length for SHA256 is 32 bytes, so that is the maximum result length.
	if length > 32 {
		panic("Can only produce HKDF outputs up to 32 bytes long")
	}

	// Extract
	mac := hmac.New(sha256.New, salt)
	mac.Write(ikm)
	prk := mac.Sum(nil)

	// Expand
	mac = hmac.New(sha256.New, prk)
	mac.Write(info)
	mac.Write([]byte{1})
	return mac.Sum(nil)[0:length]
}

// Encrypt the plaintext message using AES128/GCM
func encrypt(plaintext, key, nonce []byte) ([]byte, error) {
	// Add padding. There is a uint16 size followed by that number of bytes of
	// padding.
	// TODO: Right now we leave the size at zero. We should add a padding option
	// that allows the payload size to be obscured.
	padding := make([]byte, 2)
	data := append(padding, plaintext...)

	c, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	gcm, err := cipher.NewGCM(c)
	if err != nil {
		return nil, err
	}

	return gcm.Seal([]byte{}, nonce, data, nil), nil
}

// Given the coordinates of a party A's public key and the bytes of party B's
// private key, compute a shared secret.
func sharedSecret(curve elliptic.Curve, pub, priv []byte) ([]byte, error) {
	publicX, publicY := elliptic.Unmarshal(curve, pub)
	if publicX == nil {
		return nil, fmt.Errorf("Couldn't unmarshal public key. Not a valid point on the curve")
	}
	x, _ := curve.ScalarMult(publicX, publicY, priv)
	return x.Bytes(), nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"regexp"
	"strconv"

	"github.com/jessevdk/go-flags"
	"github.com/mackerelio/checkers"
)

// https://github.com/sensu-plugins/sensu-plugins-process-checks
var opts struct {
	WarnOver      *int64   `short:"w" long:"warn-over" value-name:"N" description:"Trigger a warning if over a number"`
	CritOver      *int64   `short:"c" long:"critical-over" value-name:"N" description:"Trigger a critical if over a number"`
	WarnUnder     int64   `short:"W" long:"warn-under" value-name:"N" default:"1" description:"Trigger a warning if under a number"`
	CritUnder     int64   `short:"C" long:"critical-under" value-name:"N" default:"1" description:"Trigger a critial if under a number"`
	MatchSelf     bool    `short:"m" long:"match-self" description:"Match itself"`
	CmdPat        string  `short:"p" long:"pattern" value-name:"PATTERN" description:"Match a command against this pattern"`
	CmdExcludePat string  `short:"x" long:"exclude-pattern" value-name:"PATTERN" description:"Don't match against a pattern to prevent false positives"`
	Ppid          string  `long:"ppid" value-name:"PPID" description:"Check against a specific PPID"`
	FilePid       string  `short:"f" long:"file-pid" value-name:"PID" description:"Check against a specific PID"`
	Vsz           int64   `short:"z" long:"virtual-memory-size" value-name:"VSZ" description:"Trigger on a Virtual Memory size is bigger than this"`
	Rss           int64   `short:"r" long:"resident-set-size" value-name:"RSS" description:"Trigger on a Resident Set size is bigger than this"`
	Pcpu          float64 `short:"P" long:"proportional-set-size" value-name:"PCPU" description:"Trigger on a Proportional Set Size is bigger than this"`
	Thcount       int64   `short:"T" long:"thread-count" value-name:"THCOUNT" description:"Trigger on a Thread Count is bigger than this"`
	State         string  `short:"s" long:"state" value-name:"STATE" description:"Trigger on a specific state, example: Z for zombie"`
	User          string  `short:"u" long:"user" value-name:"USER" description:"Trigger on a specific user"`
	Usernot       string  `short:"U" long:"user-not" value-name:"USER" description:"Trigger if not owned a specific user"`
	EsecOver      int64   `short:"e" long:"esec-over" value-name:"SECONDS" description:"Match processes that older that this, in SECONDS"`
	EsecUnder     int64   `short:"E" long:"esec-under" value-name:"SECONDS" description:"Match process that are younger than this, in SECONDS"`
	CPUOver       int64   `short:"i" long:"cpu-over" value-name:"SECONDS" description:"Match processes cpu time that is older than this, in SECONDS"`
	CPUUnder      int64   `short:"I" long:"cpu-under" value-name:"SECONDS" description:"Match processes cpu time that is younger than this, in SECONDS"`
}

type procState struct {
	cmd     string
	user    string
	ppid    string
	pid     string
	vsz     int64
	rss     int64
	pcpu    float64
	thcount int64
	state   string
	esec    int64
	csec    int64
}

func main() {
	ckr := run(os.Args[1:])
	ckr.Name = "Procs"
	ckr.Exit()
}

func run(args []string) *checkers.Checker {
	_, err := flags.ParseArgs(&opts, args)
	if err != nil {
		os.Exit(1)
	}
	procs, err := getProcs()
	cmdPatRegexp := regexp.MustCompile(".*")
	if opts.CmdPat != "" {
		r, err := regexp.Compile(opts.CmdPat)
		if err != nil {
			os.Exit(1)
		}
		cmdPatRegexp = r
	}
	cmdExcludePatRegexp := regexp.MustCompile(".*")
	if opts.CmdExcludePat != "" {
		r, err := regexp.Compile(opts.CmdExcludePat)
		if err != nil {
			os.Exit(1)
		}
		cmdExcludePatRegexp = r
	}
	var resultrocStates []procState
	for _, proc := range procs {
		if matchProc(proc, cmdPatRegexp, cmdExcludePatRegexp) {
			resultrocStates = append(resultrocStates, proc)
		}
	}
	count := int64(len(resultrocStates))
	msg := gatherMsg(count)
	result := checkers.OK
	if opts.CritUnder != 0 && count < opts.CritUnder ||
		opts.CritOver != nil && count > *opts.CritOver {
		result = checkers.CRITICAL
	} else if opts.WarnUnder != 0 && count < opts.WarnUnder ||
		opts.WarnOver != nil && count > *opts.WarnOver {
		result = checkers.WARNING
	}
	return checkers.NewChecker(result, msg)
}

func matchProc(proc procState, cmdPatRegexp *regexp.Regexp, cmdExcludePatRegexp *regexp.Regexp) bool {
	return (opts.CmdPat == "" || cmdPatRegexp.MatchString(proc.cmd)) &&
		(opts.CmdExcludePat == "" || !cmdExcludePatRegexp.MatchString(proc.cmd)) &&
		(opts.MatchSelf || proc.pid != strconv.Itoa(os.Getpid())) &&
		(opts.Ppid == "" || proc.ppid == opts.Ppid) &&
		(opts.FilePid == "" || proc.pid == opts.FilePid) &&
		(opts.Vsz == 0 || proc.vsz <= opts.Vsz) &&
		(opts.Rss == 0 || proc.rss <= opts.Rss) &&
		(opts.Pcpu == 0 || proc.pcpu <= opts.Pcpu) &&
		(opts.Thcount == 0 || proc.thcount <= opts.Thcount) &&
		(opts.State == "" || proc.state == opts.State) &&
		(opts.User == "" || proc.user == opts.User) &&
		(opts.Usernot == "" || proc.user != opts.Usernot) &&
		(opts.EsecUnder == 0 || proc.esec < opts.EsecUnder) &&
		(opts.EsecOver == 0 || proc.esec > opts.EsecOver) &&
		(opts.CPUUnder == 0 || proc.csec < opts.CPUUnder) &&
		(opts.CPUOver == 0 || proc.csec > opts.CPUOver)
}

func gatherMsg(count int64) string {
	msg := fmt.Sprintf("Found %d matching processes", count)
	if opts.CmdPat != "" {
		msg += fmt.Sprintf("; cmd /%s/", opts.CmdPat)
	}
	if opts.State != "" {
		msg += fmt.Sprintf("; state /%s/", opts.State)
	}
	if opts.User != "" {
		msg += fmt.Sprintf("; user /%s/", opts.User)
	}
	if opts.Usernot != "" {
		msg += fmt.Sprintf("; usernot /%s/", opts.Usernot)
	}
	if opts.Vsz != 0 {
		msg += fmt.Sprintf("; vsz < %d", opts.Vsz)
	}
	if opts.Rss != 0 {
		msg += fmt.Sprintf("; rss < %d", opts.Rss)
	}
	if opts.Pcpu != 0 {
		msg += fmt.Sprintf("; pcpu < %f", opts.Pcpu)
	}
	if opts.Thcount != 0 {
		msg += fmt.Sprintf("; thcount < %d", opts.Thcount)
	}
	if opts.EsecUnder != 0 {
		msg += fmt.Sprintf("; esec < %d", opts.EsecUnder)
	}
	if opts.EsecOver != 0 {
		msg += fmt.Sprintf("; esec > %d", opts.EsecOver)
	}
	if opts.CPUUnder != 0 {
		msg += fmt.Sprintf("; csec < %d", opts.CPUUnder)
	}
	if opts.CPUOver != 0 {
		msg += fmt.Sprintf("; csec > %d", opts.CPUOver)
	}
	if opts.Ppid != "" {
		msg += fmt.Sprintf("; ppid %s", opts.Ppid)
	}
	if opts.FilePid != "" {
		msg += fmt.Sprintf("; pid %s", opts.FilePid)
	}
	return msg
}
<commit_msg>Stopped counting a parent process of check-procs<commit_after>package main

import (
	"fmt"
	"os"
	"regexp"
	"strconv"

	"github.com/jessevdk/go-flags"
	"github.com/mackerelio/checkers"
)

// https://github.com/sensu-plugins/sensu-plugins-process-checks
var opts struct {
	WarnOver      *int64   `short:"w" long:"warn-over" value-name:"N" description:"Trigger a warning if over a number"`
	CritOver      *int64   `short:"c" long:"critical-over" value-name:"N" description:"Trigger a critical if over a number"`
	WarnUnder     int64   `short:"W" long:"warn-under" value-name:"N" default:"1" description:"Trigger a warning if under a number"`
	CritUnder     int64   `short:"C" long:"critical-under" value-name:"N" default:"1" description:"Trigger a critial if under a number"`
	MatchSelf     bool    `short:"m" long:"match-self" description:"Match itself"`
	MatchParent   bool    `short:"M" long:"match-parent" description:"Match parent"`
	CmdPat        string  `short:"p" long:"pattern" value-name:"PATTERN" description:"Match a command against this pattern"`
	CmdExcludePat string  `short:"x" long:"exclude-pattern" value-name:"PATTERN" description:"Don't match against a pattern to prevent false positives"`
	Ppid          string  `long:"ppid" value-name:"PPID" description:"Check against a specific PPID"`
	FilePid       string  `short:"f" long:"file-pid" value-name:"PID" description:"Check against a specific PID"`
	Vsz           int64   `short:"z" long:"virtual-memory-size" value-name:"VSZ" description:"Trigger on a Virtual Memory size is bigger than this"`
	Rss           int64   `short:"r" long:"resident-set-size" value-name:"RSS" description:"Trigger on a Resident Set size is bigger than this"`
	Pcpu          float64 `short:"P" long:"proportional-set-size" value-name:"PCPU" description:"Trigger on a Proportional Set Size is bigger than this"`
	Thcount       int64   `short:"T" long:"thread-count" value-name:"THCOUNT" description:"Trigger on a Thread Count is bigger than this"`
	State         string  `short:"s" long:"state" value-name:"STATE" description:"Trigger on a specific state, example: Z for zombie"`
	User          string  `short:"u" long:"user" value-name:"USER" description:"Trigger on a specific user"`
	Usernot       string  `short:"U" long:"user-not" value-name:"USER" description:"Trigger if not owned a specific user"`
	EsecOver      int64   `short:"e" long:"esec-over" value-name:"SECONDS" description:"Match processes that older that this, in SECONDS"`
	EsecUnder     int64   `short:"E" long:"esec-under" value-name:"SECONDS" description:"Match process that are younger than this, in SECONDS"`
	CPUOver       int64   `short:"i" long:"cpu-over" value-name:"SECONDS" description:"Match processes cpu time that is older than this, in SECONDS"`
	CPUUnder      int64   `short:"I" long:"cpu-under" value-name:"SECONDS" description:"Match processes cpu time that is younger than this, in SECONDS"`
}

type procState struct {
	cmd     string
	user    string
	ppid    string
	pid     string
	vsz     int64
	rss     int64
	pcpu    float64
	thcount int64
	state   string
	esec    int64
	csec    int64
}

func main() {
	ckr := run(os.Args[1:])
	ckr.Name = "Procs"
	ckr.Exit()
}

func run(args []string) *checkers.Checker {
	_, err := flags.ParseArgs(&opts, args)
	if err != nil {
		os.Exit(1)
	}
	procs, err := getProcs()
	cmdPatRegexp := regexp.MustCompile(".*")
	if opts.CmdPat != "" {
		r, err := regexp.Compile(opts.CmdPat)
		if err != nil {
			os.Exit(1)
		}
		cmdPatRegexp = r
	}
	cmdExcludePatRegexp := regexp.MustCompile(".*")
	if opts.CmdExcludePat != "" {
		r, err := regexp.Compile(opts.CmdExcludePat)
		if err != nil {
			os.Exit(1)
		}
		cmdExcludePatRegexp = r
	}
	var resultrocStates []procState
	for _, proc := range procs {
		if matchProc(proc, cmdPatRegexp, cmdExcludePatRegexp) {
			resultrocStates = append(resultrocStates, proc)
		}
	}
	count := int64(len(resultrocStates))
	msg := gatherMsg(count)
	result := checkers.OK
	if opts.CritUnder != 0 && count < opts.CritUnder ||
		opts.CritOver != nil && count > *opts.CritOver {
		result = checkers.CRITICAL
	} else if opts.WarnUnder != 0 && count < opts.WarnUnder ||
		opts.WarnOver != nil && count > *opts.WarnOver {
		result = checkers.WARNING
	}
	return checkers.NewChecker(result, msg)
}

func matchProc(proc procState, cmdPatRegexp *regexp.Regexp, cmdExcludePatRegexp *regexp.Regexp) bool {
	return (opts.CmdPat == "" || cmdPatRegexp.MatchString(proc.cmd)) &&
		(opts.CmdExcludePat == "" || !cmdExcludePatRegexp.MatchString(proc.cmd)) &&
		(opts.MatchSelf || proc.pid != strconv.Itoa(os.Getpid())) &&
		(opts.MatchParent || proc.pid != strconv.Itoa(os.Getppid())) &&
		(opts.Ppid == "" || proc.ppid == opts.Ppid) &&
		(opts.FilePid == "" || proc.pid == opts.FilePid) &&
		(opts.Vsz == 0 || proc.vsz <= opts.Vsz) &&
		(opts.Rss == 0 || proc.rss <= opts.Rss) &&
		(opts.Pcpu == 0 || proc.pcpu <= opts.Pcpu) &&
		(opts.Thcount == 0 || proc.thcount <= opts.Thcount) &&
		(opts.State == "" || proc.state == opts.State) &&
		(opts.User == "" || proc.user == opts.User) &&
		(opts.Usernot == "" || proc.user != opts.Usernot) &&
		(opts.EsecUnder == 0 || proc.esec < opts.EsecUnder) &&
		(opts.EsecOver == 0 || proc.esec > opts.EsecOver) &&
		(opts.CPUUnder == 0 || proc.csec < opts.CPUUnder) &&
		(opts.CPUOver == 0 || proc.csec > opts.CPUOver)
}

func gatherMsg(count int64) string {
	msg := fmt.Sprintf("Found %d matching processes", count)
	if opts.CmdPat != "" {
		msg += fmt.Sprintf("; cmd /%s/", opts.CmdPat)
	}
	if opts.State != "" {
		msg += fmt.Sprintf("; state /%s/", opts.State)
	}
	if opts.User != "" {
		msg += fmt.Sprintf("; user /%s/", opts.User)
	}
	if opts.Usernot != "" {
		msg += fmt.Sprintf("; usernot /%s/", opts.Usernot)
	}
	if opts.Vsz != 0 {
		msg += fmt.Sprintf("; vsz < %d", opts.Vsz)
	}
	if opts.Rss != 0 {
		msg += fmt.Sprintf("; rss < %d", opts.Rss)
	}
	if opts.Pcpu != 0 {
		msg += fmt.Sprintf("; pcpu < %f", opts.Pcpu)
	}
	if opts.Thcount != 0 {
		msg += fmt.Sprintf("; thcount < %d", opts.Thcount)
	}
	if opts.EsecUnder != 0 {
		msg += fmt.Sprintf("; esec < %d", opts.EsecUnder)
	}
	if opts.EsecOver != 0 {
		msg += fmt.Sprintf("; esec > %d", opts.EsecOver)
	}
	if opts.CPUUnder != 0 {
		msg += fmt.Sprintf("; csec < %d", opts.CPUUnder)
	}
	if opts.CPUOver != 0 {
		msg += fmt.Sprintf("; csec > %d", opts.CPUOver)
	}
	if opts.Ppid != "" {
		msg += fmt.Sprintf("; ppid %s", opts.Ppid)
	}
	if opts.FilePid != "" {
		msg += fmt.Sprintf("; pid %s", opts.FilePid)
	}
	return msg
}
<|endoftext|>


<commit_before>package pino

import (
	"fmt"

	irc "github.com/fluffle/goirc/client"
	"github.com/nlopes/slack"
	"gopkg.in/kyokomi/emoji.v1"
)

// 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", err.Error())
	}
	if err := pino.slackProxy.connect(); err != nil {
		return fmt.Errorf("Slack connection error: %s", err.Error())
	}

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

	go pino.handleIRCEvents(quit)
	go pino.handleSlackEvents(quit)

	<-quit

	return nil
}

// Consumes incoming IRC events in a loop
func (pino *Pino) handleIRCEvents(quit chan bool) {
	previousNickMemberships := pino.ircProxy.snapshotOfNicksInChannels()

	// For buffer playback, we care about whether the buffer playback mode changed in the previous line
	// in deciding whether to print the subsequent lines
	wasInBufferPlaybackMode := false
	isInBufferPlaybackMode := false

	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)
				}

				message := fmt.Sprintf("Connected to IRC on %v!", pino.ircProxy.config.Server)
				pino.slackProxy.sendMessageToOwner(message)

			case irc.DISCONNECTED:
				fmt.Printf("Disconnected from IRC!")
				message := fmt.Sprintf("Disconnected from IRC on %v!", pino.ircProxy.config.Server)
				pino.slackProxy.sendMessageToOwner(message)

			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)

				if !isInBufferPlaybackMode {
					pino.slackProxy.sendMessageAsUser(pino.ircChannelToSlackChannel[channel], username, message)
				}

			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) joined the channel", username, usermask)
				pino.slackProxy.sendMessageAsBot(pino.ircChannelToSlackChannel[channel], message)

				previousNickMemberships = pino.ircProxy.snapshotOfNicksInChannels()
			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:
				channel := IRCChannel(line.Target())
				kicker := line.Nick
				kickee := line.Args[1]
				reason := line.Args[2]
				fmt.Printf("KICK: (%v) %v has kicked %v (%v)\n", channel, kicker, kickee, reason)

				message := fmt.Sprintf("> *%v* kicked *%v* from the channel (%v)", kicker, kickee, reason)
				pino.slackProxy.sendMessageAsBot(pino.ircChannelToSlackChannel[channel], message)

				previousNickMemberships = pino.ircProxy.snapshotOfNicksInChannels()
			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(pino.ircChannelToSlackChannel[channel], message)
				}

			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)
				for ircChannel, nicks := range previousNickMemberships {
					if _, ok := nicks[oldNick]; !ok {
						// The user was not in this channel
						continue
					}

					slackChannel := pino.ircChannelToSlackChannel[ircChannel]
					pino.slackProxy.sendMessageAsBot(slackChannel, message)
				}

				previousNickMemberships = pino.ircProxy.snapshotOfNicksInChannels()
			case irc.PART:
				channel := IRCChannel(line.Target())
				reason := line.Text()
				username := line.Nick
				usermask := line.Src
				fmt.Printf("PART: (%v) %v(%v) has left (%s)\n", channel, username, usermask, reason)

				message := fmt.Sprintf("> *%v* (%v) left the channel", username, usermask)
				pino.slackProxy.sendMessageAsBot(pino.ircChannelToSlackChannel[channel], message)

				previousNickMemberships = pino.ircProxy.snapshotOfNicksInChannels()
			case irc.PRIVMSG:
				target := line.Target()
				username := line.Nick
				text := line.Text()

				fmt.Printf("PRIVMSG: (%v) <%v> %v\n", target, username, text)

				if isInBufferPlaybackMode {
					if isBufferPlaybackEndLine(line) {
						isInBufferPlaybackMode = false
					}
				} else {
					if isBufferPlaybackStartLine(line) {
						isInBufferPlaybackMode = true
					}
				}

				// Simply being out of buffer playback mode is not sufficient for deciding to output the line
				// because we consider ourselves out of the buffer playback mode on the line where playback ends.
				if !wasInBufferPlaybackMode && !isInBufferPlaybackMode {

					possibleChannel := IRCChannel(target)
					if slackChannel, ok := pino.ircChannelToSlackChannel[possibleChannel]; ok {

						if pino.ircProxy.shouldHighlightOwnerOnText(text) {
							pino.slackProxy.sendMessageAsBot(
								slackChannel,
								fmt.Sprintf("@%v: you were pinged by %v", pino.slackProxy.config.Owner, username),
							)
						}

						pino.slackProxy.sendMessageAsUser(slackChannel, username, text)
					}
				}

				wasInBufferPlaybackMode = isInBufferPlaybackMode

			case irc.QUIT:
				username := line.Nick
				usermask := line.Src
				reason := line.Args[0]

				fmt.Printf("QUIT: %v(%v) has quit (%v)\n", username, usermask, reason)

				message := fmt.Sprintf("> *%v* (%v) left IRC (%v)", username, usermask, reason)
				for ircChannel, nicks := range previousNickMemberships {
					if _, ok := nicks[username]; !ok {
						// The user was not in this channel
						continue
					}

					slackChannel := pino.ircChannelToSlackChannel[ircChannel]
					pino.slackProxy.sendMessageAsBot(slackChannel, message)
				}

				previousNickMemberships = pino.ircProxy.snapshotOfNicksInChannels()
			case irc.TOPIC:
				channel := IRCChannel(line.Target())
				username := line.Nick
				topic := line.Text()
				fmt.Printf("TOPIC: (%v) %v has changed the topic to \"%v\"\n", channel, username, topic)

				message := fmt.Sprintf("> *%v* changed the topic to *%v*", username, topic)
				pino.slackProxy.sendMessageAsBot(pino.ircChannelToSlackChannel[channel], message)

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

	}
}

// Consumes incoming Slack events in a loop
func (pino *Pino) handleSlackEvents(quit chan bool) {
	for {
		select {
		case msg := <-pino.slackProxy.rtm.IncomingEvents:
			switch event := msg.Data.(type) {
			case *slack.MessageEvent:
				pino.handleSlackMessageEvent(event, quit)
			case *slack.ConnectingEvent:
			case *slack.ConnectedEvent:
			case *slack.HelloEvent:
				fmt.Printf("Connected to Slack!\n")
			case *slack.UserTypingEvent:
			case *slack.LatencyReport:
			case *slack.PresenceChangeEvent:
			case *slack.ReconnectUrlEvent:
			case *slack.AckMessage:
			default:
				fmt.Printf("Received unrecognized Slack msg: %#v\n", msg.Data)
			}
		}
	}
}

func (pino *Pino) handleSlackMessageEvent(event *slack.MessageEvent, quit chan bool) {
	// For development, we'll still want to print out all received messages
	//fmt.Printf("Message: %#v\n", event)

	slackChannel := pino.slackProxy.getChannelName(event.Channel)
	destinationIRCChannel := pino.slackChannelToIRCChannel[slackChannel]

	if event.BotID != "" {
		// Sending any messages from a bot to IRC might cause a vicious cycle
		return
	}

	// We only support a small subset of message subtypes:
	// - "" (no subtype means it's a normal message)
	// - "me_message" (a /me action)
	if event.SubType != "me_message" && event.SubType != "" {
		fmt.Printf("Ignoring message with unsupported subtype: %#v\n", event)
		return
	}

	text := pino.slackProxy.renderFormattedMessageForDisplay(event.Text)

	text = decodeSlackHTMLEntities(text)

	// Convert stuff like ":pizza:" to the actual pizza emoji
	text = emoji.Sprint(text)

	if event.SubType == "me_message" {
		pino.ircProxy.sendAction(destinationIRCChannel, text)
		return
	}

	// In the normal case, it's a normal message
	pino.ircProxy.sendMessage(destinationIRCChannel, text)
}
<commit_msg>Remove default clause in IRC select to make it blocking<commit_after>package pino

import (
	"fmt"

	irc "github.com/fluffle/goirc/client"
	"github.com/nlopes/slack"
	"gopkg.in/kyokomi/emoji.v1"
)

// 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", err.Error())
	}
	if err := pino.slackProxy.connect(); err != nil {
		return fmt.Errorf("Slack connection error: %s", err.Error())
	}

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

	go pino.handleIRCEvents(quit)
	go pino.handleSlackEvents(quit)

	<-quit

	return nil
}

// Consumes incoming IRC events in a loop
func (pino *Pino) handleIRCEvents(quit chan bool) {
	previousNickMemberships := pino.ircProxy.snapshotOfNicksInChannels()

	// For buffer playback, we care about whether the buffer playback mode changed in the previous line
	// in deciding whether to print the subsequent lines
	wasInBufferPlaybackMode := false
	isInBufferPlaybackMode := false

	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)
				}

				message := fmt.Sprintf("Connected to IRC on %v!", pino.ircProxy.config.Server)
				pino.slackProxy.sendMessageToOwner(message)

			case irc.DISCONNECTED:
				fmt.Printf("Disconnected from IRC!")
				message := fmt.Sprintf("Disconnected from IRC on %v!", pino.ircProxy.config.Server)
				pino.slackProxy.sendMessageToOwner(message)

			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)

				if !isInBufferPlaybackMode {
					pino.slackProxy.sendMessageAsUser(pino.ircChannelToSlackChannel[channel], username, message)
				}

			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) joined the channel", username, usermask)
				pino.slackProxy.sendMessageAsBot(pino.ircChannelToSlackChannel[channel], message)

				previousNickMemberships = pino.ircProxy.snapshotOfNicksInChannels()
			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:
				channel := IRCChannel(line.Target())
				kicker := line.Nick
				kickee := line.Args[1]
				reason := line.Args[2]
				fmt.Printf("KICK: (%v) %v has kicked %v (%v)\n", channel, kicker, kickee, reason)

				message := fmt.Sprintf("> *%v* kicked *%v* from the channel (%v)", kicker, kickee, reason)
				pino.slackProxy.sendMessageAsBot(pino.ircChannelToSlackChannel[channel], message)

				previousNickMemberships = pino.ircProxy.snapshotOfNicksInChannels()
			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(pino.ircChannelToSlackChannel[channel], message)
				}

			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)
				for ircChannel, nicks := range previousNickMemberships {
					if _, ok := nicks[oldNick]; !ok {
						// The user was not in this channel
						continue
					}

					slackChannel := pino.ircChannelToSlackChannel[ircChannel]
					pino.slackProxy.sendMessageAsBot(slackChannel, message)
				}

				previousNickMemberships = pino.ircProxy.snapshotOfNicksInChannels()
			case irc.PART:
				channel := IRCChannel(line.Target())
				reason := line.Text()
				username := line.Nick
				usermask := line.Src
				fmt.Printf("PART: (%v) %v(%v) has left (%s)\n", channel, username, usermask, reason)

				message := fmt.Sprintf("> *%v* (%v) left the channel", username, usermask)
				pino.slackProxy.sendMessageAsBot(pino.ircChannelToSlackChannel[channel], message)

				previousNickMemberships = pino.ircProxy.snapshotOfNicksInChannels()
			case irc.PRIVMSG:
				target := line.Target()
				username := line.Nick
				text := line.Text()

				fmt.Printf("PRIVMSG: (%v) <%v> %v\n", target, username, text)

				if isInBufferPlaybackMode {
					if isBufferPlaybackEndLine(line) {
						isInBufferPlaybackMode = false
					}
				} else {
					if isBufferPlaybackStartLine(line) {
						isInBufferPlaybackMode = true
					}
				}

				// Simply being out of buffer playback mode is not sufficient for deciding to output the line
				// because we consider ourselves out of the buffer playback mode on the line where playback ends.
				if !wasInBufferPlaybackMode && !isInBufferPlaybackMode {

					possibleChannel := IRCChannel(target)
					if slackChannel, ok := pino.ircChannelToSlackChannel[possibleChannel]; ok {

						if pino.ircProxy.shouldHighlightOwnerOnText(text) {
							pino.slackProxy.sendMessageAsBot(
								slackChannel,
								fmt.Sprintf("@%v: you were pinged by %v", pino.slackProxy.config.Owner, username),
							)
						}

						pino.slackProxy.sendMessageAsUser(slackChannel, username, text)
					}
				}

				wasInBufferPlaybackMode = isInBufferPlaybackMode

			case irc.QUIT:
				username := line.Nick
				usermask := line.Src
				reason := line.Args[0]

				fmt.Printf("QUIT: %v(%v) has quit (%v)\n", username, usermask, reason)

				message := fmt.Sprintf("> *%v* (%v) left IRC (%v)", username, usermask, reason)
				for ircChannel, nicks := range previousNickMemberships {
					if _, ok := nicks[username]; !ok {
						// The user was not in this channel
						continue
					}

					slackChannel := pino.ircChannelToSlackChannel[ircChannel]
					pino.slackProxy.sendMessageAsBot(slackChannel, message)
				}

				previousNickMemberships = pino.ircProxy.snapshotOfNicksInChannels()
			case irc.TOPIC:
				channel := IRCChannel(line.Target())
				username := line.Nick
				topic := line.Text()
				fmt.Printf("TOPIC: (%v) %v has changed the topic to \"%v\"\n", channel, username, topic)

				message := fmt.Sprintf("> *%v* changed the topic to *%v*", username, topic)
				pino.slackProxy.sendMessageAsBot(pino.ircChannelToSlackChannel[channel], message)

			default:
				fmt.Printf("Received unrecognized line: %#v\n", line)
			}
		}

	}
}

// Consumes incoming Slack events in a loop
func (pino *Pino) handleSlackEvents(quit chan bool) {
	for {
		select {
		case msg := <-pino.slackProxy.rtm.IncomingEvents:
			switch event := msg.Data.(type) {
			case *slack.MessageEvent:
				pino.handleSlackMessageEvent(event, quit)
			case *slack.ConnectingEvent:
			case *slack.ConnectedEvent:
			case *slack.HelloEvent:
				fmt.Printf("Connected to Slack!\n")
			case *slack.UserTypingEvent:
			case *slack.LatencyReport:
			case *slack.PresenceChangeEvent:
			case *slack.ReconnectUrlEvent:
			case *slack.AckMessage:
			default:
				fmt.Printf("Received unrecognized Slack msg: %#v\n", msg.Data)
			}
		}
	}
}

func (pino *Pino) handleSlackMessageEvent(event *slack.MessageEvent, quit chan bool) {
	// For development, we'll still want to print out all received messages
	//fmt.Printf("Message: %#v\n", event)

	slackChannel := pino.slackProxy.getChannelName(event.Channel)
	destinationIRCChannel := pino.slackChannelToIRCChannel[slackChannel]

	if event.BotID != "" {
		// Sending any messages from a bot to IRC might cause a vicious cycle
		return
	}

	// We only support a small subset of message subtypes:
	// - "" (no subtype means it's a normal message)
	// - "me_message" (a /me action)
	if event.SubType != "me_message" && event.SubType != "" {
		fmt.Printf("Ignoring message with unsupported subtype: %#v\n", event)
		return
	}

	text := pino.slackProxy.renderFormattedMessageForDisplay(event.Text)

	text = decodeSlackHTMLEntities(text)

	// Convert stuff like ":pizza:" to the actual pizza emoji
	text = emoji.Sprint(text)

	if event.SubType == "me_message" {
		pino.ircProxy.sendAction(destinationIRCChannel, text)
		return
	}

	// In the normal case, it's a normal message
	pino.ircProxy.sendMessage(destinationIRCChannel, text)
}
<|endoftext|>


<commit_before>package arn

import "sort"

// AnimeList ...
type AnimeList struct {
	UserID string           `json:"userId"`
	Items  []*AnimeListItem `json:"items"`

	user *User
}

// Find returns the list item with the specified anime ID, if available.
func (list *AnimeList) Find(animeID string) *AnimeListItem {
	for _, item := range list.Items {
		if item.AnimeID == animeID {
			return item
		}
	}

	return nil
}

// User returns the user this anime list belongs to.
func (list *AnimeList) User() *User {
	if list.user == nil {
		list.user, _ = GetUser(list.UserID)
	}

	return list.user
}

// Sort ...
func (list *AnimeList) Sort() {
	sort.Slice(list.Items, func(i, j int) bool {
		a := list.Items[i].Anime().UpcomingEpisode()
		b := list.Items[j].Anime().UpcomingEpisode()

		if a == nil && b == nil {
			return list.Items[i].Rating.Overall > list.Items[j].Rating.Overall
		}

		if a == nil {
			return false
		}

		if b == nil {
			return true
		}

		return a.Episode.AiringDate.Start < b.Episode.AiringDate.Start
	})
}

// SplitByStatus splits the anime list into multiple ones by status.
func (list *AnimeList) SplitByStatus() map[string]*AnimeList {
	statusToList := map[string]*AnimeList{}

	statusToList[AnimeListStatusWatching] = &AnimeList{
		UserID: list.UserID,
		Items:  []*AnimeListItem{},
	}

	statusToList[AnimeListStatusCompleted] = &AnimeList{
		UserID: list.UserID,
		Items:  []*AnimeListItem{},
	}

	statusToList[AnimeListStatusPlanned] = &AnimeList{
		UserID: list.UserID,
		Items:  []*AnimeListItem{},
	}

	statusToList[AnimeListStatusHold] = &AnimeList{
		UserID: list.UserID,
		Items:  []*AnimeListItem{},
	}

	statusToList[AnimeListStatusDropped] = &AnimeList{
		UserID: list.UserID,
		Items:  []*AnimeListItem{},
	}

	for _, item := range list.Items {
		statusList := statusToList[item.Status]
		statusList.Items = append(statusList.Items, item)
	}

	return statusToList
}

// StreamAnimeLists returns a stream of all anime.
func StreamAnimeLists() (chan *AnimeList, error) {
	objects, err := DB.All("AnimeList")
	return objects.(chan *AnimeList), err
}

// AllAnimeLists returns a slice of all anime.
func AllAnimeLists() ([]*AnimeList, error) {
	var all []*AnimeList

	stream, err := StreamAnimeLists()

	if err != nil {
		return nil, err
	}

	for obj := range stream {
		all = append(all, obj)
	}

	return all, nil
}

// GetAnimeList ...
func GetAnimeList(user *User) (*AnimeList, error) {
	obj, err := DB.Get("AnimeList", user.ID)
	return obj.(*AnimeList), err
}
<commit_msg>Added WatchingAndPlanned<commit_after>package arn

import (
	"sort"
)

// AnimeList ...
type AnimeList struct {
	UserID string           `json:"userId"`
	Items  []*AnimeListItem `json:"items"`

	user *User
}

// Find returns the list item with the specified anime ID, if available.
func (list *AnimeList) Find(animeID string) *AnimeListItem {
	for _, item := range list.Items {
		if item.AnimeID == animeID {
			return item
		}
	}

	return nil
}

// User returns the user this anime list belongs to.
func (list *AnimeList) User() *User {
	if list.user == nil {
		list.user, _ = GetUser(list.UserID)
	}

	return list.user
}

// Sort ...
func (list *AnimeList) Sort() {
	sort.Slice(list.Items, func(i, j int) bool {
		a := list.Items[i].Anime().UpcomingEpisode()
		b := list.Items[j].Anime().UpcomingEpisode()

		if a == nil && b == nil {
			return list.Items[i].Rating.Overall > list.Items[j].Rating.Overall
		}

		if a == nil {
			return false
		}

		if b == nil {
			return true
		}

		return a.Episode.AiringDate.Start < b.Episode.AiringDate.Start
	})
}

// WatchingAndPlanned ...
func (list *AnimeList) WatchingAndPlanned() *AnimeList {
	newList := &AnimeList{
		UserID: list.UserID,
		Items:  []*AnimeListItem{},
	}

	for _, item := range list.Items {
		if item.Status == AnimeListStatusWatching || item.Status == AnimeListStatusPlanned {
			newList.Items = append(newList.Items, item)
		}
	}

	return newList
}

// SplitByStatus splits the anime list into multiple ones by status.
func (list *AnimeList) SplitByStatus() map[string]*AnimeList {
	statusToList := map[string]*AnimeList{}

	statusToList[AnimeListStatusWatching] = &AnimeList{
		UserID: list.UserID,
		Items:  []*AnimeListItem{},
	}

	statusToList[AnimeListStatusCompleted] = &AnimeList{
		UserID: list.UserID,
		Items:  []*AnimeListItem{},
	}

	statusToList[AnimeListStatusPlanned] = &AnimeList{
		UserID: list.UserID,
		Items:  []*AnimeListItem{},
	}

	statusToList[AnimeListStatusHold] = &AnimeList{
		UserID: list.UserID,
		Items:  []*AnimeListItem{},
	}

	statusToList[AnimeListStatusDropped] = &AnimeList{
		UserID: list.UserID,
		Items:  []*AnimeListItem{},
	}

	for _, item := range list.Items {
		statusList := statusToList[item.Status]
		statusList.Items = append(statusList.Items, item)
	}

	return statusToList
}

// StreamAnimeLists returns a stream of all anime.
func StreamAnimeLists() (chan *AnimeList, error) {
	objects, err := DB.All("AnimeList")
	return objects.(chan *AnimeList), err
}

// AllAnimeLists returns a slice of all anime.
func AllAnimeLists() ([]*AnimeList, error) {
	var all []*AnimeList

	stream, err := StreamAnimeLists()

	if err != nil {
		return nil, err
	}

	for obj := range stream {
		all = append(all, obj)
	}

	return all, nil
}

// GetAnimeList ...
func GetAnimeList(user *User) (*AnimeList, error) {
	obj, err := DB.Get("AnimeList", user.ID)
	return obj.(*AnimeList), err
}
<|endoftext|>


<commit_before>package web

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"sort"
	"strings"
	"time"

	"github.com/StackExchange/tsaf/_third_party/github.com/MiniProfiler/go/miniprofiler"
	"github.com/StackExchange/tsaf/_third_party/github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/tsaf/conf"
	"github.com/StackExchange/tsaf/expr"
	"github.com/StackExchange/tsaf/sched"
)

func Expr(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) (interface{}, error) {
	e, err := expr.New(r.FormValue("q"))
	if err != nil {
		return nil, err
	}
	now, err := getTime(r)
	if err != nil {
		return nil, err
	}
	res, queries, err := e.ExecuteOpts(opentsdb.NewCache(schedule.Conf.TsdbHost, schedule.Conf.ResponseLimit), t, now, 0)
	if err != nil {
		return nil, err
	}
	ret := struct {
		Type    string
		Results []*expr.Result
		Queries map[string]opentsdb.Request
	}{
		e.Tree.Root.Return().String(),
		res,
		make(map[string]opentsdb.Request),
	}
	for _, q := range queries {
		if e, err := url.QueryUnescape(q.String()); err == nil {
			ret.Queries[e] = q
		}
	}
	return ret, nil
}

func getTime(r *http.Request) (now time.Time, err error) {
	now = time.Now().UTC()
	if fd := r.FormValue("date"); len(fd) > 0 {
		if ft := r.FormValue("time"); len(ft) > 0 {
			fd += " " + ft
		} else {
			fd += " " + now.Format("15:04")
		}
		now, err = time.Parse("2006-01-02 15:04", fd)
	}
	return
}

type Res struct {
	*sched.Event
	Key sched.AlertKey
}

func Rule(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) (interface{}, error) {
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "tsdbHost = %s\n", schedule.Conf.TsdbHost)
	fmt.Fprintf(&buf, "smtpHost = %s\n", schedule.Conf.SmtpHost)
	fmt.Fprintf(&buf, "emailFrom = %s\n", schedule.Conf.EmailFrom)
	for k, v := range schedule.Conf.Vars {
		if strings.HasPrefix(k, "$") {
			fmt.Fprintf(&buf, "%s=%s\n", k, v)
		}
	}
	for _, v := range schedule.Conf.Notifications {
		fmt.Fprintln(&buf, v.Def)
	}
	fmt.Fprintf(&buf, "%s\n", r.FormValue("template"))
	fmt.Fprintf(&buf, "%s\n", r.FormValue("alert"))
	c, err := conf.New("Test Config", buf.String())
	if err != nil {
		return nil, err
	}
	if len(c.Alerts) != 1 {
		return nil, fmt.Errorf("exactly one alert must be defined")
	}
	s := &sched.Schedule{}
	now, err := getTime(r)
	if err != nil {
		return nil, err
	}
	s.CheckStart = now
	s.Init(c)
	var a *conf.Alert
	for _, a = range c.Alerts {
	}
	s.CheckExpr(a, a.Warn, sched.StWarning, nil)
	s.CheckExpr(a, a.Crit, sched.StCritical, nil)
	i := 0
	if len(s.RunHistory) < 1 {
		return nil, fmt.Errorf("no results returned")
	}
	keys := make(sched.AlertKeys, len(s.RunHistory))
	for k, v := range s.RunHistory {
		v.Time = now
		keys[i] = k
		i++
	}
	sort.Sort(keys)
	instance := s.Status(keys[0])
	body := new(bytes.Buffer)
	subject := new(bytes.Buffer)
	var warning []string
	if err := s.ExecuteBody(body, a, instance); err != nil {
		warning = append(warning, err.Error())
	}
	if err := s.ExecuteSubject(subject, a, instance); err != nil {
		warning = append(warning, err.Error())
	}
	b, _ := ioutil.ReadAll(body)
	sub, _ := ioutil.ReadAll(subject)
	return struct {
		Body    string
		Subject string
		Data    interface{}
		Result  map[sched.AlertKey]*sched.Event
		Warning []string
		Time    int64
	}{
		string(b),
		string(sub),
		s.Data(instance, a),
		s.RunHistory,
		warning,
		now.Unix(),
	}, nil
}
<commit_msg>Display check errors on rule test page<commit_after>package web

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"sort"
	"strings"
	"time"

	"github.com/StackExchange/tsaf/_third_party/github.com/MiniProfiler/go/miniprofiler"
	"github.com/StackExchange/tsaf/_third_party/github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/tsaf/conf"
	"github.com/StackExchange/tsaf/expr"
	"github.com/StackExchange/tsaf/sched"
)

func Expr(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) (interface{}, error) {
	e, err := expr.New(r.FormValue("q"))
	if err != nil {
		return nil, err
	}
	now, err := getTime(r)
	if err != nil {
		return nil, err
	}
	res, queries, err := e.ExecuteOpts(opentsdb.NewCache(schedule.Conf.TsdbHost, schedule.Conf.ResponseLimit), t, now, 0)
	if err != nil {
		return nil, err
	}
	ret := struct {
		Type    string
		Results []*expr.Result
		Queries map[string]opentsdb.Request
	}{
		e.Tree.Root.Return().String(),
		res,
		make(map[string]opentsdb.Request),
	}
	for _, q := range queries {
		if e, err := url.QueryUnescape(q.String()); err == nil {
			ret.Queries[e] = q
		}
	}
	return ret, nil
}

func getTime(r *http.Request) (now time.Time, err error) {
	now = time.Now().UTC()
	if fd := r.FormValue("date"); len(fd) > 0 {
		if ft := r.FormValue("time"); len(ft) > 0 {
			fd += " " + ft
		} else {
			fd += " " + now.Format("15:04")
		}
		now, err = time.Parse("2006-01-02 15:04", fd)
	}
	return
}

type Res struct {
	*sched.Event
	Key sched.AlertKey
}

func Rule(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) (interface{}, error) {
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "tsdbHost = %s\n", schedule.Conf.TsdbHost)
	fmt.Fprintf(&buf, "smtpHost = %s\n", schedule.Conf.SmtpHost)
	fmt.Fprintf(&buf, "emailFrom = %s\n", schedule.Conf.EmailFrom)
	for k, v := range schedule.Conf.Vars {
		if strings.HasPrefix(k, "$") {
			fmt.Fprintf(&buf, "%s=%s\n", k, v)
		}
	}
	for _, v := range schedule.Conf.Notifications {
		fmt.Fprintln(&buf, v.Def)
	}
	fmt.Fprintf(&buf, "%s\n", r.FormValue("template"))
	fmt.Fprintf(&buf, "%s\n", r.FormValue("alert"))
	c, err := conf.New("Test Config", buf.String())
	if err != nil {
		return nil, err
	}
	if len(c.Alerts) != 1 {
		return nil, fmt.Errorf("exactly one alert must be defined")
	}
	s := &sched.Schedule{}
	now, err := getTime(r)
	if err != nil {
		return nil, err
	}
	s.CheckStart = now
	s.Init(c)
	var a *conf.Alert
	for _, a = range c.Alerts {
	}
	if _, err := s.CheckExpr(a, a.Warn, sched.StWarning, nil); err != nil {
		return nil, err
	}
	if _, err := s.CheckExpr(a, a.Crit, sched.StCritical, nil); err != nil {
		return nil, err
	}
	i := 0
	if len(s.RunHistory) < 1 {
		return nil, fmt.Errorf("no results returned")
	}
	keys := make(sched.AlertKeys, len(s.RunHistory))
	for k, v := range s.RunHistory {
		v.Time = now
		keys[i] = k
		i++
	}
	sort.Sort(keys)
	instance := s.Status(keys[0])
	body := new(bytes.Buffer)
	subject := new(bytes.Buffer)
	var warning []string
	if err := s.ExecuteBody(body, a, instance); err != nil {
		warning = append(warning, err.Error())
	}
	if err := s.ExecuteSubject(subject, a, instance); err != nil {
		warning = append(warning, err.Error())
	}
	b, _ := ioutil.ReadAll(body)
	sub, _ := ioutil.ReadAll(subject)
	return struct {
		Body    string
		Subject string
		Data    interface{}
		Result  map[sched.AlertKey]*sched.Event
		Warning []string
		Time    int64
	}{
		string(b),
		string(sub),
		s.Data(instance, a),
		s.RunHistory,
		warning,
		now.Unix(),
	}, nil
}
<|endoftext|>