<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Pipe adapter to connect code expecting an io.Reader
// with code expecting an io.Writer.

package io

import (
	"os"
	"runtime"
	"sync"
)

type pipeResult struct {
	n   int
	err os.Error
}

// Shared pipe structure.
type pipe struct {
	// Reader sends on cr1, receives on cr2.
	// Writer does the same on cw1, cw2.
	r1, w1 chan []byte
	r2, w2 chan pipeResult

	rclose chan os.Error // read close; error to return to writers
	wclose chan os.Error // write close; error to return to readers

	done chan int // read or write half is done
}

func (p *pipe) run() {
	var (
		rb    []byte      // pending Read
		wb    []byte      // pending Write
		wn    int         // amount written so far from wb
		rerr  os.Error    // if read end is closed, error to send to writers
		werr  os.Error    // if write end is closed, error to send to readers
		r1    chan []byte // p.cr1 or nil depending on whether Read is ok
		w1    chan []byte // p.cw1 or nil depending on whether Write is ok
		ndone int
	)

	// Read and Write are enabled at the start.
	r1 = p.r1
	w1 = p.w1

	for {
		select {
		case <-p.done:
			if ndone++; ndone == 2 {
				// both reader and writer are gone
				// close out any existing i/o
				if r1 == nil {
					p.r2 <- pipeResult{0, os.EINVAL}
				}
				if w1 == nil {
					p.w2 <- pipeResult{0, os.EINVAL}
				}
				return
			}
			continue
		case rerr = <-p.rclose:
			if w1 == nil {
				// finish pending Write
				p.w2 <- pipeResult{wn, rerr}
				wn = 0
				w1 = p.w1 // allow another Write
			}
			if r1 == nil {
				// Close of read side during Read.
				// finish pending Read with os.EINVAL.
				p.r2 <- pipeResult{0, os.EINVAL}
				r1 = p.r1 // allow another Read
			}
			continue
		case werr = <-p.wclose:
			if r1 == nil {
				// finish pending Read
				p.r2 <- pipeResult{0, werr}
				r1 = p.r1 // allow another Read
			}
			if w1 == nil {
				// Close of write side during Write.
				// finish pending Write with os.EINVAL.
				p.w2 <- pipeResult{wn, os.EINVAL}
				wn = 0
				w1 = p.w1 // allow another Write
			}
			continue
		case rb = <-r1:
			if werr != nil {
				// write end is closed
				p.r2 <- pipeResult{0, werr}
				continue
			}
			if rerr != nil {
				// read end is closed
				p.r2 <- pipeResult{0, os.EINVAL}
				continue
			}
			r1 = nil // disable Read until this one is done
		case wb = <-w1:
			if rerr != nil {
				// read end is closed
				p.w2 <- pipeResult{0, rerr}
				continue
			}
			if werr != nil {
				// write end is closed
				p.w2 <- pipeResult{0, os.EINVAL}
				continue
			}
			w1 = nil // disable Write until this one is done
		}

		if r1 == nil && w1 == nil {
			// Have rb and wb.  Execute.
			n := copy(rb, wb)
			wn += n
			wb = wb[n:]

			// Finish Read.
			p.r2 <- pipeResult{n, nil}
			r1 = p.r1 // allow another Read

			// Maybe finish Write.
			if len(wb) == 0 {
				p.w2 <- pipeResult{wn, nil}
				wn = 0
				w1 = p.w1 // allow another Write
			}
		}
	}
}

// Read/write halves of the pipe.
// They are separate structures for two reasons:
//  1.  If one end becomes garbage without being Closed,
//      its finalizer can Close so that the other end
//      does not hang indefinitely.
//  2.  Clients cannot use interface conversions on the
//      read end to find the Write method, and vice versa.

type pipeHalf struct {
	c1     chan []byte
	c2     chan pipeResult
	cclose chan os.Error
	done   chan int

	lock   sync.Mutex
	closed bool

	io       sync.Mutex
	ioclosed bool
}

func (p *pipeHalf) rw(data []byte) (n int, err os.Error) {
	// Run i/o operation.
	// Check ioclosed flag under lock to make sure we're still allowed to do i/o.
	p.io.Lock()
	if p.ioclosed {
		p.io.Unlock()
		return 0, os.EINVAL
	}
	p.io.Unlock()
	p.c1 <- data
	res := <-p.c2
	return res.n, res.err
}

func (p *pipeHalf) close(err os.Error) os.Error {
	// Close pipe half.
	// Only first call to close does anything.
	p.lock.Lock()
	if p.closed {
		p.lock.Unlock()
		return os.EINVAL
	}
	p.closed = true
	p.lock.Unlock()

	// First, send the close notification.
	p.cclose <- err

	// Runner is now responding to rw operations
	// with os.EINVAL.  Cut off future rw operations
	// by setting ioclosed flag.
	p.io.Lock()
	p.ioclosed = true
	p.io.Unlock()

	// With ioclosed set, there will be no more rw operations
	// working on the channels.
	// Tell the runner we won't be bothering it anymore.
	p.done <- 1

	// Successfully torn down; can disable finalizer.
	runtime.SetFinalizer(p, nil)

	return nil
}

func (p *pipeHalf) finalizer() {
	p.close(os.EINVAL)
}

// A PipeReader is the read half of a pipe.
type PipeReader struct {
	pipeHalf
}

// Read implements the standard Read interface:
// it reads data from the pipe, blocking until a writer
// arrives or the write end is closed.
// If the write end is closed with an error, that error is
// returned as err; otherwise err is nil.
func (r *PipeReader) Read(data []byte) (n int, err os.Error) {
	return r.rw(data)
}

// Close closes the reader; subsequent writes to the
// write half of the pipe will return the error os.EPIPE.
func (r *PipeReader) Close() os.Error {
	return r.CloseWithError(nil)
}

// CloseWithError closes the reader; subsequent writes
// to the write half of the pipe will return the error err.
func (r *PipeReader) CloseWithError(err os.Error) os.Error {
	if err == nil {
		err = os.EPIPE
	}
	return r.close(err)
}

// A PipeWriter is the write half of a pipe.
type PipeWriter struct {
	pipeHalf
}

// Write implements the standard Write interface:
// it writes data to the pipe, blocking until readers
// have consumed all the data or the read end is closed.
// If the read end is closed with an error, that err is
// returned as err; otherwise err is os.EPIPE.
func (w *PipeWriter) Write(data []byte) (n int, err os.Error) {
	return w.rw(data)
}

// Close closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and os.EOF.
func (w *PipeWriter) Close() os.Error {
	return w.CloseWithError(nil)
}

// CloseWithError closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and the error err.
func (w *PipeWriter) CloseWithError(err os.Error) os.Error {
	if err == nil {
		err = os.EOF
	}
	return w.close(err)
}

// Pipe creates a synchronous in-memory pipe.
// It can be used to connect code expecting an io.Reader
// with code expecting an io.Writer.
// Reads on one end are matched with writes on the other,
// copying data directly between the two; there is no internal buffering.
func Pipe() (*PipeReader, *PipeWriter) {
	p := &pipe{
		r1:     make(chan []byte),
		r2:     make(chan pipeResult),
		w1:     make(chan []byte),
		w2:     make(chan pipeResult),
		rclose: make(chan os.Error),
		wclose: make(chan os.Error),
		done:   make(chan int),
	}
	go p.run()

	// NOTE: Cannot use composite literal here:
	//	pipeHalf{c1: p.cr1, c2: p.cr2, cclose: p.crclose, cdone: p.cdone}
	// because this implicitly copies the pipeHalf, which copies the inner mutex.

	r := new(PipeReader)
	r.c1 = p.r1
	r.c2 = p.r2
	r.cclose = p.rclose
	r.done = p.done
	// TODO(rsc): Should be able to write
	//	runtime.SetFinalizer(r, (*PipeReader).finalizer)
	// but 6g doesn't see the finalizer method.
	runtime.SetFinalizer(&r.pipeHalf, (*pipeHalf).finalizer)

	w := new(PipeWriter)
	w.c1 = p.w1
	w.c2 = p.w2
	w.cclose = p.wclose
	w.done = p.done
	// TODO(rsc): Should be able to write
	//	runtime.SetFinalizer(w, (*PipeWriter).finalizer)
	// but 6g doesn't see the finalizer method.
	runtime.SetFinalizer(&w.pipeHalf, (*pipeHalf).finalizer)

	return r, w
}
<commit_msg>io: use SetFinalizer more elegantly in Pipe<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Pipe adapter to connect code expecting an io.Reader
// with code expecting an io.Writer.

package io

import (
	"os"
	"runtime"
	"sync"
)

type pipeResult struct {
	n   int
	err os.Error
}

// Shared pipe structure.
type pipe struct {
	// Reader sends on cr1, receives on cr2.
	// Writer does the same on cw1, cw2.
	r1, w1 chan []byte
	r2, w2 chan pipeResult

	rclose chan os.Error // read close; error to return to writers
	wclose chan os.Error // write close; error to return to readers

	done chan int // read or write half is done
}

func (p *pipe) run() {
	var (
		rb    []byte      // pending Read
		wb    []byte      // pending Write
		wn    int         // amount written so far from wb
		rerr  os.Error    // if read end is closed, error to send to writers
		werr  os.Error    // if write end is closed, error to send to readers
		r1    chan []byte // p.cr1 or nil depending on whether Read is ok
		w1    chan []byte // p.cw1 or nil depending on whether Write is ok
		ndone int
	)

	// Read and Write are enabled at the start.
	r1 = p.r1
	w1 = p.w1

	for {
		select {
		case <-p.done:
			if ndone++; ndone == 2 {
				// both reader and writer are gone
				// close out any existing i/o
				if r1 == nil {
					p.r2 <- pipeResult{0, os.EINVAL}
				}
				if w1 == nil {
					p.w2 <- pipeResult{0, os.EINVAL}
				}
				return
			}
			continue
		case rerr = <-p.rclose:
			if w1 == nil {
				// finish pending Write
				p.w2 <- pipeResult{wn, rerr}
				wn = 0
				w1 = p.w1 // allow another Write
			}
			if r1 == nil {
				// Close of read side during Read.
				// finish pending Read with os.EINVAL.
				p.r2 <- pipeResult{0, os.EINVAL}
				r1 = p.r1 // allow another Read
			}
			continue
		case werr = <-p.wclose:
			if r1 == nil {
				// finish pending Read
				p.r2 <- pipeResult{0, werr}
				r1 = p.r1 // allow another Read
			}
			if w1 == nil {
				// Close of write side during Write.
				// finish pending Write with os.EINVAL.
				p.w2 <- pipeResult{wn, os.EINVAL}
				wn = 0
				w1 = p.w1 // allow another Write
			}
			continue
		case rb = <-r1:
			if werr != nil {
				// write end is closed
				p.r2 <- pipeResult{0, werr}
				continue
			}
			if rerr != nil {
				// read end is closed
				p.r2 <- pipeResult{0, os.EINVAL}
				continue
			}
			r1 = nil // disable Read until this one is done
		case wb = <-w1:
			if rerr != nil {
				// read end is closed
				p.w2 <- pipeResult{0, rerr}
				continue
			}
			if werr != nil {
				// write end is closed
				p.w2 <- pipeResult{0, os.EINVAL}
				continue
			}
			w1 = nil // disable Write until this one is done
		}

		if r1 == nil && w1 == nil {
			// Have rb and wb.  Execute.
			n := copy(rb, wb)
			wn += n
			wb = wb[n:]

			// Finish Read.
			p.r2 <- pipeResult{n, nil}
			r1 = p.r1 // allow another Read

			// Maybe finish Write.
			if len(wb) == 0 {
				p.w2 <- pipeResult{wn, nil}
				wn = 0
				w1 = p.w1 // allow another Write
			}
		}
	}
}

// Read/write halves of the pipe.
// They are separate structures for two reasons:
//  1.  If one end becomes garbage without being Closed,
//      its finalizer can Close so that the other end
//      does not hang indefinitely.
//  2.  Clients cannot use interface conversions on the
//      read end to find the Write method, and vice versa.

type pipeHalf struct {
	c1     chan []byte
	c2     chan pipeResult
	cclose chan os.Error
	done   chan int

	lock   sync.Mutex
	closed bool

	io       sync.Mutex
	ioclosed bool
}

func (p *pipeHalf) rw(data []byte) (n int, err os.Error) {
	// Run i/o operation.
	// Check ioclosed flag under lock to make sure we're still allowed to do i/o.
	p.io.Lock()
	if p.ioclosed {
		p.io.Unlock()
		return 0, os.EINVAL
	}
	p.io.Unlock()
	p.c1 <- data
	res := <-p.c2
	return res.n, res.err
}

func (p *pipeHalf) close(err os.Error) os.Error {
	// Close pipe half.
	// Only first call to close does anything.
	p.lock.Lock()
	if p.closed {
		p.lock.Unlock()
		return os.EINVAL
	}
	p.closed = true
	p.lock.Unlock()

	// First, send the close notification.
	p.cclose <- err

	// Runner is now responding to rw operations
	// with os.EINVAL.  Cut off future rw operations
	// by setting ioclosed flag.
	p.io.Lock()
	p.ioclosed = true
	p.io.Unlock()

	// With ioclosed set, there will be no more rw operations
	// working on the channels.
	// Tell the runner we won't be bothering it anymore.
	p.done <- 1

	// Successfully torn down; can disable finalizer.
	runtime.SetFinalizer(p, nil)

	return nil
}

