<commit_before>package disgo

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/gorilla/websocket"
	"github.com/slf4go/logger"
)

type shard struct {
	// Parent session
	session *Session

	// Websocket information used for identification and reconnection
	webSocket *websocket.Conn
	shard     int
	sessionID string
	sequence  int
	heartbeat int

	// Mutex locks, reconnect to make sure there is only 1 process reconnecting and concurrent read/write accesses on the socket
	readLock, writeLock sync.Mutex

	// Channels used to synchronize shutdown of this shards goroutines
	isShuttingDown    bool
	closeMainLoop     chan bool
	closeConfirmation chan bool
}

// Shard constructor, automatically connects with the given shardNum
func newShard(session *Session, shardNum int) (*shard, error) {
	s := &shard{
		session:           session,
		shard:             shardNum,
		closeMainLoop:     make(chan bool),
		closeConfirmation: make(chan bool),
	}

	// These will be unlocked once a connection is made.
	s.readLock.Lock()
	s.writeLock.Lock()

	if err := s.connect(); err != nil {
		return nil, err
	}

	return s, nil
}

// Builds a new connection with Discord, waits for the "hello" frame and then proceeds to identify itself to the Discord service
func (s *shard) connect() error {
	conn, _, err := websocket.DefaultDialer.Dial(s.session.wsUrl, http.Header{})
	if err != nil {
		return err
	}

	s.webSocket = conn
	s.webSocket.SetCloseHandler(s.onClose)

	helloFrame, err := s.readFrame(true)
	if err != nil {
		return err
	} else if helloFrame.Op != opHello {
		return errors.New("First frame sent from the Discord Gateway is not hello")
	}

	hello := helloPayload{}
	if err = json.Unmarshal(helloFrame.Data, &hello); err != nil {
		return err
	}

	logger.Debugf("Connected to Discord servers: %s", strings.Join(hello.Servers, ", "))
	logger.Debugf("Setting up a heartbeat interval of %d ms", hello.HeartbeatInterval)
	s.heartbeat = hello.HeartbeatInterval

	if err = s.identify(); err != nil {
		return err
	}

	go s.mainLoop()
	return nil
}

// identify takes care of the identification using the bot token on the discord server
func (s *shard) identify() error {
	if s.sessionID != "" {
		logger.Debugf("Resuming connection starting at sequence %d.", s.sequence)
		s.sendFrame(&gatewayFrame{opResume, resumePayload{
			Token:     s.session.token,
			SessionID: s.sessionID,
			Sequence:  s.sequence,
		}}, true)
	} else {
		logger.Debugf("Identifying to websocket")
		s.sendFrame(&gatewayFrame{opIdentify, identifyPayload{
			Token:          s.session.token,
			Compress:       true,
			LargeThreshold: 250,
			Shard:          [2]int{s.shard, cap(s.session.shards)},
			Properties: propertiesPayload{
				OS:      runtime.GOOS,
				Browser: "DisGo",
				Device:  "DisGo",
			},
		}}, true)
	}

	for {
		frame, err := s.readFrame(true)
		if err != nil {
			return err
		}

		switch frame.Op {
		case opDispatch:
			switch frame.EventName {
			case "READY":
				ready := ReadyEvent{}
				if err := json.Unmarshal(frame.Data, &ready); err != nil {
					return err
				}

				s.sessionID = ready.SessionID

				fallthrough
			case "RESUMED":
				s.session.dispatchEvent(frame)

				s.readLock.Unlock()
				s.writeLock.Unlock()

				return nil // Break out of the loop, we have what we want
			default:
				s.session.dispatchEvent(frame) // Nope, resume action, let's wait for more frames
			}
		case opInvalidSession:
			s.sessionID = "" // Invalidate session and retry
			return s.identify()
		default:
			return fmt.Errorf("Unexpected opCode received from Discord: %d", frame.Op)
		}
	}
}

// Main loop of the shard connection, also responsible for starting the read loop.
// This goroutine will pass around all the messages through the rest of the library.
func (s *shard) mainLoop() {
	logger.Debugf("Starting main loop for shard [%d/%d]", s.shard+1, cap(s.session.shards))
	defer logger.Debugf("Exiting main loop for shard [%d/%d]", s.shard+1, cap(s.session.shards))
	defer func() { s.closeConfirmation <- true }()

	heartbeat := time.NewTicker(time.Duration(s.heartbeat) * time.Millisecond)
	defer heartbeat.Stop()
	sentHeartBeat := false

	reader := make(chan *receivedFrame, 1)
	go s.readWebSocket(reader)

	for {
		select {
		case <-heartbeat.C:
			if !sentHeartBeat {
				go s.sendFrame(&gatewayFrame{opHeartbeat, s.sequence}, false)
				sentHeartBeat = true
			} else {
				go s.disconnect(websocket.ClosePolicyViolation, "Did not respond to previous heartbeat")
			}
		case <-s.closeMainLoop:
			return
		case frame := <-reader:
			switch frame.Op {
			case opHeartbeat:
				s.sendFrame(&gatewayFrame{Op: opHeartbeatAck}, false)
			case opHeartbeatAck:
				sentHeartBeat = false
			case opReconnect:
				go s.disconnect(websocket.CloseNormalClosure, "op Reconnect")
			case opInvalidSession:
				s.sessionID = ""
				s.identify()
			case opDispatch:
				s.session.dispatchEvent(frame)
			default:
				logger.Errorf("Unexpected opCode received: %d", frame.Op)
			}
		}
	}
}

// The secondary goroutine of each shard, responsible for reading frames and putting them in the channel.
func (s *shard) readWebSocket(reader chan *receivedFrame) {
	logger.Debugf("Starting read loop for shard [%d/%d]", s.shard+1, cap(s.session.shards))
	defer logger.Debugf("Exiting read loop for shard [%d/%d]", s.shard+1, cap(s.session.shards))
	defer func() { s.closeConfirmation <- true }()

	for {
		frame, err := s.readFrame(false)
		if err != nil {
			if !s.isShuttingDown {
				s.onClose(websocket.CloseAbnormalClosure, err.Error())
			}
			return
		}

		reader <- frame
	}

}

// Reads 1 frame from the websocket.
func (s *shard) readFrame(isConnecting bool) (*receivedFrame, error) {
	if !isConnecting {
		s.readLock.Lock()
		defer s.readLock.Unlock()
	}

	logger.Tracef("Shard.readFrame() called")
	msgType, msg, err := s.webSocket.ReadMessage()
	if err != nil {
		return nil, err
	}

	var reader io.Reader
	reader = bytes.NewBuffer(msg)

	if msgType == websocket.BinaryMessage {
		zReader, err := zlib.NewReader(reader)
		if err != nil {
			return nil, err
		}

		defer zReader.Close()

		reader = zReader
	}

	frame := receivedFrame{Sequence: -1}
	err = json.NewDecoder(reader).Decode(&frame)
	if err != nil {
		return nil, err
	}

	logger.Debugf("Received frame with opCode: %d", frame.Op)

	if frame.Sequence > s.sequence {
		logger.Tracef("Last sequence received set to %d.", frame.Sequence)
		s.sequence = frame.Sequence
	}
	return &frame, nil
}

// Sends 1 frame to the websocket
func (s *shard) sendFrame(frame *gatewayFrame, isConnecting bool) {
	if !isConnecting {
		s.writeLock.Lock()
		defer s.writeLock.Unlock()
	}

	logger.Debugf("Sending frame with opCode: %d", frame.Op)
	s.webSocket.WriteJSON(frame)
}

// Called when we have received a closing intention that we have not initiated (ws close message, recv error)
func (s *shard) onClose(code int, text string) error {
	go func() {
		logger.Warnf("Received Close Frame from Discord. Code: %d. Text: %s", code, text)

		s.isShuttingDown = true
		s.stopRoutines()
		s.readLock.Lock()
		s.writeLock.Lock()

		if err := s.webSocket.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(code, text)); err != nil {
			logger.Error("Could not confirm close message.")
			logger.ErrorE(err)
		}

		s.cleanupWebSocket()
	}()

	return nil
}

// Called by us to disconnect the websocket (shutdown, protocol errors, missed heartbeats)
func (s *shard) disconnect(code int, text string) {
	s.isShuttingDown = true
	s.writeLock.Lock()

	closeMessage := make(chan int)
	s.webSocket.SetCloseHandler(func(code int, _ string) error {
		closeMessage <- code
		return nil
	})

	if err := s.webSocket.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(code, text)); err != nil {
		logger.Error("Could not write close message to Discord, connection already dead?")
		logger.ErrorE(err)
	} else {
		select {
		case code := <-closeMessage:
			logger.Debugf("Discord connection closed with code %d", code)
		case <-time.After(1 * time.Second):
			logger.Warn("Discord did not reply to the close message, force-closing connection.")
		}
	}

	s.stopRoutines()
	s.readLock.Lock()
	s.cleanupWebSocket()
}

// Stops the two shard goroutines
func (s *shard) stopRoutines() {
	s.webSocket.SetReadDeadline(time.Now()) // Stop the read loop, in case it hasn't already due to an error
	<-s.closeConfirmation                   // Wait for the read loop
	s.closeMainLoop <- true                 // Stop the main loop
	<-s.closeConfirmation                   // Wait for the main loop
}

// Cleans up the current websocket and tries to reconnect it if needed
func (s *shard) cleanupWebSocket() {
	s.webSocket.Close()
	s.webSocket = nil

	for !s.session.isShuttingDown() {
		if err := s.connect(); err != nil {
			logger.Error("Could not reconnect to Discord.")
			logger.ErrorE(err)

			time.Sleep(500 * time.Millisecond)
		} else {
			break
		}
	}
}
<commit_msg>Added connection cleanup on failed identification<commit_after>package disgo

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/gorilla/websocket"
	"github.com/slf4go/logger"
)

type shard struct {
	// Parent session
	session *Session

	// Websocket information used for identification and reconnection
	webSocket *websocket.Conn
	shard     int
	sessionID string
	sequence  int
	heartbeat int

	// Mutex locks, reconnect to make sure there is only 1 process reconnecting and concurrent read/write accesses on the socket
	readLock, writeLock sync.Mutex

	// Channels used to synchronize shutdown of this shards goroutines
	isShuttingDown    bool
	closeMainLoop     chan bool
	closeConfirmation chan bool
}

// Shard constructor, automatically connects with the given shardNum
func newShard(session *Session, shardNum int) (*shard, error) {
	s := &shard{
		session:           session,
		shard:             shardNum,
		closeMainLoop:     make(chan bool),
		closeConfirmation: make(chan bool),
	}

	// These will be unlocked once a connection is made.
	s.readLock.Lock()
	s.writeLock.Lock()

	if err := s.connect(); err != nil {
		return nil, err
	}

	return s, nil
}

// Builds a new connection with Discord, waits for the "hello" frame and then proceeds to identify itself to the Discord service
func (s *shard) connect() error {
	// Open the websocket
	conn, _, err := websocket.DefaultDialer.Dial(s.session.wsUrl, http.Header{})
	if err != nil {
		return err
	}

	s.webSocket = conn
	s.webSocket.SetCloseHandler(s.onClose)

	// At the end of this function, clean up the socket if we didn't identify correctly.
	defer func() {
		if err != nil {
			conn.Close()
			s.webSocket = nil
		}
	}()

	// Discord always sends a hello frame upon opening the connection
	var helloFrame *receivedFrame
	helloFrame, err = s.readFrame(true)
	if err != nil {
		return err
	} else if helloFrame.Op != opHello {
		return errors.New("First frame sent from the Discord Gateway is not hello")
	}

	hello := helloPayload{}
	if err = json.Unmarshal(helloFrame.Data, &hello); err != nil {
		return err
	}

	// We've succesfully connected.
	logger.Debugf("Connected to Discord servers: %s", strings.Join(hello.Servers, ", "))
	logger.Debugf("Setting up a heartbeat interval of %d ms", hello.HeartbeatInterval)
	s.heartbeat = hello.HeartbeatInterval

	// Now identify
	if err = s.identify(); err != nil {
		return err
	}

	// Identification succesful, unlock reading/writing and start the goroutines
	s.readLock.Unlock()
	s.writeLock.Unlock()
	go s.mainLoop()

	return nil
}

