<commit_before>package uri

import (
	"io"
	"net/url"
	"os"
	"path/filepath"
	"reflect"
	"runtime"
	"time"
)

var protocolRegistry map[string]reflect.Type

type Handler func(u Uri) error

func init() {
	protocolRegistry = make(map[string]reflect.Type, 4)
	protocolRegistry["local"] = reflect.TypeOf((*UriLocal)(nil)).Elem()
}

type Uri interface {
	Scheme() string
	Host() string
	Path() string
	Uri() string
	Abs() string
	Parent() Uri

	Create(bool, os.FileMode) error
	OpenRead() (io.ReadCloser, error)
	OpenWrite() (io.WriteCloser, error)
	Remove() error
	Walk(Handler) error

	IsDir() bool
	Exist() bool

	Mode() os.FileMode
	ModTime() time.Time

	setHost(h string)
	setPath(p string)
	setScheme(s string)
}

func Parse(u string) (Uri, error) {
	urlp, err := url.Parse(u)
	if err != nil {
		return nil, ParseError{u, err.Error()}
	}

	UriType, exist := protocolRegistry[urlp.Scheme]
	if !exist {
		return nil, ProtocolError{urlp.Scheme, "protocol not supported."}
	}

	UriVal := reflect.New(UriType)
	i := UriVal.Interface()
	Urip, ok := i.(Uri)
	if !ok {
		return nil, ProtocolError{urlp.Scheme, "protocol not fully supported."}
	}
	Urip.setScheme(urlp.Scheme)
	Urip.setHost(urlp.Host)
	Urip.setPath(urlp.Path)

	return Urip, nil

}

type UriLocal struct {
	scheme string
	path   string
	host   string
}

func (u *UriLocal) Host() string {
	return u.host

}

func (u *UriLocal) Uri() string {
	return u.scheme + "://" + u.host + u.path
}

func (u *UriLocal) Abs() string {
	return u.host + u.path
}

func (u *UriLocal) Scheme() string {
	return u.scheme
}

func (u *UriLocal) Mode() os.FileMode {
	fi, err := os.Stat(u.host + u.path)
	if err != nil {
		return os.ModePerm
	}
	return fi.Mode()
}

func (u *UriLocal) Exist() bool {
	FullPath := u.host + u.path

	fi, _ := os.Stat(FullPath)
	if fi != nil {
		return true
	}
	return false
}

func (u *UriLocal) ModTime() time.Time {
	fi, err := os.Stat(u.host + u.path)
	if err != nil {
		return time.Now()
	}
	return fi.ModTime()
}

func (u *UriLocal) Create(IsDir bool, m os.FileMode) (err error) {

	if u.Exist() {
		return nil
	}

	if IsDir {
		err = os.Mkdir(u.Abs(), m)
		if err != nil {
			return
		}
	} else {
		var fd *os.File
		fd, err = os.OpenFile(u.Abs(), os.O_CREATE, m)
		defer fd.Close()
		if err != nil {
			return
		}
	}
	return nil
}

func (u *UriLocal) OpenRead() (io.ReadCloser, error) {
	if u.IsDir() {
		return nil, OpenError{u.Uri(), "is a directory."}
	}
	AbsPath := u.host + u.path

	if !filepath.IsAbs(AbsPath) {
		return nil, OpenError{u.Uri(), "is not an absolute path."}
	}
	return os.OpenFile(AbsPath, os.O_RDONLY, u.Mode())

}
func (u *UriLocal) OpenWrite() (io.WriteCloser, error) {
	if u.IsDir() {
		return nil, OpenError{u.Uri(), "is a directory."}
	}
	AbsPath := u.host + u.path

	if !filepath.IsAbs(AbsPath) {
		return nil, OpenError{u.Uri(), "is not an absolute path."}
	}

	return os.OpenFile(AbsPath, os.O_WRONLY, u.Mode())

}

func (u *UriLocal) Remove() error {
	return os.Remove(u.host + u.path)
}

func (u *UriLocal) Walk(h Handler) error {
	return nil
}

func (u *UriLocal) Path() string {
	return u.path
}

func (u *UriLocal) Parent() Uri {
	return nil
}

func (u *UriLocal) IsDir() bool {
	return false
}

func (u *UriLocal) setHost(h string) {
	u.host = h
}
func (u *UriLocal) setPath(p string) {
	u.path = p
}
func (u *UriLocal) setScheme(s string) {
	u.scheme = s
}

type ParseError struct {
	Uri     string
	Message string
}

func (e ParseError) Error() string {
	return "Error parsing " + e.Uri + " on " + runtime.GOOS + ": " + e.Message
}

type ProtocolError struct {
	Protocol string
	Message  string
}

func (e ProtocolError) Error() string {
	return "When handling protocol " + e.Protocol + ": " + e.Message
}

type OpenError struct {
	Uri     string
	Message string
}

func (e OpenError) Error() string {
	return "Open " + e.Uri + "error: " + e.Message
}
<commit_msg>Update and learn git.<commit_after>package uri

import (
	"io"
	"net/url"
	"os"
	"path/filepath"
	"reflect"
	"runtime"
	"time"
)

var protocolRegistry map[string]reflect.Type

type Handler func(u Uri) error

func init() {
	protocolRegistry = make(map[string]reflect.Type, 4)
	protocolRegistry["local"] = reflect.TypeOf((*UriLocal)(nil)).Elem()
}

type Uri interface {
	Scheme() string
	Host() string
	Path() string
	Uri() string
	Abs() string
	Parent() Uri

	Create(bool, os.FileMode) error
	OpenRead() (io.ReadCloser, error)
	OpenWrite() (io.WriteCloser, error)
	Remove() error
	Walk(Handler) error

	IsDir() bool
	Exist() bool

	Mode() os.FileMode
	ModTime() time.Time

	setHost(h string)
	setPath(p string)
	setScheme(s string)
}

func Parse(u string) (Uri, error) {
	urlp, err := url.Parse(u)
	if err != nil {
		return nil, ParseError{u, err.Error()}
	}

	UriType, exist := protocolRegistry[urlp.Scheme]
	if !exist {
		return nil, ProtocolError{urlp.Scheme, "protocol not supported."}
	}

	UriVal := reflect.New(UriType)
	i := UriVal.Interface()
	Urip, ok := i.(Uri)
	if !ok {
		return nil, ProtocolError{urlp.Scheme, "protocol not fully supported."}
	}
	Urip.setScheme(urlp.Scheme)
	Urip.setHost(urlp.Host)
	Urip.setPath(urlp.Path)

	return Urip, nil

}

type UriLocal struct {
	scheme string
	path   string
	host   string
}

func (u *UriLocal) Host() string {
	return u.host

}

func (u *UriLocal) Uri() string {
	return u.scheme + "://" + u.host + u.path
}

func (u *UriLocal) Abs() string {
	return u.host + u.path
}

func (u *UriLocal) Scheme() string {
	return u.scheme
}

func (u *UriLocal) Mode() os.FileMode {
	fi, err := os.Stat(u.host + u.path)
	if err != nil {
		return os.ModePerm
	}
	return fi.Mode()
}

func (u *UriLocal) Exist() bool {
	fi, _ := os.Stat(u.Abs())
	if fi != nil {
		return true
	}
	return false
}

func (u *UriLocal) ModTime() time.Time {
	fi, err := os.Stat(u.host + u.path)
	if err != nil {
		return time.Now()
	}
	return fi.ModTime()
}

func (u *UriLocal) Create(IsDir bool, m os.FileMode) (err error) {

	if u.Exist() {
		return nil
	}

	if IsDir {
		err = os.Mkdir(u.Abs(), m)
		if err != nil {
			return
		}
	} else {
		var fd *os.File
		fd, err = os.OpenFile(u.Abs(), os.O_CREATE, m)
		defer fd.Close()
		if err != nil {
			return
		}
	}
	return nil
}

func (u *UriLocal) OpenRead() (io.ReadCloser, error) {
	if u.IsDir() {
		return nil, OpenError{u.Uri(), "is a directory."}
	}
	AbsPath := u.host + u.path

	if !filepath.IsAbs(AbsPath) {
		return nil, OpenError{u.Uri(), "is not an absolute path."}
	}
	return os.OpenFile(AbsPath, os.O_RDONLY, u.Mode())

}
func (u *UriLocal) OpenWrite() (io.WriteCloser, error) {
	if u.IsDir() {
		return nil, OpenError{u.Uri(), "is a directory."}
	}
	AbsPath := u.Abs()

	if !filepath.IsAbs(AbsPath) {
		return nil, OpenError{u.Uri(), "is not an absolute path."}
	}

	return os.OpenFile(AbsPath, os.O_WRONLY, u.Mode())

}

func (u *UriLocal) Remove() error {
	return os.Remove(u.host + u.path)
}

func (u *UriLocal) Walk(h Handler) error {
	return nil
}

func (u *UriLocal) Path() string {
	return u.path
}

func (u *UriLocal) Parent() Uri {
	return nil
}

func (u *UriLocal) IsDir() bool {
	return false
}

func (u *UriLocal) setHost(h string) {
	u.host = h
}
func (u *UriLocal) setPath(p string) {
	u.path = p
}
func (u *UriLocal) setScheme(s string) {
	u.scheme = s
}

type ParseError struct {
	Uri     string
	Message string
}

func (e ParseError) Error() string {
	return "Error parsing " + e.Uri + " on " + runtime.GOOS + ": " + e.Message
}

type ProtocolError struct {
	Protocol string
	Message  string
}

func (e ProtocolError) Error() string {
	return "When handling protocol " + e.Protocol + ": " + e.Message
}

type OpenError struct {
	Uri     string
	Message string
}

func (e OpenError) Error() string {
	return "Open " + e.Uri + "error: " + e.Message
}
<|endoftext|>