func (p *pipeHalf) finalizer() {
	p.close(os.EINVAL)
}

// A PipeReader is the read half of a pipe.
type PipeReader struct {
	pipeHalf
}

// Read implements the standard Read interface:
// it reads data from the pipe, blocking until a writer
// arrives or the write end is closed.
// If the write end is closed with an error, that error is
// returned as err; otherwise err is nil.
func (r *PipeReader) Read(data []byte) (n int, err os.Error) {
	return r.rw(data)
}

// Close closes the reader; subsequent writes to the
// write half of the pipe will return the error os.EPIPE.
func (r *PipeReader) Close() os.Error {
	return r.CloseWithError(nil)
}

// CloseWithError closes the reader; subsequent writes
// to the write half of the pipe will return the error err.
func (r *PipeReader) CloseWithError(err os.Error) os.Error {
	if err == nil {
		err = os.EPIPE
	}
	return r.close(err)
}

// A PipeWriter is the write half of a pipe.
type PipeWriter struct {
	pipeHalf
}

// Write implements the standard Write interface:
// it writes data to the pipe, blocking until readers
// have consumed all the data or the read end is closed.
// If the read end is closed with an error, that err is
// returned as err; otherwise err is os.EPIPE.
func (w *PipeWriter) Write(data []byte) (n int, err os.Error) {
	return w.rw(data)
}

// Close closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and os.EOF.
func (w *PipeWriter) Close() os.Error {
	return w.CloseWithError(nil)
}

// CloseWithError closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and the error err.
func (w *PipeWriter) CloseWithError(err os.Error) os.Error {
	if err == nil {
		err = os.EOF
	}
	return w.close(err)
}

// Pipe creates a synchronous in-memory pipe.
// It can be used to connect code expecting an io.Reader
// with code expecting an io.Writer.
// Reads on one end are matched with writes on the other,
// copying data directly between the two; there is no internal buffering.
func Pipe() (*PipeReader, *PipeWriter) {
	p := &pipe{
		r1:     make(chan []byte),
		r2:     make(chan pipeResult),
		w1:     make(chan []byte),
		w2:     make(chan pipeResult),
		rclose: make(chan os.Error),
		wclose: make(chan os.Error),
		done:   make(chan int),
	}
	go p.run()

	// NOTE: Cannot use composite literal here:
	//	pipeHalf{c1: p.cr1, c2: p.cr2, cclose: p.crclose, cdone: p.cdone}
	// because this implicitly copies the pipeHalf, which copies the inner mutex.

	r := new(PipeReader)
	r.c1 = p.r1
	r.c2 = p.r2
	r.cclose = p.rclose
	r.done = p.done
	runtime.SetFinalizer(r, (*PipeReader).finalizer)

	w := new(PipeWriter)
	w.c1 = p.w1
	w.c2 = p.w2
	w.cclose = p.wclose
	w.done = p.done
	runtime.SetFinalizer(w, (*PipeWriter).finalizer)

	return r, w
}
<|endoftext|>


<commit_before>package bot

import (
	"math/rand"

	"fmt"
	"regexp"

	"github.com/nlopes/slack"
)

func simpleMatch(content string, matches ...string) bool {
	for _, match := range matches {
		pattern := fmt.Sprintf("(^|[^가-힣\\S]|\u3000)%s($|[^가-힣\\S]|\u3000)", match)
		matched, _ := regexp.MatchString(pattern, content)
		if matched {
			return true
		}
	}

	return false
}

func postResponse(bot *BaseBot, channel string, emoji string, name string, response string) {
	bot.PostMessage(channel, response, slack.PostMessageParameters{
		AsUser:    false,
		IconEmoji: emoji,
		Username:  name,
		Parse:     "full",
	})
}

func randomResponse(bot *BaseBot, channel string, emoji string, name string, responses []string) {
	response := responses[rand.Intn(len(responses))]
	postResponse(bot, channel, emoji, name, response)
}

var (
	anduinresp []string = []string{
		"안녕하세요!",
		"감사합니다!",
		"이게... 아닌데...",
		"빛이 당신을 태울 것입니다!",
		"정말 잘하셨어요.",
		"죄송합니다.",
	}
	yayoiresp []string = []string{
		"ζ*'ヮ')ζ 웃우─!",
		"ζ° ͜ʖ ͡° ζ/ 웃우─! 프로듀서 로우탓-치!",
		"ζ*'ヮ')ζ / 프로듀사 하이탓-치! 이예이!",
		"ζ*'ヮ')ζ 오늘은 숙주나물 축제에요!",
		"ζ*'ヮ')ζ 저기, 타카츠키 야요이, 14세입니다. 저, 집이 빈곤해서, 저도 무언가 할 수 있는게 없을까 생각해서 아이돌이 되보려고 했습니다. 잘 부탁드립니다! 이에이!",
		"ζ*'ヮ')ζ타카츠키 야요이, 14세입니다-! 저, 건강이 장점이니까, 아무리 많은 일이어도 걱정 없어요. 그러니까 척척 일해나가서, 같이 톱 아이돌을 목표해주세요. 에헤헤♪",
		"ζ*'ヮ')ζ 타카츠키 야요이에요! 조금이라도 집안에 보탬이 되지 않을까 해서 아이돌을 시작했어요. 저, 건강과 의욕만큼은 분명하니까, 프로듀스 잘 부탁드려요! 에헤헷♪",
		"ζ*'ヮ')ζ 최근 상점가에서 쇼핑을 하고 있으면, 누가 말을 거는 일이 많아졌어요-. 이것도, 아이돌로서 유명해졌다는 걸까나! 웃우-, 프로듀서 감사합니다-!",
		"ζ*'ヮ')ζ 수영복을 입으면, 청소로 젖어도 갈아입지 않아도 괜찮아서 득일까나! 프로듀서도 수영복으로 갈아입어서, 같이 놀지 않을래요? 아, 물론 청소를 끝내는 것이 우선이에요-!",
		"ζ*'ヮ')ζ 이 옷, 팔랑팔랑~ 둥실둥실~ 거려서, 왠지 제가 아닌 것 같아요-. 조금 쑥스러울지도! 에헤헤.... 프로듀서, 저, 팔랑팔랑하고 둥실둥실 거리는 거, 어울리나요-?",
		"ζ*'ヮ')ζ 프, 프로듀서. 미아 오리씨들이 저를 따라버려서, 모두가 뒤를 쫒아 오고 있어요-! 어...어쩌면 좋죠-! 하앗, 저기, 모두? 저는 엄마가 아니에요-!",
		"ζ*'ヮ')ζ 프로듀서, 봐주세요-! 오리씨와 오리 엄마와 개구리씨와 돼지씨와... 그리고... 어쨌든, 잔뜩 잔뜩 있는 모두와 노래할게요-♪ 에헤헷, 귀여워요-!",
		"ζ*'ヮ')ζ 에헤헷, 늑대씨 의상이에요-! 커흠-, 먹어버릴테다-! ...앗, 사실은 먹지 않을테니까 무서워하지 말아주세요~! 상냥한 늑대씨가 되고 싶으니깐요!",
	}
	guguresp []string = []string{
		"구구구",
		"@scarlet9",
	}
)

func specialResponses(bot *BaseBot, e *slack.MessageEvent) {
	// ignore all bot_message
	if e.SubType == "bot_message" {
		return
	}

	text := e.Text

	if simpleMatch(text, "72", "치하야", "큿") {
		postResponse(bot, e.Channel, ":kutt:", "치하야", "큿")
	}
	if simpleMatch(text, "크킄") {
		postResponse(bot, e.Channel, ":chuni:", "Dark Flame Master", "흐콰한다")
	}
	if simpleMatch(text, "안두인") {
		randomResponse(bot, e.Channel, ":anduin:", "안두인", anduinresp)
	}
	if simpleMatch(text, "웃우") {
		randomResponse(bot, e.Channel, ":yayoyee:", "타카츠키 야요이", yayoiresp)
	}
	if simpleMatch(text, "혼란하다 혼란해") {
		postResponse(bot, e.Channel, ":honse:", "혼세마왕", "혼세혼세")
	}
	if simpleMatch(text, "비둘기") {
		randomResponse(bot, e.Channel, ":gugu:", "비둘기", guguresp)
	}
	if simpleMatch(text, "신촌 셔틀") {
		processShuttleCommand(bot, e.Channel)
	}
}
<commit_msg>Add comment to bot/special.go<commit_after>package bot

import (
	"math/rand"

	"fmt"
	"regexp"

	"github.com/nlopes/slack"
)

// Simply match patterns
// check boundary of patterns
func simpleMatch(content string, matches ...string) bool {
	for _, match := range matches {
		pattern := fmt.Sprintf("(^|[^가-힣\\S]|\u3000)%s($|[^가-힣\\S]|\u3000)", match)
		matched, _ := regexp.MatchString(pattern, content)
		if matched {
			return true
		}
	}

	return false
}

// Post response as bot
func postResponse(bot *BaseBot, channel string, emoji string, name string, response string) {
	bot.PostMessage(channel, response, slack.PostMessageParameters{
		AsUser:    false,
		IconEmoji: emoji,
		Username:  name,
		Parse:     "full",
	})
}

// Post random response from responses array
func randomResponse(bot *BaseBot, channel string, emoji string, name string, responses []string) {
	response := responses[rand.Intn(len(responses))]
	postResponse(bot, channel, emoji, name, response)
}

var (
	anduinresp []string = []string{
		"안녕하세요!",
		"감사합니다!",
		"이게... 아닌데...",
		"빛이 당신을 태울 것입니다!",
		"정말 잘하셨어요.",
		"죄송합니다.",
	}
	yayoiresp []string = []string{
		"ζ*'ヮ')ζ 웃우─!",
		"ζ° ͜ʖ ͡° ζ/ 웃우─! 프로듀서 로우탓-치!",
		"ζ*'ヮ')ζ / 프로듀사 하이탓-치! 이예이!",
		"ζ*'ヮ')ζ 오늘은 숙주나물 축제에요!",
		"ζ*'ヮ')ζ 저기, 타카츠키 야요이, 14세입니다. 저, 집이 빈곤해서, 저도 무언가 할 수 있는게 없을까 생각해서 아이돌이 되보려고 했습니다. 잘 부탁드립니다! 이에이!",
		"ζ*'ヮ')ζ타카츠키 야요이, 14세입니다-! 저, 건강이 장점이니까, 아무리 많은 일이어도 걱정 없어요. 그러니까 척척 일해나가서, 같이 톱 아이돌을 목표해주세요. 에헤헤♪",
		"ζ*'ヮ')ζ 타카츠키 야요이에요! 조금이라도 집안에 보탬이 되지 않을까 해서 아이돌을 시작했어요. 저, 건강과 의욕만큼은 분명하니까, 프로듀스 잘 부탁드려요! 에헤헷♪",
		"ζ*'ヮ')ζ 최근 상점가에서 쇼핑을 하고 있으면, 누가 말을 거는 일이 많아졌어요-. 이것도, 아이돌로서 유명해졌다는 걸까나! 웃우-, 프로듀서 감사합니다-!",
		"ζ*'ヮ')ζ 수영복을 입으면, 청소로 젖어도 갈아입지 않아도 괜찮아서 득일까나! 프로듀서도 수영복으로 갈아입어서, 같이 놀지 않을래요? 아, 물론 청소를 끝내는 것이 우선이에요-!",
		"ζ*'ヮ')ζ 이 옷, 팔랑팔랑~ 둥실둥실~ 거려서, 왠지 제가 아닌 것 같아요-. 조금 쑥스러울지도! 에헤헤.... 프로듀서, 저, 팔랑팔랑하고 둥실둥실 거리는 거, 어울리나요-?",
		"ζ*'ヮ')ζ 프, 프로듀서. 미아 오리씨들이 저를 따라버려서, 모두가 뒤를 쫒아 오고 있어요-! 어...어쩌면 좋죠-! 하앗, 저기, 모두? 저는 엄마가 아니에요-!",
		"ζ*'ヮ')ζ 프로듀서, 봐주세요-! 오리씨와 오리 엄마와 개구리씨와 돼지씨와... 그리고... 어쨌든, 잔뜩 잔뜩 있는 모두와 노래할게요-♪ 에헤헷, 귀여워요-!",
		"ζ*'ヮ')ζ 에헤헷, 늑대씨 의상이에요-! 커흠-, 먹어버릴테다-! ...앗, 사실은 먹지 않을테니까 무서워하지 말아주세요~! 상냥한 늑대씨가 되고 싶으니깐요!",
	}
	guguresp []string = []string{
		"구구구",
		"@scarlet9",
	}
)