// identify takes care of the identification using the bot token on the discord server
func (s *shard) identify() error {
	if s.sessionID != "" {
		logger.Debugf("Resuming connection starting at sequence %d.", s.sequence)
		s.sendFrame(&gatewayFrame{opResume, resumePayload{
			Token:     s.session.token,
			SessionID: s.sessionID,
			Sequence:  s.sequence,
		}}, true)
	} else {
		logger.Debugf("Identifying to websocket")
		s.sendFrame(&gatewayFrame{opIdentify, identifyPayload{
			Token:          s.session.token,
			Compress:       true,
			LargeThreshold: 250,
			Shard:          [2]int{s.shard, cap(s.session.shards)},
			Properties: propertiesPayload{
				OS:      runtime.GOOS,
				Browser: "DisGo",
				Device:  "DisGo",
			},
		}}, true)
	}

	for {
		frame, err := s.readFrame(true)
		if err != nil {
			return err
		}

		switch frame.Op {
		case opDispatch:
			switch frame.EventName {
			case "READY":
				ready := ReadyEvent{}
				if err := json.Unmarshal(frame.Data, &ready); err != nil {
					return err
				}

				s.sessionID = ready.SessionID

				fallthrough
			case "RESUMED":
				s.session.dispatchEvent(frame)
				return nil // Break out of the loop, we have what we want
			default:
				s.session.dispatchEvent(frame) // Nope, resume action, let's wait for more frames
			}
		case opInvalidSession:
			s.sessionID = "" // Invalidate session and retry
			return s.identify()
		default:
			return fmt.Errorf("Unexpected opCode received from Discord: %d", frame.Op)
		}
	}
}

// Main loop of the shard connection, also responsible for starting the read loop.
// This goroutine will pass around all the messages through the rest of the library.
func (s *shard) mainLoop() {
	logger.Debugf("Starting main loop for shard [%d/%d]", s.shard+1, cap(s.session.shards))
	defer logger.Debugf("Exiting main loop for shard [%d/%d]", s.shard+1, cap(s.session.shards))
	defer func() { s.closeConfirmation <- true }()

	heartbeat := time.NewTicker(time.Duration(s.heartbeat) * time.Millisecond)
	defer heartbeat.Stop()
	sentHeartBeat := false

	reader := make(chan *receivedFrame, 1)
	go s.readWebSocket(reader)

	for {
		select {
		case <-heartbeat.C:
			if !sentHeartBeat {
				go s.sendFrame(&gatewayFrame{opHeartbeat, s.sequence}, false)
				sentHeartBeat = true
			} else {
				go s.disconnect(websocket.ClosePolicyViolation, "Did not respond to previous heartbeat")
			}
		case <-s.closeMainLoop:
			return
		case frame := <-reader:
			switch frame.Op {
			case opHeartbeat:
				s.sendFrame(&gatewayFrame{Op: opHeartbeatAck}, false)
			case opHeartbeatAck:
				sentHeartBeat = false
			case opReconnect:
				go s.disconnect(websocket.CloseNormalClosure, "op Reconnect")
			case opInvalidSession:
				s.sessionID = ""
				s.identify()
			case opDispatch:
				s.session.dispatchEvent(frame)
			default:
				logger.Errorf("Unexpected opCode received: %d", frame.Op)
			}
		}
	}
}

// The secondary goroutine of each shard, responsible for reading frames and putting them in the channel.
func (s *shard) readWebSocket(reader chan *receivedFrame) {
	logger.Debugf("Starting read loop for shard [%d/%d]", s.shard+1, cap(s.session.shards))
	defer logger.Debugf("Exiting read loop for shard [%d/%d]", s.shard+1, cap(s.session.shards))
	defer func() { s.closeConfirmation <- true }()

	for {
		frame, err := s.readFrame(false)
		if err != nil {
			if !s.isShuttingDown {
				s.onClose(websocket.CloseAbnormalClosure, err.Error())
			}
			return
		}

		reader <- frame
	}

}

// Reads 1 frame from the websocket.
func (s *shard) readFrame(isConnecting bool) (*receivedFrame, error) {
	if !isConnecting {
		s.readLock.Lock()
		defer s.readLock.Unlock()
	}

	logger.Tracef("Shard.readFrame() called")
	msgType, msg, err := s.webSocket.ReadMessage()
	if err != nil {
		return nil, err
	}

	var reader io.Reader
	reader = bytes.NewBuffer(msg)

	if msgType == websocket.BinaryMessage {
		zReader, err := zlib.NewReader(reader)
		if err != nil {
			return nil, err
		}

		defer zReader.Close()

		reader = zReader
	}

	frame := receivedFrame{Sequence: -1}
	err = json.NewDecoder(reader).Decode(&frame)
	if err != nil {
		return nil, err
	}

	logger.Debugf("Received frame with opCode: %d", frame.Op)

	if frame.Sequence > s.sequence {
		logger.Tracef("Last sequence received set to %d.", frame.Sequence)
		s.sequence = frame.Sequence
	}
	return &frame, nil
}

// Sends 1 frame to the websocket
func (s *shard) sendFrame(frame *gatewayFrame, isConnecting bool) {
	if !isConnecting {
		s.writeLock.Lock()
		defer s.writeLock.Unlock()
	}

	logger.Debugf("Sending frame with opCode: %d", frame.Op)
	s.webSocket.WriteJSON(frame)
}

// Called when we have received a closing intention that we have not initiated (ws close message, recv error)
func (s *shard) onClose(code int, text string) error {
	go func() {
		logger.Warnf("Received Close Frame from Discord. Code: %d. Text: %s", code, text)

		s.isShuttingDown = true
		s.stopRoutines()
		s.readLock.Lock()
		s.writeLock.Lock()

		if err := s.webSocket.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(code, text)); err != nil {
			logger.Error("Could not confirm close message.")
			logger.ErrorE(err)
		}

		s.cleanupWebSocket()
	}()

	return nil
}

// Called by us to disconnect the websocket (shutdown, protocol errors, missed heartbeats)
func (s *shard) disconnect(code int, text string) {
	s.isShuttingDown = true
	s.writeLock.Lock()

	closeMessage := make(chan int)
	s.webSocket.SetCloseHandler(func(code int, _ string) error {
		closeMessage <- code
		return nil
	})

	if err := s.webSocket.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(code, text)); err != nil {
		logger.Error("Could not write close message to Discord, connection already dead?")
		logger.ErrorE(err)
	} else {
		select {
		case code := <-closeMessage:
			logger.Debugf("Discord connection closed with code %d", code)
		case <-time.After(1 * time.Second):
			logger.Warn("Discord did not reply to the close message, force-closing connection.")
		}
	}

	s.stopRoutines()
	s.readLock.Lock()
	s.cleanupWebSocket()
}

// Stops the two shard goroutines
func (s *shard) stopRoutines() {
	s.webSocket.SetReadDeadline(time.Now()) // Stop the read loop, in case it hasn't already due to an error
	<-s.closeConfirmation                   // Wait for the read loop
	s.closeMainLoop <- true                 // Stop the main loop
	<-s.closeConfirmation                   // Wait for the main loop
}

// Cleans up the current websocket and tries to reconnect it if needed
func (s *shard) cleanupWebSocket() {
	s.webSocket.Close()
	s.webSocket = nil

	for !s.session.isShuttingDown() {
		if err := s.connect(); err != nil {
			logger.Error("Could not reconnect to Discord.")
			logger.ErrorE(err)

			time.Sleep(500 * time.Millisecond)
		} else {
			break
		}
	}
}
<|endoftext|>


<commit_before>package xlsx

import (
	"errors"
	"fmt"
	"strconv"
)

// Sheet is a high level structure intended to provide user access to
// the contents of a particular sheet within an XLSX file.
type Sheet struct {
	Name        string
	File        *File
	Rows        []*Row
	Cols        []*Col
	MaxRow      int
	MaxCol      int
	Hidden      bool
	Selected    bool
	SheetViews  []SheetView
	SheetFormat SheetFormat
	AutoFilter  *AutoFilter
}

type SheetView struct {
	Pane *Pane
}

type Pane struct {
	XSplit      float64
	YSplit      float64
	TopLeftCell string
	ActivePane  string
	State       string // Either "split" or "frozen"
}

type SheetFormat struct {
	DefaultColWidth  float64
	DefaultRowHeight float64
	OutlineLevelCol  uint8
	OutlineLevelRow  uint8
}

type AutoFilter struct {
	TopLeftCell     string
	BottomRightCell string
}

// Add a new Row to a Sheet
func (s *Sheet) AddRow() *Row {
	row := &Row{Sheet: s}
	s.Rows = append(s.Rows, row)
	if len(s.Rows) > s.MaxRow {
		s.MaxRow = len(s.Rows)
	}
	return row
}

// Make sure we always have as many Cols as we do cells.
func (s *Sheet) maybeAddCol(cellCount int) {
	if cellCount > s.MaxCol {
		loopCnt := cellCount - s.MaxCol
		currIndex := s.MaxCol + 1
		for i := 0; i < loopCnt; i++ {

			col := &Col{
				style:     NewStyle(),
				Min:       currIndex,
				Max:       currIndex,
				Hidden:    false,
				Collapsed: false}
			s.Cols = append(s.Cols, col)
			currIndex++
		}
		s.MaxCol = cellCount
	}
}

// Make sure we always have as many Cols as we do cells.
func (s *Sheet) Col(idx int) *Col {
	s.maybeAddCol(idx + 1)
	return s.Cols[idx]
}

// Get a Cell by passing it's cartesian coordinates (zero based) as
// row and column integer indexes.
//
// For example:
//
//    cell := sheet.Cell(0,0)
//
// ... would set the variable "cell" to contain a Cell struct
// containing the data from the field "A1" on the spreadsheet.
func (sh *Sheet) Cell(row, col int) *Cell {

	// If the user requests a row beyond what we have, then extend.
	for len(sh.Rows) <= row {
		sh.AddRow()
	}

	r := sh.Rows[row]
	for len(r.Cells) <= col {
		r.AddCell()
	}

	return r.Cells[col]
}

//Set the width of a single column or multiple columns.
func (s *Sheet) SetColWidth(startcol, endcol int, width float64) error {
	if startcol > endcol {
		return fmt.Errorf("Could not set width for range %d-%d: startcol must be less than endcol.", startcol, endcol)
	}
	col := &Col{
		style:     NewStyle(),
		Min:       startcol + 1,
		Max:       endcol + 1,
		Hidden:    false,
		Collapsed: false,
		Width:     width}
	s.Cols = append(s.Cols, col)
	if endcol+1 > s.MaxCol {
		s.MaxCol = endcol + 1
	}
	return nil
}