<commit_before>// This file is part of Ringot.
/*
Copyright 2016 tSU-RooT <tsu.root@gmail.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"errors"
	"github.com/ChimeraCoder/anaconda"
	"github.com/mattn/go-runewidth"
	"github.com/nsf/termbox-go"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"sync/atomic"
	"unicode/utf8"
)

func byteSliceRemove(bytes []byte, from int, to int) []byte {
	copy(bytes[from:], bytes[to:])
	return bytes[:len(bytes)+from-to]
}

func byteSliceInsert(dst []byte, src []byte, pos int) []byte {
	length := len(dst) + len(src)
	if cap(dst) < length {
		s := make([]byte, len(dst), length)
		copy(s, dst)
		dst = s
	}
	dst = dst[:length]
	copy(dst[pos+len(src):], dst[pos:])
	copy(dst[pos:], src)
	return dst

}

func centeringStr(str string, width int) string {
	sub := width - len(str)
	if sub <= 0 {
		return str
	}
	val := ""
	if sub%2 == 0 {
		for i := 0; i < (sub / 2); i++ {
			val += " "
		}
	} else {
		for i := 0; i < (sub/2)+1; i++ {
			val += " "
		}
	}
	val += str

	for i := 0; i < (sub / 2); i++ {
		val += " "
	}
	return val
}

func drawText(str string, x int, y int, fg termbox.Attribute, bg termbox.Attribute) {
	i := 0
	for _, c := range str {
		termbox.SetCell(x+i, y, c, fg, bg)
		i += runewidth.RuneWidth(c)
	}
}

func drawTextWithAutoNotice(str string, x int, y int, fg termbox.Attribute, bg termbox.Attribute) {
	pos := 0
	foreColor := fg
	backColor := bg
	fgChanging := false
	bgChanging := false
	t := []byte(str)
	for {
		if len(t) == 0 {
			break
		}
		c, s := utf8.DecodeRune(t)
		if !(bgChanging || fgChanging) && len(t) > s {
			if c == '@' {
				tc, _ := utf8.DecodeRune(t[s:])
				if isScreenNameUsable(tc) {
					backColor = ColorLowlight
					bgChanging = true
				}
			} else {
				found := false
				s2 := 0
				if c == ' ' {
					var tc rune
					tc, s2 = utf8.DecodeRune(t[s:])
					if tc == '#' {
						found = true
					}
				} else if c == '#' && pos == 0 {
					found = true
				}
				if found {
					tc, _ := utf8.DecodeRune(t[s+s2:])
					if tc != ' ' {
						foreColor = ColorBlue
						fgChanging = true
					}
				}
			}
		} else {
			if bgChanging && !isScreenNameUsable(c) {
				backColor = bg
				bgChanging = false
			} else if fgChanging && c == ' ' {
				tc, _ := utf8.DecodeRune(t[s:])
				if tc != '#' {
					foreColor = fg
					fgChanging = false
				}
			}
		}

		termbox.SetCell(x+pos, y, c, foreColor, backColor)
		pos += runewidth.RuneWidth(c)
		t = t[s:]
	}
}

func isScreenNameUsable(r rune) bool {
	if r >= 'a' && r <= 'z' {
		return true
	} else if r >= 'A' && r <= 'Z' {
		return true
	} else if r >= '0' && r <= '9' {
		return true
	} else if r == '_' {
		return true
	}
	return false
}

func fillLine(offset int, y int, bg termbox.Attribute) {
	width, _ := getTermSize()
	x := offset
	for {
		if x >= width {
			break
		}
		termbox.SetCell(x, y, ' ', ColorBackground, bg)
		x++
	}
}

func generateLabelColorByUserID(id int64) termbox.Attribute {
	if val, ok := LabelColorMap[id]; ok {
		return LabelColors[val]
	}

	rand.Seed(id)
	val := rand.Intn(len(LabelColors))
	LabelColorMap[id] = val
	return LabelColors[val]
}

var (
	replacer = strings.NewReplacer(
		"&", "&",
		"<", "<",
		">", ">")
)

func wrapTweets(tweets []anaconda.Tweet) []tweetstatus {
	result := make([]tweetstatus, len(tweets))
	for i := 0; i < len(tweets); i++ {
		tweet := &tweets[i]
		for {
			if tweet.RetweetedStatus != nil {
				tweet = tweet.RetweetedStatus
			} else {
				break
			}
		}
		tweet.Text = replacer.Replace(tweet.Text)
		for _, url := range tweet.Entities.Urls {
			tweet.Text = strings.Replace(tweet.Text, url.Url, url.Display_url, -1)
		}
		for _, media := range tweet.ExtendedEntities.Media {
			tweet.Text = strings.Replace(tweet.Text, media.Url, media.Display_url, -1)
		}
		result[i] = tweetstatus{Content: &tweets[i]}
	}
	return result
}

func wrapTweet(t *anaconda.Tweet) tweetstatus {
	tweet := t
	for {
		if tweet.RetweetedStatus != nil {
			tweet = tweet.RetweetedStatus
		} else {
			break
		}
	}
	tweet.Text = replacer.Replace(tweet.Text)
	for _, url := range tweet.Entities.Urls {
		tweet.Text = strings.Replace(tweet.Text, url.Url, url.Display_url, -1)
	}
	for _, media := range tweet.ExtendedEntities.Media {
		tweet.Text = strings.Replace(tweet.Text, media.Url, media.Display_url, -1)
	}
	return tweetstatus{Content: t}
}

func sumTweetLines(tweetsStatusSlice []tweetstatus) int {
	sum := 0
	tweets := tweetsStatusSlice
	for _, t := range tweets {
		sum += t.countLines()
	}
	return sum
}

func openCommand(path string) {
	var commandName string
	switch runtime.GOOS {
	case "linux":
		commandName = "xdg-open"
	case "darwin":
		commandName = "open"
	default:
		return

	}
	exec.Command(commandName, path).Run()
}

const (
	tempDir = "ringot"
)

func downloadMedia(url string) (fullpath string, err error) {
	_, filename := path.Split(url)
	fullpath = filepath.Join(os.TempDir(), tempDir, filename)
	if _, err := os.Stat(fullpath); err == nil {
		return "", os.ErrExist
	}

	res, err := http.Get(url)
	if err != nil {
		return "", err
	}
	if res.StatusCode != 200 {
		return "", errors.New(res.Status)
	}
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	tempdir := filepath.Join(os.TempDir(), tempDir)
	if _, err := os.Stat(tempdir); err != nil {
		err := os.Mkdir(tempdir, 0775)
		if err != nil {
			return "", err
		}
	}
	file, err := os.OpenFile(fullpath, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0664)
	if err != nil {
		return "", err
	}
	defer file.Close()
	file.Write(body)
	return fullpath, nil
}

func openMedia(url string) {
	defer func() {
		if err := recover(); err != nil {
			changeBufferState("Media Download Err")
		}
	}()
	fullpath, err := downloadMedia(url)
	if err != nil && err != os.ErrExist {
		panic(err)
	}
	openCommand(fullpath)
}

func favoriteTweet(id int64) {
	_, err := api.Favorite(id)
	if err != nil {
		changeBufferState("Err:Favorite")
		return
	}
}

func unfavoriteTweet(id int64) {
	_, err := api.Unfavorite(id)
	if err != nil {
		changeBufferState("Err:Unfavorite")
		return
	}
}

func retweet(id int64) {
	_, err := api.Retweet(id, false)
	if err != nil {
		changeBufferState("Err:Retweet")
		return
	}
}

func changeBufferState(state string) {
	go func() { stateCh <- state }()
}

func getTermSize() (int, int) {
	return termWidth, termHeight
}

func setTermSize(w, h int) {
	termWidth, termHeight = w, h
}

type lock struct {
	mutex   sync.Mutex
	locking uint32
}

// Errors
var (
	ErrAlreayLocking = errors.New("already locking")
)

func (l *lock) lock() error {
	if atomic.LoadUint32(&l.locking) == 1 {
		return ErrAlreayLocking
	}
	l.mutex.Lock()
	defer l.mutex.Unlock()
	if l.locking == 0 {
		atomic.StoreUint32(&l.locking, 1)
	}
	return nil
}

func (l *lock) unlock() {
	l.mutex.Lock()
	defer l.mutex.Unlock()
	if l.locking == 1 {
		atomic.StoreUint32(&l.locking, 0)
	}
}

func (l *lock) isLocking() bool {
	l.mutex.Lock()
	defer l.mutex.Unlock()
	return atomic.LoadUint32(&l.locking) == 1
}
<commit_msg>Fix download media handling<commit_after>// This file is part of Ringot.
/*
Copyright 2016 tSU-RooT <tsu.root@gmail.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"errors"
	"github.com/ChimeraCoder/anaconda"
	"github.com/mattn/go-runewidth"
	"github.com/nsf/termbox-go"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"sync/atomic"
	"unicode/utf8"
)

func byteSliceRemove(bytes []byte, from int, to int) []byte {
	copy(bytes[from:], bytes[to:])
	return bytes[:len(bytes)+from-to]
}

func byteSliceInsert(dst []byte, src []byte, pos int) []byte {
	length := len(dst) + len(src)
	if cap(dst) < length {
		s := make([]byte, len(dst), length)
		copy(s, dst)
		dst = s
	}
	dst = dst[:length]
	copy(dst[pos+len(src):], dst[pos:])
	copy(dst[pos:], src)
	return dst

}

func centeringStr(str string, width int) string {
	sub := width - len(str)
	if sub <= 0 {
		return str
	}
	val := ""
	if sub%2 == 0 {
		for i := 0; i < (sub / 2); i++ {
			val += " "
		}
	} else {
		for i := 0; i < (sub/2)+1; i++ {
			val += " "
		}
	}
	val += str

	for i := 0; i < (sub / 2); i++ {
		val += " "
	}
	return val
}

func drawText(str string, x int, y int, fg termbox.Attribute, bg termbox.Attribute) {
	i := 0
	for _, c := range str {
		termbox.SetCell(x+i, y, c, fg, bg)
		i += runewidth.RuneWidth(c)
	}
}

func drawTextWithAutoNotice(str string, x int, y int, fg termbox.Attribute, bg termbox.Attribute) {
	pos := 0
	foreColor := fg
	backColor := bg
	fgChanging := false
	bgChanging := false
	t := []byte(str)
	for {
		if len(t) == 0 {
			break
		}
		c, s := utf8.DecodeRune(t)
		if !(bgChanging || fgChanging) && len(t) > s {
			if c == '@' {
				tc, _ := utf8.DecodeRune(t[s:])
				if isScreenNameUsable(tc) {
					backColor = ColorLowlight
					bgChanging = true
				}
			} else {
				found := false
				s2 := 0
				if c == ' ' {
					var tc rune
					tc, s2 = utf8.DecodeRune(t[s:])
					if tc == '#' {
						found = true
					}
				} else if c == '#' && pos == 0 {
					found = true
				}
				if found {
					tc, _ := utf8.DecodeRune(t[s+s2:])
					if tc != ' ' {
						foreColor = ColorBlue
						fgChanging = true
					}
				}
			}
		} else {
			if bgChanging && !isScreenNameUsable(c) {
				backColor = bg
				bgChanging = false
			} else if fgChanging && c == ' ' {
				tc, _ := utf8.DecodeRune(t[s:])
				if tc != '#' {
					foreColor = fg
					fgChanging = false
				}
			}
		}

		termbox.SetCell(x+pos, y, c, foreColor, backColor)
		pos += runewidth.RuneWidth(c)
		t = t[s:]
	}
}

func isScreenNameUsable(r rune) bool {
	if r >= 'a' && r <= 'z' {
		return true
	} else if r >= 'A' && r <= 'Z' {
		return true
	} else if r >= '0' && r <= '9' {
		return true
	} else if r == '_' {
		return true
	}
	return false
}

func fillLine(offset int, y int, bg termbox.Attribute) {
	width, _ := getTermSize()
	x := offset
	for {
		if x >= width {
			break
		}
		termbox.SetCell(x, y, ' ', ColorBackground, bg)
		x++
	}
}

func generateLabelColorByUserID(id int64) termbox.Attribute {
	if val, ok := LabelColorMap[id]; ok {
		return LabelColors[val]
	}

	rand.Seed(id)
	val := rand.Intn(len(LabelColors))
	LabelColorMap[id] = val
	return LabelColors[val]
}

var (
	replacer = strings.NewReplacer(
		"&", "&",
		"<", "<",
		">", ">")
)

func wrapTweets(tweets []anaconda.Tweet) []tweetstatus {
	result := make([]tweetstatus, len(tweets))
	for i := 0; i < len(tweets); i++ {
		tweet := &tweets[i]
		for {
			if tweet.RetweetedStatus != nil {
				tweet = tweet.RetweetedStatus
			} else {
				break
			}
		}
		tweet.Text = replacer.Replace(tweet.Text)
		for _, url := range tweet.Entities.Urls {
			tweet.Text = strings.Replace(tweet.Text, url.Url, url.Display_url, -1)
		}
		for _, media := range tweet.ExtendedEntities.Media {
			tweet.Text = strings.Replace(tweet.Text, media.Url, media.Display_url, -1)
		}
		result[i] = tweetstatus{Content: &tweets[i]}
	}
	return result
}

func wrapTweet(t *anaconda.Tweet) tweetstatus {
	tweet := t
	for {
		if tweet.RetweetedStatus != nil {
			tweet = tweet.RetweetedStatus
		} else {
			break
		}
	}
	tweet.Text = replacer.Replace(tweet.Text)
	for _, url := range tweet.Entities.Urls {
		tweet.Text = strings.Replace(tweet.Text, url.Url, url.Display_url, -1)
	}
	for _, media := range tweet.ExtendedEntities.Media {
		tweet.Text = strings.Replace(tweet.Text, media.Url, media.Display_url, -1)
	}
	return tweetstatus{Content: t}
}

func sumTweetLines(tweetsStatusSlice []tweetstatus) int {
	sum := 0
	tweets := tweetsStatusSlice
	for _, t := range tweets {
		sum += t.countLines()
	}
	return sum
}

func openCommand(path string) {
	var commandName string
	switch runtime.GOOS {
	case "linux":
		commandName = "xdg-open"
	case "darwin":
		commandName = "open"
	default:
		return

	}
	exec.Command(commandName, path).Run()
}

const (
	tempDir = "ringot"
)

func downloadMedia(url string) (fullpath string, err error) {
	_, filename := path.Split(url)
	fullpath = filepath.Join(os.TempDir(), tempDir, filename)
	if _, err := os.Stat(fullpath); err == nil {
		return fullpath, os.ErrExist
	}

	res, err := http.Get(url)
	if err != nil {
		return "", err
	}
	if res.StatusCode != 200 {
		return "", errors.New(res.Status)
	}
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	tempdir := filepath.Join(os.TempDir(), tempDir)
	if _, err := os.Stat(tempdir); err != nil {
		err := os.Mkdir(tempdir, 0775)
		if err != nil {
			return "", err
		}
	}
	file, err := os.OpenFile(fullpath, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0664)
	if err != nil {
		return "", err
	}
	defer file.Close()
	file.Write(body)
	return fullpath, nil
}

func openMedia(url string) {
	defer func() {
		if err := recover(); err != nil {
			changeBufferState("Media Download Err")
		}
	}()
	fullpath, err := downloadMedia(url)
	if err != nil && err != os.ErrExist {
		panic(err)
	}
	openCommand(fullpath)
}

func favoriteTweet(id int64) {
	_, err := api.Favorite(id)
	if err != nil {
		changeBufferState("Err:Favorite")
		return
	}
}

func unfavoriteTweet(id int64) {
	_, err := api.Unfavorite(id)
	if err != nil {
		changeBufferState("Err:Unfavorite")
		return
	}
}

func retweet(id int64) {
	_, err := api.Retweet(id, false)
	if err != nil {
		changeBufferState("Err:Retweet")
		return
	}
}

func changeBufferState(state string) {
	go func() { stateCh <- state }()
}

func getTermSize() (int, int) {
	return termWidth, termHeight
}

func setTermSize(w, h int) {
	termWidth, termHeight = w, h
}

type lock struct {
	mutex   sync.Mutex
	locking uint32
}

// Errors
var (
	ErrAlreayLocking = errors.New("already locking")
)

func (l *lock) lock() error {
	if atomic.LoadUint32(&l.locking) == 1 {
		return ErrAlreayLocking
	}
	l.mutex.Lock()
	defer l.mutex.Unlock()
	if l.locking == 0 {
		atomic.StoreUint32(&l.locking, 1)
	}
	return nil
}

func (l *lock) unlock() {
	l.mutex.Lock()
	defer l.mutex.Unlock()
	if l.locking == 1 {
		atomic.StoreUint32(&l.locking, 0)
	}
}

func (l *lock) isLocking() bool {
	l.mutex.Lock()
	defer l.mutex.Unlock()
	return atomic.LoadUint32(&l.locking) == 1
}
<|endoftext|>


<commit_before>// Licensed to The Moov Authors under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. The Moov Authors licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

package ach

// Version Number
const Version = "v1.2.0-rc1"
<commit_msg>release v1.2.0-rc2<commit_after>// Licensed to The Moov Authors under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. The Moov Authors licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

package ach

// Version Number
const Version = "v1.2.0-rc2"
<|endoftext|>


<commit_before><commit_msg>version.go: version bump<commit_after>package main

func getVersion() string {
	return "heads/master-0-gc024c28"
}
<|endoftext|>


<commit_before>package gf

const VERSION = "v1.15.6"
const AUTHORS = "john<john@goframe.org>"
<commit_msg>version updates<commit_after>package gf

const VERSION = "v1.15.7"
const AUTHORS = "john<john@goframe.org>"
<|endoftext|>


<commit_before>// Copyright 2018 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package web

import (
	"runtime"
	"strings"

	"github.com/issue9/version"
)

const (
	// Version 当前框架的版本
	Version = "0.14.0+20180527"

	// MinimumGoVersion 需求的最低 Go 版本
	// 修改此值，记得同时修改 .travis.yml 文件中的版本依赖。
	MinimumGoVersion = "1.10"
)

// 作最低版本检测
func init() {
	checkVersion(runtime.Version())
}

func checkVersion(goversion string) {
	goversion = strings.TrimPrefix(goversion, "go")

	// tip 版本，不作检测
	if strings.HasPrefix(goversion, "devel ") {
		return
	}

	v, err := version.SemVerCompare(goversion, MinimumGoVersion)
	if err != nil {
		panic(err)
	}

	if v < 0 {
		panic("低于最小版本需求")
	}
}
<commit_msg>可以根据用户的 Accept 和 Accept-Charset 来确定返回的数据类型，而不是限定在特定的编码上<commit_after>// Copyright 2018 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package web

import (
	"runtime"
	"strings"

	"github.com/issue9/version"
)

const (
	// Version 当前框架的版本
	Version = "0.15.0+20180605"

	// MinimumGoVersion 需求的最低 Go 版本
	// 修改此值，记得同时修改 .travis.yml 文件中的版本依赖。
	MinimumGoVersion = "1.10"
)

// 作最低版本检测
func init() {
	checkVersion(runtime.Version())
}

func checkVersion(goversion string) {
	goversion = strings.TrimPrefix(goversion, "go")

	// tip 版本，不作检测
	if strings.HasPrefix(goversion, "devel ") {
		return
	}

	v, err := version.SemVerCompare(goversion, MinimumGoVersion)
	if err != nil {
		panic(err)
	}

	if v < 0 {
		panic("低于最小版本需求")
	}
}
<|endoftext|>


<commit_before>package revealgo

var Version string = "v1.2.0"
<commit_msg>update version<commit_after>package revealgo

var Version string = "v1.2.2"
<|endoftext|>


<commit_before>package main

// Name of Package
const Name string = "mox"

// Version of Package
const Version string = "0.2.1"
<commit_msg>bump version to 0.2.2<commit_after>package main

// Name of Package
const Name string = "mox"

// Version of Package
const Version string = "0.2.2"
<|endoftext|>


<commit_before>// (c) Copyright IBM Corp. 2021
// (c) Copyright Instana Inc. 2021

package instana

// Version is the version of Instana sensor
const Version = "1.29.0"
<commit_msg>Bump version to v1.30.0<commit_after>// (c) Copyright IBM Corp. 2021
// (c) Copyright Instana Inc. 2021

package instana

// Version is the version of Instana sensor
const Version = "1.30.0"
<|endoftext|>


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

package grpc

// Version is the current grpc version.
const Version = "1.45.0-dev"
<commit_msg>Change version to 1.46.0-dev (#5204)<commit_after>/*
 *
 * Copyright 2018 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package grpc

// Version is the current grpc version.
const Version = "1.46.0-dev"
<|endoftext|>


<commit_before>package mailfull

// Version is a version number.
const Version = "v1.0.1"
<commit_msg>Bump version to v1.0.2<commit_after>package mailfull

// Version is a version number.
const Version = "v1.0.2"
<|endoftext|>


<commit_before>package sdk

const VERSION = "8.1.4"
<commit_msg>Incremented version to 8.1.5<commit_after>package sdk

const VERSION = "8.1.5"
<|endoftext|>


<commit_before>package db

import (
	turtle "github.com/gtfierro/hod/goraptor"
	"github.com/pkg/errors"
)

// make sure to call this after we've populated the entity and publickey databases
// via db.LoadDataset
// This function builds the graph structure inside another leveldb kv store
// This is done in several passes (which we can optimize later):
//
// First pass:
//  - loop through all the triples and add the entities to the graph kv
//  - during this, we:
//	  - make a small local cache of predicateBytes => uint32 hash
//    - allocate an entity for both the subject AND object of a triple and add those
//      if they are not already added.
//		Make sure to use the entity/pk databases to look up their hashes (db.GetHash)
// Second pass:
//  - fill in all of the edges in the graph
func (db *DB) buildGraph(dataset turtle.DataSet) error {
	var predicates = make(map[string][4]byte)
	var subjAdded = 0
	var objAdded = 0
	graphtx, err := db.graphDB.OpenTransaction()
	if err != nil {
		return errors.Wrap(err, "Could not open transaction on graph dataset")
	}
	// first pass
	for _, triple := range dataset.Triples {
		// populate predicate cache
		if _, found := predicates[triple.Predicate.String()]; !found {
			predHash, err := db.GetHash(triple.Predicate)
			if err != nil {
				return err
			}
			predicates[triple.Predicate.String()] = predHash
		}
		if reversePredicate, hasReverse := db.relationships[triple.Predicate]; hasReverse {
			if _, found := predicates[reversePredicate.String()]; !found {
				predHash, err := db.GetHash(reversePredicate)
				if err != nil {
					return err
				}
				predicates[reversePredicate.String()] = predHash
			}
		}

		// make subject entity
		subjHash, err := db.GetHash(triple.Subject)
		if err != nil {
			return err
		}
		// check if entity exists
		if exists, err := graphtx.Has(subjHash[:], nil); err == nil && !exists {
			// if not exists, create a new entity and insert it
			subjAdded += 1
			subEnt := NewEntity()
			subEnt.PK = subjHash
			bytes, err := subEnt.MarshalMsg(nil)
			if err != nil {
				return err
			}
			if err := graphtx.Put(subjHash[:], bytes, nil); err != nil {
				return err
			}
		} else if err != nil {
			return err
		}

		// make object entity
		objHash, err := db.GetHash(triple.Object)
		if err != nil {
			return err
		}
		// check if entity exists
		if exists, err := graphtx.Has(objHash[:], nil); err == nil && !exists {
			// if not exists, create a new entity and insert it
			objAdded += 1
			objEnt := NewEntity()
			objEnt.PK = objHash
			bytes, err := objEnt.MarshalMsg(nil)
			if err != nil {
				return err
			}
			if err := graphtx.Put(objHash[:], bytes, nil); err != nil {
				return err
			}
		} else if err != nil {
			return err
		}
	}
	if err := graphtx.Commit(); err != nil {
		return errors.Wrap(err, "Could not commit transaction")
	}

	log.Errorf("subjects %d, objects %d", subjAdded, objAdded)

	graphtx, err = db.graphDB.OpenTransaction()
	if err != nil {
		return errors.Wrap(err, "Could not open transaction on graph dataset")
	}

	// second pass
	for _, triple := range dataset.Triples {
		var (
			reAddSubject = false
			reAddObject  = false
		)
		subject, err := db.GetEntityTx(graphtx, triple.Subject)
		if err != nil {
			return err
		}
		object, err := db.GetEntityTx(graphtx, triple.Object)
		if err != nil {
			return err
		}

		// add the forward edge
		predHash := predicates[triple.Predicate.String()]
		reAddSubject = reAddSubject || subject.AddOutEdge(predHash, object.PK)
		reAddObject = reAddObject || object.AddInEdge(predHash, subject.PK)

		// find the inverse edge
		reverseEdge, hasReverseEdge := db.relationships[triple.Predicate]
		// if an inverse edge exists, then we add it to the object
		if hasReverseEdge {
			reverseEdgeHash := predicates[reverseEdge.String()]
			reAddObject = reAddObject || object.AddOutEdge(reverseEdgeHash, subject.PK)
			reAddSubject = reAddSubject || subject.AddInEdge(reverseEdgeHash, object.PK)
		}

		if reAddSubject {
			// re-put in graph
			bytes, err := subject.MarshalMsg(nil)
			if err != nil {
				return err
			}
			if err := graphtx.Put(subject.PK[:], bytes, nil); err != nil {
				return err
			}
		}

		if reAddObject {
			bytes, err := object.MarshalMsg(nil)
			if err != nil {
				return err
			}
			if err := graphtx.Put(object.PK[:], bytes, nil); err != nil {
				return err
			}
		}
	}
	if err = graphtx.Commit(); err != nil {
		return errors.Wrap(err, "Could not commit transaction")
	}

	return nil
}
<commit_msg>clearer print<commit_after>package db

import (
	turtle "github.com/gtfierro/hod/goraptor"
	"github.com/pkg/errors"
)

// make sure to call this after we've populated the entity and publickey databases
// via db.LoadDataset
// This function builds the graph structure inside another leveldb kv store
// This is done in several passes (which we can optimize later):
//
// First pass:
//  - loop through all the triples and add the entities to the graph kv
//  - during this, we:
//	  - make a small local cache of predicateBytes => uint32 hash
//    - allocate an entity for both the subject AND object of a triple and add those
//      if they are not already added.
//		Make sure to use the entity/pk databases to look up their hashes (db.GetHash)
// Second pass:
//  - fill in all of the edges in the graph
func (db *DB) buildGraph(dataset turtle.DataSet) error {
	var predicates = make(map[string][4]byte)
	var subjAdded = 0
	var objAdded = 0
	graphtx, err := db.graphDB.OpenTransaction()
	if err != nil {
		return errors.Wrap(err, "Could not open transaction on graph dataset")
	}
	// first pass
	for _, triple := range dataset.Triples {
		// populate predicate cache
		if _, found := predicates[triple.Predicate.String()]; !found {
			predHash, err := db.GetHash(triple.Predicate)
			if err != nil {
				return err
			}
			predicates[triple.Predicate.String()] = predHash
		}
		if reversePredicate, hasReverse := db.relationships[triple.Predicate]; hasReverse {
			if _, found := predicates[reversePredicate.String()]; !found {
				predHash, err := db.GetHash(reversePredicate)
				if err != nil {
					return err
				}
				predicates[reversePredicate.String()] = predHash
			}
		}

		// make subject entity
		subjHash, err := db.GetHash(triple.Subject)
		if err != nil {
			return err
		}
		// check if entity exists
		if exists, err := graphtx.Has(subjHash[:], nil); err == nil && !exists {
			// if not exists, create a new entity and insert it
			subjAdded += 1
			subEnt := NewEntity()
			subEnt.PK = subjHash
			bytes, err := subEnt.MarshalMsg(nil)
			if err != nil {
				return err
			}
			if err := graphtx.Put(subjHash[:], bytes, nil); err != nil {
				return err
			}
		} else if err != nil {
			return err
		}

		// make object entity
		objHash, err := db.GetHash(triple.Object)
		if err != nil {
			return err
		}
		// check if entity exists
		if exists, err := graphtx.Has(objHash[:], nil); err == nil && !exists {
			// if not exists, create a new entity and insert it
			objAdded += 1
			objEnt := NewEntity()
			objEnt.PK = objHash
			bytes, err := objEnt.MarshalMsg(nil)
			if err != nil {
				return err
			}
			if err := graphtx.Put(objHash[:], bytes, nil); err != nil {
				return err
			}
		} else if err != nil {
			return err
		}
	}
	if err := graphtx.Commit(); err != nil {
		return errors.Wrap(err, "Could not commit transaction")
	}

	log.Errorf("ADDED subjects %d, objects %d", subjAdded, objAdded)

	graphtx, err = db.graphDB.OpenTransaction()
	if err != nil {
		return errors.Wrap(err, "Could not open transaction on graph dataset")
	}

	// second pass
	for _, triple := range dataset.Triples {
		var (
			reAddSubject = false
			reAddObject  = false
		)
		subject, err := db.GetEntityTx(graphtx, triple.Subject)
		if err != nil {
			return err
		}
		object, err := db.GetEntityTx(graphtx, triple.Object)
		if err != nil {
			return err
		}

		// add the forward edge
		predHash := predicates[triple.Predicate.String()]
		reAddSubject = reAddSubject || subject.AddOutEdge(predHash, object.PK)
		reAddObject = reAddObject || object.AddInEdge(predHash, subject.PK)

		// find the inverse edge
		reverseEdge, hasReverseEdge := db.relationships[triple.Predicate]
		// if an inverse edge exists, then we add it to the object
		if hasReverseEdge {
			reverseEdgeHash := predicates[reverseEdge.String()]
			reAddObject = reAddObject || object.AddOutEdge(reverseEdgeHash, subject.PK)
			reAddSubject = reAddSubject || subject.AddInEdge(reverseEdgeHash, object.PK)
		}

		if reAddSubject {
			// re-put in graph
			bytes, err := subject.MarshalMsg(nil)
			if err != nil {
				return err
			}
			if err := graphtx.Put(subject.PK[:], bytes, nil); err != nil {
				return err
			}
		}

		if reAddObject {
			bytes, err := object.MarshalMsg(nil)
			if err != nil {
				return err
			}
			if err := graphtx.Put(object.PK[:], bytes, nil); err != nil {
				return err
			}
		}
	}
	if err = graphtx.Commit(); err != nil {
		return errors.Wrap(err, "Could not commit transaction")
	}

	return nil
}
<|endoftext|>


<commit_before>package db

import (
	"fmt"

	"github.com/boltdb/bolt"
)

const indiceBucket string = "indices"

// getLeagueIndexBucketRO returns the bucket corresponding
// to a specific league's index. This will never write
// and can be used safely with a readonly transaction.
//
// Will either panic or return a valid bucket.
func getLeagueIndexBucket(league LeagueHeapID, tx *bolt.Tx) *bolt.Bucket {
	// Grab league bucket
	leagueBucket := getLeagueBucket(league, tx)

	// This can never fail, its a guarantee that the itemStoreBucket was registered
	// and will always appear on a valid leagueBucket
	indices := leagueBucket.Bucket([]byte(indiceBucket))
	if indices == nil {
		panic(fmt.Sprintf("%s bucket not found when expected", itemStoreBucket))
	}

	return indices
}

// getItemModIndexBucket returns a bucket which a given mod can be put
// when considering the item containing it.
//
// This WILL write if a bucket is not found. Hence, readonly tx unsafe.
func getItemModIndexBucket(rootType, rootFlavor, mod StringHeapID,
	league LeagueHeapID, tx *bolt.Tx) (*bolt.Bucket, error) {
	// Keys towards the bucket we want to return, they may or may not exist
	keys := []StringHeapID{rootType, rootFlavor, mod}

	// Start at the index bucket
	currentBucket := getLeagueIndexBucket(league, tx)

	// Create all of the intervening keys
	for i, key := range keys {
		keyBytes := key.ToBytes()
		prevBucket := currentBucket.Bucket(keyBytes)
		if prevBucket == nil {
			// Create the bucket
			var err error
			if i == 0 {
				// fmt.Println("creating non-existent bucket!", keyBytes)
			}
			prevBucket, err = currentBucket.CreateBucket(keyBytes)
			if err != nil {
				return nil,
					fmt.Errorf("failed to add index intermediary bucket bucket, bucket=%s, chain=%v, err=%s",
						key, keys, err)
			}
		}
		currentBucket = prevBucket
	}

	// If we made it through, our currentBucket should be the one we want
	return currentBucket, nil
}

// getItemModIndexBucketRO returns a bucket which a given mod can be put
// when considering the item containing it.
//
// This WILL NOT write if a bucket is not found. Hence, readonly tx unsafe.
func getItemModIndexBucketRO(rootType, rootFlavor, mod StringHeapID,
	league LeagueHeapID, tx *bolt.Tx) (*bolt.Bucket, error) {
	// Keys towards the bucket we want to return, they may or may not exist
	keys := []StringHeapID{rootType, rootFlavor, mod}

	// Start at the index bucket
	currentBucket := getLeagueIndexBucket(league, tx)

	// Traverse all intervening buckets
	for _, key := range keys {
		keyBytes := key.ToBytes()
		prevBucket := currentBucket.Bucket(keyBytes)
		if prevBucket == nil {
			return nil, fmt.Errorf("invalid bucket, key=%d, chain=%v", key, keys)
		}
		currentBucket = prevBucket
	}

	// If we made it through, our currentBucket should be the one we want
	return currentBucket, nil
}

// ModIndexKeySuffixLength allows us to fetch variable numbers
// of pre-pended values given their length.
const ModIndexKeySuffixLength = TimestampSize + 2

// encodeModIndexKey generates a mod key based off of the provided data
//
// The mod index key is generated as [mod.Values..., now, updateSequence]
func encodeModIndexKey(mod ItemMod, now Timestamp, updateSequence uint16) []byte {
	// Generate the suffix
	suffix := make([]byte, 0)
	suffix = append(suffix, now[:]...)
	suffix = append(suffix, i16tob(updateSequence)...)

	if len(suffix) != ModIndexKeySuffixLength {
		panic(fmt.Sprintf("unexpected suffix length, got %d, expected %d",
			len(suffix), ModIndexKeySuffixLength))
	}

	// Fill in the index from the front
	//
	// TODO: avoid appends, pre-size the backing slice to accomodate the
	// contents including the header
	index := make([]byte, 0)
	for _, value := range mod.Values {
		index = append(index, i16tob(value)...)
	}

	// And return the index with its suffix
	return append(index, suffix...)
}

// decodeModIndexKey decodes a provided mod index key
//
// This returns the values encoded in the key.
//
// This is possible as the suffix is a fixed length and format while
// the values of the modifer are simple appended
func decodeModIndexKey(key []byte) ([]uint16, error) {

	// Basic sanity check
	if len(key) < ModIndexKeySuffixLength {
		return nil, fmt.Errorf("invalid index key passed, less than length of suffix")
	}

	// Ensure we are divisible by 2 following the removal of the suffix
	if (len(key)-ModIndexKeySuffixLength)%2 != 0 {
		return nil, fmt.Errorf("invalid index key passed, values malformed")
	}

	valueBytes := key[:len(key)-ModIndexKeySuffixLength]
	values := make([]uint16, len(valueBytes)/2)
	for index := 0; index*2 < len(valueBytes); index++ {
		values[index] = btoi16(valueBytes[index*2:])
	}

	return values, nil

}

// IndexItems adds tbe given items to their correct indices
// for efficient lookup. Returns number of index entries added.
//
// Provided items CAN differ in their league.
func IndexItems(items []Item, now Timestamp, tx *bolt.Tx) (int, error) {

	// Sanity check passed in transaction, better to do this than panic.
	if !tx.Writable() {
		return 0, fmt.Errorf("cannot IndexItems on readonly transaction")
	}

	// Silently exit when no items present to add
	if len(items) < 1 {
		return 0, nil
	}

	var added int

	for _, item := range items {

		for _, mod := range item.Mods {
			// Grab the bucket we can actually insert things into

			itemModBucket, err := getItemModIndexBucket(item.RootType, item.RootFlavor,
				mod.Mod, item.League, tx)
			if err != nil {
				return 0, fmt.Errorf("failed to get item mod bucket")
			}

			modKey := encodeModIndexKey(mod, now, item.UpdateSequence)

			itemModBucket.Put(modKey, item.ID[:])
			added++
		}
	}

	return added, nil

}

// LookupItems returns up to n item IDs where those items
// are of the given type and flavor while also containing
// the provided mod with a given minimum value
//
// Right now minModValue checks only against the first value
// if a mod contains multiple values, this can be an array
// in the future. We could even validate this by checking
// the mod StringHeapID to ensure it has the right number of
// placeholder signs.
// TODO: review using array for minModValue
func LookupItems(rootType, rootFlavor, mod StringHeapID,
	league LeagueHeapID,
	minModValue uint16,
	n int, db *bolt.DB) ([]ID, error) {

	// ids presized...
	ids := make([]ID, n)
	lastIDFound := 0

	err := db.View(func(tx *bolt.Tx) error {

		itemModBucket, err := getItemModIndexBucketRO(rootType, rootFlavor, mod, league, tx)
		if err != nil {
			return fmt.Errorf("faield to get item mod index bucket, err=%s", err)
		}

		// Grab a cursor
		c := itemModBucket.Cursor()

		// Iterate over items in reverse sorted key order. This starts
		// from the last key/value pair and updates the k/v variables to
		// the previous key/value on each iteration.
		//
		// The loop finishes at the beginning of the cursor when a nil key
		// is returned.
		for k, v := c.Last(); k != nil; k, v = c.Prev() {
			values, err := decodeModIndexKey(k)
			if err != nil {
				return fmt.Errorf("failed to decode item mod index key, key=%v, err=%s",
					k, err)
			}
			if len(values) == 0 {
				return fmt.Errorf("decoded item mod index key to no values, key=%v", k)
			}

			// Ensure the mod is the correct value
			if values[0] >= minModValue {
				if len(v) != IDSize {
					panic(fmt.Sprintf("malformed id value in index, incorrect length; id=%v", v))
				}
				var id ID
				copy(id[:], v)
				ids[lastIDFound] = id
				lastIDFound++
				// Check if we're done
				if lastIDFound >= n {
					return nil
				}
			}
		}

		return nil
	})

	// Truncate ids to however many we actually found
	ids = ids[:lastIDFound]

	return ids, err
}
<commit_msg>db correct buffer reuse issue in IndexItems<commit_after>package db

import (
	"fmt"

	"github.com/boltdb/bolt"
)

const indiceBucket string = "indices"

// getLeagueIndexBucketRO returns the bucket corresponding
// to a specific league's index. This will never write
// and can be used safely with a readonly transaction.
//
// Will either panic or return a valid bucket.
func getLeagueIndexBucket(league LeagueHeapID, tx *bolt.Tx) *bolt.Bucket {
	// Grab league bucket
	leagueBucket := getLeagueBucket(league, tx)

	// This can never fail, its a guarantee that the itemStoreBucket was registered
	// and will always appear on a valid leagueBucket
	indices := leagueBucket.Bucket([]byte(indiceBucket))
	if indices == nil {
		panic(fmt.Sprintf("%s bucket not found when expected", itemStoreBucket))
	}

	return indices
}

// getItemModIndexBucket returns a bucket which a given mod can be put
// when considering the item containing it.
//
// This WILL write if a bucket is not found. Hence, readonly tx unsafe.
func getItemModIndexBucket(rootType, rootFlavor, mod StringHeapID,
	league LeagueHeapID, tx *bolt.Tx) (*bolt.Bucket, error) {
	// Keys towards the bucket we want to return, they may or may not exist
	keys := []StringHeapID{rootType, rootFlavor, mod}

	// Start at the index bucket
	currentBucket := getLeagueIndexBucket(league, tx)

	// Create all of the intervening keys
	for i, key := range keys {
		keyBytes := key.ToBytes()
		prevBucket := currentBucket.Bucket(keyBytes)
		if prevBucket == nil {
			// Create the bucket
			var err error
			if i == 0 {
				// fmt.Println("creating non-existent bucket!", keyBytes)
			}
			prevBucket, err = currentBucket.CreateBucket(keyBytes)
			if err != nil {
				return nil,
					fmt.Errorf("failed to add index intermediary bucket bucket, bucket=%s, chain=%v, err=%s",
						key, keys, err)
			}
		}
		currentBucket = prevBucket
	}

	// If we made it through, our currentBucket should be the one we want
	return currentBucket, nil
}

// getItemModIndexBucketRO returns a bucket which a given mod can be put
// when considering the item containing it.
//
// This WILL NOT write if a bucket is not found. Hence, readonly tx unsafe.
func getItemModIndexBucketRO(rootType, rootFlavor, mod StringHeapID,
	league LeagueHeapID, tx *bolt.Tx) (*bolt.Bucket, error) {
	// Keys towards the bucket we want to return, they may or may not exist
	keys := []StringHeapID{rootType, rootFlavor, mod}

	// Start at the index bucket
	currentBucket := getLeagueIndexBucket(league, tx)

	// Traverse all intervening buckets
	for _, key := range keys {
		keyBytes := key.ToBytes()
		prevBucket := currentBucket.Bucket(keyBytes)
		if prevBucket == nil {
			return nil, fmt.Errorf("invalid bucket, key=%d, chain=%v", key, keys)
		}
		currentBucket = prevBucket
	}

	// If we made it through, our currentBucket should be the one we want
	return currentBucket, nil
}

// ModIndexKeySuffixLength allows us to fetch variable numbers
// of pre-pended values given their length.
const ModIndexKeySuffixLength = TimestampSize + 2

// encodeModIndexKey generates a mod key based off of the provided data
//
// The mod index key is generated as [mod.Values..., now, updateSequence]
func encodeModIndexKey(mod ItemMod, now Timestamp, updateSequence uint16) []byte {
	// Generate the suffix
	suffix := make([]byte, 0)
	suffix = append(suffix, now[:]...)
	suffix = append(suffix, i16tob(updateSequence)...)

	if len(suffix) != ModIndexKeySuffixLength {
		panic(fmt.Sprintf("unexpected suffix length, got %d, expected %d",
			len(suffix), ModIndexKeySuffixLength))
	}

	// Fill in the index from the front
	//
	// TODO: avoid appends, pre-size the backing slice to accomodate the
	// contents including the header
	index := make([]byte, 0)
	for _, value := range mod.Values {
		index = append(index, i16tob(value)...)
	}

	// And return the index with its suffix
	return append(index, suffix...)
}

// decodeModIndexKey decodes a provided mod index key
//
// This returns the values encoded in the key.
//
// This is possible as the suffix is a fixed length and format while
// the values of the modifer are simple appended
func decodeModIndexKey(key []byte) ([]uint16, error) {

	// Basic sanity check
	if len(key) < ModIndexKeySuffixLength {
		return nil, fmt.Errorf("invalid index key passed, less than length of suffix")
	}

	// Ensure we are divisible by 2 following the removal of the suffix
	if (len(key)-ModIndexKeySuffixLength)%2 != 0 {
		return nil, fmt.Errorf("invalid index key passed, values malformed")
	}

	valueBytes := key[:len(key)-ModIndexKeySuffixLength]
	values := make([]uint16, len(valueBytes)/2)
	for index := 0; index*2 < len(valueBytes); index++ {
		values[index] = btoi16(valueBytes[index*2:])
	}

	return values, nil

}

// IndexItems adds tbe given items to their correct indices
// for efficient lookup. Returns number of index entries added.
//
// Provided items CAN differ in their league.
func IndexItems(items []Item, now Timestamp, tx *bolt.Tx) (int, error) {

	// Sanity check passed in transaction, better to do this than panic.
	if !tx.Writable() {
		return 0, fmt.Errorf("cannot IndexItems on readonly transaction")
	}

	// Silently exit when no items present to add
	if len(items) < 1 {
		return 0, nil
	}

	var added int

	for _, item := range items {

		for _, mod := range item.Mods {
			// Grab the bucket we can actually insert things into

			itemModBucket, err := getItemModIndexBucket(item.RootType, item.RootFlavor,
				mod.Mod, item.League, tx)
			if err != nil {
				return 0, fmt.Errorf("failed to get item mod bucket")
			}

			modKey := encodeModIndexKey(mod, now, item.UpdateSequence)

			// We need to make a copy of the item ID or bolt
			// will get a buffer reused for all items.
			//
			// Without this, all index entries will point to the last
			// item added.
			idCopy := make([]byte, IDSize)
			copy(idCopy, item.ID[:])

			itemModBucket.Put(modKey, idCopy)
			fmt.Printf("inserting index with id %x", item.ID[:])
			added++
		}
	}

	return added, nil

}

// LookupItems returns up to n item IDs where those items
// are of the given type and flavor while also containing
// the provided mod with a given minimum value
//
// Right now minModValue checks only against the first value
// if a mod contains multiple values, this can be an array
// in the future. We could even validate this by checking
// the mod StringHeapID to ensure it has the right number of
// placeholder signs.
// TODO: review using array for minModValue
func LookupItems(rootType, rootFlavor, mod StringHeapID,
	league LeagueHeapID,
	minModValue uint16,
	n int, db *bolt.DB) ([]ID, error) {

	// ids presized...
	ids := make([]ID, n)
	lastIDFound := 0

	err := db.View(func(tx *bolt.Tx) error {

		itemModBucket, err := getItemModIndexBucketRO(rootType, rootFlavor, mod, league, tx)
		if err != nil {
			return fmt.Errorf("faield to get item mod index bucket, err=%s", err)
		}

		// Grab a cursor
		c := itemModBucket.Cursor()

		// Iterate over items in reverse sorted key order. This starts
		// from the last key/value pair and updates the k/v variables to
		// the previous key/value on each iteration.
		//
		// The loop finishes at the beginning of the cursor when a nil key
		// is returned.
		for k, v := c.Last(); k != nil; k, v = c.Prev() {
			values, err := decodeModIndexKey(k)
			if err != nil {
				return fmt.Errorf("failed to decode item mod index key, key=%v, err=%s",
					k, err)
			}
			if len(values) == 0 {
				return fmt.Errorf("decoded item mod index key to no values, key=%v", k)
			}

			// Ensure the mod is the correct value
			if values[0] >= minModValue {
				if len(v) != IDSize {
					panic(fmt.Sprintf("malformed id value in index, incorrect length; id=%v", v))
				}
				var id ID
				copy(id[:], v)
				ids[lastIDFound] = id
				lastIDFound++
				// Check if we're done
				if lastIDFound >= n {
					return nil
				}
			}
		}

		return nil
	})

	// Truncate ids to however many we actually found
	ids = ids[:lastIDFound]

	return ids, err
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"sync"

	"github.com/AdRoll/goamz/aws"
	"github.com/AdRoll/goamz/sqs"
	_ "github.com/lib/pq"
)

var SQS *sqs.SQS

func main() {
	n := runtime.NumCPU()
	log.Println("Num CPUS:", n)
	runtime.GOMAXPROCS(n)
	for k, v := range os.Args {
		log.Println(k, v)
	}
	log.Println("-----")
	if len(os.Args) > 1 {
		rawData := os.Args[1]

		var kpayload KinesisPayload
		err := json.Unmarshal([]byte(rawData), &kpayload)
		if err != nil {
			log.Println("Error Kinesisis Payload:", err)
		}
		for _, v := range kpayload.Records {
			log.Println("Record:", v)
			var tpm topicPageMessage
			sDec, errDec := base64.StdEncoding.DecodeString(v.Kinesis.Data)
			if errDec != nil {
				log.Println("Error:", errDec)
			} else {
				log.Println(string(sDec))
				errJSON := json.Unmarshal(sDec, &tpm)
				if errJSON != nil {
					log.Println("Error:", errJSON)
					return
				}
				arns := getDevicesArnsByTopicIDPage(tpm.TopicID, tpm.PageNum, 10000)
				//This should return the arn & the lang for the user
				//we'd then pull the correct iten out of the message map
				msgSlice := make([]sqs.Message, 0, 10)
				msgAll := [][]sqs.Message{}
				for _, v := range arns {
					tempData := fmt.Sprintf("arn:%v|%v", v, tpm.Message)
					msg := sqs.Message{Body: base64.StdEncoding.EncodeToString([]byte(tempData))}
					msgSlice = append(msgSlice, msg)
					if len(msgSlice) == 10 {
						msgAll = append(msgAll, msgSlice)
						msgSlice = []sqs.Message{}
					}
				}
				var wg sync.WaitGroup
				for _, s := range msgAll {
					s := s //It's idomatic go I swear! http://golang.org/doc/effective_go.html#channels
					wg.Add(1)
					go func(sl10 []sqs.Message) {
						proxySNS(sl10)
						defer wg.Done()
					}(s)

				}
				wg.Done()
				log.Println("All done!")
			}
		}
		return

	}
	log.Println("Error: os.Args was 1 length.")
}

func getDevicesArnsByTopicIDPage(topicID, pagenum, pagesize int) []string {
	var arns []string
	info := getDBSettings()
	db, errCon := sql.Open("postgres", fmt.Sprintf("host=%v user=%v password=%v dbname=%v sslmode=require", info.Host, info.Username, info.Password, info.Database))
	defer db.Close()
	if errCon != nil {
		log.Fatal(errCon)
	}
	rows, err := db.Query(`
		select
			u.endpointarn
		from
			subscription s ,userdevices u
		where
			s.topicid= $1 and
			s.userID=u.userid
			order by u.userid
			limit $2 offset $3
;`, topicID, pagesize, (pagenum-1)*pagesize)
	if err != nil {
		panic(err)
	}
	for rows.Next() {
		var arn string
		errScan := rows.Scan(&arn)
		if errScan != nil {
			panic(errScan)
		}
		arns = append(arns, arn)
	}
	return arns
}

type topicPageMessage struct {
	TopicID int    `json:"topic_id"`
	Message string `json:"message"`
	PageNum int    `json:"page_num"`
}

type KinesisPayload struct {
	Records []struct {
		AwsRegion         string `json:"awsRegion"`
		EventID           string `json:"eventID"`
		EventName         string `json:"eventName"`
		EventSource       string `json:"eventSource"`
		EventSourceARN    string `json:"eventSourceARN"`
		EventVersion      string `json:"eventVersion"`
		InvokeIdentityArn string `json:"invokeIdentityArn"`
		Kinesis           struct {
			Data                 string `json:"data"`
			KinesisSchemaVersion string `json:"kinesisSchemaVersion"`
			PartitionKey         string `json:"partitionKey"`
			SequenceNumber       string `json:"sequenceNumber"`
		} `json:"kinesis"`
	} `json:"Records"`
}

func getSettings() (string, string, error) {
	file, err := ioutil.ReadFile("./settings.json")
	if err != nil {
		return "", "", nil
	}
	settingsMap := make(map[string]string)
	json.Unmarshal(file, &settingsMap)
	return settingsMap["Access"], settingsMap["Secret"], nil
}

func getDBSettings() *dbInfo {
	file, err := ioutil.ReadFile("./settings.json")
	if err != nil {
		log.Println("Error:", err)
		return nil
	}
	db := dbInfo{}
	err2 := json.Unmarshal(file, &db)
	if err2 != nil {
		log.Println("Error:", err2)
		return nil
	}
	return &db
}

type dbInfo struct {
	Host     string
	Database string
	Username string
	Password string
}

func proxySNS(msgs []sqs.Message) {
	pub, sec, _ := getSettings()
	sqs, err := getQueue("sns-prox", pub, sec)
	if err != nil {
		panic(err)
	}
	_, respErr := sqs.SendMessageBatch(msgs)
	if respErr != nil {
		log.Println("ERROR:", respErr)
	}
}

func getQueue(name, public, secret string) (*sqs.Queue, error) {
	auth := aws.Auth{AccessKey: public, SecretKey: secret}
	region := aws.Region{}
	region.Name = "us-east-1"
	region.SQSEndpoint = "http://sqs.us-east-1.amazonaws.com"
	SQS = sqs.New(auth, region)
	if SQS == nil {
		return nil, fmt.Errorf("Can't get sqs reference for %v %v", auth, region)
	}
	return SQS.GetQueue(name)
}
<commit_msg>.Wait(), not .Done()....duh<commit_after>package main

import (
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"sync"

	"github.com/AdRoll/goamz/aws"
	"github.com/AdRoll/goamz/sqs"
	_ "github.com/lib/pq"
)

var SQS *sqs.SQS

func main() {
	n := runtime.NumCPU()
	log.Println("Num CPUS:", n)
	runtime.GOMAXPROCS(n)
	for k, v := range os.Args {
		log.Println(k, v)
	}
	log.Println("-----")
	if len(os.Args) > 1 {
		rawData := os.Args[1]

		var kpayload KinesisPayload
		err := json.Unmarshal([]byte(rawData), &kpayload)
		if err != nil {
			log.Println("Error Kinesisis Payload:", err)
		}
		for _, v := range kpayload.Records {
			log.Println("Record:", v)
			var tpm topicPageMessage
			sDec, errDec := base64.StdEncoding.DecodeString(v.Kinesis.Data)
			if errDec != nil {
				log.Println("Error:", errDec)
			} else {
				log.Println(string(sDec))
				errJSON := json.Unmarshal(sDec, &tpm)
				if errJSON != nil {
					log.Println("Error:", errJSON)
					return
				}
				arns := getDevicesArnsByTopicIDPage(tpm.TopicID, tpm.PageNum, 10000)
				//This should return the arn & the lang for the user
				//we'd then pull the correct iten out of the message map
				msgSlice := make([]sqs.Message, 0, 10)
				msgAll := [][]sqs.Message{}
				for _, v := range arns {
					tempData := fmt.Sprintf("arn:%v|%v", v, tpm.Message)
					msg := sqs.Message{Body: base64.StdEncoding.EncodeToString([]byte(tempData))}
					msgSlice = append(msgSlice, msg)
					if len(msgSlice) == 10 {
						msgAll = append(msgAll, msgSlice)
						msgSlice = []sqs.Message{}
					}
				}
				var wg sync.WaitGroup
				for _, s := range msgAll {
					s := s //It's idomatic go I swear! http://golang.org/doc/effective_go.html#channels
					wg.Add(1)
					go func(sl10 []sqs.Message) {
						proxySNS(sl10)
						defer wg.Done()
					}(s)

				}
				wg.Wait()
				log.Println("All done!")
			}
		}
		return

	}
	log.Println("Error: os.Args was 1 length.")
}

func getDevicesArnsByTopicIDPage(topicID, pagenum, pagesize int) []string {
	var arns []string
	info := getDBSettings()
	db, errCon := sql.Open("postgres", fmt.Sprintf("host=%v user=%v password=%v dbname=%v sslmode=require", info.Host, info.Username, info.Password, info.Database))
	defer db.Close()
	if errCon != nil {
		log.Fatal(errCon)
	}
	rows, err := db.Query(`
		select
			u.endpointarn
		from
			subscription s ,userdevices u
		where
			s.topicid= $1 and
			s.userID=u.userid
			order by u.userid
			limit $2 offset $3
;`, topicID, pagesize, (pagenum-1)*pagesize)
	if err != nil {
		panic(err)
	}
	for rows.Next() {
		var arn string
		errScan := rows.Scan(&arn)
		if errScan != nil {
			panic(errScan)
		}
		arns = append(arns, arn)
	}
	return arns
}

type topicPageMessage struct {
	TopicID int    `json:"topic_id"`
	Message string `json:"message"`
	PageNum int    `json:"page_num"`
}

type KinesisPayload struct {
	Records []struct {
		AwsRegion         string `json:"awsRegion"`
		EventID           string `json:"eventID"`
		EventName         string `json:"eventName"`
		EventSource       string `json:"eventSource"`
		EventSourceARN    string `json:"eventSourceARN"`
		EventVersion      string `json:"eventVersion"`
		InvokeIdentityArn string `json:"invokeIdentityArn"`
		Kinesis           struct {
			Data                 string `json:"data"`
			KinesisSchemaVersion string `json:"kinesisSchemaVersion"`
			PartitionKey         string `json:"partitionKey"`
			SequenceNumber       string `json:"sequenceNumber"`
		} `json:"kinesis"`
	} `json:"Records"`
}

func getSettings() (string, string, error) {
	file, err := ioutil.ReadFile("./settings.json")
	if err != nil {
		return "", "", nil
	}
	settingsMap := make(map[string]string)
	json.Unmarshal(file, &settingsMap)
	return settingsMap["Access"], settingsMap["Secret"], nil
}

func getDBSettings() *dbInfo {
	file, err := ioutil.ReadFile("./settings.json")
	if err != nil {
		log.Println("Error:", err)
		return nil
	}
	db := dbInfo{}
	err2 := json.Unmarshal(file, &db)
	if err2 != nil {
		log.Println("Error:", err2)
		return nil
	}
	return &db
}

type dbInfo struct {
	Host     string
	Database string
	Username string
	Password string
}

func proxySNS(msgs []sqs.Message) {
	pub, sec, _ := getSettings()
	sqs, err := getQueue("sns-prox", pub, sec)
	if err != nil {
		panic(err)
	}
	_, respErr := sqs.SendMessageBatch(msgs)
	if respErr != nil {
		log.Println("ERROR:", respErr)
	}
}

func getQueue(name, public, secret string) (*sqs.Queue, error) {
	auth := aws.Auth{AccessKey: public, SecretKey: secret}
	region := aws.Region{}
	region.Name = "us-east-1"
	region.SQSEndpoint = "http://sqs.us-east-1.amazonaws.com"
	SQS = sqs.New(auth, region)
	if SQS == nil {
		return nil, fmt.Errorf("Can't get sqs reference for %v %v", auth, region)
	}
	return SQS.GetQueue(name)
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"github.com/hoop33/limo/config"
	"github.com/hoop33/limo/model"
	"github.com/spf13/cobra"
)

// DeleteCmd renames a tag
var DeleteCmd = &cobra.Command{
	Use:     "delete <tag>",
	Aliases: []string{"rm"},
	Short:   "Delete a tag",
	Long:    "Delete the tag named <tag>.",
	Example: fmt.Sprintf("  %s delete frameworks", config.ProgramName),
	Run: func(cmd *cobra.Command, args []string) {
		output := getOutput()

		if len(args) == 0 {
			output.Fatal("You must specify a tag")
		}

		db, err := getDatabase()
		fatalOnError(err)

		tag, err := model.FindTagByName(db, args[0])
		fatalOnError(err)

		if tag == nil {
			output.Fatal(fmt.Sprintf("Tag '%s' not found", args[0]))
		}

		fatalOnError(tag.Delete(db))
	},
}

func init() {
	RootCmd.AddCommand(DeleteCmd)
}
<commit_msg>Show tag deletion message<commit_after>package cmd

import (
	"fmt"

	"github.com/hoop33/limo/config"
	"github.com/hoop33/limo/model"
	"github.com/spf13/cobra"
)

// DeleteCmd renames a tag
var DeleteCmd = &cobra.Command{
	Use:     "delete <tag>",
	Aliases: []string{"rm"},
	Short:   "Delete a tag",
	Long:    "Delete the tag named <tag>.",
	Example: fmt.Sprintf("  %s delete frameworks", config.ProgramName),
	Run: func(cmd *cobra.Command, args []string) {
		output := getOutput()

		if len(args) == 0 {
			output.Fatal("You must specify a tag")
		}

		db, err := getDatabase()
		fatalOnError(err)

		tag, err := model.FindTagByName(db, args[0])
		fatalOnError(err)

		if tag == nil {
			output.Fatal(fmt.Sprintf("Tag '%s' not found", args[0]))
		}

		fatalOnError(tag.Delete(db))

		output.Info(fmt.Sprintf("Deleted tag '%s'", tag.Name))
	},
}

func init() {
	RootCmd.AddCommand(DeleteCmd)
}
<|endoftext|>


<commit_before>// Copyright 2010 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.

package main

import (
	"bytes"
	"exec"
	"flag"
	"http"
	"io"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"strconv"
	"template"
)

var (
	httpListen = flag.String("http", "127.0.0.1:3999", "host:port to listen on")
	htmlOutput = flag.Bool("html", false, "render program output as HTML")
)

var (
	// a source of numbers, for naming temporary files
	uniq = make(chan int)
	// the architecture-identifying character of the tool chain, 5, 6, or 8
	archChar string
)

func main() {
	flag.Parse()

	// set archChar
	switch runtime.GOARCH {
	case "arm":
		archChar = "5"
	case "amd64":
		archChar = "6"
	case "386":
		archChar = "8"
	default:
		log.Exitln("unrecognized GOARCH:", runtime.GOARCH)
	}

	// source of unique numbers
	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()

	http.HandleFunc("/", FrontPage)
	http.HandleFunc("/compile", Compile)
	log.Exit(http.ListenAndServe(*httpListen, nil))
}

// FrontPage is an HTTP handler that renders the goplay interface.
// If a filename is supplied in the path component of the URI,
// its contents will be put in the interface's text area.
// Otherwise, the default "hello, world" program is displayed.
func FrontPage(w http.ResponseWriter, req *http.Request) {
	data, err := ioutil.ReadFile(req.URL.Path[1:])
	if err != nil {
		data = helloWorld
	}
	frontPage.Execute(data, w)
}

// Compile is an HTTP handler that reads Go source code from the request,
// compiles and links the code (returning any errors), runs the program,
// and sends the program's output as the HTTP response.
func Compile(w http.ResponseWriter, req *http.Request) {
	// x is the base name for .go, .6, executable files
	x := "/tmp/compile" + strconv.Itoa(<-uniq)

	// write request Body to x.go
	f, err := os.Open(x+".go", os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0666)
	if err != nil {
		error(w, nil, err)
		return
	}
	defer os.Remove(x + ".go")
	defer f.Close()
	_, err = io.Copy(f, req.Body)
	if err != nil {
		error(w, nil, err)
		return
	}
	f.Close()

	// build x.go, creating x.6
	out, err := run(archChar+"g", "-o", x+"."+archChar, x+".go")
	defer os.Remove(x + "." + archChar)
	if err != nil {
		error(w, out, err)
		return
	}

	// link x.6, creating x (the program binary)
	out, err = run(archChar+"l", "-o", x, x+"."+archChar)
	defer os.Remove(x)
	if err != nil {
		error(w, out, err)
		return
	}

	// run x
	out, err = run(x)
	if err != nil {
		error(w, out, err)
	}

	// write the output of x as the http response
	if *htmlOutput {
		w.Write(out)
	} else {
		output.Execute(out, w)
	}
}

// error writes compile, link, or runtime errors to the HTTP connection.
// The JavaScript interface uses the 404 status code to identify the error.
func error(w http.ResponseWriter, out []byte, err os.Error) {
	w.WriteHeader(404)
	if out != nil {
		output.Execute(out, w)
	} else {
		output.Execute(err.String(), w)
	}
}

// run executes the specified command and returns its output and an error.
func run(cmd ...string) ([]byte, os.Error) {
	// find the specified binary
	bin, err := exec.LookPath(cmd[0])
	if err != nil {
		// report binary as well as the error
		return nil, os.NewError(cmd[0] + ": " + err.String())
	}

	// run the binary and read its combined stdout and stderr into a buffer
	p, err := exec.Run(bin, cmd, os.Environ(), "", exec.DevNull, exec.Pipe, exec.MergeWithStdout)
	if err != nil {
		return nil, err
	}
	var buf bytes.Buffer
	io.Copy(&buf, p.Stdout)
	w, err := p.Wait(0)
	p.Close()

	// set the error return value if the program had a non-zero exit status
	if !w.Exited() || w.ExitStatus() != 0 {
		err = os.ErrorString("running " + cmd[0] + ": " + w.String())
	}

	return buf.Bytes(), err
}

var frontPage, output *template.Template // HTML templates

func init() {
	frontPage = template.New(nil)
	frontPage.SetDelims("«", "»")
	if err := frontPage.Parse(frontPageText); err != nil {
		panic(err)
	}
	output = template.MustParse(outputText, nil)
}

var outputText = `<pre>{@|html}</pre>`

var frontPageText = `<!doctype html>

<textarea autofocus="true" id="edit" spellcheck="false" onkeydown="keyHandler();" onkeyup="autocompile();">«@|html»</textarea>

(Shift-Enter to compile and run.)
<input type="checkbox" id="autocompile" value="checked" /> Compile and run after each keystroke

`

var helloWorld = []byte(`package main

import "fmt"

func main() {
	fmt.Println("hello, world")
}
`)
<commit_msg>goplay: fix to run under windows.<commit_after>// Copyright 2010 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.

package main

import (
	"bytes"
	"exec"
	"flag"
	"http"
	"io"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"strconv"
	"template"
)

var (
	httpListen = flag.String("http", "127.0.0.1:3999", "host:port to listen on")
	htmlOutput = flag.Bool("html", false, "render program output as HTML")
)

var (
	// a source of numbers, for naming temporary files
	uniq = make(chan int)
	// the architecture-identifying character of the tool chain, 5, 6, or 8
	archChar string
)

func main() {
	flag.Parse()

	// set archChar
	switch runtime.GOARCH {
	case "arm":
		archChar = "5"
	case "amd64":
		archChar = "6"
	case "386":
		archChar = "8"
	default:
		log.Exitln("unrecognized GOARCH:", runtime.GOARCH)
	}

	// source of unique numbers
	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()

	http.HandleFunc("/", FrontPage)
	http.HandleFunc("/compile", Compile)
	log.Exit(http.ListenAndServe(*httpListen, nil))
}

// FrontPage is an HTTP handler that renders the goplay interface.
// If a filename is supplied in the path component of the URI,
// its contents will be put in the interface's text area.
// Otherwise, the default "hello, world" program is displayed.
func FrontPage(w http.ResponseWriter, req *http.Request) {
	data, err := ioutil.ReadFile(req.URL.Path[1:])
	if err != nil {
		data = helloWorld
	}
	frontPage.Execute(data, w)
}

// Compile is an HTTP handler that reads Go source code from the request,
// compiles and links the code (returning any errors), runs the program,
// and sends the program's output as the HTTP response.
func Compile(w http.ResponseWriter, req *http.Request) {
	// x is the base name for .go, .6, executable files
	x := os.TempDir() + "/compile" + strconv.Itoa(<-uniq)
	src := x + ".go"
	obj := x + "." + archChar
	bin := x
	if runtime.GOOS == "windows" {
		bin += ".exe"
	}

	// write request Body to x.go
	f, err := os.Open(src, os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0666)
	if err != nil {
		error(w, nil, err)
		return
	}
	defer os.Remove(src)
	defer f.Close()
	_, err = io.Copy(f, req.Body)
	if err != nil {
		error(w, nil, err)
		return
	}
	f.Close()

	// build x.go, creating x.6
	out, err := run(archChar+"g", "-o", obj, src)
	defer os.Remove(obj)
	if err != nil {
		error(w, out, err)
		return
	}

	// link x.6, creating x (the program binary)
	out, err = run(archChar+"l", "-o", bin, obj)
	defer os.Remove(bin)
	if err != nil {
		error(w, out, err)
		return
	}

	// run x
	out, err = run(bin)
	if err != nil {
		error(w, out, err)
	}

	// write the output of x as the http response
	if *htmlOutput {
		w.Write(out)
	} else {
		output.Execute(out, w)
	}
}

// error writes compile, link, or runtime errors to the HTTP connection.
// The JavaScript interface uses the 404 status code to identify the error.
func error(w http.ResponseWriter, out []byte, err os.Error) {
	w.WriteHeader(404)
	if out != nil {
		output.Execute(out, w)
	} else {
		output.Execute(err.String(), w)
	}
}

// run executes the specified command and returns its output and an error.
func run(cmd ...string) ([]byte, os.Error) {
	// find the specified binary
	bin, err := exec.LookPath(cmd[0])
	if err != nil {
		// report binary as well as the error
		return nil, os.NewError(cmd[0] + ": " + err.String())
	}

	// run the binary and read its combined stdout and stderr into a buffer
	p, err := exec.Run(bin, cmd, os.Environ(), "", exec.DevNull, exec.Pipe, exec.MergeWithStdout)
	if err != nil {
		return nil, err
	}
	var buf bytes.Buffer
	io.Copy(&buf, p.Stdout)
	w, err := p.Wait(0)
	p.Close()
	if err != nil {
		return nil, err
	}

	// set the error return value if the program had a non-zero exit status
	if !w.Exited() || w.ExitStatus() != 0 {
		err = os.ErrorString("running " + cmd[0] + ": " + w.String())
	}

	return buf.Bytes(), err
}

var frontPage, output *template.Template // HTML templates

func init() {
	frontPage = template.New(nil)
	frontPage.SetDelims("«", "»")
	if err := frontPage.Parse(frontPageText); err != nil {
		panic(err)
	}
	output = template.MustParse(outputText, nil)
}

var outputText = `<pre>{@|html}</pre>`

var frontPageText = `<!doctype html>

<textarea autofocus="true" id="edit" spellcheck="false" onkeydown="keyHandler();" onkeyup="autocompile();">«@|html»</textarea>

(Shift-Enter to compile and run.)
<input type="checkbox" id="autocompile" value="checked" /> Compile and run after each keystroke

`

var helloWorld = []byte(`package main

import "fmt"

func main() {
	fmt.Println("hello, world")
}
`)
<|endoftext|>


<commit_before>package cmd

import (
	"errors"
	"fmt"
	"io"
	"regexp"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ecs"
	"github.com/spf13/cobra"
)

type deployCmd struct {
	cluster     string
	serviceName string
	revision    int
}

func NewDeployCommand(out, errOut io.Writer) *cobra.Command {
	f := &deployCmd{}
	cmd := &cobra.Command{
		Use:   "deploy [options]",
		Short: "",
		RunE: func(cmd *cobra.Command, args []string) error {
			err := f.execute(cmd, args, out)
			if err != nil {
				return err
			}
			return nil
		},
	}
	cmd.Flags().StringVar(&f.cluster, "cluster", "", "ECS Cluster Name")
	cmd.Flags().StringVar(&f.serviceName, "service-name", "", "ECS Service Name")
	cmd.Flags().IntVar(&f.revision, "revision", 0, "revision of ECS task definition")

	return cmd
}

func (f *deployCmd) execute(_ *cobra.Command, args []string, out io.Writer) error {
	if f.cluster == "" {
		return errors.New("--cluster is required")
	}

	if f.serviceName == "" {
		return errors.New("--service-name is required")
	}

	sess, err := session.NewSession()
	if err != nil {
		return err
	}

	client := ecs.New(sess, &aws.Config{
		Region: aws.String("ap-northeast-1"),
	})

	service, err := describeService(client, f.cluster, f.serviceName)
	if err != nil {
		return err
	}

	taskDefArn := *service.TaskDefinition
	taskDefArn, err = specifyRevision(f.revision, taskDefArn)
	if err != nil {
		return err
	}

	taskDef, err := describeTaskDefinition(client, taskDefArn)
	if err != nil {
		return err
	}

	newTaskDef, err := registerTaskDefinition(client, taskDef)
	if err != nil {
		return err
	}

	fmt.Fprintf(out, "task definition registerd successfully: revision %d -> %d\n", *taskDef.Revision, *newTaskDef.Revision)

	err = updateService(client, service, newTaskDef)
	if err != nil {
		return err
	}

	fmt.Fprintf(out, "service updating\n")

	err = waitUpdateService(client, f.cluster, f.serviceName, out)
	if err != nil {
		return err
	}

	fmt.Fprintf(out, "service updated successfully\n")

	return nil
}

func describeService(client *ecs.ECS, cluster, serviceName string) (*ecs.Service, error) {
	params := &ecs.DescribeServicesInput{
		Services: []*string{aws.String(serviceName)},
		Cluster:  aws.String(cluster),
	}

	res, err := client.DescribeServices(params)
	if err != nil {
		return nil, err
	}

	if len(res.Services) == 0 {
		return nil, errors.New("service is not found")
	}

	return res.Services[0], nil
}

func describeTaskDefinition(client *ecs.ECS, arn string) (*ecs.TaskDefinition, error) {
	params := &ecs.DescribeTaskDefinitionInput{
		TaskDefinition: aws.String(arn),
	}

	res, err := client.DescribeTaskDefinition(params)
	if err != nil {
		return nil, err
	}

	return res.TaskDefinition, nil
}

func registerTaskDefinition(client *ecs.ECS, taskDef *ecs.TaskDefinition) (*ecs.TaskDefinition, error) {
	params := &ecs.RegisterTaskDefinitionInput{
		ContainerDefinitions: taskDef.ContainerDefinitions,
		Family:               taskDef.Family,
		NetworkMode:          taskDef.NetworkMode,
		PlacementConstraints: taskDef.PlacementConstraints,
		TaskRoleArn:          taskDef.TaskRoleArn,
		Volumes:              taskDef.Volumes,
	}

	res, err := client.RegisterTaskDefinition(params)
	if err != nil {
		return nil, err
	}

	return res.TaskDefinition, nil
}

func updateService(client *ecs.ECS, service *ecs.Service, taskDef *ecs.TaskDefinition) error {
	params := &ecs.UpdateServiceInput{
		Cluster:                 service.ClusterArn,
		DeploymentConfiguration: service.DeploymentConfiguration,
		DesiredCount:            service.DesiredCount,
		Service:                 service.ServiceName,
		TaskDefinition:          taskDef.TaskDefinitionArn,
	}

	_, err := client.UpdateService(params)
	if err != nil {
		return err
	}

	return nil
}

func waitUpdateService(client *ecs.ECS, cluster, serviceName string, out io.Writer) error {
	t := time.NewTicker(10 * time.Second)
	for {
		select {
		case <-t.C:
			s, err := describeService(client, cluster, serviceName)
			if err != nil {
				return err
			}

			for _, v := range s.Deployments {
				fmt.Fprintf(out,
					"status: %s | desired: %d, pending: %d, running: %d\n",
					*v.Status, *v.DesiredCount, *v.PendingCount, *v.RunningCount)
			}

			if len(s.Deployments) == 1 && *s.RunningCount == *s.DesiredCount {
				return nil
			}
		}
	}
}

func specifyRevision(revision int, arn string) (string, error) {
	if revision <= 0 {
		return arn, nil
	}

	re, err := regexp.Compile(`(.*):[1-9][0-9]*$`)
	if err != nil {
		return "", err
	}

	return re.ReplaceAllString(arn, fmt.Sprintf("${1}:%d", revision)), nil
}
<commit_msg>block multiple deploy<commit_after>package cmd

import (
	"errors"
	"fmt"
	"io"
	"regexp"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ecs"
	"github.com/spf13/cobra"
)

type deployCmd struct {
	cluster     string
	serviceName string
	revision    int
}

func NewDeployCommand(out, errOut io.Writer) *cobra.Command {
	f := &deployCmd{}
	cmd := &cobra.Command{
		Use:   "deploy [options]",
		Short: "",
		RunE: func(cmd *cobra.Command, args []string) error {
			err := f.execute(cmd, args, out)
			if err != nil {
				return err
			}
			return nil
		},
	}
	cmd.Flags().StringVar(&f.cluster, "cluster", "", "ECS Cluster Name")
	cmd.Flags().StringVar(&f.serviceName, "service-name", "", "ECS Service Name")
	cmd.Flags().IntVar(&f.revision, "revision", 0, "revision of ECS task definition")

	return cmd
}

func (f *deployCmd) execute(_ *cobra.Command, args []string, out io.Writer) error {
	if f.cluster == "" {
		return errors.New("--cluster is required")
	}

	if f.serviceName == "" {
		return errors.New("--service-name is required")
	}

	sess, err := session.NewSession()
	if err != nil {
		return err
	}

	client := ecs.New(sess, &aws.Config{
		Region: aws.String("ap-northeast-1"),
	})

	service, err := describeService(client, f.cluster, f.serviceName)
	if err != nil {
		return err
	}

	if len(service.Deployments) > 1 {
		return errors.New(fmt.Sprintf("%s is currently deployed", f.serviceName))
	}

	taskDefArn := *service.TaskDefinition
	taskDefArn, err = specifyRevision(f.revision, taskDefArn)
	if err != nil {
		return err
	}

	taskDef, err := describeTaskDefinition(client, taskDefArn)
	if err != nil {
		return err
	}

	newTaskDef, err := registerTaskDefinition(client, taskDef)
	if err != nil {
		return err
	}

	fmt.Fprintf(out, "task definition registerd successfully: revision %d -> %d\n", *taskDef.Revision, *newTaskDef.Revision)

	err = updateService(client, service, newTaskDef)
	if err != nil {
		return err
	}

	fmt.Fprintf(out, "service updating\n")

	err = waitUpdateService(client, f.cluster, f.serviceName, out)
	if err != nil {
		return err
	}

	fmt.Fprintf(out, "service updated successfully\n")

	return nil
}

func describeService(client *ecs.ECS, cluster, serviceName string) (*ecs.Service, error) {
	params := &ecs.DescribeServicesInput{
		Services: []*string{aws.String(serviceName)},
		Cluster:  aws.String(cluster),
	}

	res, err := client.DescribeServices(params)
	if err != nil {
		return nil, err
	}

	if len(res.Services) == 0 {
		return nil, errors.New("service is not found")
	}

	return res.Services[0], nil
}

func describeTaskDefinition(client *ecs.ECS, arn string) (*ecs.TaskDefinition, error) {
	params := &ecs.DescribeTaskDefinitionInput{
		TaskDefinition: aws.String(arn),
	}

	res, err := client.DescribeTaskDefinition(params)
	if err != nil {
		return nil, err
	}

	return res.TaskDefinition, nil
}

func registerTaskDefinition(client *ecs.ECS, taskDef *ecs.TaskDefinition) (*ecs.TaskDefinition, error) {
	params := &ecs.RegisterTaskDefinitionInput{
		ContainerDefinitions: taskDef.ContainerDefinitions,
		Family:               taskDef.Family,
		NetworkMode:          taskDef.NetworkMode,
		PlacementConstraints: taskDef.PlacementConstraints,
		TaskRoleArn:          taskDef.TaskRoleArn,
		Volumes:              taskDef.Volumes,
	}

	res, err := client.RegisterTaskDefinition(params)
	if err != nil {
		return nil, err
	}

	return res.TaskDefinition, nil
}

func updateService(client *ecs.ECS, service *ecs.Service, taskDef *ecs.TaskDefinition) error {
	params := &ecs.UpdateServiceInput{
		Cluster:                 service.ClusterArn,
		DeploymentConfiguration: service.DeploymentConfiguration,
		DesiredCount:            service.DesiredCount,
		Service:                 service.ServiceName,
		TaskDefinition:          taskDef.TaskDefinitionArn,
	}

	_, err := client.UpdateService(params)
	if err != nil {
		return err
	}

	return nil
}

func waitUpdateService(client *ecs.ECS, cluster, serviceName string, out io.Writer) error {
	t := time.NewTicker(10 * time.Second)
	for {
		select {
		case <-t.C:
			s, err := describeService(client, cluster, serviceName)
			if err != nil {
				return err
			}

			for _, v := range s.Deployments {
				fmt.Fprintf(out,
					"status: %s | desired: %d, pending: %d, running: %d\n",
					*v.Status, *v.DesiredCount, *v.PendingCount, *v.RunningCount)
			}

			if len(s.Deployments) == 1 && *s.RunningCount == *s.DesiredCount {
				return nil
			}
		}
	}
}

func specifyRevision(revision int, arn string) (string, error) {
	if revision <= 0 {
		return arn, nil
	}

	re, err := regexp.Compile(`(.*):[1-9][0-9]*$`)
	if err != nil {
		return "", err
	}

	return re.ReplaceAllString(arn, fmt.Sprintf("${1}:%d", revision)), nil
}
<|endoftext|>