func specialResponses(bot *BaseBot, e *slack.MessageEvent) {
	// ignore all bot_message
	if e.SubType == "bot_message" {
		return
	}

	text := e.Text
	channel := e.Channel

	if simpleMatch(text, "72", "치하야", "큿") {
		postResponse(bot, channel, ":kutt:", "치하야", "큿")
	}
	if simpleMatch(text, "크킄") {
		postResponse(bot, channel, ":chuni:", "Dark Flame Master", "흐콰한다")
	}
	if simpleMatch(text, "안두인") {
		randomResponse(bot, channel, ":anduin:", "안두인", anduinresp)
	}
	if simpleMatch(text, "웃우") {
		randomResponse(bot, channel, ":yayoyee:", "타카츠키 야요이", yayoiresp)
	}
	if simpleMatch(text, "혼란하다 혼란해") {
		postResponse(bot, channel, ":honse:", "혼세마왕", "혼세혼세")
	}
	if simpleMatch(text, "비둘기") {
		randomResponse(bot, channel, ":gugu:", "비둘기", guguresp)
	}
	if simpleMatch(text, "신촌 셔틀") {
		processShuttleCommand(bot, channel)
	}
}
<|endoftext|>


<commit_before>package facade

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"path"
	"strings"

	"github.com/spiegel-im-spiegel/gocli"
	"github.com/spiegel-im-spiegel/gpgpdump/internal/parse"
)

// Exit Status
const (
	ExitSuccess = iota
	ExitFailure
)

// Errors
var (
	ErrFacadeTest = errors.New("facade test")
)

// Facade of facade context
type Facade struct {
	// UI is Command line user interface
	*gocli.UI
	// Name of application
	Name string
	// Version of application
	Version string
}

// NewFacade returns a new Facade instance
func NewFacade(appName, version string, ui *gocli.UI) *Facade {
	return &Facade{UI: ui, Name: appName, Version: version}
}

// Run Application
func (f *Facade) Run(args []string) (int, error) {
	cmd := parse.Command(f.UI)

	flags := flag.NewFlagSet(f.Name, flag.ContinueOnError)
	flags.BoolVar(&cmd.Hflag, "h", false, "displays this help")
	flags.BoolVar(&cmd.Vflag, "v", false, "displays version")
	flags.BoolVar(&cmd.Aflag, "a", false, "accepts ASCII input only")
	flags.BoolVar(&cmd.Gflag, "g", false, "selects alternate dump format")
	flags.BoolVar(&cmd.Iflag, "i", false, "dumps integer packets")
	flags.BoolVar(&cmd.Lflag, "l", false, "dumps literal packets")
	flags.BoolVar(&cmd.Mflag, "m", false, "dumps marker packets")
	flags.BoolVar(&cmd.Pflag, "p", false, "dumps private packets")
	flags.BoolVar(&cmd.Uflag, "u", false, "displays UTC time")
	ftest := flags.Bool("ftest", false, "facade test")
	flags.Usage = func() {
		f.showUsage()
	}
	// Parse commandline flag
	if err := flags.Parse(args); err != nil {
		return ExitFailure, nil
	}
	if cmd.Hflag {
		f.showUsage()
		return ExitSuccess, nil
	}
	if cmd.Vflag {
		f.showVersion()
		return ExitSuccess, nil
	}

	switch flags.NArg() {
	case 0:
		cmd.InputFile = ""
	case 1:
		cmd.InputFile = flags.Arg(0)
	default:
		return ExitFailure, os.ErrInvalid
	}

	if *ftest { // for facade test
		return ExitSuccess, ErrFacadeTest
	}
	if err := cmd.Run(); err != nil {
		return ExitFailure, err
	}
	return ExitSuccess, nil
}

func (f *Facade) showUsage() {
	usageText := `
USAGE:
   %s [options] [OpenPGP file]

OPTIONS:
   -h -- displays this help
   -v -- displays version
   -a -- accepts ASCII input only
   -g -- selects alternate dump format
   -i -- dumps integer packets
   -l -- dumps literal packets
   -m -- dumps marker packets
   -p -- dumps private packets
   -u -- displays UTC time
`
	f.OutputErrln(fmt.Sprintf(strings.Trim(usageText, " \t\n\r"), f.Name))
}

func (f *Facade) showVersion() {
	f.OutputErrln(fmt.Sprintf("%s %s", path.Base(f.Name), f.Version))
}
<commit_msg>remove -g option.<commit_after>package facade

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"path"
	"strings"

	"github.com/spiegel-im-spiegel/gocli"
	"github.com/spiegel-im-spiegel/gpgpdump/internal/parse"
)

// Exit Status
const (
	ExitSuccess = iota
	ExitFailure
)

// Errors
var (
	ErrFacadeTest = errors.New("facade test")
)

// Facade of facade context
type Facade struct {
	// UI is Command line user interface
	*gocli.UI
	// Name of application
	Name string
	// Version of application
	Version string
}

// NewFacade returns a new Facade instance
func NewFacade(appName, version string, ui *gocli.UI) *Facade {
	return &Facade{UI: ui, Name: appName, Version: version}
}

// Run Application
func (f *Facade) Run(args []string) (int, error) {
	cmd := parse.Command(f.UI)

	flags := flag.NewFlagSet(f.Name, flag.ContinueOnError)
	flags.BoolVar(&cmd.Hflag, "h", false, "displays this help")
	flags.BoolVar(&cmd.Vflag, "v", false, "displays version")
	flags.BoolVar(&cmd.Aflag, "a", false, "accepts ASCII input only")
	//flags.BoolVar(&cmd.Gflag, "g", false, "selects alternate dump format") // do not use g option
	flags.BoolVar(&cmd.Iflag, "i", false, "dumps multi-precision integer")
	flags.BoolVar(&cmd.Lflag, "l", false, "dumps literal packets (tag 11)")
	flags.BoolVar(&cmd.Mflag, "m", false, "dumps marker packets (tag 10)")
	flags.BoolVar(&cmd.Pflag, "p", false, "dumps private packets (tag 60-63)")
	flags.BoolVar(&cmd.Uflag, "u", false, "displays UTC time")
	ftest := flags.Bool("ftest", false, "facade test")
	flags.Usage = func() {
		f.showUsage()
	}
	// Parse commandline flag
	if err := flags.Parse(args); err != nil {
		return ExitFailure, nil
	}
	if cmd.Hflag {
		f.showUsage()
		return ExitSuccess, nil
	}
	if cmd.Vflag {
		f.showVersion()
		return ExitSuccess, nil
	}

	switch flags.NArg() {
	case 0:
		cmd.InputFile = ""
	case 1:
		cmd.InputFile = flags.Arg(0)
	default:
		return ExitFailure, os.ErrInvalid
	}

	if *ftest { // for facade test
		return ExitSuccess, ErrFacadeTest
	}
	if err := cmd.Run(); err != nil {
		return ExitFailure, err
	}
	return ExitSuccess, nil
}

func (f *Facade) showUsage() {
	usageText := `
USAGE:
   %s [options] [OpenPGP file]

OPTIONS:
   -h -- displays this help
   -v -- displays version
   -a -- accepts ASCII input only
   -i -- dumps integer packets
   -l -- dumps literal packets
   -m -- dumps marker packets
   -p -- dumps private packets
   -u -- displays UTC time
`
	f.OutputErrln(fmt.Sprintf(strings.Trim(usageText, " \t\n\r"), f.Name))
}

func (f *Facade) showVersion() {
	f.OutputErrln(fmt.Sprintf("%s %s", path.Base(f.Name), f.Version))
}
<|endoftext|>


<commit_before>package jwthelper

import (
	"net/http"
	"time"
)

// CookieOption represent cookie option.
type CookieOption struct {
	f func(c *http.Cookie)
}

// CookieName returns the option for cookie name.
func CookieName(name string) CookieOption {
	return CookieOption{func(c *http.Cookie) {
		c.Name = name
	}}
}

// CookiePath returns the option for cookie path.
func CookiePath(path string) CookieOption {
	return CookieOption{func(c *http.Cookie) {
		c.Path = path
	}}
}

// CookieDomain returns the option for cookie domain.
func CookieDomain(domain string) CookieOption {
	return CookieOption{func(c *http.Cookie) {
		c.Domain = domain
	}}
}

// CookieExpires returns the option for cookie expires.
func CookieExpires(expires time.Time) CookieOption {
	return CookieOption{func(c *http.Cookie) {
		c.Expires = expires
	}}
}

// CookieMaxAge returns the option for cookie max age.
func CookieMaxAge(maxAge int) CookieOption {
	return CookieOption{func(c *http.Cookie) {
		c.MaxAge = maxAge
	}}
}

// CookieSecure returns the option for secure cookie.
func CookieSecure(secure bool) CookieOption {
	return CookieOption{func(c *http.Cookie) {
		c.Secure = secure
	}}
}

// CookieHttpOnly returns the option for HTTP only cookie.
func CookieHttpOnly(httpOnly bool) CookieOption {
	return CookieOption{func(c *http.Cookie) {
		c.HttpOnly = httpOnly
	}}
}

// NewCookie news a cookie contains JWT token.
//
//     Params:
//         tokenString: JWT token string. It'll be set as cookie value.
//         options: Cookie options(optional).
//                  Use helper functions to get options: CookieName(), CookieDomain()...
//     Comments:
//         It'll set cookie name to "jwt" if no name option specified.
func NewCookie(tokenString string, options ...CookieOption) *http.Cookie {
	cookie := http.Cookie{
		// Use "jwt" as cookie name by default.
		Name:     "jwt",
		Value:    tokenString,
		Secure:   true,
		HttpOnly: true,
	}

	// Override default cookie with customized options.
	for _, op := range options {
		op.f(&cookie)
	}

	return &cookie
}
<commit_msg>Add comment of CookieName() for the default JWT cookie name<commit_after>package jwthelper

import (
	"net/http"
	"time"
)

// CookieOption represent cookie option.
type CookieOption struct {
	f func(c *http.Cookie)
}

// CookieName returns the option for cookie name.
// It'll use "jwt" as cookie name by default.
func CookieName(name string) CookieOption {
	return CookieOption{func(c *http.Cookie) {
		c.Name = name
	}}
}

// CookiePath returns the option for cookie path.
func CookiePath(path string) CookieOption {
	return CookieOption{func(c *http.Cookie) {
		c.Path = path
	}}
}

// CookieDomain returns the option for cookie domain.
func CookieDomain(domain string) CookieOption {
	return CookieOption{func(c *http.Cookie) {
		c.Domain = domain
	}}
}

// CookieExpires returns the option for cookie expires.
func CookieExpires(expires time.Time) CookieOption {
	return CookieOption{func(c *http.Cookie) {
		c.Expires = expires
	}}
}

// CookieMaxAge returns the option for cookie max age.
func CookieMaxAge(maxAge int) CookieOption {
	return CookieOption{func(c *http.Cookie) {
		c.MaxAge = maxAge
	}}
}

// CookieSecure returns the option for secure cookie.
func CookieSecure(secure bool) CookieOption {
	return CookieOption{func(c *http.Cookie) {
		c.Secure = secure
	}}
}

// CookieHttpOnly returns the option for HTTP only cookie.
func CookieHttpOnly(httpOnly bool) CookieOption {
	return CookieOption{func(c *http.Cookie) {
		c.HttpOnly = httpOnly
	}}
}

// NewCookie news a cookie contains JWT token.
//
//     Params:
//         tokenString: JWT token string. It'll be set as cookie value.
//         options: Cookie options(optional).
//                  Use helper functions to get options: CookieName(), CookieDomain()...
//     Comments:
//         It'll set cookie name to "jwt" if no name option specified.
func NewCookie(tokenString string, options ...CookieOption) *http.Cookie {
	cookie := http.Cookie{
		// Use "jwt" as cookie name by default.
		Name:     "jwt",
		Value:    tokenString,
		Secure:   true,
		HttpOnly: true,
	}

	// Override default cookie with customized options.
	for _, op := range options {
		op.f(&cookie)
	}

	return &cookie
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"compress/gzip"
	"fmt"
	"math"
	"os"
	"sort"
	"strconv"
	"strings"
)

func VAddSub(A, B []float64, polarity float64) []float64 {
	if len(A) != len(B) {
		panic("Requires equal length")
	}
	vec := make([]float64, len(A))
	for i := range A {
		vec[i] = A[i] + polarity*B[i]
	}
	return vec
}

func VAdd(A, B []float64) []float64 {
	return VAddSub(A, B, +1)
}

func VSub(A, B []float64) []float64 {
	return VAddSub(A, B, -1)
}

func VDot(A, B []float64) float64 {
	dot := 0.0
	for i := range A {
		dot += A[i] * B[i]
	}
	return dot
}

func VNorm(A []float64) float64 {
	dot := VDot(A, A)
	return math.Sqrt(dot)
}

func VCosine(A, B []float64) float64 {
	return VDot(A, B) / VNorm(A) / VNorm(B)
}

type StringFloatTuple struct {
	Key   string
	Value float64
}

type ByValue []*StringFloatTuple

func (r ByValue) Len() int           { return len(r) }
func (r ByValue) Swap(i, j int)      { r[i], r[j] = r[j], r[i] }
func (r ByValue) Less(i, j int) bool { return r[i].Value > r[j].Value }

var words map[string][]float64