// When merging cells, the cell may be the 'original' or the 'covered'.
// First, figure out which cells are merge starting points. Then create
// the necessary cells underlying the merge area.
// Then go through all the underlying cells and apply the appropriate
// border, based on the original cell.
func (s *Sheet) handleMerged() {
	merged := make(map[string]*Cell)

	for r, row := range s.Rows {
		for c, cell := range row.Cells {
			if cell.HMerge > 0 || cell.VMerge > 0 {
				coord := GetCellIDStringFromCoords(c, r)
				merged[coord] = cell
			}
		}
	}

	// This loop iterates over all cells that should be merged and applies the correct
	// borders to them depending on their position. If any cells required by the merge
	// are missing, they will be allocated by s.Cell().
	for key, cell := range merged {
		mainstyle := cell.GetStyle()

		top := mainstyle.Border.Top
		left := mainstyle.Border.Left
		right := mainstyle.Border.Right
		bottom := mainstyle.Border.Bottom

		// When merging cells, the upper left cell does not maintain
		// the original borders
		mainstyle.Border.Top = "none"
		mainstyle.Border.Left = "none"
		mainstyle.Border.Right = "none"
		mainstyle.Border.Bottom = "none"

		maincol, mainrow, _ := GetCoordsFromCellIDString(key)
		for rownum := 0; rownum <= cell.VMerge; rownum++ {
			for colnum := 0; colnum <= cell.HMerge; colnum++ {
				tmpcell := s.Cell(mainrow+rownum, maincol+colnum)
				style := tmpcell.GetStyle()
				style.ApplyBorder = true

				if rownum == 0 {
					style.Border.Top = top
				}

				if rownum == (cell.VMerge) {
					style.Border.Bottom = bottom
				}

				if colnum == 0 {
					style.Border.Left = left
				}

				if colnum == (cell.HMerge) {
					style.Border.Right = right
				}
			}
		}
	}
}

// Dump sheet to its XML representation, intended for internal use only
func (s *Sheet) makeXLSXSheet(refTable *RefTable, styles *xlsxStyleSheet) *xlsxWorksheet {
	worksheet := newXlsxWorksheet()
	xSheet := xlsxSheetData{}
	maxRow := 0
	maxCell := 0
	var maxLevelCol, maxLevelRow uint8

	// Scan through the sheet and see if there are any merged cells. If there
	// are, we may need to extend the size of the sheet. There needs to be
	// phantom cells underlying the area covered by the merged cell
	s.handleMerged()

	for index, sheetView := range s.SheetViews {
		if sheetView.Pane != nil {
			worksheet.SheetViews.SheetView[index].Pane = &xlsxPane{
				XSplit:      sheetView.Pane.XSplit,
				YSplit:      sheetView.Pane.YSplit,
				TopLeftCell: sheetView.Pane.TopLeftCell,
				ActivePane:  sheetView.Pane.ActivePane,
				State:       sheetView.Pane.State,
			}

		}
	}

	if s.Selected {
		worksheet.SheetViews.SheetView[0].TabSelected = true
	}

	if s.SheetFormat.DefaultRowHeight != 0 {
		worksheet.SheetFormatPr.DefaultRowHeight = s.SheetFormat.DefaultRowHeight
	}
	worksheet.SheetFormatPr.DefaultColWidth = s.SheetFormat.DefaultColWidth

	colsXfIdList := make([]int, len(s.Cols))
	worksheet.Cols = &xlsxCols{Col: []xlsxCol{}}
	for c, col := range s.Cols {
		XfId := 0
		if col.Min == 0 {
			col.Min = 1
		}
		if col.Max == 0 {
			col.Max = 1
		}
		style := col.GetStyle()
		//col's style always not nil
		if style != nil {
			xNumFmt := styles.newNumFmt(col.numFmt)
			XfId = handleStyleForXLSX(style, xNumFmt.NumFmtId, styles)
		}
		colsXfIdList[c] = XfId

		var customWidth bool
		if col.Width == 0 {
			col.Width = ColWidth
			customWidth = false

		} else {
			customWidth = true
		}
		worksheet.Cols.Col = append(worksheet.Cols.Col,
			xlsxCol{Min: col.Min,
				Max:          col.Max,
				Hidden:       col.Hidden,
				Width:        col.Width,
				CustomWidth:  customWidth,
				Collapsed:    col.Collapsed,
				OutlineLevel: col.OutlineLevel,
				Style:        XfId,
			})

		if col.OutlineLevel > maxLevelCol {
			maxLevelCol = col.OutlineLevel
		}
	}

	for r, row := range s.Rows {
		if r > maxRow {
			maxRow = r
		}
		xRow := xlsxRow{}
		xRow.R = r + 1
		if row.isCustom {
			xRow.CustomHeight = true
			xRow.Ht = fmt.Sprintf("%g", row.Height)
		}
		xRow.OutlineLevel = row.OutlineLevel
		if row.OutlineLevel > maxLevelRow {
			maxLevelRow = row.OutlineLevel
		}
		for c, cell := range row.Cells {
			XfId := colsXfIdList[c]

			// generate NumFmtId and add new NumFmt
			xNumFmt := styles.newNumFmt(cell.NumFmt)

			style := cell.style
			if style != nil {
				XfId = handleStyleForXLSX(style, xNumFmt.NumFmtId, styles)
			} else if len(cell.NumFmt) > 0 && !compareFormatString(s.Cols[c].numFmt, cell.NumFmt) {
				XfId = handleNumFmtIdForXLSX(xNumFmt.NumFmtId, styles)
			}

			if c > maxCell {
				maxCell = c
			}
			xC := xlsxC{
				S: XfId,
				R: GetCellIDStringFromCoords(c, r),
			}
			if cell.formula != "" {
				xC.F = &xlsxF{Content: cell.formula}
			}
			switch cell.cellType {
			case CellTypeInline:
				// Inline strings are turned into shared strings since they are more efficient.
				// This is what Excel does as well.
				fallthrough
			case CellTypeString:
				if len(cell.Value) > 0 {
					xC.V = strconv.Itoa(refTable.AddString(cell.Value))
				}
				xC.T = "s"
			case CellTypeNumeric:
				// Numeric is the default, so the type can be left blank
				xC.V = cell.Value
			case CellTypeBool:
				xC.V = cell.Value
				xC.T = "b"
			case CellTypeError:
				xC.V = cell.Value
				xC.T = "e"
			case CellTypeDate:
				xC.V = cell.Value
				xC.T = "d"
			case CellTypeStringFormula:
				xC.V = cell.Value
				xC.T = "str"
			default:
				panic(errors.New("unknown cell type cannot be marshaled"))
			}

			xRow.C = append(xRow.C, xC)

			if cell.HMerge > 0 || cell.VMerge > 0 {
				// r == rownum, c == colnum
				mc := xlsxMergeCell{}
				start := GetCellIDStringFromCoords(c, r)
				endCol := c + cell.HMerge
				endRow := r + cell.VMerge
				end := GetCellIDStringFromCoords(endCol, endRow)
				mc.Ref = start + ":" + end
				if worksheet.MergeCells == nil {
					worksheet.MergeCells = &xlsxMergeCells{}
				}
				worksheet.MergeCells.Cells = append(worksheet.MergeCells.Cells, mc)
			}
		}
		xSheet.Row = append(xSheet.Row, xRow)
	}

	// Update sheet format with the freshly determined max levels
	s.SheetFormat.OutlineLevelCol = maxLevelCol
	s.SheetFormat.OutlineLevelRow = maxLevelRow
	// .. and then also apply this to the xml worksheet
	worksheet.SheetFormatPr.OutlineLevelCol = s.SheetFormat.OutlineLevelCol
	worksheet.SheetFormatPr.OutlineLevelRow = s.SheetFormat.OutlineLevelRow

	if worksheet.MergeCells != nil {
		worksheet.MergeCells.Count = len(worksheet.MergeCells.Cells)
	}

	if s.AutoFilter != nil {
		worksheet.AutoFilter = &xlsxAutoFilter{Ref: fmt.Sprintf("%v:%v", s.AutoFilter.TopLeftCell, s.AutoFilter.BottomRightCell)}
	}

	worksheet.SheetData = xSheet
	dimension := xlsxDimension{}
	dimension.Ref = "A1:" + GetCellIDStringFromCoords(maxCell, maxRow)
	if dimension.Ref == "A1:A1" {
		dimension.Ref = "A1"
	}
	worksheet.Dimension = dimension
	return worksheet
}

func handleStyleForXLSX(style *Style, NumFmtId int, styles *xlsxStyleSheet) (XfId int) {
	xFont, xFill, xBorder, xCellXf := style.makeXLSXStyleElements()
	fontId := styles.addFont(xFont)
	fillId := styles.addFill(xFill)

	// HACK - adding light grey fill, as in OO and Google
	greyfill := xlsxFill{}
	greyfill.PatternFill.PatternType = "lightGray"
	styles.addFill(greyfill)

	borderId := styles.addBorder(xBorder)
	xCellXf.FontId = fontId
	xCellXf.FillId = fillId
	xCellXf.BorderId = borderId
	xCellXf.NumFmtId = NumFmtId
	// apply the numFmtId when it is not the default cellxf
	if xCellXf.NumFmtId > 0 {
		xCellXf.ApplyNumberFormat = true
	}

	xCellXf.Alignment.Horizontal = style.Alignment.Horizontal
	xCellXf.Alignment.Indent = style.Alignment.Indent
	xCellXf.Alignment.ShrinkToFit = style.Alignment.ShrinkToFit
	xCellXf.Alignment.TextRotation = style.Alignment.TextRotation
	xCellXf.Alignment.Vertical = style.Alignment.Vertical
	xCellXf.Alignment.WrapText = style.Alignment.WrapText

	XfId = styles.addCellXf(xCellXf)
	return
}

func handleNumFmtIdForXLSX(NumFmtId int, styles *xlsxStyleSheet) (XfId int) {
	xCellXf := makeXLSXCellElement()
	xCellXf.NumFmtId = NumFmtId
	if xCellXf.NumFmtId > 0 {
		xCellXf.ApplyNumberFormat = true
	}
	XfId = styles.addCellXf(xCellXf)
	return
}
<commit_msg>SetColWidth index out of range  issue #268<commit_after>package xlsx

import (
	"errors"
	"fmt"
	"strconv"
)

// Sheet is a high level structure intended to provide user access to
// the contents of a particular sheet within an XLSX file.
type Sheet struct {
	Name        string
	File        *File
	Rows        []*Row
	Cols        []*Col
	MaxRow      int
	MaxCol      int
	Hidden      bool
	Selected    bool
	SheetViews  []SheetView
	SheetFormat SheetFormat
	AutoFilter  *AutoFilter
}

type SheetView struct {
	Pane *Pane
}

type Pane struct {
	XSplit      float64
	YSplit      float64
	TopLeftCell string
	ActivePane  string
	State       string // Either "split" or "frozen"
}

type SheetFormat struct {
	DefaultColWidth  float64
	DefaultRowHeight float64
	OutlineLevelCol  uint8
	OutlineLevelRow  uint8
}

type AutoFilter struct {
	TopLeftCell     string
	BottomRightCell string
}

// Add a new Row to a Sheet
func (s *Sheet) AddRow() *Row {
	row := &Row{Sheet: s}
	s.Rows = append(s.Rows, row)
	if len(s.Rows) > s.MaxRow {
		s.MaxRow = len(s.Rows)
	}
	return row
}

// Make sure we always have as many Cols as we do cells.
func (s *Sheet) maybeAddCol(cellCount int) {
	if cellCount > s.MaxCol {
		loopCnt := cellCount - s.MaxCol
		currIndex := s.MaxCol + 1
		for i := 0; i < loopCnt; i++ {

			col := &Col{
				style:     NewStyle(),
				Min:       currIndex,
				Max:       currIndex,
				Hidden:    false,
				Collapsed: false}
			s.Cols = append(s.Cols, col)
			currIndex++
		}
		s.MaxCol = cellCount
	}
}

// Make sure we always have as many Cols as we do cells.
func (s *Sheet) Col(idx int) *Col {
	s.maybeAddCol(idx + 1)
	return s.Cols[idx]
}

// Get a Cell by passing it's cartesian coordinates (zero based) as
// row and column integer indexes.
//
// For example:
//
//    cell := sheet.Cell(0,0)
//
// ... would set the variable "cell" to contain a Cell struct
// containing the data from the field "A1" on the spreadsheet.
func (sh *Sheet) Cell(row, col int) *Cell {

	// If the user requests a row beyond what we have, then extend.
	for len(sh.Rows) <= row {
		sh.AddRow()
	}

	r := sh.Rows[row]
	for len(r.Cells) <= col {
		r.AddCell()
	}

	return r.Cells[col]
}

//Set the width of a single column or multiple columns.
func (s *Sheet) SetColWidth(startcol, endcol int, width float64) error {
	if startcol > endcol {
		return fmt.Errorf("Could not set width for range %d-%d: startcol must be less than endcol.", startcol, endcol)
	}
	s.maybeAddCol(endcol + 1)
	for ; startcol <= endcol; startcol++ {
		s.Cols[startcol].Width = width
	}

	return nil
}

// When merging cells, the cell may be the 'original' or the 'covered'.
// First, figure out which cells are merge starting points. Then create
// the necessary cells underlying the merge area.
// Then go through all the underlying cells and apply the appropriate
// border, based on the original cell.
func (s *Sheet) handleMerged() {
	merged := make(map[string]*Cell)

	for r, row := range s.Rows {
		for c, cell := range row.Cells {
			if cell.HMerge > 0 || cell.VMerge > 0 {
				coord := GetCellIDStringFromCoords(c, r)
				merged[coord] = cell
			}
		}
	}

	// This loop iterates over all cells that should be merged and applies the correct
	// borders to them depending on their position. If any cells required by the merge
	// are missing, they will be allocated by s.Cell().
	for key, cell := range merged {
		mainstyle := cell.GetStyle()

		top := mainstyle.Border.Top
		left := mainstyle.Border.Left
		right := mainstyle.Border.Right
		bottom := mainstyle.Border.Bottom

		// When merging cells, the upper left cell does not maintain
		// the original borders
		mainstyle.Border.Top = "none"
		mainstyle.Border.Left = "none"
		mainstyle.Border.Right = "none"
		mainstyle.Border.Bottom = "none"

		maincol, mainrow, _ := GetCoordsFromCellIDString(key)
		for rownum := 0; rownum <= cell.VMerge; rownum++ {
			for colnum := 0; colnum <= cell.HMerge; colnum++ {
				tmpcell := s.Cell(mainrow+rownum, maincol+colnum)
				style := tmpcell.GetStyle()
				style.ApplyBorder = true

				if rownum == 0 {
					style.Border.Top = top
				}

				if rownum == (cell.VMerge) {
					style.Border.Bottom = bottom
				}

				if colnum == 0 {
					style.Border.Left = left
				}

				if colnum == (cell.HMerge) {
					style.Border.Right = right
				}
			}
		}
	}
}

// Dump sheet to its XML representation, intended for internal use only
func (s *Sheet) makeXLSXSheet(refTable *RefTable, styles *xlsxStyleSheet) *xlsxWorksheet {
	worksheet := newXlsxWorksheet()
	xSheet := xlsxSheetData{}
	maxRow := 0
	maxCell := 0
	var maxLevelCol, maxLevelRow uint8

	// Scan through the sheet and see if there are any merged cells. If there
	// are, we may need to extend the size of the sheet. There needs to be
	// phantom cells underlying the area covered by the merged cell
	s.handleMerged()

	for index, sheetView := range s.SheetViews {
		if sheetView.Pane != nil {
			worksheet.SheetViews.SheetView[index].Pane = &xlsxPane{
				XSplit:      sheetView.Pane.XSplit,
				YSplit:      sheetView.Pane.YSplit,
				TopLeftCell: sheetView.Pane.TopLeftCell,
				ActivePane:  sheetView.Pane.ActivePane,
				State:       sheetView.Pane.State,
			}

		}
	}

	if s.Selected {
		worksheet.SheetViews.SheetView[0].TabSelected = true
	}

	if s.SheetFormat.DefaultRowHeight != 0 {
		worksheet.SheetFormatPr.DefaultRowHeight = s.SheetFormat.DefaultRowHeight
	}
	worksheet.SheetFormatPr.DefaultColWidth = s.SheetFormat.DefaultColWidth

	colsXfIdList := make([]int, len(s.Cols))
	worksheet.Cols = &xlsxCols{Col: []xlsxCol{}}
	for c, col := range s.Cols {
		XfId := 0
		if col.Min == 0 {
			col.Min = 1
		}
		if col.Max == 0 {
			col.Max = 1
		}
		style := col.GetStyle()
		//col's style always not nil
		if style != nil {
			xNumFmt := styles.newNumFmt(col.numFmt)
			XfId = handleStyleForXLSX(style, xNumFmt.NumFmtId, styles)
		}
		colsXfIdList[c] = XfId

		var customWidth bool
		if col.Width == 0 {
			col.Width = ColWidth
			customWidth = false

		} else {
			customWidth = true
		}
		worksheet.Cols.Col = append(worksheet.Cols.Col,
			xlsxCol{Min: col.Min,
				Max:          col.Max,
				Hidden:       col.Hidden,
				Width:        col.Width,
				CustomWidth:  customWidth,
				Collapsed:    col.Collapsed,
				OutlineLevel: col.OutlineLevel,
				Style:        XfId,
			})

		if col.OutlineLevel > maxLevelCol {
			maxLevelCol = col.OutlineLevel
		}
	}

	for r, row := range s.Rows {
		if r > maxRow {
			maxRow = r
		}
		xRow := xlsxRow{}
		xRow.R = r + 1
		if row.isCustom {
			xRow.CustomHeight = true
			xRow.Ht = fmt.Sprintf("%g", row.Height)
		}
		xRow.OutlineLevel = row.OutlineLevel
		if row.OutlineLevel > maxLevelRow {
			maxLevelRow = row.OutlineLevel
		}
		for c, cell := range row.Cells {
			XfId := colsXfIdList[c]

			// generate NumFmtId and add new NumFmt
			xNumFmt := styles.newNumFmt(cell.NumFmt)

			style := cell.style
			if style != nil {
				XfId = handleStyleForXLSX(style, xNumFmt.NumFmtId, styles)
			} else if len(cell.NumFmt) > 0 && !compareFormatString(s.Cols[c].numFmt, cell.NumFmt) {
				XfId = handleNumFmtIdForXLSX(xNumFmt.NumFmtId, styles)
			}

			if c > maxCell {
				maxCell = c
			}
			xC := xlsxC{
				S: XfId,
				R: GetCellIDStringFromCoords(c, r),
			}
			if cell.formula != "" {
				xC.F = &xlsxF{Content: cell.formula}
			}
			switch cell.cellType {
			case CellTypeInline:
				// Inline strings are turned into shared strings since they are more efficient.
				// This is what Excel does as well.
				fallthrough
			case CellTypeString:
				if len(cell.Value) > 0 {
					xC.V = strconv.Itoa(refTable.AddString(cell.Value))
				}
				xC.T = "s"
			case CellTypeNumeric:
				// Numeric is the default, so the type can be left blank
				xC.V = cell.Value
			case CellTypeBool:
				xC.V = cell.Value
				xC.T = "b"
			case CellTypeError:
				xC.V = cell.Value
				xC.T = "e"
			case CellTypeDate:
				xC.V = cell.Value
				xC.T = "d"
			case CellTypeStringFormula:
				xC.V = cell.Value
				xC.T = "str"
			default:
				panic(errors.New("unknown cell type cannot be marshaled"))
			}

			xRow.C = append(xRow.C, xC)

			if cell.HMerge > 0 || cell.VMerge > 0 {
				// r == rownum, c == colnum
				mc := xlsxMergeCell{}
				start := GetCellIDStringFromCoords(c, r)
				endCol := c + cell.HMerge
				endRow := r + cell.VMerge
				end := GetCellIDStringFromCoords(endCol, endRow)
				mc.Ref = start + ":" + end
				if worksheet.MergeCells == nil {
					worksheet.MergeCells = &xlsxMergeCells{}
				}
				worksheet.MergeCells.Cells = append(worksheet.MergeCells.Cells, mc)
			}
		}
		xSheet.Row = append(xSheet.Row, xRow)
	}

	// Update sheet format with the freshly determined max levels
	s.SheetFormat.OutlineLevelCol = maxLevelCol
	s.SheetFormat.OutlineLevelRow = maxLevelRow
	// .. and then also apply this to the xml worksheet
	worksheet.SheetFormatPr.OutlineLevelCol = s.SheetFormat.OutlineLevelCol
	worksheet.SheetFormatPr.OutlineLevelRow = s.SheetFormat.OutlineLevelRow

	if worksheet.MergeCells != nil {
		worksheet.MergeCells.Count = len(worksheet.MergeCells.Cells)
	}

	if s.AutoFilter != nil {
		worksheet.AutoFilter = &xlsxAutoFilter{Ref: fmt.Sprintf("%v:%v", s.AutoFilter.TopLeftCell, s.AutoFilter.BottomRightCell)}
	}

	worksheet.SheetData = xSheet
	dimension := xlsxDimension{}
	dimension.Ref = "A1:" + GetCellIDStringFromCoords(maxCell, maxRow)
	if dimension.Ref == "A1:A1" {
		dimension.Ref = "A1"
	}
	worksheet.Dimension = dimension
	return worksheet
}

func handleStyleForXLSX(style *Style, NumFmtId int, styles *xlsxStyleSheet) (XfId int) {
	xFont, xFill, xBorder, xCellXf := style.makeXLSXStyleElements()
	fontId := styles.addFont(xFont)
	fillId := styles.addFill(xFill)

	// HACK - adding light grey fill, as in OO and Google
	greyfill := xlsxFill{}
	greyfill.PatternFill.PatternType = "lightGray"
	styles.addFill(greyfill)

	borderId := styles.addBorder(xBorder)
	xCellXf.FontId = fontId
	xCellXf.FillId = fillId
	xCellXf.BorderId = borderId
	xCellXf.NumFmtId = NumFmtId
	// apply the numFmtId when it is not the default cellxf
	if xCellXf.NumFmtId > 0 {
		xCellXf.ApplyNumberFormat = true
	}

	xCellXf.Alignment.Horizontal = style.Alignment.Horizontal
	xCellXf.Alignment.Indent = style.Alignment.Indent
	xCellXf.Alignment.ShrinkToFit = style.Alignment.ShrinkToFit
	xCellXf.Alignment.TextRotation = style.Alignment.TextRotation
	xCellXf.Alignment.Vertical = style.Alignment.Vertical
	xCellXf.Alignment.WrapText = style.Alignment.WrapText

	XfId = styles.addCellXf(xCellXf)
	return
}

func handleNumFmtIdForXLSX(NumFmtId int, styles *xlsxStyleSheet) (XfId int) {
	xCellXf := makeXLSXCellElement()
	xCellXf.NumFmtId = NumFmtId
	if xCellXf.NumFmtId > 0 {
		xCellXf.ApplyNumberFormat = true
	}
	XfId = styles.addCellXf(xCellXf)
	return
}
<|endoftext|>


<commit_before>package scene

import (
	"image"
	"image/color"

	"golang.org/x/mobile/asset"

	"github.com/pankona/gomo-simra/simra"
)

const (
	// ScreenWidth is screen width
	ScreenWidth = 1080 / 2
	// ScreenHeight is screen height
	ScreenHeight = 1920 / 2
)

// Title represents a scene object for Title
type Title struct {
	simra     simra.Simraer
	audio     simra.Audioer
	isPlaying bool
}

// Initialize initializes title scene
// This is called from simra.
// simra.SetDesiredScreenSize should be called to determine
// screen size of this scene.
func (title *Title) Initialize(sim simra.Simraer) {
	title.simra = sim
	title.simra.SetDesiredScreenSize(ScreenWidth, ScreenHeight)
	// initialize sprites
	title.initialize()
}