func main() {
	words := make(map[string][]float64)

	fn := os.Args[1]
	f, _ := os.Open(fn)
	gz, _ := gzip.NewReader(f)
	defer gz.Close()
	defer f.Close()
	fscanner := bufio.NewScanner(gz)
	fmt.Println("Loading", fn, "...")
	for fscanner.Scan() {
		splits := strings.SplitN(fscanner.Text(), " ", 2)
		word := splits[0]
		nums := strings.Split(splits[1], " ")
		vec := make([]float64, len(nums))
		for i, n := range nums {
			vec[i], _ = strconv.ParseFloat(n, 64)
		}
		words[word] = vec
	}
	fmt.Println("Loaded", len(words))

	scanner := bufio.NewScanner(os.Stdin)
	fmt.Printf(">>> ")
	for scanner.Scan() {

		testWords := strings.Split(scanner.Text(), " ")
		var tvec []float64
		fmt.Println("=-=-=-=-=")
		if len(testWords) == 1 {
			tvec = words[testWords[0]]
		} else if len(testWords) == 3 {
			fmt.Println("Finding similar words for", testWords[0], "-", testWords[1], "+", testWords[2])
			tvec = VAdd(VSub(words[testWords[0]], words[testWords[1]]), words[testWords[2]])
		} else {
			fmt.Println("Testing only works for one or three words")
			continue
		}
		//
		var results ByValue
		for word, wvec := range words {
			//sim := VCosine(tvec, wvec)
			sim := VDot(wvec, tvec) / VNorm(tvec) / VNorm(wvec)
			results = append(results, &StringFloatTuple{word, sim})
		}

		sort.Sort(results)
		for i := 0; i < 10; i++ {
			fmt.Println(results[i].Key, results[i].Value)
		}

		fmt.Printf(">>> ")
	}
}
<commit_msg>cosine.go: Added comments and feedback when words are missing<commit_after>package main

import (
	"bufio"
	"compress/gzip"
	"fmt"
	"math"
	"os"
	"sort"
	"strconv"
	"strings"
)

func VAddSub(A, B []float64, polarity float64) []float64 {
	if len(A) != len(B) {
		panic("Requires equal length")
	}
	vec := make([]float64, len(A))
	for i := range A {
		vec[i] = A[i] + polarity*B[i]
	}
	return vec
}

func VAdd(A, B []float64) []float64 {
	return VAddSub(A, B, +1)
}

func VSub(A, B []float64) []float64 {
	return VAddSub(A, B, -1)
}

func VDot(A, B []float64) float64 {
	dot := 0.0
	for i := range A {
		dot += A[i] * B[i]
	}
	return dot
}

func VNorm(A []float64) float64 {
	dot := VDot(A, A)
	return math.Sqrt(dot)
}

func VCosine(A, B []float64) float64 {
	return VDot(A, B) / VNorm(A) / VNorm(B)
}

type StringFloatTuple struct {
	Key   string
	Value float64
}

// Add sorting by the value or a StringFloatTuple
type ByValue []*StringFloatTuple

func (r ByValue) Len() int           { return len(r) }
func (r ByValue) Swap(i, j int)      { r[i], r[j] = r[j], r[i] }
func (r ByValue) Less(i, j int) bool { return r[i].Value > r[j].Value }

var words map[string][]float64

func main() {
	words := make(map[string][]float64)

	// Load the word vectors from a gzipped input file, passed in by the first command line argument
	fn := os.Args[1]
	f, _ := os.Open(fn)
	gz, _ := gzip.NewReader(f)
	defer gz.Close()
	defer f.Close()
	fscanner := bufio.NewScanner(gz)
	fmt.Println("Loading", fn, "...")
	//
	for fscanner.Scan() {
		splits := strings.SplitN(fscanner.Text(), " ", 2)
		word := splits[0]
		nums := strings.Split(splits[1], " ")
		vec := make([]float64, len(nums))
		for i, n := range nums {
			vec[i], _ = strconv.ParseFloat(n, 64)
		}
		words[word] = vec
	}
	fmt.Println("Loaded", len(words))

	// Allow the user to query in an interpreter style interface
	scanner := bufio.NewScanner(os.Stdin)
	fmt.Printf(">>> ")
	for scanner.Scan() {
		testWords := strings.Split(scanner.Text(), " ")
		fmt.Println("=-=-=-=-=")
		// Ensure all the words are in the vocabulary
		notInVocab := make([]string, 0)
		for _, word := range testWords {
			if _, ok := words[word]; !ok {
				notInVocab = append(notInVocab, word)
			}
		}
		if len(notInVocab) > 0 {
			fmt.Println("Words not found in the vocabulary:", notInVocab)
			fmt.Printf(">>> ")
			continue
		}
		// Generate the test vector to compare against
		var tvec []float64
		if len(testWords) == 1 {
			tvec = words[testWords[0]]
		} else if len(testWords) == 3 {
			fmt.Println("Finding similar words for", testWords[0], "-", testWords[1], "+", testWords[2])
			tvec = VAdd(VSub(words[testWords[0]], words[testWords[1]]), words[testWords[2]])
		} else {
			fmt.Println("Testing only works for one or three words")
			fmt.Printf(">>> ")
			continue
		}
		//
		var results ByValue
		for word, wvec := range words {
			//sim := VCosine(tvec, wvec)
			sim := VDot(wvec, tvec) / VNorm(tvec) / VNorm(wvec)
			results = append(results, &StringFloatTuple{word, sim})
		}
		// Sort the results and return the top 10 to the user
		sort.Sort(results)
		for i := 0; i < 10; i++ {
			fmt.Println(results[i].Key, results[i].Value)
		}
		//
		fmt.Printf(">>> ")
	}
}
<|endoftext|>


<commit_before>package cruncy

// VERSION of the application
const VERSION = "0.6.2"
<commit_msg>0.6.3<commit_after>package cruncy

// VERSION of the application
const VERSION = "0.6.3"
<|endoftext|>


<commit_before>package daemon

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

type Daemon struct {
	PidFileName string
	PidFileMode os.FileMode
}

func (d *Daemon) Daemonize(workDir string, inFile *os.File, outFile *os.File, errFile *os.File) error {
	if syscall.Getppid() != 1 {
		path, err := filepath.Abs(os.Args[0])
		if err != nil {
			return err
		}
		cmd := exec.Command(path, os.Args[1:]...)
		cmd.Stdin = inFile
		cmd.Stdout = outFile
		cmd.Stderr = errFile
		if err := cmd.Start(); err != nil {
			return err
		}
		os.Exit(0)
	}
	if workDir != "" {
		if err := os.Chdir(workDir); err != nil {
			return err
		}
		os.Chdir(workDir)
	}

	syscall.Umask(0)

	s_ret, s_err := syscall.Setsid()
	if s_err != nil {
		return s_err
	}

	if err := ioutil.WriteFile(d.PidFileName, []byte(strconv.Itoa(s_ret)), d.PidFileMode); err != nil {
		return err
	}

	return nil
}

func (d *Daemon) Cleanup() error {
	if d.PidFileName == "" {
		return nil
	}
	return os.Remove(d.PidFileName)
}

func (d *Daemon) Pid() int {
	pid, _ := ioutil.ReadFile(d.PidFileName)
	p, _ := strconv.Atoi(string(pid))
	return p
}

func (d *Daemon) Process() (*os.Process, error) {
	return os.FindProcess(d.Pid())
}

func (d *Daemon) Signal(sig os.Signal) error {
	process, err := d.Process()
	if err != nil {
		return err
	}
	return process.Signal(sig)
}

func (d *Daemon) Status() (pid int, err error) {
	p, err := d.Process()
	if err != nil {
		return 0, err
	}
	return p.Pid, p.Signal(syscall.Signal(0x0))
}

func (d *Daemon) Stop() error {
	process, err := d.Process()
	if err != nil {
		return err
	}
	if err := process.Signal(syscall.SIGTERM); err != nil {
		return process.Kill()
	}
	return nil
}
<commit_msg>Add comments<commit_after>// Copyright 2015 Janos Guljas. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package resenje.org/daemon provides functionality to execute binaries
// in the background. It requires no external dependencies.

package daemon

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

// Structure that holds information about PID file.
type Daemon struct {
	PidFileName string
	PidFileMode os.FileMode
}

// Daemonize terminates the execution of the initial process
// and starts a new process in the background. If workDir is not
// zero length string, os.Chdir is executed with that value.
// New process will have standard input, output and error specified by
// inFile, outFile and errFile.
// PID file will be created with the second process ID.
func (d *Daemon) Daemonize(workDir string, inFile io.Reader, outFile io.Writer, errFile io.Writer) error {
	if syscall.Getppid() != 1 {
		path, err := filepath.Abs(os.Args[0])
		if err != nil {
			return err
		}
		cmd := exec.Command(path, os.Args[1:]...)
		cmd.Stdin = inFile
		cmd.Stdout = outFile
		cmd.Stderr = errFile
		if err := cmd.Start(); err != nil {
			return err
		}
		os.Exit(0)
	}
	if workDir != "" {
		if err := os.Chdir(workDir); err != nil {
			return err
		}
		os.Chdir(workDir)
	}

	syscall.Umask(0)

	s_ret, s_err := syscall.Setsid()
	if s_err != nil {
		return s_err
	}

	if err := ioutil.WriteFile(d.PidFileName, []byte(strconv.Itoa(s_ret)), d.PidFileMode); err != nil {
		return err
	}

	return nil
}

// Cleanup removes PID file.
func (d *Daemon) Cleanup() error {
	if d.PidFileName == "" {
		return nil
	}
	return os.Remove(d.PidFileName)
}

// Pid returns process ID if available.
func (d *Daemon) Pid() int {
	pid, _ := ioutil.ReadFile(d.PidFileName)
	p, _ := strconv.Atoi(string(pid))
	return p
}

// Process returns an os.Process and error returned by os.FindProcess
// based on the content from PID file.
func (d *Daemon) Process() (*os.Process, error) {
	return os.FindProcess(d.Pid())
}

// Signal sends os.Signal to the daemonized process.
func (d *Daemon) Signal(sig os.Signal) error {
	process, err := d.Process()
	if err != nil {
		return err
	}
	return process.Signal(sig)
}

// Status returns PID as int of a daemonized process. If the process is
// not running, returned error is not nil.
func (d *Daemon) Status() (pid int, err error) {
	p, err := d.Process()
	if err != nil {
		return 0, err
	}
	return p.Pid, p.Signal(syscall.Signal(0x0))
}

// Stops sends SIGTERM signal to the daemonized process. If it fails,
// SIGKILL signal is sent.
func (d *Daemon) Stop() error {
	process, err := d.Process()
	if err != nil {
		return err
	}
	if err := process.Signal(syscall.SIGTERM); err != nil {
		return process.Kill()
	}
	return nil
}
<|endoftext|>


<commit_before>package immortal

import (
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"sync/atomic"
	"syscall"
)

type Daemon struct {
	*Config
	*Control
	Forker
	Logger
	count       uint32
	count_defer uint32
	process     *os.Process
}

func (self *Daemon) Run() {
	if atomic.SwapUint32(&self.count, uint32(1)) != 0 {
		log.Printf("PID: %d running", self.process.Pid)
		return
	}
	cmd := exec.Command(self.command[0], self.command[1:]...)

	// change working directory
	if self.Cwd != "" {
		cmd.Dir = self.Cwd
	}

	// set environment vars
	if self.Env != nil {
		env := os.Environ()
		for k, v := range self.Env {
			env = append(env, fmt.Sprintf("%s=%s", k, v))
		}
		cmd.Env = env
	}

	sysProcAttr := new(syscall.SysProcAttr)

	// set owner
	if self.user != nil {
		uid, err := strconv.Atoi(self.user.Uid)
		if err != nil {
			self.Control.state <- err
		}

		gid, err := strconv.Atoi(self.user.Gid)
		if err != nil {
			self.Control.state <- err
		}

		//	https://golang.org/pkg/syscall/#SysProcAttr
		sysProcAttr.Credential = &syscall.Credential{
			Uid: uint32(uid),
			Gid: uint32(gid),
		}
	}

	// Set process group ID to Pgid, or, if Pgid == 0, to new pid
	sysProcAttr.Setpgid = true
	sysProcAttr.Pgid = 0

	cmd.SysProcAttr = sysProcAttr

	// log only if are available loggers
	var (
		r *io.PipeReader
		w *io.PipeWriter
	)
	if self.Logger.IsLogging() {
		r, w = io.Pipe()
		cmd.Stdout = w
		cmd.Stderr = w
		go self.Logger.StdHandler(r)
	} else {
		cmd.Stdin = nil
		cmd.Stdout = nil
		cmd.Stderr = nil
	}

	go func() {
		// count_defer defaults to 0, 1 to run only once/down (don't restart)
		defer func() {
			atomic.StoreUint32(&self.count, self.count_defer)
		}()

		if self.Logger.IsLogging() {
			defer w.Close()
		}

		if err := cmd.Start(); err != nil {
			self.Control.state <- err
		}

		self.process = cmd.Process

		// follow pid
		if self.Pid.Follow != "" {
			//			go self.watchPid(self.process.Pid)
		}

		// write parent pid
		if self.Pid.Parent != "" {
			if err := WritePid(self.Pid.Parent, os.Getpid()); err != nil {
				log.Print(err)
			}
		}

		// write child pid
		if self.Pid.Child != "" {
			if err := WritePid(self.Pid.Child, self.process.Pid); err != nil {
				log.Print(err)
			}
		}

		self.Control.state <- cmd.Wait()
	}()
}