func (title *Title) initialize() {

	title.simra.AddTouchListener(title)

	sprite := title.simra.NewSprite()
	sprite.SetScale(ScreenWidth, 80)
	sprite.SetPosition(ScreenWidth/2, ScreenHeight/2)
	title.simra.AddSprite(sprite)
	s := sprite.GetScale()
	tex := title.simra.NewTextTexture("tap to play sound",
		60, color.RGBA{255, 0, 0, 255}, image.Rect(0, 0, s.W, s.H))
	sprite.ReplaceTexture(tex)

}

// Drive is called from simra.
// This is used to update sprites position.
// Thsi will be called 60 times per sec.
func (title *Title) Drive() {
}

// OnTouchBegin is called when Title scene is Touched.
func (title *Title) OnTouchBegin(x, y float32) {
}

// OnTouchMove is called when Title scene is Touched and moved.
func (title *Title) OnTouchMove(x, y float32) {
}

// OnTouchEnd is called when Title scene is Touched and it is released.
func (title *Title) OnTouchEnd(x, y float32) {
	if title.isPlaying {
		err := title.audio.Stop()
		if err != nil {
			panic(err.Error())
		}
		title.isPlaying = false

	} else {
		title.audio = simra.NewAudio()
		resource, err := asset.Open("test_se.mp3")
		if err != nil {
			panic(err.Error())
		}

		err = title.audio.Play(resource, true, func(err error) {
			title.isPlaying = false
		})
		if err != nil {
			panic(err)
		}
		title.isPlaying = true
	}
}
<commit_msg>use short receiver name for audio<commit_after>package scene

import (
	"image"
	"image/color"

	"golang.org/x/mobile/asset"

	"github.com/pankona/gomo-simra/simra"
)

const (
	// ScreenWidth is screen width
	ScreenWidth = 1080 / 2
	// ScreenHeight is screen height
	ScreenHeight = 1920 / 2
)

// Title represents a scene object for Title
type Title struct {
	simra     simra.Simraer
	audio     simra.Audioer
	isPlaying bool
}

// Initialize initializes title scene
// This is called from simra.
// simra.SetDesiredScreenSize should be called to determine
// screen size of this scene.
func (t *Title) Initialize(sim simra.Simraer) {
	t.simra = sim
	t.simra.SetDesiredScreenSize(ScreenWidth, ScreenHeight)
	// initialize sprites
	t.initialize()
}

func (t *Title) initialize() {

	t.simra.AddTouchListener(t)

	sprite := t.simra.NewSprite()
	sprite.SetScale(ScreenWidth, 80)
	sprite.SetPosition(ScreenWidth/2, ScreenHeight/2)
	t.simra.AddSprite(sprite)
	s := sprite.GetScale()
	tex := t.simra.NewTextTexture("tap to play sound",
		60, color.RGBA{255, 0, 0, 255}, image.Rect(0, 0, s.W, s.H))
	sprite.ReplaceTexture(tex)

}

// Drive is called from simra.
// This is used to update sprites position.
// Thsi will be called 60 times per sec.
func (t *Title) Drive() {
}

// OnTouchBegin is called when Title scene is Touched.
func (t *Title) OnTouchBegin(x, y float32) {
}

// OnTouchMove is called when Title scene is Touched and moved.
func (t *Title) OnTouchMove(x, y float32) {
}

// OnTouchEnd is called when Title scene is Touched and it is released.
func (t *Title) OnTouchEnd(x, y float32) {
	if t.isPlaying {
		err := t.audio.Stop()
		if err != nil {
			panic(err.Error())
		}
		t.isPlaying = false

	} else {
		t.audio = simra.NewAudio()
		resource, err := asset.Open("test_se.mp3")
		if err != nil {
			panic(err.Error())
		}

		err = t.audio.Play(resource, true, func(err error) {
			t.isPlaying = false
		})
		if err != nil {
			panic(err)
		}
		t.isPlaying = true
	}
}
<|endoftext|>


<commit_before>package wc

import (
	"bufio"
	"io"
	"os"
	"runtime"
	"sync"
	"sync/atomic"
	"unicode/utf8"
)

type Counter struct {
	f *os.File

	Multibytes uint64
	Bytes      uint64
	Lines      uint64
	Words      uint64
}

var BufferSize = 1 << 20

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
}

func NewCounter(f io.Reader) *Counter {
	return &Counter{
		f: f,
	}
}

func (c *Counter) Count(count_multibytes, count_bytes, count_lines, count_words bool) error {

	workers, wg := runtime.NumCPU()*2, new(sync.WaitGroup)

	wg.Add(workers)

	buffers := make(chan []byte, workers<<3)

	for i := 0; i < workers; i++ {
		go func() {

			var multibyte_ct, byte_ct, line_ct, word_ct uint64

			for buf := range buffers {

				if count_multibytes {
					multibyte_ct += uint64(utf8.RuneCount(buf))
				}
				if count_bytes {
					byte_ct += uint64(len(buf))
				}

				if count_words {
					var in_word bool
					for _, c := range buf {
						if isSpace(c) {
							if c == '\n' {
								line_ct++
							}
							in_word = false
						} else if !in_word {
							word_ct++
							in_word = true
						}
					}
				} else if count_lines {
					for _, c := range buf {
						if c == '\n' {
							line_ct++
						}
					}
				}

			}

			atomic.AddUint64(&c.Multibytes, multibyte_ct)
			atomic.AddUint64(&c.Lines, line_ct)
			atomic.AddUint64(&c.Words, word_ct)
			atomic.AddUint64(&c.Bytes, byte_ct)

			wg.Done()
		}()
	}

	br := bufio.NewReaderSize(c.f, BufferSize)

	for {
		buf := make([]byte, BufferSize)

		n, err := br.Read(buf)
		if err != nil && err != io.EOF {
			return err
		}
		if n == 0 {
			break
		}
		buf = buf[:n]

		// read to a newline to prevent
		// spanning a word across two buffers
		if count_words && buf[len(buf)-1] != '\n' {
			extra, err := br.ReadBytes('\n')
			if err != nil && err != io.EOF {
				return err
			}
			buf = append(buf, extra...)
		}

		buffers <- buf
	}

	close(buffers)
	wg.Wait()

	return nil

}

// isspace() man page spec
// http://linux.die.net/man/3/isspace
func isSpace(c byte) bool {
	return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == '\f'
}
<commit_msg>better buffer size and fixing io.Reader bug<commit_after>package wc

import (
	"bufio"
	"io"
	"os"
	"runtime"
	"sync"
	"sync/atomic"
	"unicode/utf8"
)

type Counter struct {
	f *os.File

	Multibytes uint64
	Bytes      uint64
	Lines      uint64
	Words      uint64
}

var BufferSize = 4 << 20

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
}

func NewCounter(f *os.File) *Counter {
	return &Counter{
		f: f,
	}
}

func (c *Counter) Count(count_multibytes, count_bytes, count_lines, count_words bool) error {

	workers, wg := runtime.NumCPU()*2, new(sync.WaitGroup)

	wg.Add(workers)

	buffers := make(chan []byte, workers<<3)

	for i := 0; i < workers; i++ {
		go func() {

			var multibyte_ct, byte_ct, line_ct, word_ct uint64

			for buf := range buffers {

				if count_multibytes {
					multibyte_ct += uint64(utf8.RuneCount(buf))
				}
				if count_bytes {
					byte_ct += uint64(len(buf))
				}

				if count_words {
					var in_word bool
					for _, c := range buf {
						if isSpace(c) {
							if c == '\n' {
								line_ct++
							}
							in_word = false
						} else if !in_word {
							word_ct++
							in_word = true
						}
					}
				} else if count_lines {
					for _, c := range buf {
						if c == '\n' {
							line_ct++
						}
					}
				}

			}

			atomic.AddUint64(&c.Multibytes, multibyte_ct)
			atomic.AddUint64(&c.Lines, line_ct)
			atomic.AddUint64(&c.Words, word_ct)
			atomic.AddUint64(&c.Bytes, byte_ct)

			wg.Done()
		}()
	}

	br := bufio.NewReaderSize(c.f, BufferSize)

	for {
		buf := make([]byte, BufferSize)

		n, err := br.Read(buf)
		if err != nil && err != io.EOF {
			return err
		}
		if n == 0 {
			break
		}
		buf = buf[:n]

		// read to a newline to prevent
		// spanning a word across two buffers
		if count_words && buf[len(buf)-1] != '\n' {
			extra, err := br.ReadBytes('\n')
			if err != nil && err != io.EOF {
				return err
			}
			buf = append(buf, extra...)
		}

		buffers <- buf
	}

	close(buffers)
	wg.Wait()

	return nil

}

// isspace() man page spec
// http://linux.die.net/man/3/isspace
func isSpace(c byte) bool {
	return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == '\f'
}
<|endoftext|>


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

package unsplash

import (
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

// Response has pagination information whenever applicable
type Response struct {
	httpResponse                            *http.Response
	HasNextPage                             bool
	body                                    *[]byte
	FirstPage, LastPage, NextPage, PrevPage int
	err                                     error
	RateLimit                               int
	RateLimitRemaining                      int
}

func (r *Response) checkForErrors() error {
	switch r.httpResponse.StatusCode {

	case 401:
		return &AuthorizationError{ErrString: "401: Unauthorized request"}

	case 403:
		if r.RateLimitRemaining == 0 {
			return &RateLimitError{ErrString: "403: Rate limit exhausted"}
		}

		return &AuthorizationError{ErrString: "403: Access forbidden request"}

	case 404:
		return &NotFoundError{ErrString: "404: The cat got tired of the Laser"}

	}
	return nil
}

func newResponse(r *http.Response) (*Response, error) {
	if nil == r {
		return nil,
			&IllegalArgumentError{ErrString: "*http.Response cannot be null"}
	}
	resp := new(Response)
	resp.httpResponse = r
	//populate first
	resp.populatePagingInfo()
	resp.populateRateLimits()
	//now check for errors
	err := resp.checkForErrors()
	if err != nil {
		return nil, err
	}
	//looks good, read the response
	buf, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return nil, err
	}
	resp.body = &buf
	return resp, nil
}

func (r *Response) populateRateLimits() {
	//fails silently
	maxLimit, ok := r.httpResponse.Header["X-Ratelimit-Limit"]
	if ok && len(maxLimit) == 1 {
		r.RateLimit, _ = strconv.Atoi(maxLimit[0])
	}
	rateRemaining, ok := r.httpResponse.Header["X-Ratelimit-Remaining"]
	if ok && len(rateRemaining) == 1 {
		r.RateLimitRemaining, _ = strconv.Atoi(rateRemaining[0])
	}
}

func (r *Response) populatePagingInfo() {
	//fails silently
	rawLinks, ok := r.httpResponse.Header["Link"]
	if !ok || 0 == len(rawLinks) {
		return
	}

	links := strings.Split(rawLinks[0], ",") //TODO why is Headers returning []string?

	for _, link := range links {
		parts := strings.Split(link, ";")
		if !strings.Contains(parts[0], "page") && !strings.Contains(parts[1], "rel=") {
			continue
		}
		href := parts[0]
		//strip out '<' and '>'
		href = href[strings.Index(href, "<")+1 : strings.Index(href, ">")]
		url, err := url.Parse(href)
		if err != nil {
			continue
		}
		pageString := url.Query().Get("page")
		pageNumber, err := strconv.Atoi(string(pageString))
		if err != nil {
			continue
		}

		switch strings.TrimSpace(parts[1]) {
		case `rel="first"`:
			r.FirstPage = pageNumber
		case `rel="last"`:
			r.LastPage = pageNumber
		case `rel="next"`:
			r.NextPage = pageNumber
			r.HasNextPage = true
		case `rel="prev"`:
			r.PrevPage = pageNumber
		default:
			continue
		}
	}
}
<commit_msg>Improved error processing; Not really, onus on the dev-user<commit_after>// Copyright (c) 2017 Hardik Bagdi <hbagdi1@binghamton.edu>
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

package unsplash

import (
	"bytes"
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

// Response has pagination information whenever applicable
type Response struct {
	httpResponse                            *http.Response
	HasNextPage                             bool
	body                                    *[]byte
	FirstPage, LastPage, NextPage, PrevPage int
	err                                     error
	RateLimit                               int
	RateLimitRemaining                      int
}

func (r *Response) checkForErrors() error {
	switch r.httpResponse.StatusCode {
	case 200, 201, 202, 204, 205:
		return nil
	case 401:
		return &AuthorizationError{ErrString: errStringHelper(r.httpResponse.StatusCode, "Unauthorized request", r.body)}
	case 403:
		if r.RateLimitRemaining == 0 {
			return &RateLimitError{ErrString: errStringHelper(r.httpResponse.StatusCode, "Rate limit exhausted", r.body)}
		}

		return &AuthorizationError{ErrString: errStringHelper(r.httpResponse.StatusCode, "Access forbidden request", r.body)}

	case 404:
		return &NotFoundError{ErrString: errStringHelper(r.httpResponse.StatusCode, "The cat got tired of the Laser", r.body)}
	default:
		return errors.New(errStringHelper(r.httpResponse.StatusCode, "API returned an error", r.body))

	}
}
func errStringHelper(statusCode int, msg string, errBody *[]byte) string {
	var buf bytes.Buffer
	//XXX Writes can fail?
	buf.WriteString(strconv.Itoa(statusCode))
	buf.WriteString(": ")
	buf.WriteString(msg)
	buf.WriteString(", Body: ")
	buf.Write(*errBody)
	return buf.String()
}

func newResponse(r *http.Response) (*Response, error) {
	if nil == r {
		return nil,
			&IllegalArgumentError{ErrString: "*http.Response cannot be null"}
	}
	resp := new(Response)
	resp.httpResponse = r
	//populate first
	resp.populatePagingInfo()
	resp.populateRateLimits()
	//read the response
	buf, err := ioutil.ReadAll(resp.httpResponse.Body)
	if err != nil {
		return nil, err
	}
	resp.body = &buf
	//now check for errors
	err = resp.checkForErrors()
	if err != nil {
		return nil, err
	}
	return resp, nil
}

func (r *Response) populateRateLimits() {
	//fails silently
	maxLimit, ok := r.httpResponse.Header["X-Ratelimit-Limit"]
	if ok && len(maxLimit) == 1 {
		r.RateLimit, _ = strconv.Atoi(maxLimit[0])
	}
	rateRemaining, ok := r.httpResponse.Header["X-Ratelimit-Remaining"]
	if ok && len(rateRemaining) == 1 {
		r.RateLimitRemaining, _ = strconv.Atoi(rateRemaining[0])
	}
}

func (r *Response) populatePagingInfo() {
	//fails silently
	rawLinks, ok := r.httpResponse.Header["Link"]
	if !ok || 0 == len(rawLinks) {
		return
	}

	links := strings.Split(rawLinks[0], ",") //TODO why is Headers returning []string?

	for _, link := range links {
		parts := strings.Split(link, ";")
		if !strings.Contains(parts[0], "page") && !strings.Contains(parts[1], "rel=") {
			continue
		}
		href := parts[0]
		//strip out '<' and '>'
		href = href[strings.Index(href, "<")+1 : strings.Index(href, ">")]
		url, err := url.Parse(href)
		if err != nil {
			continue
		}
		pageString := url.Query().Get("page")
		pageNumber, err := strconv.Atoi(string(pageString))
		if err != nil {
			continue
		}

		switch strings.TrimSpace(parts[1]) {
		case `rel="first"`:
			r.FirstPage = pageNumber
		case `rel="last"`:
			r.LastPage = pageNumber
		case `rel="next"`:
			r.NextPage = pageNumber
			r.HasNextPage = true
		case `rel="prev"`:
			r.PrevPage = pageNumber
		default:
			continue
		}
	}
}
<|endoftext|>


<commit_before>//package shout provides a broadcast channel that works in select
//statements.
package shout

//Shout represents a broadcast channel. Each Shout instance has a
//goroutine that takes messages from the Send channel and transmits
//them to all subscribed Listen channels.
type Shout struct {
	subscribers map[chan interface{}]bool
	sub         chan chan interface{}
	unsub       chan chan interface{}
	send        chan interface{}
}

//Send returns the broadcast channel. All Listen channels receive
//messages sent on this channel. Closing this channel causes a panic.
//Use the Close() method to close down both the Send channel and all
//Listen channels.
func (b *Shout) Send() chan<- interface{} {
	return b.send
}

//run is the Shout event loop. It dies when unsub is closed.
func (s *Shout) run() {
	for {
		select {
		case sub := <-s.sub:
			s.subscribers[sub] = true
		case unsub, ok := <-s.unsub:
			if !ok {
				return
			}
			delete(s.subscribers, unsub)
		case msg, ok := <-s.send:
			if !ok {
				panic("Send channel is closed")
			}
			for key := range s.subscribers {
				key <- msg
			}
		}
	}
}

//New creates a Shout with the given buffer size on the Send channel.
func New(n int) *Shout {
	s := Shout{}
	s.subscribers = make(map[chan interface{}]bool)
	s.sub = make(chan chan interface{})
	s.unsub = make(chan chan interface{})
	s.send = make(chan interface{}, n)
	go s.run()
	return &s
}

//Listen returns a new Listen channel with the given buffer size.
func (s *Shout) Listen(n int) *Listen {
	c := make(chan interface{}, n)
	s.sub <- c
	return &Listen{s, c}
}

//Close closes the Shout broadcast channel and all subscriber channels.
func (s *Shout) Close() {
	for k := range s.subscribers {
		close(k)
	}
	close(s.unsub) //this causes run() to return
	close(s.sub)
	close(s.send)
}

//Listen is a receiving channel for Shout broadcast messages.
type Listen struct {
	s   *Shout
	rcv chan interface{}
}

//Rcv returns the receiving channel for Shout broadcast messages.
func (c *Listen) Rcv() <-chan interface{} {
	return c.rcv
}

//Close unsubscribes Listen from a Shout channel. You should always
//Close an unused Listen, because eventually Shout will block trying to
//send a message to it, and no other subscribed Listen channels will
//receive messages. Alternatively, closing the Shout this Listen is
//subscribed to will close the Listen.
func (c *Listen) Close() {
	c.s.unsub <- c.rcv
	close(c.rcv)
}
<commit_msg>Use done chan for run(), sync subscribe/unsubscribe<commit_after>//package shout provides a broadcast channel that works in select
//statements.
package shout

import "sync"

//Shout represents a broadcast channel. Each Shout instance has a
//goroutine that takes messages from the Send channel and transmits
//them to all subscribed Listen channels.
type Shout struct {
	msub        sync.Mutex //subscribers mutex
	subscribers map[chan interface{}]bool
	send        chan interface{}
	done        chan struct{}
}

//Send returns the broadcast channel. All Listen channels receive
//messages sent on this channel. Closing this channel causes a panic.
//Use the Close() method to close down both the Send channel and all
//Listen channels.
func (b *Shout) Send() chan<- interface{} {
	return b.send
}

//run is the Shout event loop. It returns when it receives a message
//on s.done.
func (s *Shout) run() {
	for {
		select {
		case msg, ok := <-s.send:
			if !ok {
				panic("Send channel is closed")
			}
			s.msub.Lock()
			for key := range s.subscribers {
				key <- msg
			}
			s.msub.Unlock()
		case <-s.done:
			return
		}
	}
}

//New creates a Shout with the given buffer size on the Send channel.
func New(n int) *Shout {
	s := Shout{}
	s.subscribers = make(map[chan interface{}]bool)
	s.send = make(chan interface{}, n)
	s.done = make(chan struct{})
	go s.run()
	return &s
}

//Listen returns a new Listen channel with the given buffer size.
func (s *Shout) Listen(n int) *Listen {
	s.msub.Lock()
	defer s.msub.Unlock()
	c := make(chan interface{}, n)
	s.subscribers[c] = true
	return &Listen{s, c}
}

//Close closes the Shout broadcast channel and all subscriber channels.
func (s *Shout) Close() {
	s.msub.Lock()
	defer s.msub.Unlock()
	for k := range s.subscribers {
		close(k)
	}
	//Tell run() to return. Can't do close(s.done) because the
	//close(s.send) might be processed by run() first, causing a panic.
	s.done <- struct{}{}
	close(s.send)
}

//Listen is a receiving channel for Shout broadcast messages.
type Listen struct {
	s   *Shout
	rcv chan interface{}
}

//Rcv returns the receiving channel for Shout broadcast messages.
func (c *Listen) Rcv() <-chan interface{} {
	return c.rcv
}

//Close unsubscribes Listen from a Shout channel. You should always
//Close an unused Listen, because eventually Shout will block trying to
//send a message to it, and no other subscribed Listen channels will
//receive messages.
func (c *Listen) Close() {
	c.s.msub.Lock()
	defer c.s.msub.Unlock()
	delete(c.s.subscribers, c.rcv)
	close(c.rcv)
}
<|endoftext|>


<commit_before>// Package validate provides routines for validating tweets
package validate

import (
	"github.com/kylemcc/twitter-text-go/extract"
	"strings"
	"unicode/utf8"
)

const (
	maxLength           = 140
	shortUrlLength      = 22
	shortHttpsUrlLength = 23
)

// Returns the length of the string as it would be displayed. This is equivilent to the length of the Unicode NFC
// (See: http://www.unicode.org/reports/tr15). This is needed in order to consistently calculate the length of a
// string no matter which actual form was transmitted. For example:
//
//     U+0065  Latin Small Letter E
// +   U+0301  Combining Acute Accent
// ----------
// =   2 bytes, 2 characters, displayed as é (1 visual glyph)
//     … The NFC of {U+0065, U+0301} is {U+00E9}, which is a single chracter and a +display_length+ of 1
//
// The string could also contain U+00E9 already, in which case the canonicalization will not change the value.
func TweetLength(text string) int {
    // TODO: input may require normalization. Will have to research
    // Go's implementation
	length := utf8.RuneCountInString(text)

	urls := extract.ExtractUrls(text)
	for _, url := range urls {
		length -= url.Range.Length()
		if strings.HasPrefix(url.Text, "https://") {
			length += shortHttpsUrlLength
		} else {
			length += shortUrlLength
		}
	}
	return length
}

func TweetIsValid(text string) bool {
	return false
}

func UsernameIsValid(username string) bool {
	return false
}

func ListIsValid(list string) bool {
	return false
}

func HashtagIsValid(hashtag string) bool {
	return false
}

func UrlIsValid(url string) bool {
	return false
}
<commit_msg>input does need to be normalized. the runtime doesn't normalize strings<commit_after>// Package validate provides routines for validating tweets
package validate

import (
	"code.google.com/p/go.text/unicode/norm"
	"github.com/kylemcc/twitter-text-go/extract"
	"strings"
	"unicode/utf8"
)

const (
	maxLength           = 140
	shortUrlLength      = 22
	shortHttpsUrlLength = 23
)

var formC = norm.NFC

// Returns the length of the string as it would be displayed. This is equivilent to the length of the Unicode NFC
// (See: http://www.unicode.org/reports/tr15). This is needed in order to consistently calculate the length of a
// string no matter which actual form was transmitted. For example:
//
//     U+0065  Latin Small Letter E
// +   U+0301  Combining Acute Accent
// ----------
// =   2 bytes, 2 characters, displayed as é (1 visual glyph)
//     … The NFC of {U+0065, U+0301} is {U+00E9}, which is a single chracter and a +display_length+ of 1
//
// The string could also contain U+00E9 already, in which case the canonicalization will not change the value.
func TweetLength(text string) int {
	length := utf8.RuneCountInString(formC.String(text))

	urls := extract.ExtractUrls(text)
	for _, url := range urls {
		length -= url.Range.Length()
		if strings.HasPrefix(url.Text, "https://") {
			length += shortHttpsUrlLength
		} else {
			length += shortUrlLength
		}
	}
	return length
}

func TweetIsValid(text string) bool {
	return false
}

func UsernameIsValid(username string) bool {
	return false
}

func ListIsValid(list string) bool {
	return false
}

func HashtagIsValid(hashtag string) bool {
	return false
}

func UrlIsValid(url string) bool {
	return false
}
<|endoftext|>


<commit_before>package bittrex

import (
	"encoding/json"
	"fmt"

	"github.com/thebotguys/signalr"
)

type OrderUpdate struct {
	Orderb
	Type int
}

type Fill struct {
	Orderb
	OrderType string
	Timestamp jTime
}

type ExchangeState struct {
	MarketName string
	Nounce     int
	Buys       []OrderUpdate
	Sells      []OrderUpdate
	Fills      []Fill
	Initial    bool
}

func (b *Bittrex) SubscribeExchangeUpdate(market string, dataCh chan<- ExchangeState, stop <-chan bool) error {
	client := signalr.NewWebsocketClient()
	sendUpdate := func(st ExchangeState) {
		select {
		case dataCh <- st:
		default:
		}
	}
	client.OnClientMethod = func(hub string, method string, messages []json.RawMessage) {
		if hub != "CoreHub" || method != "updateExchangeState" {
			return
		}
		for _, msg := range messages {
			var st ExchangeState
			if err := json.Unmarshal(msg, &st); err != nil {
				fmt.Println(err)
				continue
			}
			if st.MarketName != market {
				continue
			}
			sendUpdate(st)
		}
	}
	if err := client.Connect("https", WS_BASE, []string{WS_HUB}); err != nil {
		return err
	}
	defer client.Close()
	_, err := client.CallHub(WS_HUB, "SubscribeToExchangeDeltas", market)
	if err != nil {
		return err
	}
	msg, err := client.CallHub(WS_HUB, "QueryExchangeState", market)
	if err != nil {
		return err
	}
	var st ExchangeState
	if err := json.Unmarshal(msg, &st); err != nil {
		return err
	}
	st.Initial = true
	sendUpdate(st)
	<-stop
	return nil
}
<commit_msg>ws: remove log.<commit_after>package bittrex

import (
	"encoding/json"

	"github.com/thebotguys/signalr"
)

type OrderUpdate struct {
	Orderb
	Type int
}

type Fill struct {
	Orderb
	OrderType string
	Timestamp jTime
}

type ExchangeState struct {
	MarketName string
	Nounce     int
	Buys       []OrderUpdate
	Sells      []OrderUpdate
	Fills      []Fill
	Initial    bool
}

func (b *Bittrex) SubscribeExchangeUpdate(market string, dataCh chan<- ExchangeState, stop <-chan bool) error {
	client := signalr.NewWebsocketClient()
	sendUpdate := func(st ExchangeState) {
		select {
		case dataCh <- st:
		default:
		}
	}
	client.OnClientMethod = func(hub string, method string, messages []json.RawMessage) {
		if hub != "CoreHub" || method != "updateExchangeState" {
			return
		}
		for _, msg := range messages {
			var st ExchangeState
			if err := json.Unmarshal(msg, &st); err != nil {
				continue
			}
			if st.MarketName != market {
				continue
			}
			sendUpdate(st)
		}
	}
	if err := client.Connect("https", WS_BASE, []string{WS_HUB}); err != nil {
		return err
	}
	defer client.Close()
	_, err := client.CallHub(WS_HUB, "SubscribeToExchangeDeltas", market)
	if err != nil {
		return err
	}
	msg, err := client.CallHub(WS_HUB, "QueryExchangeState", market)
	if err != nil {
		return err
	}
	var st ExchangeState
	if err := json.Unmarshal(msg, &st); err != nil {
		return err
	}
	st.Initial = true
	sendUpdate(st)
	<-stop
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/russross/blackfriday"
)

const (
	ZSDIR  = ".zs"
	PUBDIR = ".pub"
)

type EvalFn func(args []string, vars map[string]string) (string, error)

func split2(s, delim string) (string, string) {
	parts := strings.SplitN(s, delim, 2)
	if len(parts) == 2 {
		return parts[0], parts[1]
	} else {
		return parts[0], ""
	}
}

func md(path, s string) (map[string]string, string) {
	url := path[:len(path)-len(filepath.Ext(path))] + ".html"
	v := map[string]string{
		"file":   path,
		"url":    url,
		"output": filepath.Join(PUBDIR, url),
		"layout": "index.html",
	}
	if strings.Index(s, "\n\n") == -1 {
		return map[string]string{}, s
	}
	header, body := split2(s, "\n\n")
	for _, line := range strings.Split(header, "\n") {
		key, value := split2(line, ":")
		v[strings.ToLower(strings.TrimSpace(key))] = strings.TrimSpace(value)
	}
	if strings.HasPrefix(v["url"], "./") {
		v["url"] = v["url"][2:]
	}
	return v, body
}

func render(s string, vars map[string]string, eval EvalFn) (string, error) {
	delim_open := "{{"
	delim_close := "}}"

	out := bytes.NewBuffer(nil)
	for {
		if from := strings.Index(s, delim_open); from == -1 {
			out.WriteString(s)
			return out.String(), nil
		} else {
			if to := strings.Index(s, delim_close); to == -1 {
				return "", fmt.Errorf("Close delim not found")
			} else {
				out.WriteString(s[:from])
				cmd := s[from+len(delim_open) : to]
				s = s[to+len(delim_close):]
				m := strings.Fields(cmd)
				if len(m) == 1 {
					if v, ok := vars[m[0]]; ok {
						out.WriteString(v)
						continue
					}
				}
				if res, err := eval(m, vars); err == nil {
					out.WriteString(res)
				} else {
					log.Println(err) // silent
				}
			}
		}
	}
}

func env(vars map[string]string) []string {
	env := []string{"ZS=" + os.Args[0], "ZS_OUTDIR=" + PUBDIR}
	env = append(env, os.Environ()...)
	if vars != nil {
		for k, v := range vars {
			env = append(env, "ZS_"+strings.ToUpper(k)+"="+v)
		}
	}
	return env
}

func run(cmd string, args []string, vars map[string]string, output io.Writer) error {
	var errbuf bytes.Buffer
	c := exec.Command(cmd, args...)
	c.Env = env(vars)
	c.Stdout = output
	c.Stderr = &errbuf

	err := c.Run()

	if errbuf.Len() > 0 {
		log.Println(errbuf.String())
	}

	if err != nil {
		return err
	}
	return nil
}

func eval(cmd []string, vars map[string]string) (string, error) {
	outbuf := bytes.NewBuffer(nil)
	err := run(path.Join(ZSDIR, cmd[0]), cmd[1:], vars, outbuf)
	if err != nil {
		if _, ok := err.(*exec.ExitError); ok {
			return "", err
		}
		outbuf = bytes.NewBuffer(nil)
		err := run(cmd[0], cmd[1:], vars, outbuf)
		// Return exit errors, but ignore if the command was not found
		if _, ok := err.(*exec.ExitError); ok {
			return "", err
		}
	}
	return outbuf.String(), nil
}

func buildMarkdown(path string) error {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	v, body := md(path, string(b))
	content, err := render(body, v, eval)
	if err != nil {
		return err
	}
	v["content"] = string(blackfriday.MarkdownBasic([]byte(content)))
	return buildPlain(filepath.Join(ZSDIR, v["layout"]), v)
}

func buildPlain(path string, vars map[string]string) error {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	content, err := render(string(b), vars, eval)
	if err != nil {
		return err
	}
	output := filepath.Join(PUBDIR, path)
	if s, ok := vars["output"]; ok {
		output = s
	}
	err = ioutil.WriteFile(output, []byte(content), 0666)
	if err != nil {
		return err
	}
	return nil
}

func copyFile(path string) (err error) {
	var in, out *os.File
	if in, err = os.Open(path); err == nil {
		defer in.Close()
		if out, err = os.Create(filepath.Join(PUBDIR, path)); err == nil {
			defer out.Close()
			_, err = io.Copy(out, in)
		}
	}
	return err
}

func buildAll(once bool) {
	lastModified := time.Unix(0, 0)
	modified := false
	for {
		os.Mkdir(PUBDIR, 0755)
		err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
			// ignore hidden files and directories
			if filepath.Base(path)[0] == '.' || strings.HasPrefix(path, ".") {
				return nil
			}

			if info.IsDir() {
				os.Mkdir(filepath.Join(PUBDIR, path), 0755)
				return nil
			} else if info.ModTime().After(lastModified) {
				if !modified {
					// About to be modified, so run pre-build hook
					run(filepath.Join(ZSDIR, "pre"), []string{}, nil, nil)
					modified = true
				}
				ext := filepath.Ext(path)
				if ext == ".md" || ext == ".mkd" {
					log.Println("mkd: ", path)
					return buildMarkdown(path)
				} else {
					log.Println("raw: ", path)
					return copyFile(path)
				}
			}
			return nil
		})
		if err != nil {
			log.Println("ERROR:", err)
		}
		if modified {
			// Something was modified, so post-build hook
			run(filepath.Join(ZSDIR, "post"), []string{}, nil, nil)
			modified = false
		}
		lastModified = time.Now()
		if once {
			break
		}
		time.Sleep(1 * time.Second)
	}
}