func New(cfg *Config) (*Daemon, error) {
	var (
		supDir string
		err    error
	)

	if cfg.Cwd != "" {
		supDir = filepath.Join(cfg.Cwd, "supervise")
	} else {
		d, err := os.Getwd()
		if err != nil {
			return nil, err
		}
		supDir = filepath.Join(d, "supervise")
	}

	control := &Control{
		fifo:  make(chan Return),
		quit:  make(chan struct{}),
		state: make(chan error),
	}

	// if ctrl create supervise dir
	if cfg.ctrl {
		// lock
		if lock, err := os.Create(filepath.Join(supDir, "lock")); err != nil {
			return nil, err
		} else if err = syscall.Flock(int(lock.Fd()), syscall.LOCK_EX+syscall.LOCK_NB); err != nil {
			return nil, err
		}

		// fifo
		var ctrl = []string{"control", "ok"}
		for _, v := range ctrl {
			if err := MakeFifo(filepath.Join(supDir, v)); err != nil {
				return nil, err
			}
		}
		if control.fifo_control, err = OpenFifo(filepath.Join(supDir, "control")); err != nil {
			return nil, err
		}
		if control.fifo_ok, err = OpenFifo(filepath.Join(supDir, "ok")); err != nil {
			return nil, err
		}
	}

	return &Daemon{
		Config:  cfg,
		Control: control,
		Forker:  &Fork{},
		Logger: &LogWriter{
			logger: NewLogger(cfg),
		},
	}, nil
}
<commit_msg>	modified:   daemon.go<commit_after>package immortal

import (
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"sync/atomic"
	"syscall"
)

type Daemon struct {
	*Config
	*Control
	Forker
	Logger
	count       uint32
	count_defer uint32
	process     *os.Process
}

func (self *Daemon) Run() {
	if atomic.SwapUint32(&self.count, uint32(1)) != 0 {
		log.Printf("PID: %d running", self.process.Pid)
		return
	}
	cmd := exec.Command(self.command[0], self.command[1:]...)

	// change working directory
	if self.Cwd != "" {
		cmd.Dir = self.Cwd
	}

	// set environment vars
	if self.Env != nil {
		env := os.Environ()
		for k, v := range self.Env {
			env = append(env, fmt.Sprintf("%s=%s", k, v))
		}
		cmd.Env = env
	}

	sysProcAttr := new(syscall.SysProcAttr)

	// set owner
	if self.user != nil {
		uid, err := strconv.Atoi(self.user.Uid)
		if err != nil {
			self.Control.state <- err
		}

		gid, err := strconv.Atoi(self.user.Gid)
		if err != nil {
			self.Control.state <- err
		}

		//	https://golang.org/pkg/syscall/#SysProcAttr
		sysProcAttr.Credential = &syscall.Credential{
			Uid: uint32(uid),
			Gid: uint32(gid),
		}
	}

	// Set process group ID to Pgid, or, if Pgid == 0, to new pid
	sysProcAttr.Setpgid = true
	sysProcAttr.Pgid = 0

	cmd.SysProcAttr = sysProcAttr

	// log only if are available loggers
	var (
		r *io.PipeReader
		w *io.PipeWriter
	)
	if self.Logger.IsLogging() {
		r, w = io.Pipe()
		cmd.Stdout = w
		cmd.Stderr = w
		go self.Logger.StdHandler(r)
	} else {
		cmd.Stdin = nil
		cmd.Stdout = nil
		cmd.Stderr = nil
	}

	go func() {
		// count_defer defaults to 0, 1 to run only once/down (don't restart)
		defer func() {
			atomic.StoreUint32(&self.count, self.count_defer)
		}()

		if self.Logger.IsLogging() {
			defer w.Close()
		}

		if err := cmd.Start(); err != nil {
			self.Control.state <- err
		}

		self.process = cmd.Process

		// follow pid
		if self.Pid.Follow != "" {
			//			go self.watchPid(self.process.Pid)
		}

		// write parent pid
		if self.Pid.Parent != "" {
			if err := WritePid(self.Pid.Parent, os.Getpid()); err != nil {
				log.Print(err)
			}
		}

		// write child pid
		if self.Pid.Child != "" {
			if err := WritePid(self.Pid.Child, self.process.Pid); err != nil {
				log.Print(err)
			}
		}

		self.Control.state <- cmd.Wait()
	}()
}

func New(cfg *Config) (*Daemon, error) {
	var (
		supDir string
		err    error
	)

	if cfg.Cwd != "" {
		supDir = filepath.Join(cfg.Cwd, "supervise")
	} else {
		d, err := os.Getwd()
		if err != nil {
			return nil, err
		}
		supDir = filepath.Join(d, "supervise")
	}

	control := &Control{
		fifo:  make(chan Return),
		quit:  make(chan struct{}),
		state: make(chan error),
	}

	// if ctrl create supervise dir
	if cfg.ctrl {
		// create fifo
		var ctrl = []string{"control", "ok"}
		for _, v := range ctrl {
			if err := MakeFifo(filepath.Join(supDir, v)); err != nil {
				return nil, err
			}
		}

		// lock
		if lock, err := os.Create(filepath.Join(supDir, "lock")); err != nil {
			return nil, err
		} else if err = syscall.Flock(int(lock.Fd()), syscall.LOCK_EX+syscall.LOCK_NB); err != nil {
			return nil, err
		}

		// read fifo
		if control.fifo_control, err = OpenFifo(filepath.Join(supDir, "control")); err != nil {
			return nil, err
		}
		if control.fifo_ok, err = OpenFifo(filepath.Join(supDir, "ok")); err != nil {
			return nil, err
		}
	}

	return &Daemon{
		Config:  cfg,
		Control: control,
		Forker:  &Fork{},
		Logger: &LogWriter{
			logger: NewLogger(cfg),
		},
	}, nil
}
<|endoftext|>


<commit_before>package controller

import (
	"github.com/argoproj/gitops-engine/pkg/health"
	hookutil "github.com/argoproj/gitops-engine/pkg/sync/hook"
	"github.com/argoproj/gitops-engine/pkg/sync/ignore"
	kubeutil "github.com/argoproj/gitops-engine/pkg/utils/kube"
	"k8s.io/apimachinery/pkg/runtime/schema"

	"github.com/argoproj/argo-cd/v2/pkg/apis/application"
	appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
	"github.com/argoproj/argo-cd/v2/util/lua"
)

// setApplicationHealth updates the health statuses of all resources performed in the comparison
func setApplicationHealth(resources []managedResource, statuses []appv1.ResourceStatus, resourceOverrides map[string]appv1.ResourceOverride, app *appv1.Application, persistResourceHealth bool) (*appv1.HealthStatus, error) {
	var savedErr error
	appHealth := appv1.HealthStatus{Status: health.HealthStatusHealthy}
	for i, res := range resources {
		if res.Target != nil && hookutil.Skip(res.Target) {
			continue
		}

		if res.Live != nil && (hookutil.IsHook(res.Live) || ignore.Ignore(res.Live)) {
			continue
		}

		var healthStatus *health.HealthStatus
		var err error
		healthOverrides := lua.ResourceHealthOverrides(resourceOverrides)
		gvk := schema.GroupVersionKind{Group: res.Group, Version: res.Version, Kind: res.Kind}
		if res.Live == nil {
			healthStatus = &health.HealthStatus{Status: health.HealthStatusMissing}
		} else {
			// App the manages itself should not affect own health
			if isSelfReferencedApp(app, kubeutil.GetObjectRef(res.Live)) {
				continue
			}
			healthStatus, err = health.GetResourceHealth(res.Live, healthOverrides)
			if err != nil && savedErr == nil {
				savedErr = err
			}
		}
		if healthStatus != nil {
			if persistResourceHealth {
				resHealth := appv1.HealthStatus{Status: healthStatus.Status, Message: healthStatus.Message}
				statuses[i].Health = &resHealth
			} else {
				statuses[i].Health = nil
			}

			// Is health status is missing but resource has not built-in/custom health check then it should not affect parent app health
			if _, hasOverride := healthOverrides[lua.GetConfigMapKey(gvk)]; healthStatus.Status == health.HealthStatusMissing && !hasOverride && health.GetHealthCheckFunc(gvk) == nil {
				continue
			}

			// Missing or Unknown health status of child Argo CD app should not affect parent
			if res.Kind == application.ApplicationKind && res.Group == application.Group && (healthStatus.Status == health.HealthStatusMissing || healthStatus.Status == health.HealthStatusUnknown) {
				continue
			}

			if health.IsWorse(appHealth.Status, healthStatus.Status) {
				appHealth.Status = healthStatus.Status
			}
		}
	}
	if persistResourceHealth {
		app.Status.ResourceHealthSource = appv1.ResourceHealthLocationInline
	} else {
		app.Status.ResourceHealthSource = appv1.ResourceHealthLocationAppTree
	}
	return &appHealth, savedErr
}
<commit_msg>chore: decreased indent level in setApplicationHealth (#10980)<commit_after>package controller

import (
	"github.com/argoproj/gitops-engine/pkg/health"
	hookutil "github.com/argoproj/gitops-engine/pkg/sync/hook"
	"github.com/argoproj/gitops-engine/pkg/sync/ignore"
	kubeutil "github.com/argoproj/gitops-engine/pkg/utils/kube"
	"k8s.io/apimachinery/pkg/runtime/schema"

	"github.com/argoproj/argo-cd/v2/pkg/apis/application"
	appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
	"github.com/argoproj/argo-cd/v2/util/lua"
)

// setApplicationHealth updates the health statuses of all resources performed in the comparison
func setApplicationHealth(resources []managedResource, statuses []appv1.ResourceStatus, resourceOverrides map[string]appv1.ResourceOverride, app *appv1.Application, persistResourceHealth bool) (*appv1.HealthStatus, error) {
	var savedErr error
	appHealth := appv1.HealthStatus{Status: health.HealthStatusHealthy}
	for i, res := range resources {
		if res.Target != nil && hookutil.Skip(res.Target) {
			continue
		}

		if res.Live != nil && (hookutil.IsHook(res.Live) || ignore.Ignore(res.Live)) {
			continue
		}

		var healthStatus *health.HealthStatus
		var err error
		healthOverrides := lua.ResourceHealthOverrides(resourceOverrides)
		gvk := schema.GroupVersionKind{Group: res.Group, Version: res.Version, Kind: res.Kind}
		if res.Live == nil {
			healthStatus = &health.HealthStatus{Status: health.HealthStatusMissing}
		} else {
			// App the manages itself should not affect own health
			if isSelfReferencedApp(app, kubeutil.GetObjectRef(res.Live)) {
				continue
			}
			healthStatus, err = health.GetResourceHealth(res.Live, healthOverrides)
			if err != nil && savedErr == nil {
				savedErr = err
			}
		}

		if healthStatus == nil {
			continue
		}

		if persistResourceHealth {
			resHealth := appv1.HealthStatus{Status: healthStatus.Status, Message: healthStatus.Message}
			statuses[i].Health = &resHealth
		} else {
			statuses[i].Health = nil
		}

		// Is health status is missing but resource has not built-in/custom health check then it should not affect parent app health
		if _, hasOverride := healthOverrides[lua.GetConfigMapKey(gvk)]; healthStatus.Status == health.HealthStatusMissing && !hasOverride && health.GetHealthCheckFunc(gvk) == nil {
			continue
		}

		// Missing or Unknown health status of child Argo CD app should not affect parent
		if res.Kind == application.ApplicationKind && res.Group == application.Group && (healthStatus.Status == health.HealthStatusMissing || healthStatus.Status == health.HealthStatusUnknown) {
			continue
		}

		if health.IsWorse(appHealth.Status, healthStatus.Status) {
			appHealth.Status = healthStatus.Status
		}
	}
	if persistResourceHealth {
		app.Status.ResourceHealthSource = appv1.ResourceHealthLocationInline
	} else {
		app.Status.ResourceHealthSource = appv1.ResourceHealthLocationAppTree
	}
	return &appHealth, savedErr
}
<|endoftext|>


<commit_before>package controllers

import (
	"encoding/json"
	"net/http"
	"strings"

	"github.com/byuoitav/av-api/helpers"
	"github.com/labstack/echo"
)

type fusionResponse struct {
	APIRooms []fusionRoom `json:"API_Rooms"`
}

type fusionRoom struct {
	RoomID   string
	RoomName string
	Symbols  []fusionSymbol
}

type fusionSymbol struct {
	ProcessorName string
	ConnectInfo   string
	SymbolID      string
}

type room struct {
	Building string
	Room     string
	Hostname string
	Address  string
	Health   helpers.Health
}

type roomWithAvailability struct {
	Building  string
	Room      string
	Hostname  string
	Address   string
	Health    helpers.Health
	Available bool
}

// GetRooms returns a list of all rooms Crestron Fusion knows about
func GetRooms(c echo.Context) error {
	response, err := helpers.RequestHTTP("GET", "http://lazyeye.byu.edu/fusion/apiservice/rooms/") // MAKE SURE YOU HAVE THE TRAILING SLASH
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	rooms := fusionResponse{}
	err = json.Unmarshal(response, &rooms)

	return c.JSON(http.StatusOK, rooms)
}

// GetRoomByName get a room from Fusion using only its name
func GetRoomByName(c echo.Context) error {
	// Get the room's ID from its name
	response, err := helpers.RequestHTTP("GET", "http://lazyeye.byu.edu/fusion/apiservice/rooms/?search="+c.Param("building")+"+"+c.Param("room"))
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	rooms := fusionResponse{}
	err = json.Unmarshal(response, &rooms)
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	// Get info about the room using its ID
	response, err = helpers.RequestHTTP("GET", "http://lazyeye.byu.edu/fusion/apiservice/rooms/"+rooms.APIRooms[0].RoomID)
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	rooms = fusionResponse{}
	err = json.Unmarshal(response, &rooms)
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	hostname := rooms.APIRooms[0].Symbols[0].ProcessorName
	address := rooms.APIRooms[0].Symbols[0].ConnectInfo
	building := strings.Split(c.Param("room"), "+")
	roomName := strings.Split(c.Param("room"), "+")

	roomResponse := room{Building: building[0], Room: roomName[1], Hostname: hostname, Address: address}

	return c.JSON(http.StatusOK, roomResponse)
}

// GetRoomByNameAndBuilding is almost identical to GetRoomByName with the addition of room availability checking (possible because of the supplying of a building in the API call)
func GetRoomByNameAndBuilding(c echo.Context) error {
	// Get the room's ID from its name
	response, err := helpers.RequestHTTP("GET", "http://lazyeye.byu.edu/fusion/apiservice/rooms/?search="+c.Param("building")+"+"+c.Param("room"))
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	rooms := fusionResponse{}
	err = json.Unmarshal(response, &rooms)
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	if len(rooms.APIRooms) == 0 { // Return an error if Fusion doesn't have record of the room specified
		return c.String(http.StatusNotFound, "An error was encountered. Please contact your system administrator.\nError: Could not find room "+c.Param("room")+" in the "+c.Param("building")+" building in the Fusion database")
	} else if len(rooms.APIRooms) > 1 {
		return c.String(http.StatusNotFound, "Error: Your search \""+c.Param("building")+" "+c.Param("room")+"\" returned multiple results from the Fusion database")
	}

	// Get info about the room using its ID
	response, err = helpers.RequestHTTP("GET", "http://lazyeye.byu.edu/fusion/apiservice/rooms/"+rooms.APIRooms[0].RoomID)
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	rooms = fusionResponse{}
	err = json.Unmarshal(response, &rooms)
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	hostname := rooms.APIRooms[0].Symbols[0].ProcessorName
	address := rooms.APIRooms[0].Symbols[0].ConnectInfo
	health, err := helpers.GetHealth(address)
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	availability, err := helpers.CheckAvailability(c.Param("building"), c.Param("room"), rooms.APIRooms[0].Symbols[0].SymbolID)
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	roomResponse := roomWithAvailability{Building: c.Param("building"), Room: c.Param("room"), Hostname: hostname, Address: address, Health: health, Available: availability}

	return c.JSON(http.StatusOK, roomResponse)
}
<commit_msg>Switching to a new branch for a hotfix<commit_after>package controllers

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
	"strconv"
	"strings"

	"github.com/byuoitav/av-api/helpers"
	"github.com/labstack/echo"
)

type fusionResponse struct {
	APIRooms   []fusionRoom `json:"API_Rooms"`
	Pagination string       `json:"Message"`
}

type fusionRoom struct {
	RoomID   string
	RoomName string
	Symbols  []fusionSymbol
}

type fusionSymbol struct {
	ProcessorName string
	ConnectInfo   string
	SymbolID      string
}

type room struct {
	Building string
	Room     string
	Hostname string
	Address  string
	Health   helpers.Health
}

type roomWithAvailability struct {
	Building  string
	Room      string
	Hostname  string
	Address   string
	Health    helpers.Health
	Available bool
}

// GetRooms returns a list of all rooms Crestron Fusion knows about
func GetRooms(c echo.Context) error {
	// response, err := helpers.RequestHTTP("GET", "http://lazyeye.byu.edu/fusion/apiservice/rooms/") // MAKE SURE YOU HAVE THE TRAILING SLASH
	// if err != nil {
	// 	return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	// }
	//
	// rooms := fusionResponse{}
	// err = json.Unmarshal(response, &rooms)

	currentPage := 1
	lastPage := 1

	var toReturn []FusionRoomInfo

	for currentPage <= lastPage {
		reqAddress := address + "?page=" + strconv.Itoa(currentPage)
		fmt.Printf("\nRequestAddress %s \n", reqAddress)
		req, err := http.NewRequest("GET", reqAddress, nil)
		req.Header.Add("Content-Type", "application/json")
		check(err)

		resp, err := client.Do(req)
		check(err)

		var response = FusionRoomResponse{}
		bits, err := ioutil.ReadAll(resp.Body)
		check(err)

		fmt.Printf("\nResponse: %s\n", bits)

		err = json.Unmarshal(bits, &response)
		check(err)

		myExp := regexp.MustCompile(`Page ([0-9]+) of ([0-9]+)`)

		match := myExp.FindStringSubmatch(response.Message)

		toReturn = append(toReturn, response.APIRooms...)

		currentPage, err = strconv.Atoi(match[1])
		check(err)
		lastPage, err = strconv.Atoi(match[2])
		check(err)
		fmt.Printf("\nDownloaded page %v of %v\n", currentPage, lastPage)

		currentPage++
	}

	return c.JSON(http.StatusOK, rooms)
}

// GetRoomByName get a room from Fusion using only its name
func GetRoomByName(c echo.Context) error {
	// Get the room's ID from its name
	response, err := helpers.RequestHTTP("GET", "http://lazyeye.byu.edu/fusion/apiservice/rooms/?search="+c.Param("building")+"+"+c.Param("room"))
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	rooms := fusionResponse{}
	err = json.Unmarshal(response, &rooms)
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	// Get info about the room using its ID
	response, err = helpers.RequestHTTP("GET", "http://lazyeye.byu.edu/fusion/apiservice/rooms/"+rooms.APIRooms[0].RoomID)
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	rooms = fusionResponse{}
	err = json.Unmarshal(response, &rooms)
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	hostname := rooms.APIRooms[0].Symbols[0].ProcessorName
	address := rooms.APIRooms[0].Symbols[0].ConnectInfo
	building := strings.Split(c.Param("room"), "+")
	roomName := strings.Split(c.Param("room"), "+")

	roomResponse := room{Building: building[0], Room: roomName[1], Hostname: hostname, Address: address}

	return c.JSON(http.StatusOK, roomResponse)
}

// GetRoomByNameAndBuilding is almost identical to GetRoomByName with the addition of room availability checking (possible because of the supplying of a building in the API call)
func GetRoomByNameAndBuilding(c echo.Context) error {
	// Get the room's ID from its name
	response, err := helpers.RequestHTTP("GET", "http://lazyeye.byu.edu/fusion/apiservice/rooms/?search="+c.Param("building")+"+"+c.Param("room"))
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	rooms := fusionResponse{}
	err = json.Unmarshal(response, &rooms)
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	if len(rooms.APIRooms) == 0 { // Return an error if Fusion doesn't have record of the room specified
		return c.String(http.StatusNotFound, "An error was encountered. Please contact your system administrator.\nError: Could not find room "+c.Param("room")+" in the "+c.Param("building")+" building in the Fusion database")
	} else if len(rooms.APIRooms) > 1 {
		return c.String(http.StatusNotFound, "Error: Your search \""+c.Param("building")+" "+c.Param("room")+"\" returned multiple results from the Fusion database")
	}

	// Get info about the room using its ID
	response, err = helpers.RequestHTTP("GET", "http://lazyeye.byu.edu/fusion/apiservice/rooms/"+rooms.APIRooms[0].RoomID)
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	rooms = fusionResponse{}
	err = json.Unmarshal(response, &rooms)
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	hostname := rooms.APIRooms[0].Symbols[0].ProcessorName
	address := rooms.APIRooms[0].Symbols[0].ConnectInfo
	health, err := helpers.GetHealth(address)
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	availability, err := helpers.CheckAvailability(c.Param("building"), c.Param("room"), rooms.APIRooms[0].Symbols[0].SymbolID)
	if err != nil {
		return c.String(http.StatusBadRequest, "An error was encountered. Please contact your system administrator.\nError: "+err.Error())
	}

	roomResponse := roomWithAvailability{Building: c.Param("building"), Room: c.Param("room"), Hostname: hostname, Address: address, Health: health, Available: availability}

	return c.JSON(http.StatusOK, roomResponse)
}
<|endoftext|>


<commit_before>package ffplay

import (
	"bytes"
	"encoding/binary"
	"errors"
	"io"
	"io/ioutil"
	"os"
	"os/exec"

	"github.com/1lann/dissonance/audio"
)

// SampleRate is the sample rate used by FFMPEG.
const SampleRate = 48000

type FFPlaySink struct {
	cmd   *exec.Cmd
	debug bool
}

func (f *FFPlaySink) Close() {
	if f.cmd != nil && f.cmd.Process != nil {
		f.cmd.Process.Kill()
	}
}

func (f *FFPlaySink) PlayStream(stream audio.Stream) error {
	if stream.SampleRate() != SampleRate {
		return errors.New("ffplay: sample rate must be 48000")
	}

	stderr, err := f.cmd.StderrPipe()
	if err != nil {
		return err
	}

	wr, err := f.cmd.StdinPipe()
	if err != nil {
		return err
	}

	err = f.cmd.Start()
	if err != nil {
		return err
	}

	if f.debug {
		go io.Copy(os.Stderr, stderr)
	} else {
		go io.Copy(ioutil.Discard, stderr)
	}

	go func() {
		f.cmd.Wait()
		stderr.Close()
		wr.Close()
	}()

	buffer := make([]int32, 2400)
	writeBuffer := new(bytes.Buffer)

	for {
		n, err := stream.Read(buffer)
		if err != nil {
			return err
		}

		for _, sample := range buffer[:n] {
			binary.Write(writeBuffer, binary.LittleEndian, sample)
		}

		_, err = writeBuffer.WriteTo(wr)
		if err != nil {
			return err
		}
	}
}

// NewFFPlaySink creates a ffplay audio sink.
func NewFFPlaySink(debug ...bool) audio.PlaybackDevice {
	shouldDebug := false
	if len(debug) > 0 && debug[0] == true {
		shouldDebug = true
	}

	return &FFPlaySink{
		cmd:   exec.Command("ffplay", "-f", "s32le", "-ar", "48000", "-ac", "1", "-"),
		debug: shouldDebug,
	}
}
<commit_msg>Add ability to close ffplay<commit_after>package ffplay

import (
	"bytes"
	"encoding/binary"
	"errors"
	"io"
	"io/ioutil"
	"os"
	"os/exec"

	"github.com/1lann/dissonance/audio"
)

// SampleRate is the sample rate used by FFMPEG.
const SampleRate = 48000

type FFPlaySink struct {
	cmd   *exec.Cmd
	debug bool
}

func (f *FFPlaySink) Close() {
	if f.cmd != nil && f.cmd.Process != nil {
		f.cmd.Process.Kill()
	}
}

func (f *FFPlaySink) PlayStream(stream audio.Stream) error {
	if stream.SampleRate() != SampleRate {
		return errors.New("ffplay: sample rate must be 48000")
	}

	stderr, err := f.cmd.StderrPipe()
	if err != nil {
		return err
	}

	wr, err := f.cmd.StdinPipe()
	if err != nil {
		return err
	}

	err = f.cmd.Start()
	if err != nil {
		return err
	}

	if f.debug {
		go io.Copy(os.Stderr, stderr)
	} else {
		go io.Copy(ioutil.Discard, stderr)
	}

	go func() {
		f.cmd.Wait()
		stderr.Close()
		wr.Close()
	}()

	buffer := make([]int32, 2400)
	writeBuffer := new(bytes.Buffer)

	defer f.Close()

	for {
		n, err := stream.Read(buffer)
		if err != nil {
			return err
		}

		for _, sample := range buffer[:n] {
			binary.Write(writeBuffer, binary.LittleEndian, sample)
		}

		_, err = writeBuffer.WriteTo(wr)
		if err != nil {
			return err
		}
	}
}

// NewFFPlaySink creates a ffplay audio sink.
func NewFFPlaySink(debug ...bool) audio.PlaybackDevice {
	shouldDebug := false
	if len(debug) > 0 && debug[0] == true {
		shouldDebug = true
	}

	return &FFPlaySink{
		cmd:   exec.Command("ffplay", "-f", "s32le", "-ar", "48000", "-ac", "1", "-"),
		debug: shouldDebug,
	}
}
<|endoftext|>


<commit_before>package fields

import (
	"github.com/kirves/go-form-it/common"
)

// Submit button type
type SubmitButtonType struct {
	Field
}

// Reset button type
type ResetButtonType struct {
	Field
}

// SubmitButton creates a default button with the provided name and text.
func SubmitButton(name string, text string) *SubmitButtonType {
	ret := &SubmitButtonType{
		FieldWithType(name, formcommon.SUBMIT),
	}
	ret.SetText(text)
	return ret
}