func main() {
	if len(os.Args) == 1 {
		fmt.Println(os.Args[0], "<command> [args]")
		return
	}
	cmd := os.Args[1]
	args := os.Args[2:]
	switch cmd {
	case "build":
		buildAll(true)
	case "watch":
		buildAll(false) // pass duration
	case "var":
		if len(args) == 0 {
			log.Println("ERROR: filename expected")
			return
		}
		if b, err := ioutil.ReadFile(args[0]); err == nil {
			vars, _ := md(args[0], string(b))
			if len(args) > 1 {
				for _, a := range args[1:] {
					fmt.Println(vars[a])
				}
			} else {
				for k, v := range vars {
					fmt.Println(k + ":" + v)
				}
			}
		} else {
			log.Println(err)
		}
	default:
		err := run(path.Join(ZSDIR, cmd), args, map[string]string{}, os.Stdout)
		if err != nil {
			log.Println(err)
		}
	}
}
<commit_msg>added rendering support for html and xml<commit_after>package main

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/russross/blackfriday"
)

const (
	ZSDIR  = ".zs"
	PUBDIR = ".pub"
)

type EvalFn func(args []string, vars map[string]string) (string, error)

func split2(s, delim string) (string, string) {
	parts := strings.SplitN(s, delim, 2)
	if len(parts) == 2 {
		return parts[0], parts[1]
	} else {
		return parts[0], ""
	}
}

func md(path, s string) (map[string]string, string) {
	url := path[:len(path)-len(filepath.Ext(path))] + ".html"
	v := map[string]string{
		"file":   path,
		"url":    url,
		"output": filepath.Join(PUBDIR, url),
		"layout": "index.html",
	}
	if strings.Index(s, "\n\n") == -1 {
		return map[string]string{}, s
	}
	header, body := split2(s, "\n\n")
	for _, line := range strings.Split(header, "\n") {
		key, value := split2(line, ":")
		v[strings.ToLower(strings.TrimSpace(key))] = strings.TrimSpace(value)
	}
	if strings.HasPrefix(v["url"], "./") {
		v["url"] = v["url"][2:]
	}
	return v, body
}