// ResetButton creates a default reset button with the provided name and text.
func ResetButton(name string, text string) *ResetButtonType {
	ret := &ResetButtonType{
		FieldWithType(name, formcommon.RESET),
	}
	ret.SetText(text)
	return ret
}
<commit_msg>Added generic button<commit_after>package fields

import (
	"github.com/kirves/go-form-it/common"
)

// Generic button type
type ButtonType struct {
	Field
}

// Submit button type
type SubmitButtonType struct {
	Field
}

// Reset button type
type ResetButtonType struct {
	Field
}

// SubmitButton creates a default button with the provided name and text.
func SubmitButton(name string, text string) *SubmitButtonType {
	ret := &SubmitButtonType{
		FieldWithType(name, formcommon.SUBMIT),
	}
	ret.SetText(text)
	return ret
}

// ResetButton creates a default reset button with the provided name and text.
func ResetButton(name string, text string) *ResetButtonType {
	ret := &ResetButtonType{
		FieldWithType(name, formcommon.RESET),
	}
	ret.SetText(text)
	return ret
}

// Button creates a default generic button
func Button(name string, text string) *ButtonType {
	ret := &ButtonType{
		FieldWithType(name, formcommon.BUTTON),
	}
	ret.SetText(text)
	return ret
}
<|endoftext|>


<commit_before>package file

import (
    "os"
    "archive/zip"
    "io"
    "path/filepath"
    "strings"
    "errors"
    "fmt"
)

// Similar to: http://stackoverflow.com/questions/26050380/go-tracking-post-request-progress
type ProgressWriter struct {
    io.Writer
    Reporter func(r int64)
}

func (pw *ProgressWriter) Write(p []byte) (n int, err error) {
    n, err = pw.Writer.Write(p)
    pw.Reporter(int64(n))
    return
}

func CalculateSize(items ...string) (total int64, err error) {
    total = 0

    for _, value := range items {
	var info os.FileInfo
	info, err = os.Stat(value)
	if err != nil {
	    return
	}

	if !info.IsDir() {
	    fmt.Println("BANAAN 2")
	    total += info.Size()
	} else {
	    filepath.Walk(value, func(path string, info os.FileInfo, err error) error {
		if err != nil {
		    return err
		}

		info, err = os.Stat(path)
		if err != nil {
		    return err
		}

		if !info.IsDir() {
		    total += info.Size()
		}
		return nil
	    })
	}
    }

    return
}

// http://blog.ralch.com/tutorial/golang-working-with-zip/
func ZippyMcZipface(targetName string, reporter func(w int64), items ...string) (err error) {
    if reporter == nil {
	return errors.New("reporter function can't be nil")
    }

    zipfile, err := os.Create(targetName)
    if err != nil {
	return
    }
    defer zipfile.Close()

    archive := zip.NewWriter(zipfile)
    defer archive.Close()

    for _, value := range items {
	info, err := os.Stat(value)
	if err != nil {
	    break
	}

	var baseDir string
	if info.IsDir() {
	    baseDir = filepath.Base(value)
	}

	filepath.Walk(value, func(path string, info os.FileInfo, err error) error {
	    if err != nil {
		return err
	    }

	    header, err := zip.FileInfoHeader(info)
	    if err != nil {
		return err
	    }

	    if baseDir != "" {
		header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, value))
	    }

	    if info.IsDir() {
		header.Name += "/"
	    } else {
		header.Method = zip.Deflate
	    }

	    writer, err := archive.CreateHeader(header)
	    proxyWriter := &ProgressWriter{writer, reporter}

	    if err != nil {
		return err
	    }

	    if info.IsDir() {
		return nil
	    }

	    file, err := os.Open(path)
	    if err != nil {
		return err
	    }
	    defer file.Close()
	    _, err = io.Copy(proxyWriter, file)
	    return err
	})
    }

    return
}
<commit_msg>removed banaan :)<commit_after>package file

import (
    "os"
    "archive/zip"
    "io"
    "path/filepath"
    "strings"
    "errors"
    "fmt"
)

// Similar to: http://stackoverflow.com/questions/26050380/go-tracking-post-request-progress
type ProgressWriter struct {
    io.Writer
    Reporter func(r int64)
}

func (pw *ProgressWriter) Write(p []byte) (n int, err error) {
    n, err = pw.Writer.Write(p)
    pw.Reporter(int64(n))
    return
}

func CalculateSize(items ...string) (total int64, err error) {
    total = 0

    for _, value := range items {
	var info os.FileInfo
	info, err = os.Stat(value)
	if err != nil {
	    return
	}

	if !info.IsDir() {
	    total += info.Size()
	} else {
	    filepath.Walk(value, func(path string, info os.FileInfo, err error) error {
		if err != nil {
		    return err
		}

		info, err = os.Stat(path)
		if err != nil {
		    return err
		}

		if !info.IsDir() {
		    total += info.Size()
		}
		return nil
	    })
	}
    }

    return
}

// http://blog.ralch.com/tutorial/golang-working-with-zip/
func ZippyMcZipface(targetName string, reporter func(w int64), items ...string) (err error) {
    if reporter == nil {
	return errors.New("reporter function can't be nil")
    }

    zipfile, err := os.Create(targetName)
    if err != nil {
	return
    }
    defer zipfile.Close()

    archive := zip.NewWriter(zipfile)
    defer archive.Close()

    for _, value := range items {
	info, err := os.Stat(value)
	if err != nil {
	    break
	}

	var baseDir string
	if info.IsDir() {
	    baseDir = filepath.Base(value)
	}

	filepath.Walk(value, func(path string, info os.FileInfo, err error) error {
	    if err != nil {
		return err
	    }

	    header, err := zip.FileInfoHeader(info)
	    if err != nil {
		return err
	    }

	    if baseDir != "" {
		header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, value))
	    }

	    if info.IsDir() {
		header.Name += "/"
	    } else {
		header.Method = zip.Deflate
	    }

	    writer, err := archive.CreateHeader(header)
	    proxyWriter := &ProgressWriter{writer, reporter}

	    if err != nil {
		return err
	    }

	    if info.IsDir() {
		return nil
	    }

	    file, err := os.Open(path)
	    if err != nil {
		return err
	    }
	    defer file.Close()
	    _, err = io.Copy(proxyWriter, file)
	    return err
	})
    }

    return
}
<|endoftext|>


<commit_before>// Copyright © 2017 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package handler

import (
	ttnlog "github.com/TheThingsNetwork/go-utils/log"
	"github.com/TheThingsNetwork/ttn/amqp"
	"github.com/TheThingsNetwork/ttn/core/types"
)

// AMQPBufferSize indicates the size for uplink channel buffers
var AMQPBufferSize = 10

func (h *handler) assertAMQPExchange() error {
	ch, err := h.amqpClient.(*amqp.DefaultClient).GetChannel()
	if err != nil {
		return err
	}
	err = ch.ExchangeDeclarePassive(h.amqpExchange, "topic", true, false, false, false, nil)
	if err != nil {
		h.Ctx.Warnf("Could not assert presence of AMQP Exchange %s, trying to create...", h.amqpExchange)
		ch, err := h.amqpClient.(*amqp.DefaultClient).GetChannel()
		if err != nil {
			return err
		}
		err = ch.ExchangeDeclare(h.amqpExchange, "topic", true, false, false, false, nil)
		if err != nil {
			h.Ctx.Errorf("Could not create AMQP Exchange %s.", h.amqpExchange)
			return err
		}
		h.Ctx.Infof("Created AMQP Exchange %s", h.amqpExchange)
	}
	return nil
}

func (h *handler) HandleAMQP(username, password, host, exchange, downlinkQueue string) error {
	h.amqpClient = amqp.NewClient(h.Ctx, username, password, host)

	err := h.amqpClient.Connect()
	if err != nil {
		return err
	}
	defer func() {
		if err != nil {
			h.amqpClient.Disconnect()
		}
	}()

	if err := h.assertAMQPExchange(); err != nil {
		return err
	}

	h.amqpUp = make(chan *types.UplinkMessage, AMQPBufferSize)
	h.amqpEvent = make(chan *types.DeviceEvent, AMQPBufferSize)

	subscriber := h.amqpClient.NewSubscriber(h.amqpExchange, downlinkQueue, downlinkQueue != "", downlinkQueue == "")
	err = subscriber.Open()
	if err != nil {
		return err
	}
	defer func() {
		if err != nil {
			subscriber.Close()
		}
	}()
	err = subscriber.SubscribeDownlink(func(_ amqp.Subscriber, _, _ string, req types.DownlinkMessage) {
		h.EnqueueDownlink(&req)
	})
	if err != nil {
		return err
	}
	go h.amqp()
	return nil
}

func (h *handler) amqp() error {
	ctx := h.Ctx.WithField("Protocol", "AMQP")
	publisher := h.amqpClient.NewPublisher(h.amqpExchange)
	err := publisher.Open()
	if err != nil {
		ctx.WithError(err).Error("Could not open publisher channel")
		return err
	}
	defer publisher.Close()
	for {
		select {
		case up := <-h.amqpUp:
			{
				h.amqpUplink(ctx, publisher, up)
			}
		case evt := <-h.amqpEvent:
			{
				h.amqpEvt(ctx, publisher, evt)
			}
		}
	}
	return nil
}

func (h *handler) amqpUplink(ctx ttnlog.Interface, publisher amqp.Publisher, up *types.UplinkMessage) {

	ctx.WithFields(ttnlog.Fields{
		"DevID": up.DevID,
		"AppID": up.AppID,
	}).Debug("Publish Uplink")
	err := publisher.PublishUplink(*up)
	if err != nil {
		ctx.WithError(err).Warn("Could not publish Uplink")
	}
}

func (h *handler) amqpEvt(ctx ttnlog.Interface, publisher amqp.Publisher, event *types.DeviceEvent) {

	h.Ctx.WithFields(ttnlog.Fields{
		"DevID": event.DevID,
		"AppID": event.AppID,
		"Event": event.Event,
	}).Debug("Publish Event on AMQP")
	if event.DevID == "" {
		publisher.PublishAppEvent(event.AppID, event.Event, event.Data)
	} else {
		publisher.PublishDeviceEvent(event.AppID, event.DevID, event.Event, event.Data)
	}
}
<commit_msg>Reverting change in amqp goroutine for consistency<commit_after>// Copyright © 2017 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package handler

import (
	ttnlog "github.com/TheThingsNetwork/go-utils/log"
	"github.com/TheThingsNetwork/ttn/amqp"
	"github.com/TheThingsNetwork/ttn/core/types"
)

// AMQPBufferSize indicates the size for uplink channel buffers
var AMQPBufferSize = 10

func (h *handler) assertAMQPExchange() error {
	ch, err := h.amqpClient.(*amqp.DefaultClient).GetChannel()
	if err != nil {
		return err
	}
	err = ch.ExchangeDeclarePassive(h.amqpExchange, "topic", true, false, false, false, nil)
	if err != nil {
		h.Ctx.Warnf("Could not assert presence of AMQP Exchange %s, trying to create...", h.amqpExchange)
		ch, err := h.amqpClient.(*amqp.DefaultClient).GetChannel()
		if err != nil {
			return err
		}
		err = ch.ExchangeDeclare(h.amqpExchange, "topic", true, false, false, false, nil)
		if err != nil {
			h.Ctx.Errorf("Could not create AMQP Exchange %s.", h.amqpExchange)
			return err
		}
		h.Ctx.Infof("Created AMQP Exchange %s", h.amqpExchange)
	}
	return nil
}

func (h *handler) HandleAMQP(username, password, host, exchange, downlinkQueue string) error {
	h.amqpClient = amqp.NewClient(h.Ctx, username, password, host)

	err := h.amqpClient.Connect()
	if err != nil {
		return err
	}
	defer func() {
		if err != nil {
			h.amqpClient.Disconnect()
		}
	}()

	if err := h.assertAMQPExchange(); err != nil {
		return err
	}

	h.amqpUp = make(chan *types.UplinkMessage, AMQPBufferSize)
	h.amqpEvent = make(chan *types.DeviceEvent, AMQPBufferSize)

	subscriber := h.amqpClient.NewSubscriber(h.amqpExchange, downlinkQueue, downlinkQueue != "", downlinkQueue == "")
	err = subscriber.Open()
	if err != nil {
		return err
	}
	defer func() {
		if err != nil {
			subscriber.Close()
		}
	}()
	err = subscriber.SubscribeDownlink(func(_ amqp.Subscriber, _, _ string, req types.DownlinkMessage) {
		h.EnqueueDownlink(&req)
	})
	if err != nil {
		return err
	}
	go h.amqp()
	return nil
}

func (h *handler) amqp() error {
	ctx := h.Ctx.WithField("Protocol", "AMQP")
	publisher := h.amqpClient.NewPublisher(h.amqpExchange)
	err := publisher.Open()
	if err != nil {
		ctx.WithError(err).Error("Could not open publisher channel")
		return err
	}
	defer publisher.Close()
	go h.amqpUplink(ctx, publisher)
	h.amqpEvt(ctx, publisher)
	return nil
}

func (h *handler) amqpUplink(ctx ttnlog.Interface, publisher amqp.Publisher) {

	for up := range h.amqpUp {
		ctx.WithFields(ttnlog.Fields{
			"DevID": up.DevID,
			"AppID": up.AppID,
		}).Debug("Publish Uplink")
		err := publisher.PublishUplink(*up)
		if err != nil {
			ctx.WithError(err).Warn("Could not publish Uplink")
		}
	}
}

func (h *handler) amqpEvt(ctx ttnlog.Interface, publisher amqp.Publisher) {

	for event := range h.amqpEvent {
		h.Ctx.WithFields(ttnlog.Fields{
			"DevID": event.DevID,
			"AppID": event.AppID,
			"Event": event.Event,
		}).Debug("Publish Event on AMQP")
		if event.DevID == "" {
			publisher.PublishAppEvent(event.AppID, event.Event, event.Data)
		} else {
			publisher.PublishDeviceEvent(event.AppID, event.DevID, event.Event, event.Data)
		}
	}
}
<|endoftext|>


<commit_before>// meek-client-torbrowser is an auxiliary program that helps with connecting
// meek-client to meek-http-helper running in Tor Browser.
//
// Sample usage in torrc (exact paths depend on platform):
// 	ClientTransportPlugin meek exec ./meek-client-torbrowser --log meek-client-torbrowser.log -- ./meek-client --url=https://meek-reflect.appspot.com/ --front=www.google.com --log meek-client.log
// Everything up to "--" is options for this program. Everything following it is
// a meek-client command line. The command line for running firefox is implicit
// and hardcoded in this program.
//
// This program, meek-client-torbrowser, starts a copy of firefox under the
// meek-http-helper profile, which must have configured the meek-http-helper
// extension. This program reads the stdout of firefox, looking for a special
// line with the listening port number of the extension, one that looks like
// "meek-http-helper: listen <address>". The meek-client command is then
// executed as given, except that a --helper option is added that points to the
// port number read from firefox.
//
// This program proxies stdin and stdout to and from meek-client, so it is
// actually meek-client that drives the pluggable transport negotiation with
// tor.
//
// The special --exit-on-stdin-eof is a special workaround for Windows. On
// Windows we don't get a detectable shutdown signal that allows us to kill the
// subprocesses we've started. Instead, use the --exit-on-stdin-eof option and
// run this program inside of terminateprocess-buffer. When
// terminateprocess-buffer is killed, it will close our stdin, and we can exit
// gracefully. --exit-on-stdin-eof and terminateprocess-buffer need to be used
// together.
package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"regexp"
	"syscall"
)

// This magic string is emitted by meek-http-helper.
var helperAddrPattern = regexp.MustCompile(`^meek-http-helper: listen (127\.0\.0\.1:\d+)$`)

func usage() {
	fmt.Fprintf(os.Stderr, "Usage: %s [meek-client-torbrowser args] -- meek-client [meek-client args]\n", os.Args[0])
	flag.PrintDefaults()
}

// Log a call to os.Process.Kill.
func logKill(p *os.Process) error {
	log.Printf("killing PID %d", p.Pid)
	err := p.Kill()
	if err != nil {
		log.Print(err)
	}
	return err
}

// Log a call to os.Process.Signal.
func logSignal(p *os.Process, sig os.Signal) error {
	log.Printf("sending signal %s to PID %d", sig, p.Pid)
	err := p.Signal(sig)
	if err != nil {
		log.Print(err)
	}
	return err
}

// Run firefox and return its exec.Cmd and stdout pipe.
func runFirefox() (cmd *exec.Cmd, stdout io.Reader, err error) {
	var profilePath string
	// Mac OS X needs an absolute profile path.
	profilePath, err = filepath.Abs(firefoxProfilePath)
	if err != nil {
		return
	}
	cmd = exec.Command(firefoxPath, "-no-remote", "-profile", profilePath)
	cmd.Stderr = os.Stderr
	stdout, err = cmd.StdoutPipe()
	if err != nil {
		return
	}
	log.Printf("running firefox command %q", cmd.Args)
	err = cmd.Start()
	if err != nil {
		return
	}
	log.Printf("firefox started with pid %d", cmd.Process.Pid)
	return cmd, stdout, nil
}

// Look for the magic meek-http-helper address string in the Reader, and return
// the address it contains. Start a goroutine to continue reading and discarding
// output of the Reader before returning.
func grepHelperAddr(r io.Reader) (string, error) {
	var helperAddr string
	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		line := scanner.Text()
		if m := helperAddrPattern.FindStringSubmatch(line); m != nil {
			helperAddr = m[1]
			break
		}
	}
	err := scanner.Err()
	if err != nil {
		return "", err
	}
	// Ran out of input before finding the pattern.
	if helperAddr == "" {
		return "", io.EOF
	}
	// Keep reading from the browser to avoid its output buffer filling.
	go io.Copy(ioutil.Discard, r)
	return helperAddr, nil
}

// Run meek-client and return its exec.Cmd.
func runMeekClient(helperAddr string, meekClientCommandLine []string) (cmd *exec.Cmd, err error) {
	meekClientPath := meekClientCommandLine[0]
	args := meekClientCommandLine[1:]
	args = append(args, []string{"--helper", helperAddr}...)
	cmd = exec.Command(meekClientPath, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	log.Printf("running meek-client command %q", cmd.Args)
	err = cmd.Start()
	if err != nil {
		return
	}
	log.Printf("meek-client started with pid %d", cmd.Process.Pid)
	return cmd, nil
}

func main() {
	var exitOnStdinEOF bool
	var logFilename string
	var err error

	flag.Usage = usage
	flag.BoolVar(&exitOnStdinEOF, "exit-on-stdin-eof", false, "exit when stdin is closed (use with terminateprocess-buffer)")
	flag.StringVar(&logFilename, "log", "", "name of log file")
	flag.Parse()

	if logFilename != "" {
		f, err := os.OpenFile(logFilename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
		if err != nil {
			log.Fatal(err)
		}
		defer f.Close()
		log.SetOutput(f)
	}

	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

	// Start firefox.
	firefoxCmd, stdout, err := runFirefox()
	if err != nil {
		log.Print(err)
		return
	}
	defer logKill(firefoxCmd.Process)

	// Find out the helper's listening address.
	helperAddr, err := grepHelperAddr(stdout)
	if err != nil {
		log.Print(err)
		return
	}

	// Start meek-client with the helper address.
	meekClientCmd, err := runMeekClient(helperAddr, flag.Args())
	if err != nil {
		log.Print(err)
		return
	}
	defer logKill(meekClientCmd.Process)

	if exitOnStdinEOF {
		// On Windows, we don't get a SIGINT or SIGTERM, rather we are
		// killed without a chance to clean up our subprocesses. When
		// run inside terminateprocess-buffer, it is instead
		// terminateprocess-buffer that is killed, and we can detect
		// that event by that our stdin gets closed.
		// https://trac.torproject.org/projects/tor/ticket/9330
		go func() {
			io.Copy(ioutil.Discard, os.Stdin)
			log.Printf("synthesizing SIGTERM because of stdin close")
			sigChan <- syscall.SIGTERM
		}()
	}

	sig := <-sigChan
	log.Printf("sig %s", sig)
	err = logSignal(meekClientCmd.Process, sig)
	if err != nil {
		log.Print(err)
	}

	// If SIGINT, wait for a second SIGINT.
	if sig == syscall.SIGINT {
		sig := <-sigChan
		log.Printf("sig %s", sig)
		err = logSignal(meekClientCmd.Process, sig)
		if err != nil {
			log.Print(err)
		}
	}
}
<commit_msg>Replace --exit-on-stdin-eof with TOR_PT_EXIT_ON_STDIN_CLOSE=1.<commit_after>// meek-client-torbrowser is an auxiliary program that helps with connecting
// meek-client to meek-http-helper running in Tor Browser.
//
// Sample usage in torrc (exact paths depend on platform):
// 	ClientTransportPlugin meek exec ./meek-client-torbrowser --log meek-client-torbrowser.log -- ./meek-client --url=https://meek-reflect.appspot.com/ --front=www.google.com --log meek-client.log
// Everything up to "--" is options for this program. Everything following it is
// a meek-client command line. The command line for running firefox is implicit
// and hardcoded in this program.
//
// This program, meek-client-torbrowser, starts a copy of firefox under the
// meek-http-helper profile, which must have configured the meek-http-helper
// extension. This program reads the stdout of firefox, looking for a special
// line with the listening port number of the extension, one that looks like
// "meek-http-helper: listen <address>". The meek-client command is then
// executed as given, except that a --helper option is added that points to the
// port number read from firefox.
//
// This program proxies stdin and stdout to and from meek-client, so it is
// actually meek-client that drives the pluggable transport negotiation with
// tor.
package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"regexp"
	"syscall"
)

// This magic string is emitted by meek-http-helper.
var helperAddrPattern = regexp.MustCompile(`^meek-http-helper: listen (127\.0\.0\.1:\d+)$`)

func usage() {
	fmt.Fprintf(os.Stderr, "Usage: %s [meek-client-torbrowser args] -- meek-client [meek-client args]\n", os.Args[0])
	flag.PrintDefaults()
}

// Log a call to os.Process.Kill.
func logKill(p *os.Process) error {
	log.Printf("killing PID %d", p.Pid)
	err := p.Kill()
	if err != nil {
		log.Print(err)
	}
	return err
}

// Log a call to os.Process.Signal.
func logSignal(p *os.Process, sig os.Signal) error {
	log.Printf("sending signal %s to PID %d", sig, p.Pid)
	err := p.Signal(sig)
	if err != nil {
		log.Print(err)
	}
	return err
}

// Run firefox and return its exec.Cmd and stdout pipe.
func runFirefox() (cmd *exec.Cmd, stdout io.Reader, err error) {
	var profilePath string
	// Mac OS X needs an absolute profile path.
	profilePath, err = filepath.Abs(firefoxProfilePath)
	if err != nil {
		return
	}
	cmd = exec.Command(firefoxPath, "-no-remote", "-profile", profilePath)
	cmd.Stderr = os.Stderr
	stdout, err = cmd.StdoutPipe()
	if err != nil {
		return
	}
	log.Printf("running firefox command %q", cmd.Args)
	err = cmd.Start()
	if err != nil {
		return
	}
	log.Printf("firefox started with pid %d", cmd.Process.Pid)
	return cmd, stdout, nil
}

// Look for the magic meek-http-helper address string in the Reader, and return
// the address it contains. Start a goroutine to continue reading and discarding
// output of the Reader before returning.
func grepHelperAddr(r io.Reader) (string, error) {
	var helperAddr string
	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		line := scanner.Text()
		if m := helperAddrPattern.FindStringSubmatch(line); m != nil {
			helperAddr = m[1]
			break
		}
	}
	err := scanner.Err()
	if err != nil {
		return "", err
	}
	// Ran out of input before finding the pattern.
	if helperAddr == "" {
		return "", io.EOF
	}
	// Keep reading from the browser to avoid its output buffer filling.
	go io.Copy(ioutil.Discard, r)
	return helperAddr, nil
}

// Run meek-client and return its exec.Cmd.
func runMeekClient(helperAddr string, meekClientCommandLine []string) (cmd *exec.Cmd, err error) {
	meekClientPath := meekClientCommandLine[0]
	args := meekClientCommandLine[1:]
	args = append(args, []string{"--helper", helperAddr}...)
	cmd = exec.Command(meekClientPath, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	log.Printf("running meek-client command %q", cmd.Args)
	err = cmd.Start()
	if err != nil {
		return
	}
	log.Printf("meek-client started with pid %d", cmd.Process.Pid)
	return cmd, nil
}

func main() {
	var logFilename string
	var err error

	flag.Usage = usage
	flag.StringVar(&logFilename, "log", "", "name of log file")
	flag.Parse()

	if logFilename != "" {
		f, err := os.OpenFile(logFilename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
		if err != nil {
			log.Fatal(err)
		}
		defer f.Close()
		log.SetOutput(f)
	}

	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

	// Start firefox.
	firefoxCmd, stdout, err := runFirefox()
	if err != nil {
		log.Print(err)
		return
	}
	defer logKill(firefoxCmd.Process)

	// Find out the helper's listening address.
	helperAddr, err := grepHelperAddr(stdout)
	if err != nil {
		log.Print(err)
		return
	}

	// Start meek-client with the helper address.
	meekClientCmd, err := runMeekClient(helperAddr, flag.Args())
	if err != nil {
		log.Print(err)
		return
	}
	defer logKill(meekClientCmd.Process)

	if os.Getenv("TOR_PT_EXIT_ON_STDIN_CLOSE") == "1" {
		// This environment variable means we should treat EOF on stdin
		// just like SIGTERM.
		// https://trac.torproject.org/projects/tor/ticket/15435
		go func() {
			io.Copy(ioutil.Discard, os.Stdin)
			log.Printf("synthesizing SIGTERM because of stdin close")
			sigChan <- syscall.SIGTERM
		}()
	}

	sig := <-sigChan
	log.Printf("sig %s", sig)
	err = logSignal(meekClientCmd.Process, sig)
	if err != nil {
		log.Print(err)
	}

	// If SIGINT, wait for a second SIGINT.
	if sig == syscall.SIGINT {
		sig := <-sigChan
		log.Printf("sig %s", sig)
		err = logSignal(meekClientCmd.Process, sig)
		if err != nil {
			log.Print(err)
		}
	}
}
<|endoftext|>