func render(s string, vars map[string]string, eval EvalFn) (string, error) {
	delim_open := "{{"
	delim_close := "}}"

	out := bytes.NewBuffer(nil)
	for {
		if from := strings.Index(s, delim_open); from == -1 {
			out.WriteString(s)
			return out.String(), nil
		} else {
			if to := strings.Index(s, delim_close); to == -1 {
				return "", fmt.Errorf("Close delim not found")
			} else {
				out.WriteString(s[:from])
				cmd := s[from+len(delim_open) : to]
				s = s[to+len(delim_close):]
				m := strings.Fields(cmd)
				if len(m) == 1 {
					if v, ok := vars[m[0]]; ok {
						out.WriteString(v)
						continue
					}
				}
				if res, err := eval(m, vars); err == nil {
					out.WriteString(res)
				} else {
					log.Println(err) // silent
				}
			}
		}
	}
}

func env(vars map[string]string) []string {
	env := []string{"ZS=" + os.Args[0], "ZS_OUTDIR=" + PUBDIR}
	env = append(env, os.Environ()...)
	if vars != nil {
		for k, v := range vars {
			env = append(env, "ZS_"+strings.ToUpper(k)+"="+v)
		}
	}
	return env
}

func run(cmd string, args []string, vars map[string]string, output io.Writer) error {
	var errbuf bytes.Buffer
	c := exec.Command(cmd, args...)
	c.Env = env(vars)
	c.Stdout = output
	c.Stderr = &errbuf

	err := c.Run()

	if errbuf.Len() > 0 {
		log.Println(errbuf.String())
	}

	if err != nil {
		return err
	}
	return nil
}

func eval(cmd []string, vars map[string]string) (string, error) {
	outbuf := bytes.NewBuffer(nil)
	err := run(path.Join(ZSDIR, cmd[0]), cmd[1:], vars, outbuf)
	if err != nil {
		if _, ok := err.(*exec.ExitError); ok {
			return "", err
		}
		outbuf = bytes.NewBuffer(nil)
		err := run(cmd[0], cmd[1:], vars, outbuf)
		// Return exit errors, but ignore if the command was not found
		if _, ok := err.(*exec.ExitError); ok {
			return "", err
		}
	}
	return outbuf.String(), nil
}

func buildMarkdown(path string) error {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	v, body := md(path, string(b))
	content, err := render(body, v, eval)
	if err != nil {
		return err
	}
	v["content"] = string(blackfriday.MarkdownBasic([]byte(content)))
	return buildPlain(filepath.Join(ZSDIR, v["layout"]), v)
}

func buildPlain(path string, vars map[string]string) error {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	content, err := render(string(b), vars, eval)
	if err != nil {
		return err
	}
	output := filepath.Join(PUBDIR, path)
	if s, ok := vars["output"]; ok {
		output = s
	}
	err = ioutil.WriteFile(output, []byte(content), 0666)
	if err != nil {
		return err
	}
	return nil
}

func copyFile(path string) (err error) {
	var in, out *os.File
	if in, err = os.Open(path); err == nil {
		defer in.Close()
		if out, err = os.Create(filepath.Join(PUBDIR, path)); err == nil {
			defer out.Close()
			_, err = io.Copy(out, in)
		}
	}
	return err
}

func buildAll(once bool) {
	lastModified := time.Unix(0, 0)
	modified := false
	for {
		os.Mkdir(PUBDIR, 0755)
		err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
			// ignore hidden files and directories
			if filepath.Base(path)[0] == '.' || strings.HasPrefix(path, ".") {
				return nil
			}

			if info.IsDir() {
				os.Mkdir(filepath.Join(PUBDIR, path), 0755)
				return nil
			} else if info.ModTime().After(lastModified) {
				if !modified {
					// About to be modified, so run pre-build hook
					run(filepath.Join(ZSDIR, "pre"), []string{}, nil, nil)
					modified = true
				}
				ext := filepath.Ext(path)
				if ext == ".md" || ext == ".mkd" {
					log.Println("mkd: ", path)
					return buildMarkdown(path)
				} else if ext == ".html" || ext == ".xml" {
					return buildPlain(path, map[string]string{})
				} else {
					log.Println("raw: ", path)
					return copyFile(path)
				}
			}
			return nil
		})
		if err != nil {
			log.Println("ERROR:", err)
		}
		if modified {
			// Something was modified, so post-build hook
			run(filepath.Join(ZSDIR, "post"), []string{}, nil, nil)
			modified = false
		}
		lastModified = time.Now()
		if once {
			break
		}
		time.Sleep(1 * time.Second)
	}
}

func main() {
	if len(os.Args) == 1 {
		fmt.Println(os.Args[0], "<command> [args]")
		return
	}
	cmd := os.Args[1]
	args := os.Args[2:]
	switch cmd {
	case "build":
		buildAll(true)
	case "watch":
		buildAll(false) // pass duration
	case "var":
		if len(args) == 0 {
			log.Println("ERROR: filename expected")
			return
		}
		if b, err := ioutil.ReadFile(args[0]); err == nil {
			vars, _ := md(args[0], string(b))
			if len(args) > 1 {
				for _, a := range args[1:] {
					fmt.Println(vars[a])
				}
			} else {
				for k, v := range vars {
					fmt.Println(k + ":" + v)
				}
			}
		} else {
			log.Println(err)
		}
	default:
		err := run(path.Join(ZSDIR, cmd), args, map[string]string{}, os.Stdout)
		if err != nil {
			log.Println(err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/rif/cache2go"
	"strconv"
)

func main() {
	cache := cache2go.Cache("myCache")
	cache.SetDataLoader(func(key interface{}) *cache2go.CacheItem {
		// Apply some clever loading logic here, e.g. read values for
		// this key from database, network or file
		val := "This is a test with key " + key.(string)

		// This helper method creates the cached item for us. Yay!
		item := cache2go.CreateCacheItem(key, 0, val)
		return &item
	})

	// Let's retrieve a few auto-generated items from the cache
	for i := 0; i < 10; i++ {
		res, err := cache.Value("someKey_" + strconv.Itoa(i))
		if err == nil {
			fmt.Println("Found value in cache:", res.Data())
		} else {
			fmt.Println("Error retrieving value from cache:", err)
		}
	}
}
<commit_msg>* More comments for example.<commit_after>package main

import (
	"fmt"
	"github.com/rif/cache2go"
	"strconv"
)

func main() {
	cache := cache2go.Cache("myCache")

	// The data loader gets called automatically whenever something
	// tries to retrieve a non-existing key from the cache
	cache.SetDataLoader(func(key interface{}) *cache2go.CacheItem {
		// Apply some clever loading logic here, e.g. read values for
		// this key from database, network or file
		val := "This is a test with key " + key.(string)

		// This helper method creates the cached item for us. Yay!
		item := cache2go.CreateCacheItem(key, 0, val)
		return &item
	})

	// Let's retrieve a few auto-generated items from the cache
	for i := 0; i < 10; i++ {
		res, err := cache.Value("someKey_" + strconv.Itoa(i))
		if err == nil {
			fmt.Println("Found value in cache:", res.Data())
		} else {
			fmt.Println("Error retrieving value from cache:", err)
		}
	}
}
<|endoftext|>


<commit_before>package decor

// StaticName returns name decorator.
//
//	`name` string to display
//
//	`wcc` optional WC config
func StaticName(name string, wcc ...WC) Decorator {
	return Name(name, wcc...)
}

// Name returns name decorator.
//
//	`name` string to display
//
//	`wcc` optional WC config
func Name(name string, wcc ...WC) Decorator {
	var wc WC
	for _, widthConf := range wcc {
		wc = widthConf
	}
	wc.Init()
	d := &nameDecorator{
		WC:  wc,
		msg: name,
	}
	return d
}

type nameDecorator struct {
	WC
	msg      string
	complete *string
}

func (d *nameDecorator) Decor(st *Statistics) string {
	if st.Completed && d.complete != nil {
		return d.FormatMsg(*d.complete)
	}
	return d.FormatMsg(d.msg)
}

func (d *nameDecorator) OnCompleteMessage(msg string) {
	d.complete = &msg
}
<commit_msg>remove StaticName<commit_after>package decor

// Name returns name decorator.
//
//	`name` string to display
//
//	`wcc` optional WC config
func Name(name string, wcc ...WC) Decorator {
	var wc WC
	for _, widthConf := range wcc {
		wc = widthConf
	}
	wc.Init()
	d := &nameDecorator{
		WC:  wc,
		msg: name,
	}
	return d
}

type nameDecorator struct {
	WC
	msg      string
	complete *string
}

func (d *nameDecorator) Decor(st *Statistics) string {
	if st.Completed && d.complete != nil {
		return d.FormatMsg(*d.complete)
	}
	return d.FormatMsg(d.msg)
}

func (d *nameDecorator) OnCompleteMessage(msg string) {
	d.complete = &msg
}
<|endoftext|>


<commit_before>package app

import (
	"fmt"
	"os"
	"runtime"
	"text/template"

	"github.com/Sirupsen/logrus"
	"github.com/docker/libcompose/version"
	"github.com/urfave/cli"
)

var versionTemplate = `Version:      {{.Version}} ({{.GitCommit}})
Go version:   {{.GoVersion}}
Built:        {{.BuildTime}}
OS/Arch:      {{.Os}}/{{.Arch}}`

// Version prints the libcompose version number and additionnal informations.
func Version(c *cli.Context) {
	if c.Bool("short") {
		fmt.Println(version.VERSION)
		return
	}

	tmpl, err := template.New("").Parse(versionTemplate)
	if err != nil {
		logrus.Fatal(err)
	}

	v := struct {
		Version   string
		GitCommit string
		GoVersion string
		BuildTime string
		Os        string
		Arch      string
	}{
		Version:   version.VERSION,
		GitCommit: version.GITCOMMIT,
		GoVersion: runtime.Version(),
		BuildTime: version.BUILDTIME,
		Os:        runtime.GOOS,
		Arch:      runtime.GOARCH,
	}

	if err := tmpl.Execute(os.Stdout, v); err != nil {
		logrus.Fatal(err)
	}
	fmt.Printf("\n")
	return
}
<commit_msg>Update Version signature to remove warning<commit_after>package app

import (
	"fmt"
	"os"
	"runtime"
	"text/template"

	"github.com/Sirupsen/logrus"
	"github.com/docker/libcompose/version"
	"github.com/urfave/cli"
)

var versionTemplate = `Version:      {{.Version}} ({{.GitCommit}})
Go version:   {{.GoVersion}}
Built:        {{.BuildTime}}
OS/Arch:      {{.Os}}/{{.Arch}}`

// Version prints the libcompose version number and additionnal informations.
func Version(c *cli.Context) error {
	if c.Bool("short") {
		fmt.Println(version.VERSION)
		return nil
	}

	tmpl, err := template.New("").Parse(versionTemplate)
	if err != nil {
		logrus.Fatal(err)
	}

	v := struct {
		Version   string
		GitCommit string
		GoVersion string
		BuildTime string
		Os        string
		Arch      string
	}{
		Version:   version.VERSION,
		GitCommit: version.GITCOMMIT,
		GoVersion: runtime.Version(),
		BuildTime: version.BUILDTIME,
		Os:        runtime.GOOS,
		Arch:      runtime.GOARCH,
	}

	if err := tmpl.Execute(os.Stdout, v); err != nil {
		logrus.Fatal(err)
	}
	fmt.Printf("\n")
	return nil
}
<|endoftext|>