<commit_before>package hammy

import (
	"fmt"
	"time"
	"net/http"
	"encoding/json"
	"github.com/ugorji/go-msgpack"
)

//Request handler object
type HttpServer struct{
	RHandler RequestHandler
}

//Request handler
func (h HttpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
		return
	}

	contentTypeHeader, headerFound := r.Header["Content-Type"]
	var contentType string
	if headerFound && len(contentTypeHeader) > 0 {
		contentType = contentTypeHeader[0]
	} else {
		contentType = "application/json"
	}

	type DataDecoder interface{
		Decode(interface{}) error
	}

	var dataDecoder DataDecoder
	switch contentType {
		case "application/json":
			dataDecoder = json.NewDecoder(r.Body)
		case "application/octet-stream":
			dataDecoder = msgpack.NewDecoder(r.Body, nil)
		default:
			http.Error(w, "Bad Request", http.StatusBadRequest)
			fmt.Fprintf(w, "Unsupported Content-Type\n")
			return
	}

	var data IncomingData
	err := dataDecoder.Decode(&data)
	if err != nil {
		http.Error(w, "Bad Request", http.StatusBadRequest)
		fmt.Fprintf(w, "%v\n", err);
		return
	}

	errs := h.RHandler.Handle(data)
	if len(errs) > 0 {
		//TODO: correct answer to client
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		fmt.Fprintf(w, "%v\n", errs);
		log.Printf("Internal Server Error: %v", errs)
		return
	}

	fmt.Fprint(w, "ok\n")
}

//Start http interface and lock goroutine untill fatal error
func StartHttp(rh RequestHandler, cfg Config) error {
	h := &HttpServer{
		RHandler: rh,
	}

	//Setup server
	s := &http.Server{
		Addr:				cfg.Http.Addr,
		Handler:			h,
		ReadTimeout:		30 * time.Second,
		WriteTimeout:		30 * time.Second,
		MaxHeaderBytes:		1 << 20,
	}

	return s.ListenAndServe()
}
<commit_msg>fix for previous commit<commit_after>package hammy

import (
	"fmt"
	"log"
	"time"
	"net/http"
	"encoding/json"
	"github.com/ugorji/go-msgpack"
)

//Request handler object
type HttpServer struct{
	RHandler RequestHandler
}

//Request handler
func (h HttpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
		return
	}

	contentTypeHeader, headerFound := r.Header["Content-Type"]
	var contentType string
	if headerFound && len(contentTypeHeader) > 0 {
		contentType = contentTypeHeader[0]
	} else {
		contentType = "application/json"
	}

	type DataDecoder interface{
		Decode(interface{}) error
	}

	var dataDecoder DataDecoder
	switch contentType {
		case "application/json":
			dataDecoder = json.NewDecoder(r.Body)
		case "application/octet-stream":
			dataDecoder = msgpack.NewDecoder(r.Body, nil)
		default:
			http.Error(w, "Bad Request", http.StatusBadRequest)
			fmt.Fprintf(w, "Unsupported Content-Type\n")
			return
	}

	var data IncomingData
	err := dataDecoder.Decode(&data)
	if err != nil {
		http.Error(w, "Bad Request", http.StatusBadRequest)
		fmt.Fprintf(w, "%v\n", err);
		return
	}

	errs := h.RHandler.Handle(data)
	if len(errs) > 0 {
		//TODO: correct answer to client
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		fmt.Fprintf(w, "%v\n", errs);
		log.Printf("Internal Server Error: %v", errs)
		return
	}

	fmt.Fprint(w, "ok\n")
}

//Start http interface and lock goroutine untill fatal error
func StartHttp(rh RequestHandler, cfg Config) error {
	h := &HttpServer{
		RHandler: rh,
	}

	//Setup server
	s := &http.Server{
		Addr:				cfg.Http.Addr,
		Handler:			h,
		ReadTimeout:		30 * time.Second,
		WriteTimeout:		30 * time.Second,
		MaxHeaderBytes:		1 << 20,
	}

	return s.ListenAndServe()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/bewuethr/advent-of-code/go/convert"
	"github.com/bewuethr/advent-of-code/go/ioutil"
	"github.com/bewuethr/advent-of-code/go/log"
	"github.com/bewuethr/advent-of-code/go/math"
)

func main() {
	scanner, err := ioutil.GetInputScanner()
	if err != nil {
		log.Die("getting scanner", err)
	}

	scanner.Scan()
	opCodesStr := strings.Split(scanner.Text(), ",")
	if err := scanner.Err(); err != nil {
		log.Die("reading input", err)
	}

	opCodes, err := convert.StrSliceToInt(opCodesStr)
	if err != nil {
		log.Die("converting string slice to int", err)
	}

	var max int
	for _, phases := range math.IntPermutations([]int{0, 1, 2, 3, 4}) {
		channels := []chan int{make(chan int)}
		for i := 0; i < 5; i++ {
			codesCopy := make([]int, len(opCodes))
			copy(codesCopy, opCodes)
			channels = append(channels, make(chan int))
			go runProgram(codesCopy, phases[i], channels[i], channels[i+1])
		}

		channels[0] <- 0
		max = math.IntMax(max, <-channels[len(channels)-1])
	}
	fmt.Println(max)
}

const (
	add         = 1
	mult        = 2
	input       = 3
	output      = 4
	jumpIfTrue  = 5
	jumpIfFalse = 6
	lessThan    = 7
	equals      = 8
	halt        = 99

	positionMode  = 0
	immediateMode = 1
)

var nargs = map[int]int{
	add:         3,
	mult:        3,
	input:       1,
	output:      1,
	jumpIfTrue:  2,
	jumpIfFalse: 2,
	lessThan:    3,
	equals:      3,
	halt:        0,
}

func runProgram(codes []int, phase int, in <-chan int, out chan<- int) {
	firstInput := true
	idx := 0
	for {
		code, modes := parseValue(codes[idx])
		params := getParams(codes, idx, modes)

		// 	fmt.Printf("codes: %v\nopcode: %d\ncode(idx): %d(%d)\nparams: %v\n\n", codes, codes[idx], code, idx, params)

		switch code {
		case halt:
			close(out)
			return

		case add:
			codes[codes[idx+3]] = params[0] + params[1]
			idx += nargs[add] + 1

		case mult:
			codes[codes[idx+3]] = params[0] * params[1]
			idx += nargs[mult] + 1

		case input:
			if firstInput {
				codes[codes[idx+1]] = phase
				firstInput = false
			} else {
				codes[codes[idx+1]] = <-in
			}
			idx += nargs[input] + 1

		case output:
			out <- params[0]
			idx += nargs[output] + 1

		case jumpIfTrue:
			if params[0] != 0 {
				idx = params[1]
			} else {
				idx += nargs[jumpIfTrue] + 1
			}

		case jumpIfFalse:
			if params[0] == 0 {
				idx = params[1]
			} else {
				idx += nargs[jumpIfFalse] + 1
			}

		case lessThan:
			if params[0] < params[1] {
				codes[codes[idx+3]] = 1
			} else {
				codes[codes[idx+3]] = 0
			}
			idx += nargs[lessThan] + 1

		case equals:
			if params[0] == params[1] {
				codes[codes[idx+3]] = 1
			} else {
				codes[codes[idx+3]] = 0
			}
			idx += nargs[equals] + 1

		default:
			panic(fmt.Sprintf("illegal opcode %d", codes[idx]))
		}
	}
}

func parseValue(val int) (code int, modes []int) {
	code = val % 100
	if valStr := strconv.Itoa(val); len(valStr) > 2 {
		valStr = valStr[:len(valStr)-2]

		var modesStr []string
		for _, m := range valStr {
			modesStr = append([]string{string(m)}, modesStr...)
		}

		var err error
		modes, err = convert.StrSliceToInt(modesStr)
		if err != nil {
			log.Die("converting modes to int", err)
		}
	}

	for len(modes) < nargs[code] {
		modes = append(modes, 0)
	}

	return code, modes
}

func getParams(codes []int, idx int, modes []int) []int {
	var params []int

	for i := 0; i < len(modes); i++ {
		var param int
		if modes[i] == immediateMode {
			param = codes[idx+i+1]
		} else {
			param = codes[codes[idx+i+1]]
		}
		params = append(params, param)
	}

	return params
}
<commit_msg>Remove debug line<commit_after>package main

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/bewuethr/advent-of-code/go/convert"
	"github.com/bewuethr/advent-of-code/go/ioutil"
	"github.com/bewuethr/advent-of-code/go/log"
	"github.com/bewuethr/advent-of-code/go/math"
)

func main() {
	scanner, err := ioutil.GetInputScanner()
	if err != nil {
		log.Die("getting scanner", err)
	}

	scanner.Scan()
	opCodesStr := strings.Split(scanner.Text(), ",")
	if err := scanner.Err(); err != nil {
		log.Die("reading input", err)
	}

	opCodes, err := convert.StrSliceToInt(opCodesStr)
	if err != nil {
		log.Die("converting string slice to int", err)
	}

	var max int
	for _, phases := range math.IntPermutations([]int{0, 1, 2, 3, 4}) {
		channels := []chan int{make(chan int)}
		for i := 0; i < 5; i++ {
			codesCopy := make([]int, len(opCodes))
			copy(codesCopy, opCodes)
			channels = append(channels, make(chan int))
			go runProgram(codesCopy, phases[i], channels[i], channels[i+1])
		}

		channels[0] <- 0
		max = math.IntMax(max, <-channels[len(channels)-1])
	}
	fmt.Println(max)
}

const (
	add         = 1
	mult        = 2
	input       = 3
	output      = 4
	jumpIfTrue  = 5
	jumpIfFalse = 6
	lessThan    = 7
	equals      = 8
	halt        = 99

	positionMode  = 0
	immediateMode = 1
)

var nargs = map[int]int{
	add:         3,
	mult:        3,
	input:       1,
	output:      1,
	jumpIfTrue:  2,
	jumpIfFalse: 2,
	lessThan:    3,
	equals:      3,
	halt:        0,
}

func runProgram(codes []int, phase int, in <-chan int, out chan<- int) {
	firstInput := true
	idx := 0
	for {
		code, modes := parseValue(codes[idx])
		params := getParams(codes, idx, modes)

		switch code {
		case halt:
			close(out)
			return

		case add:
			codes[codes[idx+3]] = params[0] + params[1]
			idx += nargs[add] + 1

		case mult:
			codes[codes[idx+3]] = params[0] * params[1]
			idx += nargs[mult] + 1

		case input:
			if firstInput {
				codes[codes[idx+1]] = phase
				firstInput = false
			} else {
				codes[codes[idx+1]] = <-in
			}
			idx += nargs[input] + 1

		case output:
			out <- params[0]
			idx += nargs[output] + 1

		case jumpIfTrue:
			if params[0] != 0 {
				idx = params[1]
			} else {
				idx += nargs[jumpIfTrue] + 1
			}

		case jumpIfFalse:
			if params[0] == 0 {
				idx = params[1]
			} else {
				idx += nargs[jumpIfFalse] + 1
			}

		case lessThan:
			if params[0] < params[1] {
				codes[codes[idx+3]] = 1
			} else {
				codes[codes[idx+3]] = 0
			}
			idx += nargs[lessThan] + 1

		case equals:
			if params[0] == params[1] {
				codes[codes[idx+3]] = 1
			} else {
				codes[codes[idx+3]] = 0
			}
			idx += nargs[equals] + 1

		default:
			panic(fmt.Sprintf("illegal opcode %d", codes[idx]))
		}
	}
}

func parseValue(val int) (code int, modes []int) {
	code = val % 100
	if valStr := strconv.Itoa(val); len(valStr) > 2 {
		valStr = valStr[:len(valStr)-2]

		var modesStr []string
		for _, m := range valStr {
			modesStr = append([]string{string(m)}, modesStr...)
		}

		var err error
		modes, err = convert.StrSliceToInt(modesStr)
		if err != nil {
			log.Die("converting modes to int", err)
		}
	}

	for len(modes) < nargs[code] {
		modes = append(modes, 0)
	}

	return code, modes
}

func getParams(codes []int, idx int, modes []int) []int {
	var params []int

	for i := 0; i < len(modes); i++ {
		var param int
		if modes[i] == immediateMode {
			param = codes[idx+i+1]
		} else {
			param = codes[codes[idx+i+1]]
		}
		params = append(params, param)
	}

	return params
}
<|endoftext|>


<commit_before>package jibi

import (
	"fmt"
	"sync"
)

// A list of all the special memory addresses.
const (
	AddrRom    Word = 0x0000
	AddrVRam   Word = 0x8000
	AddrRam    Word = 0xC000
	AddrOam    Word = 0xFE00
	AddrOamEnd Word = 0xFEA0

	AddrP1  Word = 0xFF00
	AddrDIV Word = 0xFF04
	AddrTMA Word = 0xFF06
	AddrIF  Word = 0xFF0F

	AddrGpuRegs    Word = 0xFF40
	AddrLCDC       Word = 0xFF40
	AddrSTAT       Word = 0xFF41
	AddrSCY        Word = 0xFF42
	AddrSCX        Word = 0xFF43
	AddrLY         Word = 0xFF44
	AddrLYC        Word = 0xFF45
	AddrDMA        Word = 0xFF46
	AddrBGP        Word = 0xFF47
	AddrOBP0       Word = 0xFF48
	AddrOBP1       Word = 0xFF49
	AddrWY         Word = 0xFF4A
	AddrWX         Word = 0xFF4B
	AddrGpuRegsEnd Word = 0xFF4C

	AddrZero Word = 0xFF80
	AddrIE   Word = 0xFFFF
)

// An Mmu is the memory management unit. Its purpose is to dispatch read and
// write requeststo the appropriate module (cpu, gpu, etc) based on the memory
// address. The Mmu is controlled by the cpu.
type Mmu struct {
	// memory blocks
	rom     []Byte
	vram    []Byte
	ram     []Byte
	oam     []Byte
	gpuregs []Byte
	zero    []Byte
	ie      Byte

	// memory mapped io
	ioIF *mmio
	ioP1 *mmio

	// memory locks
	locks []*sync.Mutex

	// internal state
	kp *Keypad
}

// NewMmu creates a new Mmu with an optional bios that replaces 0x0000-0x00FF.
func NewMmu(cart *Cartridge) *Mmu {
	var rom []Byte
	if cart != nil {
		rom = cart.Rom
	}
	locks := make([]*sync.Mutex, abLast+1)
	for i := uint16(1); i <= uint16(abLast); i = i << 1 {
		locks[i] = new(sync.Mutex)
	}
	mmu := &Mmu{
		rom:     rom,
		vram:    make([]Byte, 0x2000),
		ram:     make([]Byte, 0x2000),
		oam:     make([]Byte, 0xA0),
		ioIF:    newMmio(AddrIF),
		ioP1:    newMmio(AddrP1),
		gpuregs: make([]Byte, 12),
		zero:    make([]Byte, 0x100),
		locks:   locks,
	}
	return mmu
}

type addressBlock uint16
type AddressKeys uint16

const (
	abNil addressBlock = iota
	abRom addressBlock = 1 << iota
	abVRam
	abRam
	abOam
	abP1
	abIF
	abGpuRegs
	abZero
	abIE
	abLast = abIE
)

func (a addressBlock) String() string {
	switch a {
	case abNil:
		return "abNil"
	case abRom:
		return "abRom"
	case abVRam:
		return "abVRam"
	case abRam:
		return "abRam"
	case abOam:
		return "abOam"
	case abIF:
		return "abIF"
	case abGpuRegs:
		return "abGpuRegs"
	case abZero:
		return "abZero"
	case abIE:
		return "abIE"
	}
	return "abUNKNOWN"
}

func (m *Mmu) SetKeypad(kp *Keypad) {
	m.kp = kp
}

func (m *Mmu) selectAddressBlock(addr Worder, rw string) (addressBlock, Word) {
	a := addr.Word()
	if a < AddrVRam {
		return abRom, 0
	} else if AddrVRam <= a && a < AddrRam {
		return abVRam, AddrVRam
	} else if AddrRam <= a && a < AddrOam {
		return abRam, AddrRam
	} else if AddrOam <= a && a < AddrOamEnd {
		return abOam, AddrOam
	} else if AddrP1 == a {
		return abP1, AddrP1
	} else if AddrIF == a {
		return abIF, AddrIF
	} else if AddrGpuRegs <= a && a < AddrGpuRegsEnd {
		return abGpuRegs, AddrGpuRegs
	} else if AddrZero <= a && a < AddrIE {
		return abZero, AddrZero
	} else if AddrIE == a {
		return abIE, AddrIE
	}

	u, v := m.getAddressInfo(addr)
	if !v {
		if rw == "" {
			rw = "access"
		}
		panic(fmt.Sprintf("unhandled memory %s: 0x%04X - %s", rw, a, u))
	}
	return abNil, 0
}

// LockAddr gets a lock for an address if not already in the provided
// AddressKeys and appends it and returns this new key set.
func (m *Mmu) LockAddr(addr Worder, ak AddressKeys) AddressKeys {
	blk, _ := m.selectAddressBlock(addr, "lock")
	if addressBlock(ak)&blk == blk {
		// already have the key
		return ak
	}
	m.locks[blk].Lock()
	return ak | AddressKeys(blk)
}

func (m *Mmu) UnlockAddr(addr Worder, ak AddressKeys) AddressKeys {
	blk, _ := m.selectAddressBlock(addr, "unlock")
	if addressBlock(ak)&blk != blk {
		// don't have the key
		return ak
	}
	m.locks[blk].Unlock()
	return ak & AddressKeys(blk^0xFFFF)
}

func (m *Mmu) ReadByteAt(addr Worder, ak AddressKeys) Byte {
	blk, start := m.selectAddressBlock(addr, "read")
	owner := addressBlock(ak)&blk == blk
	if blk == abRom {
		if owner {
			return m.rom[addr.Word()-start]
		}
	}
	if blk == abVRam {
		if owner {
			return m.vram[addr.Word()-start]
		}
	} else if blk == abRam {
		if owner {
			return m.ram[(addr.Word()-start)&0x1FFF]
		}
	} else if blk == abOam {
		if owner {
			return m.oam[addr.Word()-start]
		}
	} else if blk == abP1 {
		return m.ioP1.readByte(owner)
	} else if blk == abIF {
		return m.ioIF.readByte(owner)
	} else if blk == abGpuRegs {
		if owner {
			return m.gpuregs[addr.Word()-start]
		}
	} else if blk == abZero {
		if owner {
			return m.zero[addr.Word()-start]
		}
	} else if blk == abIE {
		if owner {
			return m.ie
		}
	}
	if !owner {
		panic(fmt.Sprintf("unauthorized read: 0x%04X", addr.Word()))
	}
	if u, v := m.getAddressInfo(addr); !v {
		panic(fmt.Sprintf("unhandled memory read: 0x%04X - %s", addr.Word(), u))
	}
	return 0
}

func (m *Mmu) WriteByteAt(addr Worder, b Byter, ak AddressKeys) {
	blk, start := m.selectAddressBlock(addr, "write")
	owner := addressBlock(ak)&blk == blk
	if blk == abRom {
		return
	} else if blk == abVRam {
		if owner {
			m.vram[addr.Word()-start] = b.Byte()
			return
		}
	} else if blk == abRam {
		if owner {
			m.ram[(addr.Word()-start)&0x1FFF] = b.Byte()
			return
		}
	} else if blk == abOam {
		if owner {
			m.oam[addr.Word()-start] = b.Byte()
			return
		}
	} else if blk == abP1 {
		m.ioP1.writeByte(b, owner)
		if !owner {
			m.kp.RunCommand(CmdKeyCheck, nil)
		}
		return
	} else if blk == abIF {
		m.ioIF.writeByte(b, owner)
		return
	} else if blk == abGpuRegs {
		if owner {
			m.gpuregs[addr.Word()-start] = b.Byte()
			return
		}
	} else if blk == abZero {
		if owner {
			m.zero[addr.Word()-start] = b.Byte()
			return
		}
	} else if blk == abIE {
		if owner {
			m.ie = b.Byte()
			return
		}
	}
	if !owner {
		panic(fmt.Sprintf("unauthorized write: 0x%04X 0x%02X", addr.Word(), b.Byte()))
	}
	if u, v := m.getAddressInfo(addr); !v {
		panic(fmt.Sprintf("unhandled memory write: 0x%04X - %s", addr.Word(), u))
	}
}

func (m *Mmu) ReadIoByte(addr Worder, ak AddressKeys) (Byte, bool) {
	blk, _ := m.selectAddressBlock(addr, "write")
	owner := addressBlock(ak)&blk == blk
	if blk == abP1 {
		return m.ioP1.readIoByte(owner)
	} else if blk == abIF {
		return m.ioIF.readIoByte(owner)
	}
	panic(fmt.Sprintf("unhandled queued write: 0x%04X", addr.Word()))
}

// incomplete, used for debugging
func (m *Mmu) getAddressInfo(addr Worder) (string, bool) {
	a := addr.Word()
	if 0x9C00 <= a && a <= 0x9FFF {
		return "Background Map Data 2", false
	} else if 0xFEA0 <= a && a <= 0xFEFF {
		return "unusable memory", true
	} else if a == 0xFF00 {
		return "Register for reading joy pad info and determining system type. (R/W)", false
	} else if a == 0xFF01 {
		return "Serial transfer data (R/W)", true
	} else if a == 0xFF02 {
		return "SIO control (R/W)", true
	} else if a == 0xFF03 {
		return "no clue", true
	} else if a == 0xFF04 {
		return "DIV", true // TODO: priority
	} else if a == 0xFF05 {
		return "TIMA", true // TODO: priority
	} else if a == 0xFF06 {
		return "TMA", true // TODO: priority
	} else if a == 0xFF07 {
		return "TAC", true // TODO: priority
	} else if 0xFF08 <= a && a <= 0xFF0E {
		return "no clue", true
	} else if a == 0xFF10 {
		return "Sound Mode 1 register, Sweep register (R/W)", true
	} else if a == 0xFF11 {
		return "Sound Mode 1 register, Sound length/Wave pattern duty (R/W)", true
	} else if a == 0xFF12 {
		return "Sound Mode 1 register, Envelope (R/W)", true
	} else if a == 0xFF13 {
		return "Sound Mode 1 register, Frequency lo (W)", true
	} else if a == 0xFF14 {
		return "Sound Mode 1 register, Frequency hi (R/W)", true
	} else if a == 0xFF17 {
		return "Sound Mode 2 register, envelope (R/W)", true
	} else if a == 0xFF19 {
		return "Sound Mode 2 register, frequency", true
	} else if a == 0xFF1A {
		return "Sound Mode 3 register, Sound on/off (R/W)", true
	} else if a == 0xFF20 {
		return "Sound Mode 4 register, sound length (R/W)", true
	} else if a == 0xFF21 {
		return "Sound Mode 4 register, envelope (R/W)", true
	} else if a == 0xFF23 {
		return "Sound Mode 4 register, counter/consecutive; inital (R/W)", true
	} else if a == 0xFF24 {
		return "Channel control / ON-OFF / Volume (R/W)", true
	} else if a == 0xFF25 {
		return "Selection of Sound output terminal (R/W)", true
	} else if a == 0xFF26 {
		return "Sound on/off (R/W)", true
	} else if a == 0xFF47 {
		return "BGP", false
	} else if 0xFF4D <= a && a <= 0xFF7F {
		return "GBC", true
	} else if a == 0xFFFF {
		return "IE", false
	}
	return "unknown", false
}

// memory mapped io
type mmio struct {
	addr Word

	// accessed by owner
	value Byte

	// accessed through lock
	read   Byte
	write  Byte
	queued bool
	lock   *sync.Mutex
}

func newMmio(addr Worder) *mmio {
	m := &mmio{addr: addr.Word(),
		lock: new(sync.Mutex)}
	return m
}

func (m *mmio) readByte(owner bool) Byte {
	if owner {
		return m.value
	}
	m.lock.Lock()
	defer m.lock.Unlock()
	return m.read
}

func (m *mmio) writeByte(b Byter, owner bool) {
	if owner {
		m.lock.Lock()
		defer m.lock.Unlock()
		m.value = b.Byte()
		m.read = m.value
		if !m.queued {
			m.write = m.value
		}
	} else {
		m.lock.Lock()
		defer m.lock.Unlock()
		if m.queued {
			//panic(fmt.Sprintf("overwritten io write: 0x%04X", m.addr))
		}
		m.queued = true
		m.write = b.Byte()
	}
}

func (m *mmio) readIoByte(owner bool) (Byte, bool) {
	if owner {
		m.lock.Lock()
		defer m.lock.Unlock()
		q := m.queued
		m.queued = false
		return m.write, q
	}
	panic(fmt.Sprintf("unhandled io read: 0x%04X", m.addr))
}
<commit_msg>video ram ends at cart ram, not working ram<commit_after>package jibi

import (
	"fmt"
	"sync"
)

// A list of all the special memory addresses.
const (
	AddrRom    Word = 0x0000
	AddrVRam   Word = 0x8000
	AddrERam   Word = 0xA000
	AddrRam    Word = 0xC000
	AddrOam    Word = 0xFE00
	AddrOamEnd Word = 0xFEA0

	AddrP1  Word = 0xFF00
	AddrDIV Word = 0xFF04
	AddrTMA Word = 0xFF06
	AddrIF  Word = 0xFF0F

	AddrGpuRegs    Word = 0xFF40
	AddrLCDC       Word = 0xFF40
	AddrSTAT       Word = 0xFF41
	AddrSCY        Word = 0xFF42
	AddrSCX        Word = 0xFF43
	AddrLY         Word = 0xFF44
	AddrLYC        Word = 0xFF45
	AddrDMA        Word = 0xFF46
	AddrBGP        Word = 0xFF47
	AddrOBP0       Word = 0xFF48
	AddrOBP1       Word = 0xFF49
	AddrWY         Word = 0xFF4A
	AddrWX         Word = 0xFF4B
	AddrGpuRegsEnd Word = 0xFF4C

	AddrZero Word = 0xFF80
	AddrIE   Word = 0xFFFF
)

// An Mmu is the memory management unit. Its purpose is to dispatch read and
// write requeststo the appropriate module (cpu, gpu, etc) based on the memory
// address. The Mmu is controlled by the cpu.
type Mmu struct {
	// memory blocks
	rom     []Byte
	vram    []Byte
	ram     []Byte
	oam     []Byte
	gpuregs []Byte
	zero    []Byte
	ie      Byte

	// memory mapped io
	ioIF *mmio
	ioP1 *mmio

	// memory locks
	locks []*sync.Mutex

	// internal state
	kp *Keypad
}

// NewMmu creates a new Mmu with an optional bios that replaces 0x0000-0x00FF.
func NewMmu(cart *Cartridge) *Mmu {
	var rom []Byte
	if cart != nil {
		rom = cart.Rom
	}
	locks := make([]*sync.Mutex, abLast+1)
	for i := uint16(1); i <= uint16(abLast); i = i << 1 {
		locks[i] = new(sync.Mutex)
	}
	mmu := &Mmu{
		rom:     rom,
		vram:    make([]Byte, 0x2000),
		ram:     make([]Byte, 0x2000),
		oam:     make([]Byte, 0xA0),
		ioIF:    newMmio(AddrIF),
		ioP1:    newMmio(AddrP1),
		gpuregs: make([]Byte, 12),
		zero:    make([]Byte, 0x100),
		locks:   locks,
	}
	return mmu
}

type addressBlock uint16
type AddressKeys uint16

const (
	abNil addressBlock = iota
	abRom addressBlock = 1 << iota
	abVRam
	abERam
	abRam
	abOam
	abP1
	abIF
	abGpuRegs
	abZero
	abIE
	abLast = abIE
)

func (a addressBlock) String() string {
	switch a {
	case abNil:
		return "abNil"
	case abRom:
		return "abRom"
	case abVRam:
		return "abVRam"
	case abERam:
		return "abERam"
	case abRam:
		return "abRam"
	case abOam:
		return "abOam"
	case abIF:
		return "abIF"
	case abGpuRegs:
		return "abGpuRegs"
	case abZero:
		return "abZero"
	case abIE:
		return "abIE"
	}
	return "abUNKNOWN"
}

func (m *Mmu) SetKeypad(kp *Keypad) {
	m.kp = kp
}

func (m *Mmu) selectAddressBlock(addr Worder, rw string) (addressBlock, Word) {
	a := addr.Word()
	if a < AddrVRam {
		return abRom, 0
	} else if AddrVRam <= a && a < AddrERam {
		return abVRam, AddrVRam
	} else if AddrERam <= a && a < AddrRam {
		return abERam, AddrERam
	} else if AddrRam <= a && a < AddrOam {
		return abRam, AddrRam
	} else if AddrOam <= a && a < AddrOamEnd {
		return abOam, AddrOam
	} else if AddrP1 == a {
		return abP1, AddrP1
	} else if AddrIF == a {
		return abIF, AddrIF
	} else if AddrGpuRegs <= a && a < AddrGpuRegsEnd {
		return abGpuRegs, AddrGpuRegs
	} else if AddrZero <= a && a < AddrIE {
		return abZero, AddrZero
	} else if AddrIE == a {
		return abIE, AddrIE
	}

	u, v := m.getAddressInfo(addr)
	if !v {
		if rw == "" {
			rw = "access"
		}
		panic(fmt.Sprintf("unhandled memory %s: 0x%04X - %s", rw, a, u))
	}
	return abNil, 0
}

// LockAddr gets a lock for an address if not already in the provided
// AddressKeys and appends it and returns this new key set.
func (m *Mmu) LockAddr(addr Worder, ak AddressKeys) AddressKeys {
	blk, _ := m.selectAddressBlock(addr, "lock")
	if addressBlock(ak)&blk == blk {
		// already have the key
		return ak
	}
	m.locks[blk].Lock()
	return ak | AddressKeys(blk)
}

func (m *Mmu) UnlockAddr(addr Worder, ak AddressKeys) AddressKeys {
	blk, _ := m.selectAddressBlock(addr, "unlock")
	if addressBlock(ak)&blk != blk {
		// don't have the key
		return ak
	}
	m.locks[blk].Unlock()
	return ak & AddressKeys(blk^0xFFFF)
}

func (m *Mmu) ReadByteAt(addr Worder, ak AddressKeys) Byte {
	blk, start := m.selectAddressBlock(addr, "read")
	owner := addressBlock(ak)&blk == blk
	if blk == abRom {
		if owner {
			return m.rom[addr.Word()-start]
		}
	}
	if blk == abVRam {
		if owner {
			return m.vram[addr.Word()-start]
		}
	} else if blk == abRam {
		if owner {
			return m.ram[(addr.Word()-start)&0x1FFF]
		}
	} else if blk == abOam {
		if owner {
			return m.oam[addr.Word()-start]
		}
	} else if blk == abP1 {
		return m.ioP1.readByte(owner)
	} else if blk == abIF {
		return m.ioIF.readByte(owner)
	} else if blk == abGpuRegs {
		if owner {
			return m.gpuregs[addr.Word()-start]
		}
	} else if blk == abZero {
		if owner {
			return m.zero[addr.Word()-start]
		}
	} else if blk == abIE {
		if owner {
			return m.ie
		}
	}
	if !owner {
		panic(fmt.Sprintf("unauthorized read: 0x%04X", addr.Word()))
	}
	if u, v := m.getAddressInfo(addr); !v {
		panic(fmt.Sprintf("unhandled memory read: 0x%04X - %s", addr.Word(), u))
	}
	return 0
}

func (m *Mmu) WriteByteAt(addr Worder, b Byter, ak AddressKeys) {
	blk, start := m.selectAddressBlock(addr, "write")
	owner := addressBlock(ak)&blk == blk
	if blk == abRom {
		return
	} else if blk == abVRam {
		if owner {
			m.vram[addr.Word()-start] = b.Byte()
			return
		}
	} else if blk == abRam {
		if owner {
			m.ram[(addr.Word()-start)&0x1FFF] = b.Byte()
			return
		}
	} else if blk == abOam {
		if owner {
			m.oam[addr.Word()-start] = b.Byte()
			return
		}
	} else if blk == abP1 {
		m.ioP1.writeByte(b, owner)
		if !owner {
			m.kp.RunCommand(CmdKeyCheck, nil)
		}
		return
	} else if blk == abIF {
		m.ioIF.writeByte(b, owner)
		return
	} else if blk == abGpuRegs {
		if owner {
			m.gpuregs[addr.Word()-start] = b.Byte()
			return
		}
	} else if blk == abZero {
		if owner {
			m.zero[addr.Word()-start] = b.Byte()
			return
		}
	} else if blk == abIE {
		if owner {
			m.ie = b.Byte()
			return
		}
	}
	if !owner {
		panic(fmt.Sprintf("unauthorized write: 0x%04X 0x%02X", addr.Word(), b.Byte()))
	}
	if u, v := m.getAddressInfo(addr); !v {
		panic(fmt.Sprintf("unhandled memory write: 0x%04X - %s", addr.Word(), u))
	}
}

func (m *Mmu) ReadIoByte(addr Worder, ak AddressKeys) (Byte, bool) {
	blk, _ := m.selectAddressBlock(addr, "write")
	owner := addressBlock(ak)&blk == blk
	if blk == abP1 {
		return m.ioP1.readIoByte(owner)
	} else if blk == abIF {
		return m.ioIF.readIoByte(owner)
	}
	panic(fmt.Sprintf("unhandled queued write: 0x%04X", addr.Word()))
}

// incomplete, used for debugging
func (m *Mmu) getAddressInfo(addr Worder) (string, bool) {
	a := addr.Word()
	if 0x9C00 <= a && a <= 0x9FFF {
		return "Background Map Data 2", false
	} else if 0xFEA0 <= a && a <= 0xFEFF {
		return "unusable memory", true
	} else if a == 0xFF00 {
		return "Register for reading joy pad info and determining system type. (R/W)", false
	} else if a == 0xFF01 {
		return "Serial transfer data (R/W)", true
	} else if a == 0xFF02 {
		return "SIO control (R/W)", true
	} else if a == 0xFF03 {
		return "no clue", true
	} else if a == 0xFF04 {
		return "DIV", true // TODO: priority
	} else if a == 0xFF05 {
		return "TIMA", true // TODO: priority
	} else if a == 0xFF06 {
		return "TMA", true // TODO: priority
	} else if a == 0xFF07 {
		return "TAC", true // TODO: priority
	} else if 0xFF08 <= a && a <= 0xFF0E {
		return "no clue", true
	} else if a == 0xFF10 {
		return "Sound Mode 1 register, Sweep register (R/W)", true
	} else if a == 0xFF11 {
		return "Sound Mode 1 register, Sound length/Wave pattern duty (R/W)", true
	} else if a == 0xFF12 {
		return "Sound Mode 1 register, Envelope (R/W)", true
	} else if a == 0xFF13 {
		return "Sound Mode 1 register, Frequency lo (W)", true
	} else if a == 0xFF14 {
		return "Sound Mode 1 register, Frequency hi (R/W)", true
	} else if a == 0xFF17 {
		return "Sound Mode 2 register, envelope (R/W)", true
	} else if a == 0xFF19 {
		return "Sound Mode 2 register, frequency", true
	} else if a == 0xFF1A {
		return "Sound Mode 3 register, Sound on/off (R/W)", true
	} else if a == 0xFF20 {
		return "Sound Mode 4 register, sound length (R/W)", true
	} else if a == 0xFF21 {
		return "Sound Mode 4 register, envelope (R/W)", true
	} else if a == 0xFF23 {
		return "Sound Mode 4 register, counter/consecutive; inital (R/W)", true
	} else if a == 0xFF24 {
		return "Channel control / ON-OFF / Volume (R/W)", true
	} else if a == 0xFF25 {
		return "Selection of Sound output terminal (R/W)", true
	} else if a == 0xFF26 {
		return "Sound on/off (R/W)", true
	} else if a == 0xFF47 {
		return "BGP", false
	} else if 0xFF4D <= a && a <= 0xFF7F {
		return "GBC", true
	} else if a == 0xFFFF {
		return "IE", false
	}
	return "unknown", false
}

// memory mapped io
type mmio struct {
	addr Word

	// accessed by owner
	value Byte

	// accessed through lock
	read   Byte
	write  Byte
	queued bool
	lock   *sync.Mutex
}

func newMmio(addr Worder) *mmio {
	m := &mmio{addr: addr.Word(),
		lock: new(sync.Mutex)}
	return m
}

func (m *mmio) readByte(owner bool) Byte {
	if owner {
		return m.value
	}
	m.lock.Lock()
	defer m.lock.Unlock()
	return m.read
}

func (m *mmio) writeByte(b Byter, owner bool) {
	if owner {
		m.lock.Lock()
		defer m.lock.Unlock()
		m.value = b.Byte()
		m.read = m.value
		if !m.queued {
			m.write = m.value
		}
	} else {
		m.lock.Lock()
		defer m.lock.Unlock()
		if m.queued {
			//panic(fmt.Sprintf("overwritten io write: 0x%04X", m.addr))
		}
		m.queued = true
		m.write = b.Byte()
	}
}

func (m *mmio) readIoByte(owner bool) (Byte, bool) {
	if owner {
		m.lock.Lock()
		defer m.lock.Unlock()
		q := m.queued
		m.queued = false
		return m.write, q
	}
	panic(fmt.Sprintf("unhandled io read: 0x%04X", m.addr))
}
<|endoftext|>


<commit_before>package main

type JobStepStatus int

const (
	STARTING = 1 + iota
	SUCCESS
	FAILURE
)

func (jss JobStepStatus) String() string {
	switch jss {
	case STARTING: return "STARTING"
	case SUCCESS: return "SUCCESS"
	case FAILURE: return "FAILURE"
	default: return "Unknown"
	}
}

type JobStep int

const (
	PREPARING   = 1 + iota
	DOWNLOADING
	EXECUTING
	UPLOADING
	CANCELLING
	ACKSENDING
	NACKSENDING
	CLEANUP
)

var (
	JOB_STEP_DEFS = map[JobStep][]string {
		PREPARING:    []string{"PREPARING"	, "info" , "error"},
		DOWNLOADING:	[]string{"DOWNLOADING", "info" , "error"},
		EXECUTING:		[]string{"EXECUTING"	,	"info" , "error"},
		UPLOADING:		[]string{"UPLOADING"	,	"info" , "error"},
		CANCELLING:		[]string{"CANCELLING" , "info" , "fatal"},
		ACKSENDING:		[]string{"ACKSENDING" , "info" , "error"},
		NACKSENDING:	[]string{"NACKSENDING", "info" , "warn" },
		CLEANUP:			[]string{"CLEANUP"		, "debug", "warn" },
	}
)

func (js JobStep) String() string {
	return JOB_STEP_DEFS[js][0]
}
func (js JobStep) successLogLevel() string {
	return JOB_STEP_DEFS[js][1]
}
func (js JobStep) failureLogLevel() string {
	return JOB_STEP_DEFS[js][2]
}

func (js JobStep) completed(st JobStepStatus) bool {
	return (js == ACKSENDING) && (st == SUCCESS)
}
func (js JobStep) logLevelFor(st JobStepStatus) string {
	switch st {
	// case STARTING: return "info"
	case SUCCESS: return js.successLogLevel()
	case FAILURE: return js.failureLogLevel()
	default: return "info"
	}
}
<commit_msg>:+1: Define constants with their type<commit_after>package main

type JobStepStatus int

const (
	STARTING JobStepStatus = 1 + iota
	SUCCESS
	FAILURE
)

func (jss JobStepStatus) String() string {
	switch jss {
	case STARTING: return "STARTING"
	case SUCCESS: return "SUCCESS"
	case FAILURE: return "FAILURE"
	default: return "Unknown"
	}
}

type JobStep int

const (
	PREPARING   JobStep = 1 + iota
	DOWNLOADING
	EXECUTING
	UPLOADING
	CANCELLING
	ACKSENDING
	NACKSENDING
	CLEANUP
)

var (
	JOB_STEP_DEFS = map[JobStep][]string {
		PREPARING:    []string{"PREPARING"	, "info" , "error"},
		DOWNLOADING:	[]string{"DOWNLOADING", "info" , "error"},
		EXECUTING:		[]string{"EXECUTING"	,	"info" , "error"},
		UPLOADING:		[]string{"UPLOADING"	,	"info" , "error"},
		CANCELLING:		[]string{"CANCELLING" , "info" , "fatal"},
		ACKSENDING:		[]string{"ACKSENDING" , "info" , "error"},
		NACKSENDING:	[]string{"NACKSENDING", "info" , "warn" },
		CLEANUP:			[]string{"CLEANUP"		, "debug", "warn" },
	}
)

func (js JobStep) String() string {
	return JOB_STEP_DEFS[js][0]
}
func (js JobStep) successLogLevel() string {
	return JOB_STEP_DEFS[js][1]
}
func (js JobStep) failureLogLevel() string {
	return JOB_STEP_DEFS[js][2]
}

func (js JobStep) completed(st JobStepStatus) bool {
	return (js == ACKSENDING) && (st == SUCCESS)
}
func (js JobStep) logLevelFor(st JobStepStatus) string {
	switch st {
	// case STARTING: return "info"
	case SUCCESS: return js.successLogLevel()
	case FAILURE: return js.failureLogLevel()
	default: return "info"
	}
}
<|endoftext|>


<commit_before>package jpegsegs

import (
	"errors"
	"fmt"
	"io"
)

const (
	TEM  = 0x01
	SOF0 = 0xC0 // SOFn = SOF0+n, n = 0-15 excluding 4, 8 and 12
	DHT  = 0xC4
	JPG  = 0xC8
	DAC  = 0xCC
	RST0 = 0xD0 // RSTn = RST0+n, n = 0-7
	SOI  = 0xD8
	EOI  = 0xD9
	SOS  = 0xDA
	DQT  = 0xDB
	DNL  = 0xDC
	DRI  = 0xDD
	DHP  = 0xDE
	EXP  = 0xDF
	APP0 = 0xE0 // APPn = APP0+n, n = 0-15
	JPG0 = 0xF0 // JPGn = JPG0+n  n = 0-13
	COM  = 0xFE
)

// Marker represents a JPEG marker, which usually indicates the start of a
// segment.
type Marker uint8

var markerNames [256]string

// Initialize markerNames
func init() {
	markerNames[0] = "NUL"
	markerNames[TEM] = "TEM"
	markerNames[DHT] = "DHT"
	markerNames[JPG] = "JPG"
	markerNames[DAC] = "DAC"
	markerNames[SOI] = "SOI"
	markerNames[EOI] = "EOI"
	markerNames[SOS] = "SOS"
	markerNames[DQT] = "DQT"
	markerNames[DNL] = "DNL"
	markerNames[DRI] = "DRI"
	markerNames[DHP] = "DHP"
	markerNames[EXP] = "EXP"
	markerNames[COM] = "COM"
	markerNames[0xFF] = "FILL"

	var i Marker
	for i = 0x02; i <= 0xBF; i++ {
		markerNames[i] = fmt.Sprintf("RES%.2X", i) // Reserved
	}
	for i = SOF0; i <= SOF0+0xF; i++ {
		if i == SOF0+4 || i == SOF0+8 || i == SOF0+12 {
			continue
		}
		markerNames[i] = fmt.Sprintf("SOF%d", i-SOF0)
	}
	for i = RST0; i <= RST0+7; i++ {
		markerNames[i] = fmt.Sprintf("RST%d", i-RST0)
	}
	for i = APP0; i <= APP0+0xF; i++ {
		markerNames[i] = fmt.Sprintf("APP%d", i-APP0)
	}
	for i = JPG0; i <= JPG0+0xD; i++ {
		markerNames[i] = fmt.Sprintf("JPG%d", i-JPG0)
	}
}

// Name returns the name of a marker value.
func (m Marker) Name() string {
	return markerNames[m]
}

// The JPEG header is a SOI marker. Filler bytes aren't allowed.
func readHeader(reader io.Reader, buf []byte) error {
	buf = buf[0:2]
	if _, err := io.ReadFull(reader, buf); err != nil {
		return err
	}
	if buf[0] != 0xFF || buf[1] != SOI {
		return errors.New("SOI marker not found")
	}
	return nil
}

func readMarker(reader io.Reader, buf []byte) (Marker, error) {
	buf = buf[0:2]
	if _, err := io.ReadFull(reader, buf); err != nil {
		return 0, err
	}
	if buf[0] != 0xFF {
		return 0, errors.New("0xFF expected in marker")
	}
	buf = buf[1:2] // Look at the 2nd byte only.
	for {
		// Skip 0xFF fill bytes. Fill bytes don't seem to have
		// any purpose, so can be discarded.
		if buf[0] != 0xFF {
			break
		}
		if _, err := reader.Read(buf); err != nil {
			return 0, err
		}
	}
	if buf[0] == 0 {
		return 0, errors.New("Invalid marker 0")
	}
	return Marker(buf[0]), nil
}

func writeMarker(writer io.Writer, marker Marker, buf []byte) error {
	buf = buf[0:2]
	buf[0] = 0xFF
	buf[1] = byte(marker)
	_, err := writer.Write(buf)
	return err
}

func readData(reader io.Reader, buf []byte) ([]byte, error) {
	buf = buf[0:2]
	if _, err := io.ReadFull(reader, buf); err != nil {
		return nil, err
	}
	length := int(buf[0])<<8 + int(buf[1]) - 2
	buf = buf[0:length]
	_, err := io.ReadFull(reader, buf)
	return buf, err
}

func writeData(writer io.Writer, buf []byte, lenbuf []byte) error {
	len := len(buf) + 2
	if len >= 2<<15 {
		return errors.New("Buffer is too long, max 2^16 - 3")
	}
	lenbuf[0] = byte(len / 256)
	lenbuf[1] = byte(len % 256)
	if _, err := writer.Write(lenbuf); err != nil {
		return err
	}
	_, err := writer.Write(buf)
	return err
}

// Scanner represents a reader for JPEG markers and segments up to the
// SOS marker.
type Scanner struct {
	reader io.Reader
	buf    []byte // buffer of size 2^16 - 3
}

// NewScanner creates a new Scanner and checks the JPEG header.
func NewScanner(reader io.Reader) (*Scanner, error) {
	scanner := new(Scanner)
	scanner.reader = reader
	scanner.buf = make([]byte, 2<<15-3)
	if err := readHeader(reader, scanner.buf); err != nil {
		return nil, err
	}
	return scanner, nil
}

// Scan reads the next JPEG marker and its data segment if it has one.
// All markers are expected to have data except for SOS, which indicates
// the start of scan data. Scan doesn't work past that point. The data
// buffer is only valid until Scan is called again.
func (scanner *Scanner) Scan() (Marker, []byte, error) {
	marker, err := readMarker(scanner.reader, scanner.buf)
	if err != nil {
		return 0, nil, err
	}
	if marker == SOS {
		return marker, nil, nil
	}
	segment, err := readData(scanner.reader, scanner.buf)
	return marker, segment, err

}

// Dumper represents a writer for JPEG markers and segments up to the SOS
// marker.
type Dumper struct {
	writer io.Writer
	buf    []byte // buffer of size 2
}

// NewDumper creates a new Dumper and writes the JPEG header.
func NewDumper(writer io.Writer) (*Dumper, error) {
	dumper := new(Dumper)
	dumper.writer = writer
	dumper.buf = make([]byte, 2)
	if err := writeMarker(writer, SOI, dumper.buf); err != nil {
		return nil, err
	}
	return dumper, nil
}

// Dump writes a marker and its data segment from buf. buf should be nil if
// it's the SOS marker (start of scan).
func (dumper *Dumper) Dump(marker Marker, buf []byte) error {
	if err := writeMarker(dumper.writer, marker, dumper.buf); err != nil {
		return err
	}
	if buf == nil {
		return nil
	}
	return writeData(dumper.writer, buf, dumper.buf)
}

// Copy reads all remaining data from a Scanner and lets the Dumper write it.
func (dumper *Dumper) Copy(scanner *Scanner) error {
	_, err := io.Copy(dumper.writer, scanner.reader)
	return err
}

// Segment represents a marker and its segment data.
type Segment struct {
	Marker Marker
	Data   []byte
}

// ReadAll reads a JPEG stream up to and including the SOS marker and
// returns a slice with marker and segment data. The SOS marker isn't
// included in the slice.
func ReadAll(reader io.Reader) (*Scanner, []Segment, error) {
	var segments = make([]Segment, 0, 20)
	scanner, err := NewScanner(reader)
	if err != nil {
		return nil, segments, err
	}
	for {
		marker, buf, err := scanner.Scan()
		if err != nil {
			return scanner, segments, err
		}
		if marker == SOS {
			return scanner, segments, nil
		}
		cpy := make([]byte, len(buf))
		copy(cpy, buf)
		segments = append(segments, Segment{marker, cpy})
	}
}

// WriteAll writes a JPEG stream up to and including the SOS marker, given
// a slice with marker and segment data. The SOS marker is written
// automatically, it should not be included in the slice.
func WriteAll(writer io.Writer, segments []Segment) (*Dumper, error) {
	dumper, err := NewDumper(writer)
	if err != nil {
		return nil, err
	}
	for i := range segments {
		if err := dumper.Dump(segments[i].Marker, segments[i].Data); err != nil {
			return dumper, err
		}
	}
	return dumper, dumper.Dump(SOS, nil)
}
<commit_msg>writeData: Improve error message when data is too large to save<commit_after>package jpegsegs

import (
	"errors"
	"fmt"
	"io"
)

const (
	TEM  = 0x01
	SOF0 = 0xC0 // SOFn = SOF0+n, n = 0-15 excluding 4, 8 and 12
	DHT  = 0xC4
	JPG  = 0xC8
	DAC  = 0xCC
	RST0 = 0xD0 // RSTn = RST0+n, n = 0-7
	SOI  = 0xD8
	EOI  = 0xD9
	SOS  = 0xDA
	DQT  = 0xDB
	DNL  = 0xDC
	DRI  = 0xDD
	DHP  = 0xDE
	EXP  = 0xDF
	APP0 = 0xE0 // APPn = APP0+n, n = 0-15
	JPG0 = 0xF0 // JPGn = JPG0+n  n = 0-13
	COM  = 0xFE
)

// Marker represents a JPEG marker, which usually indicates the start of a
// segment.
type Marker uint8

var markerNames [256]string

// Initialize markerNames
func init() {
	markerNames[0] = "NUL"
	markerNames[TEM] = "TEM"
	markerNames[DHT] = "DHT"
	markerNames[JPG] = "JPG"
	markerNames[DAC] = "DAC"
	markerNames[SOI] = "SOI"
	markerNames[EOI] = "EOI"
	markerNames[SOS] = "SOS"
	markerNames[DQT] = "DQT"
	markerNames[DNL] = "DNL"
	markerNames[DRI] = "DRI"
	markerNames[DHP] = "DHP"
	markerNames[EXP] = "EXP"
	markerNames[COM] = "COM"
	markerNames[0xFF] = "FILL"

	var i Marker
	for i = 0x02; i <= 0xBF; i++ {
		markerNames[i] = fmt.Sprintf("RES%.2X", i) // Reserved
	}
	for i = SOF0; i <= SOF0+0xF; i++ {
		if i == SOF0+4 || i == SOF0+8 || i == SOF0+12 {
			continue
		}
		markerNames[i] = fmt.Sprintf("SOF%d", i-SOF0)
	}
	for i = RST0; i <= RST0+7; i++ {
		markerNames[i] = fmt.Sprintf("RST%d", i-RST0)
	}
	for i = APP0; i <= APP0+0xF; i++ {
		markerNames[i] = fmt.Sprintf("APP%d", i-APP0)
	}
	for i = JPG0; i <= JPG0+0xD; i++ {
		markerNames[i] = fmt.Sprintf("JPG%d", i-JPG0)
	}
}

// Name returns the name of a marker value.
func (m Marker) Name() string {
	return markerNames[m]
}

// The JPEG header is a SOI marker. Filler bytes aren't allowed.
func readHeader(reader io.Reader, buf []byte) error {
	buf = buf[0:2]
	if _, err := io.ReadFull(reader, buf); err != nil {
		return err
	}
	if buf[0] != 0xFF || buf[1] != SOI {
		return errors.New("SOI marker not found")
	}
	return nil
}

func readMarker(reader io.Reader, buf []byte) (Marker, error) {
	buf = buf[0:2]
	if _, err := io.ReadFull(reader, buf); err != nil {
		return 0, err
	}
	if buf[0] != 0xFF {
		return 0, errors.New("0xFF expected in marker")
	}
	buf = buf[1:2] // Look at the 2nd byte only.
	for {
		// Skip 0xFF fill bytes. Fill bytes don't seem to have
		// any purpose, so can be discarded.
		if buf[0] != 0xFF {
			break
		}
		if _, err := reader.Read(buf); err != nil {
			return 0, err
		}
	}
	if buf[0] == 0 {
		return 0, errors.New("Invalid marker 0")
	}
	return Marker(buf[0]), nil
}

func writeMarker(writer io.Writer, marker Marker, buf []byte) error {
	buf = buf[0:2]
	buf[0] = 0xFF
	buf[1] = byte(marker)
	_, err := writer.Write(buf)
	return err
}

func readData(reader io.Reader, buf []byte) ([]byte, error) {
	buf = buf[0:2]
	if _, err := io.ReadFull(reader, buf); err != nil {
		return nil, err
	}
	length := int(buf[0])<<8 + int(buf[1]) - 2
	buf = buf[0:length]
	_, err := io.ReadFull(reader, buf)
	return buf, err
}

func writeData(writer io.Writer, buf []byte, lenbuf []byte) error {
	len := len(buf) + 2
	if len >= 2<<15 {
		return errors.New(fmt.Sprintf("Buffer is too long (%d), max 2^16 - 3 (%d)", len - 2, 2<<15 - 3))
	}
	lenbuf[0] = byte(len / 256)
	lenbuf[1] = byte(len % 256)
	if _, err := writer.Write(lenbuf); err != nil {
		return err
	}
	_, err := writer.Write(buf)
	return err
}

// Scanner represents a reader for JPEG markers and segments up to the
// SOS marker.
type Scanner struct {
	reader io.Reader
	buf    []byte // buffer of size 2^16 - 3
}

// NewScanner creates a new Scanner and checks the JPEG header.
func NewScanner(reader io.Reader) (*Scanner, error) {
	scanner := new(Scanner)
	scanner.reader = reader
	scanner.buf = make([]byte, 2<<15-3)
	if err := readHeader(reader, scanner.buf); err != nil {
		return nil, err
	}
	return scanner, nil
}

// Scan reads the next JPEG marker and its data segment if it has one.
// All markers are expected to have data except for SOS, which indicates
// the start of scan data. Scan doesn't work past that point. The data
// buffer is only valid until Scan is called again.
func (scanner *Scanner) Scan() (Marker, []byte, error) {
	marker, err := readMarker(scanner.reader, scanner.buf)
	if err != nil {
		return 0, nil, err
	}
	if marker == SOS {
		return marker, nil, nil
	}
	segment, err := readData(scanner.reader, scanner.buf)
	return marker, segment, err

}

// Dumper represents a writer for JPEG markers and segments up to the SOS
// marker.
type Dumper struct {
	writer io.Writer
	buf    []byte // buffer of size 2
}

// NewDumper creates a new Dumper and writes the JPEG header.
func NewDumper(writer io.Writer) (*Dumper, error) {
	dumper := new(Dumper)
	dumper.writer = writer
	dumper.buf = make([]byte, 2)
	if err := writeMarker(writer, SOI, dumper.buf); err != nil {
		return nil, err
	}
	return dumper, nil
}

// Dump writes a marker and its data segment from buf. buf should be nil if
// it's the SOS marker (start of scan).
func (dumper *Dumper) Dump(marker Marker, buf []byte) error {
	if err := writeMarker(dumper.writer, marker, dumper.buf); err != nil {
		return err
	}
	if buf == nil {
		return nil
	}
	return writeData(dumper.writer, buf, dumper.buf)
}

// Copy reads all remaining data from a Scanner and lets the Dumper write it.
func (dumper *Dumper) Copy(scanner *Scanner) error {
	_, err := io.Copy(dumper.writer, scanner.reader)
	return err
}

// Segment represents a marker and its segment data.
type Segment struct {
	Marker Marker
	Data   []byte
}

// ReadAll reads a JPEG stream up to and including the SOS marker and
// returns a slice with marker and segment data. The SOS marker isn't
// included in the slice.
func ReadAll(reader io.Reader) (*Scanner, []Segment, error) {
	var segments = make([]Segment, 0, 20)
	scanner, err := NewScanner(reader)
	if err != nil {
		return nil, segments, err
	}
	for {
		marker, buf, err := scanner.Scan()
		if err != nil {
			return scanner, segments, err
		}
		if marker == SOS {
			return scanner, segments, nil
		}
		cpy := make([]byte, len(buf))
		copy(cpy, buf)
		segments = append(segments, Segment{marker, cpy})
	}
}

// WriteAll writes a JPEG stream up to and including the SOS marker, given
// a slice with marker and segment data. The SOS marker is written
// automatically, it should not be included in the slice.
func WriteAll(writer io.Writer, segments []Segment) (*Dumper, error) {
	dumper, err := NewDumper(writer)
	if err != nil {
		return nil, err
	}
	for i := range segments {
		if err := dumper.Dump(segments[i].Marker, segments[i].Data); err != nil {
			return dumper, err
		}
	}
	return dumper, dumper.Dump(SOS, nil)
}
<|endoftext|>


<commit_before>// Package bugsnagrevel adds Bugsnag to revel.
// It lets you pass *revel.Controller into bugsnag.Notify(),
// and provides a Filter to catch errors.
package bugsnagrevel

import (
	"strings"
	"sync"

	"github.com/bugsnag/bugsnag-go"
	"github.com/revel/revel"
)

var once sync.Once

const FrameworkName string = "Revel"

var errorHandlingState = bugsnag.HandledState{
	bugsnag.SeverityReasonUnhandledMiddlewareError,
	bugsnag.SeverityError,
	true,
	FrameworkName,
}

// Filter should be added to the filter chain just after the PanicFilter.
// It sends errors to Bugsnag automatically. Configuration is read out of
// conf/app.conf, you should set bugsnag.apikey, and can also set
// bugsnag.endpoint, bugsnag.releasestage, bugsnag.apptype, bugsnag.appversion,
// bugsnag.projectroot, bugsnag.projectpackages if needed.
func Filter(c *revel.Controller, fc []revel.Filter) {
	defer bugsnag.AutoNotify(c, errorHandlingState)
	fc[0](c, fc[1:])
}

// Add support to bugsnag for reading data out of *revel.Controllers
func middleware(event *bugsnag.Event, config *bugsnag.Configuration) error {
	for _, datum := range event.RawData {
		if controller, ok := datum.(*revel.Controller); ok {
			// make the request visible to the builtin HttpMiddleware
			event.RawData = append(event.RawData, controller.Request.Request)
			event.Context = controller.Action
			event.MetaData.AddStruct("Session", controller.Session)
		}
	}

	return nil
}

func init() {
	revel.OnAppStart(func() {
		bugsnag.OnBeforeNotify(middleware)

		var projectPackages []string
		if packages, ok := revel.Config.String("bugsnag.projectpackages"); ok {
			projectPackages = strings.Split(packages, ",")
		} else {
			projectPackages = []string{revel.ImportPath + "/app/*", revel.ImportPath + "/app"}
		}

		bugsnag.Configure(bugsnag.Configuration{
			APIKey:          revel.Config.StringDefault("bugsnag.apikey", ""),
			Endpoint:        revel.Config.StringDefault("bugsnag.endpoint", ""),
			AppType:         revel.Config.StringDefault("bugsnag.apptype", ""),
			AppVersion:      revel.Config.StringDefault("bugsnag.appversion", ""),
			ReleaseStage:    revel.Config.StringDefault("bugsnag.releasestage", revel.RunMode),
			ProjectPackages: projectPackages,
			Logger:          revel.ERROR,
		})
	})
}
<commit_msg>Support Revel release v0.18.0<commit_after>// Package bugsnagrevel adds Bugsnag to revel.
// It lets you pass *revel.Controller into bugsnag.Notify(),
// and provides a Filter to catch errors.
package bugsnagrevel

import (
	"strings"
	"sync"

	"github.com/bugsnag/bugsnag-go"
	"github.com/revel/revel"
)

var once sync.Once

const FrameworkName string = "Revel"

var errorHandlingState = bugsnag.HandledState{
	bugsnag.SeverityReasonUnhandledMiddlewareError,
	bugsnag.SeverityError,
	true,
	FrameworkName,
}

// Filter should be added to the filter chain just after the PanicFilter.
// It sends errors to Bugsnag automatically. Configuration is read out of
// conf/app.conf, you should set bugsnag.apikey, and can also set
// bugsnag.endpoint, bugsnag.releasestage, bugsnag.apptype, bugsnag.appversion,
// bugsnag.projectroot, bugsnag.projectpackages if needed.
func Filter(c *revel.Controller, fc []revel.Filter) {
	defer bugsnag.AutoNotify(c, errorHandlingState)
	fc[0](c, fc[1:])
}

// Add support to bugsnag for reading data out of *revel.Controllers
func middleware(event *bugsnag.Event, config *bugsnag.Configuration) error {
	for _, datum := range event.RawData {
		if controller, ok := datum.(*revel.Controller); ok {
			// make the request visible to the builtin HttpMiddleware
			event.RawData = append(event.RawData, controller.Request)
			event.Context = controller.Action
			event.MetaData.AddStruct("Session", controller.Session)
		}
	}

	return nil
}

func init() {
	revel.OnAppStart(func() {
		bugsnag.OnBeforeNotify(middleware)

		var projectPackages []string
		if packages, ok := revel.Config.String("bugsnag.projectpackages"); ok {
			projectPackages = strings.Split(packages, ",")
		} else {
			projectPackages = []string{revel.ImportPath + "/app/*", revel.ImportPath + "/app"}
		}

		bugsnag.Configure(bugsnag.Configuration{
			APIKey:          revel.Config.StringDefault("bugsnag.apikey", ""),
			Endpoint:        revel.Config.StringDefault("bugsnag.endpoint", ""),
			AppType:         revel.Config.StringDefault("bugsnag.apptype", ""),
			AppVersion:      revel.Config.StringDefault("bugsnag.appversion", ""),
			ReleaseStage:    revel.Config.StringDefault("bugsnag.releasestage", revel.RunMode),
			ProjectPackages: projectPackages,
			Logger:          revel.ERROR,
		})
	})
}
<|endoftext|>


<commit_before>package decoding

import (
	"errors"

	"github.com/mccoyst/vorbis"
)

type vorbisDecoder struct {
	decoderBase
	handle *vorbis.Vorbis
}

func (decoder *vorbisDecoder) read() error {
	return errors.New("not implemented")
}

func (decoder *vorbisDecoder) Decode() int {
	return 0
}

func (decoder *vorbisDecoder) GetData() []byte {
	return []byte{}
}

func (decoder *vorbisDecoder) Seek(s int64) bool {
	return false
}
<commit_msg>fix that bug<commit_after>package decoding

import (
	"errors"
)

type vorbisDecoder struct {
	decoderBase
}

func (decoder *vorbisDecoder) read() error {
	return errors.New("not implemented")
}

func (decoder *vorbisDecoder) Decode() int {
	return 0
}

func (decoder *vorbisDecoder) GetData() []byte {
	return []byte{}
}

func (decoder *vorbisDecoder) Seek(s int64) bool {
	return false
}
<|endoftext|>


<commit_before>package sender

import (
	"errors"
	"fmt"

	"github.com/qiniu/logkit/conf"
	"github.com/qiniu/logkit/utils"
)

// Data store as use key/value map
// e.g sum -> 1.2, url -> qiniu.com
type Data map[string]interface{}

// NotAsyncSender return when sender is not async
var ErrNotAsyncSender = errors.New("This Sender does not support for Async Push")

// Sender send data to pandora, prometheus such different destinations
type Sender interface {
	Name() string
	// send data, error if failed
	Send([]Data) error
	Close() error
}

type StatsSender interface {
	Name() string
	// send data, error if failed
	Send([]Data) error
	Close() error
	Stats() utils.StatsInfo
	// 恢复 sender 停止之前的状态
	Restore(*utils.StatsInfo)
}

type asyncSender interface {

}

// Sender's conf keys
const (
	KeySenderType    = "sender_type"
	KeyFaultTolerant = "fault_tolerant"
	KeyName          = "name"
	KeyRunnerName    = "runner_name"
)

const UnderfinedRunnerName = "UnderfinedRunnerName"

// SenderType 发送类型
const (
	TypeFile              = "file"          // 本地文件
	TypePandora           = "pandora"       // pandora 打点
	TypeMongodbAccumulate = "mongodb_acc"   // mongodb 并且按字段聚合
	TypeInfluxdb          = "influxdb"      // influxdb
	TypeMock              = "mock"          // mock sender
	TypeDiscard           = "discard"       // discard sender
	TypeElastic           = "elasticsearch" // elastic
	TypeKafka             = "kafka"         // kafka
)

const (
	InnerUserAgent = "_useragent"
)

// Ft sender默认同步一次meta信息的数据次数
const DefaultFtSyncEvery = 10

// SenderRegistry sender 的工厂类。可以注册自定义sender
type SenderRegistry struct {
	senderTypeMap map[string]func(conf.MapConf) (Sender, error)
}

func NewSenderRegistry() *SenderRegistry {
	ret := &SenderRegistry{
		senderTypeMap: map[string]func(conf.MapConf) (Sender, error){},
	}
	ret.RegisterSender(TypeFile, NewFileSender)
	ret.RegisterSender(TypePandora, NewPandoraSender)
	ret.RegisterSender(TypeMongodbAccumulate, NewMongodbAccSender)
	ret.RegisterSender(TypeInfluxdb, NewInfluxdbSender)
	ret.RegisterSender(TypeElastic, NewElasticSender)
	ret.RegisterSender(TypeMock, NewMockSender)
	ret.RegisterSender(TypeDiscard, NewDiscardSender)
	ret.RegisterSender(TypeKafka, NewKafkaSender)
	return ret
}

func (registry *SenderRegistry) RegisterSender(senderType string, constructor func(conf.MapConf) (Sender, error)) error {
	_, exist := registry.senderTypeMap[senderType]
	if exist {
		return errors.New("senderType " + senderType + " has been existed")
	}
	registry.senderTypeMap[senderType] = constructor
	return nil
}

func (r *SenderRegistry) NewSender(conf conf.MapConf, ftSaveLogPath string) (sender Sender, err error) {
	sendType, err := conf.GetString(KeySenderType)
	if err != nil {
		return
	}
	constructor, exist := r.senderTypeMap[sendType]
	if !exist {
		return nil, fmt.Errorf("sender type unsupperted : %v", sendType)
	}
	sender, err = constructor(conf)
	if err != nil {
		return
	}
	faultTolerant, _ := conf.GetBoolOr(KeyFaultTolerant, true)
	if faultTolerant {
		sender, err = NewFtSender(sender, conf, ftSaveLogPath)
		if err != nil {
			return
		}
	}
	return sender, nil
}
<commit_msg>删除多余代码<commit_after>package sender

import (
	"errors"
	"fmt"

	"github.com/qiniu/logkit/conf"
	"github.com/qiniu/logkit/utils"
)

// Data store as use key/value map
// e.g sum -> 1.2, url -> qiniu.com
type Data map[string]interface{}

// NotAsyncSender return when sender is not async
var ErrNotAsyncSender = errors.New("This Sender does not support for Async Push")

// Sender send data to pandora, prometheus such different destinations
type Sender interface {
	Name() string
	// send data, error if failed
	Send([]Data) error
	Close() error
}

type StatsSender interface {
	Name() string
	// send data, error if failed
	Send([]Data) error
	Close() error
	Stats() utils.StatsInfo
	// 恢复 sender 停止之前的状态
	Restore(*utils.StatsInfo)
}

// Sender's conf keys
const (
	KeySenderType    = "sender_type"
	KeyFaultTolerant = "fault_tolerant"
	KeyName          = "name"
	KeyRunnerName    = "runner_name"
)

const UnderfinedRunnerName = "UnderfinedRunnerName"

// SenderType 发送类型
const (
	TypeFile              = "file"          // 本地文件
	TypePandora           = "pandora"       // pandora 打点
	TypeMongodbAccumulate = "mongodb_acc"   // mongodb 并且按字段聚合
	TypeInfluxdb          = "influxdb"      // influxdb
	TypeMock              = "mock"          // mock sender
	TypeDiscard           = "discard"       // discard sender
	TypeElastic           = "elasticsearch" // elastic
	TypeKafka             = "kafka"         // kafka
)

const (
	InnerUserAgent = "_useragent"
)

// Ft sender默认同步一次meta信息的数据次数
const DefaultFtSyncEvery = 10

// SenderRegistry sender 的工厂类。可以注册自定义sender
type SenderRegistry struct {
	senderTypeMap map[string]func(conf.MapConf) (Sender, error)
}

func NewSenderRegistry() *SenderRegistry {
	ret := &SenderRegistry{
		senderTypeMap: map[string]func(conf.MapConf) (Sender, error){},
	}
	ret.RegisterSender(TypeFile, NewFileSender)
	ret.RegisterSender(TypePandora, NewPandoraSender)
	ret.RegisterSender(TypeMongodbAccumulate, NewMongodbAccSender)
	ret.RegisterSender(TypeInfluxdb, NewInfluxdbSender)
	ret.RegisterSender(TypeElastic, NewElasticSender)
	ret.RegisterSender(TypeMock, NewMockSender)
	ret.RegisterSender(TypeDiscard, NewDiscardSender)
	ret.RegisterSender(TypeKafka, NewKafkaSender)
	return ret
}

func (registry *SenderRegistry) RegisterSender(senderType string, constructor func(conf.MapConf) (Sender, error)) error {
	_, exist := registry.senderTypeMap[senderType]
	if exist {
		return errors.New("senderType " + senderType + " has been existed")
	}
	registry.senderTypeMap[senderType] = constructor
	return nil
}

func (r *SenderRegistry) NewSender(conf conf.MapConf, ftSaveLogPath string) (sender Sender, err error) {
	sendType, err := conf.GetString(KeySenderType)
	if err != nil {
		return
	}
	constructor, exist := r.senderTypeMap[sendType]
	if !exist {
		return nil, fmt.Errorf("sender type unsupperted : %v", sendType)
	}
	sender, err = constructor(conf)
	if err != nil {
		return
	}
	faultTolerant, _ := conf.GetBoolOr(KeyFaultTolerant, true)
	if faultTolerant {
		sender, err = NewFtSender(sender, conf, ftSaveLogPath)
		if err != nil {
			return
		}
	}
	return sender, nil
}
<|endoftext|>


<commit_before>// This file represents the server for sensors
// It opens communication links (for each sensor) through http protocol
// Port # 8001 for Gyroscope Sensor,
// Port # 8002 for Accelerator Sensor,
// Port # 8003 for Temperature Sensor.
// If the sensor client sends data through appropriate port,
// each http handler is initiated, decoding data to appropriate JSON file.
// Those datas are then logged to each sensor's log file
// (log/Accel.log , log/Temp.log , log/Gyro.log)

package main

// 'models' package		 : Stores basic sensor information in srtuct form
// 'net/http' package	 : To serve http connection and handle requests
// 'os' package			 : To open files for logging
// 'strings' package	 : To join strings for file path
// 'sync' package		 : To use 'WaitGroup' to hold main thread while goroutines are working

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"sync"

	"github.com/mingrammer/go-codelab/models"
)

// String constants that are used in sensor_server.go
// logDir	: Directory name to store logs
// tempLog	: File name to store temperature sensor log
// accelLog	: File name to store accelerator sensor log
// gyroLog	: File name to store gyroscope sensro log

const (
	logDir   = "log"
	tempLog  = "Temp.log"
	accelLog = "Accel.log"
	gyroLog  = "Gyro.log"
)

// This logContent struct is to store data (string) would be written in log file
// content 	: Actual string data, that would be logged in file
// location	: Indicator that where the 'content' should be stored (or written)

type logContent struct {
	content    string
	location   string
	sensorName string
}

// Three structs below are to implement ServeHTTP method
// Each handler stores the pointer to data logging channel
// Also, channel is bidirectional in these handlers, which only can store data in channel

// GyroHandler	: Gyroscopte sensor handler to implement ServeHTTP method
type GyroHandler struct {
	buf chan<- logContent
}

// AccelHandler : Accelerator sensro handler to implement ServeHTTP method
type AccelHandler struct {
	buf chan<- logContent
}

// TempHandler 	: Temperature sensor handler to implement ServeHTTP method
type TempHandler struct {
	buf chan<- logContent
}

// These methods are to handle request from each port.
// Body of request (which is in JSON format) is decoded and allocated to TempSensor variable
// and string, of which data would be saved in log fileis sent to logging channel
// Note that BOdy of http request CAN NOT BE unmarshalled, because body of request is in array of bytes.

func (m *TempHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var data models.TempSensor

	decoder := json.NewDecoder(req.Body)
	err := decoder.Decode(&data)
	if err != nil {
		fmt.Println("Something wrong")
	}
	defer req.Body.Close()

	fmt.Println(data.ReceivingOutputString())

	m.buf <- logContent{content: fmt.Sprintf("%s", data), location: tempLog, sensorName: data.Name}
}

func (m *GyroHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var data models.GyroSensor

	decoder := json.NewDecoder(req.Body)
	err := decoder.Decode(&data)
	if err != nil {
		fmt.Println("Something wrong")
	}
	defer req.Body.Close()

	fmt.Println(data.ReceivingOutputString())

	m.buf <- logContent{content: fmt.Sprintf("%s", data), location: gyroLog, sensorName: data.Name}
}

func (m *AccelHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var data models.AccelSensor

	decoder := json.NewDecoder(req.Body)
	err := decoder.Decode(&data)
	if err != nil {
		fmt.Println("Something wrong")
	}
	defer req.Body.Close()

	fmt.Println(data.ReceivingOutputString())

	m.buf <- logContent{content: fmt.Sprintf("%s", data), location: accelLog, sensorName: data.Name}
}

// This method loggs the content of sensor data
// This method waits incoming data from 'logContent' channel at range block,
// where ServeHTTP mehthod sends log data
// When data is detected, for/range block immediately processes data
// It checks the location, where the data should be stored,
// and opens file of desired location (by joining string constants)
// Note that channel used in this method is also BIDIRECTIONAL,
// You only can pop the data from channel.

func fileLogger(m <-chan logContent) {

	// When program is initialized, fileLogger checks if 'log' dir exists.
	// If it does not, it creates directory for the first time.
	// If there is problem with creating it, it throws panic and aborts the application.

	dir, _ := os.Open("log")
	dirInfo, _ := dir.Stat()

	if dirInfo == nil {
		err := os.Mkdir("log", os.ModePerm)

		if err != nil {
			log.Fatal("Error creating directory 'log'\n", err)
		}
	}
	dir.Close()

	// This part continuously wait for incoming data through channel

	for i := range m {
		joinee := []string{logDir, i.location}
		filePath := strings.Join(joinee, "/")

		fileHandle, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)

		if err != nil {
			log.Fatal("Error Opening File\n", err)
		}

		logger := log.New(fileHandle, "", log.LstdFlags)

		logger.Printf("[%s Data Received]\n%s\n", i.sensorName, i.content)

		defer fileHandle.Close()
	}
}

// This method is for main thread. It starts go application.
// It first creates handler to serve http serve for each sensors
// sync.WaitGroup is to hold main thread while go routines are still working
// Main thread indicates WaitGroup to wait 4 routines to stop.
// After goroutines we need is created, main thread has WaitGroup to wait goroutines.

func main() {
	var wg sync.WaitGroup

	wg.Add(4)

	logBuf := make(chan logContent)
	gyroHander := &GyroHandler{buf: logBuf}
	accelHandler := &AccelHandler{buf: logBuf}
	tempHandler := &TempHandler{buf: logBuf}

	go http.ListenAndServe(":8001", gyroHander)
	go http.ListenAndServe(":8002", accelHandler)
	go http.ListenAndServe(":8003", tempHandler)
	go fileLogger(logBuf)

	wg.Wait()
}
<commit_msg>Remove weird space in comment<commit_after>// This file represents the server for sensors
// It opens communication links (for each sensor) through http protocol
// Port # 8001 for Gyroscope Sensor,
// Port # 8002 for Accelerator Sensor,
// Port # 8003 for Temperature Sensor.
// If the sensor client sends data through appropriate port,
// each http handler is initiated, decoding data to appropriate JSON file.
// Those datas are then logged to each sensor's log file
// (log/Accel.log , log/Temp.log , log/Gyro.log)

package main

// 'models' package		 : Stores basic sensor information in srtuct form
// 'net/http' package	 : To serve http connection and handle requests
// 'os' package			 : To open files for logging
// 'strings' package	 : To join strings for file path
// 'sync' package		 : To use 'WaitGroup' to hold main thread while goroutines are working

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"sync"

	"github.com/mingrammer/go-codelab/models"
)

// String constants that are used in sensor_server.go
// logDir	: Directory name to store logs
// tempLog	: File name to store temperature sensor log
// accelLog	: File name to store accelerator sensor log
// gyroLog	: File name to store gyroscope sensro log

const (
	logDir   = "log"
	tempLog  = "Temp.log"
	accelLog = "Accel.log"
	gyroLog  = "Gyro.log"
)

// This logContent struct is to store data (string) would be written in log file
// content 	: Actual string data, that would be logged in file
// location	: Indicator that where the 'content' should be stored (or written)

type logContent struct {
	content    string
	location   string
	sensorName string
}

// Three structs below are to implement ServeHTTP method
// Each handler stores the pointer to data logging channel
// Also, channel is bidirectional in these handlers, which only can store data in channel

// GyroHandler : Gyroscopte sensor handler to implement ServeHTTP method
type GyroHandler struct {
	buf chan<- logContent
}

// AccelHandler : Accelerator sensro handler to implement ServeHTTP method
type AccelHandler struct {
	buf chan<- logContent
}

// TempHandler 	: Temperature sensor handler to implement ServeHTTP method
type TempHandler struct {
	buf chan<- logContent
}

// These methods are to handle request from each port.
// Body of request (which is in JSON format) is decoded and allocated to TempSensor variable
// and string, of which data would be saved in log fileis sent to logging channel
// Note that BOdy of http request CAN NOT BE unmarshalled, because body of request is in array of bytes.

func (m *TempHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var data models.TempSensor

	decoder := json.NewDecoder(req.Body)
	err := decoder.Decode(&data)
	if err != nil {
		fmt.Println("Something wrong")
	}
	defer req.Body.Close()

	fmt.Println(data.ReceivingOutputString())

	m.buf <- logContent{content: fmt.Sprintf("%s", data), location: tempLog, sensorName: data.Name}
}

func (m *GyroHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var data models.GyroSensor

	decoder := json.NewDecoder(req.Body)
	err := decoder.Decode(&data)
	if err != nil {
		fmt.Println("Something wrong")
	}
	defer req.Body.Close()

	fmt.Println(data.ReceivingOutputString())

	m.buf <- logContent{content: fmt.Sprintf("%s", data), location: gyroLog, sensorName: data.Name}
}

func (m *AccelHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var data models.AccelSensor

	decoder := json.NewDecoder(req.Body)
	err := decoder.Decode(&data)
	if err != nil {
		fmt.Println("Something wrong")
	}
	defer req.Body.Close()

	fmt.Println(data.ReceivingOutputString())

	m.buf <- logContent{content: fmt.Sprintf("%s", data), location: accelLog, sensorName: data.Name}
}

// This method loggs the content of sensor data
// This method waits incoming data from 'logContent' channel at range block,
// where ServeHTTP mehthod sends log data
// When data is detected, for/range block immediately processes data
// It checks the location, where the data should be stored,
// and opens file of desired location (by joining string constants)
// Note that channel used in this method is also BIDIRECTIONAL,
// You only can pop the data from channel.

func fileLogger(m <-chan logContent) {

	// When program is initialized, fileLogger checks if 'log' dir exists.
	// If it does not, it creates directory for the first time.
	// If there is problem with creating it, it throws panic and aborts the application.

	dir, _ := os.Open("log")
	dirInfo, _ := dir.Stat()

	if dirInfo == nil {
		err := os.Mkdir("log", os.ModePerm)

		if err != nil {
			log.Fatal("Error creating directory 'log'\n", err)
		}
	}
	dir.Close()

	// This part continuously wait for incoming data through channel

	for i := range m {
		joinee := []string{logDir, i.location}
		filePath := strings.Join(joinee, "/")

		fileHandle, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)

		if err != nil {
			log.Fatal("Error Opening File\n", err)
		}

		logger := log.New(fileHandle, "", log.LstdFlags)

		logger.Printf("[%s Data Received]\n%s\n", i.sensorName, i.content)

		defer fileHandle.Close()
	}
}

// This method is for main thread. It starts go application.
// It first creates handler to serve http serve for each sensors
// sync.WaitGroup is to hold main thread while go routines are still working
// Main thread indicates WaitGroup to wait 4 routines to stop.
// After goroutines we need is created, main thread has WaitGroup to wait goroutines.

func main() {
	var wg sync.WaitGroup

	wg.Add(4)

	logBuf := make(chan logContent)
	gyroHander := &GyroHandler{buf: logBuf}
	accelHandler := &AccelHandler{buf: logBuf}
	tempHandler := &TempHandler{buf: logBuf}

	go http.ListenAndServe(":8001", gyroHander)
	go http.ListenAndServe(":8002", accelHandler)
	go http.ListenAndServe(":8003", tempHandler)
	go fileLogger(logBuf)

	wg.Wait()
}
<|endoftext|>


<commit_before>package html

import (
	"code.google.com/p/go.net/html"
	"errors"
	"github.com/slyrz/newscat/util"
	"strings"
)

// A Chunk is a chunk of consecutive text found in the HTML document.
// It combines the content of one or more html.TextNodes. Whitespace is
// ignored, but interword spaces are preserved. Therefore each Chunk
// must contain actual text and whitespace-only html.TextNodes don't
// result Chunks.
type Chunk struct {
	Prev      *Chunk     // previous chunk
	Next      *Chunk     // next chunk
	Text      *util.Text // text of this chunk
	Base      *html.Node // element node which contained this chunk
	Block     *html.Node // parent block node of base node
	Container *html.Node // parent block node of block node
	Classes   []string   // list of classes this chunk belongs to
	Ancestors int        // bitmask of the ancestors of this chunk
	LinkText  float32    // link text to normal text ratio.
}

func getParentBlock(n *html.Node) *html.Node {
	// Keep ascending as long as the node points to an HTML inline element.
	// We stop at the first block-level element. The list of inline elements
	// was taken from:
	// https://developer.mozilla.org/en-US/docs/HTML/Inline_elements
	for ; n != nil && n.Parent != nil; n = n.Parent {
		switch n.Data {
		case "a", "abbr", "acronym", "b", "bdo", "big", "br", "button", "cite",
			"code", "dfn", "em", "i", "img", "input", "kbd", "label", "map",
			"object", "q", "samp", "script", "select", "small", "span",
			"strong", "sub", "sup", "textarea", "tt", "var":
			continue
		default:
			return n
		}
	}
	return n
}

func NewChunk(doc *Document, n *html.Node) (*Chunk, error) {
	chunk := new(Chunk)
	chunk.Text = util.NewText()

	switch n.Type {
	// If an ElementNode was passed, create Text property using all
	// TextNode children.
	case html.ElementNode:
		chunk.Base = n
		chunk.addText(n)
	// If a TextNode was passed, use the parent ElementNode for the
	// base field.
	case html.TextNode:
		// We don't allow baseless Chunks.
		if n.Parent == nil {
			return nil, errors.New("orphaned TextNode")
		}
		chunk.Base = n.Parent
		chunk.addText(n)
	}

	// We perform text extraction, not whitespace extraction.
	if chunk.Text.Len() == 0 {
		return nil, errors.New("no text")
	}

	// Now we detect the HTML block and container of the base node. The block
	// is the first block-level element found when ascending from base node.
	// The container is the first block-level element found when ascending
	// from the block's parent.
	//
	// Example:
	//
	// a) Base node is a block-level element:
	//
	//
                        <- Container
	//
Hello World
         <- Base & Block
	//

	//
	// b) Base node is not a block-level element:
	//
	//
                         <- Container
	//
                         <- Block
	//
	//          Hello World      <- Base
	//
	//

	//

	if block := getParentBlock(chunk.Base); block != nil {
		chunk.Block = block
	} else {
		return nil, errors.New("no block found")
	}

	// If there happens to be no block-level element after the block's parent,
	// use block as container as well. This ensures that the container field
	// is never nil and we avoid nil pointer handling in our code.
	if container := getParentBlock(chunk.Block.Parent); container != nil {
		chunk.Container = container
	} else {
		chunk.Container = chunk.Block
	}

	// Remember the ancestors in our chunk.
	chunk.Ancestors = doc.ancestors

	// Calculate the ratio between text inside links and text outside links
	// for the current element's block node. This is useful to determine the
	// quality of a link. Links used as cross references inside the article
	// content have a small link text to text ratio,
	//
	//
Long text .... short text ...

	//
	// whereas related content / navigation links have a high link text
	// to text ratio:
	//
	//
See also: ...

	//
	linkText := doc.linkText[chunk.Block]
	normText := doc.normText[chunk.Block]
	if normText == 0 && linkText == 0 {
		chunk.LinkText = 0.0
	} else {
		chunk.LinkText = float32(linkText) / float32(linkText+normText)
	}

	// Detect the classes of the current node. We use the good old class
	// attribute and the new HTML5 microdata (itemprop attribute) to determine
	// the content class. Most IDs aren't really meaningful, so no IDs here.
	chunk.Classes = make([]string, 0)

	// Ascend parent nodes until we found a class attribute and some
	// microdata.
	haveClass := false
	haveMicro := false
	for prev := chunk.Base; prev != nil; prev = prev.Parent {
		if prev.Type != html.ElementNode {
			continue
		}
		for _, attr := range prev.Attr {
			switch {
			case !haveClass && attr.Key == "class":
				haveClass = true
			case !haveMicro && attr.Key == "itemprop":
				haveMicro = true
			default:
				continue
			}
			// The default: continue case keeps us from reaching this for values
			// we are not interested in.
			for _, val := range strings.Fields(attr.Val) {
				chunk.Classes = append(chunk.Classes, val)
			}
		}
		if haveClass && haveMicro {
			break
		}
	}
	return chunk, nil
}

// Add all text from a html.Node to our chunk.
func (ch *Chunk) addText(n *html.Node) {
	switch n.Type {
	case html.TextNode:
		ch.Text.WriteString(n.Data)
	case html.ElementNode:
		for c := n.FirstChild; c != nil; c = c.NextSibling {
			ch.addText(c)
		}
	}
}

// Return the types of the base node's siblings.
func (ch *Chunk) GetSiblingTypes() []string {
	result := make([]string, 0, 8)
	for s := ch.Base.PrevSibling; s != nil; s = s.PrevSibling {
		if s.Type == html.ElementNode {
			result = append(result, s.Data)
		}
	}
	for s := ch.Base.NextSibling; s != nil; s = s.NextSibling {
		if s.Type == html.ElementNode {
			result = append(result, s.Data)
		}
	}
	return result
}

// Return the types of the base node's children.
func (ch *Chunk) GetChildTypes() []string {
	result := make([]string, 0, 8)
	for s := ch.Base.FirstChild; s != nil; s = s.NextSibling {
		if s.Type == html.ElementNode {
			result = append(result, s.Data)
		}
	}
	return result
}
<commit_msg>spelling<commit_after>package html

import (
	"code.google.com/p/go.net/html"
	"errors"
	"github.com/slyrz/newscat/util"
	"strings"
)

// A Chunk is a chunk of consecutive text found in the HTML document.
// It combines the content of one or more html.TextNodes. Whitespace is
// ignored, but interword spaces are preserved. Therefore each Chunk
// must contain actual text and whitespace-only html.TextNodes don't
// result in Chunks.
type Chunk struct {
	Prev      *Chunk     // previous chunk
	Next      *Chunk     // next chunk
	Text      *util.Text // text of this chunk
	Base      *html.Node // element node which contained this chunk
	Block     *html.Node // parent block node of base node
	Container *html.Node // parent block node of block node
	Classes   []string   // list of classes this chunk belongs to
	Ancestors int        // bitmask of the ancestors of this chunk
	LinkText  float32    // link text to normal text ratio.
}

func getParentBlock(n *html.Node) *html.Node {
	// Keep ascending as long as the node points to an HTML inline element.
	// We stop at the first block-level element. The list of inline elements
	// was taken from:
	// https://developer.mozilla.org/en-US/docs/HTML/Inline_elements
	for ; n != nil && n.Parent != nil; n = n.Parent {
		switch n.Data {
		case "a", "abbr", "acronym", "b", "bdo", "big", "br", "button", "cite",
			"code", "dfn", "em", "i", "img", "input", "kbd", "label", "map",
			"object", "q", "samp", "script", "select", "small", "span",
			"strong", "sub", "sup", "textarea", "tt", "var":
			continue
		default:
			return n
		}
	}
	return n
}

func NewChunk(doc *Document, n *html.Node) (*Chunk, error) {
	chunk := new(Chunk)
	chunk.Text = util.NewText()

	switch n.Type {
	// If an ElementNode was passed, create Text property using all
	// TextNode children.
	case html.ElementNode:
		chunk.Base = n
		chunk.addText(n)
	// If a TextNode was passed, use the parent ElementNode for the
	// base field.
	case html.TextNode:
		// We don't allow baseless Chunks.
		if n.Parent == nil {
			return nil, errors.New("orphaned TextNode")
		}
		chunk.Base = n.Parent
		chunk.addText(n)
	}

	// We perform text extraction, not whitespace extraction.
	if chunk.Text.Len() == 0 {
		return nil, errors.New("no text")
	}

	// Now we detect the HTML block and container of the base node. The block
	// is the first block-level element found when ascending from base node.
	// The container is the first block-level element found when ascending
	// from the block's parent.
	//
	// Example:
	//
	// a) Base node is a block-level element:
	//
	//
                        <- Container
	//
Hello World
         <- Base & Block
	//

	//
	// b) Base node is not a block-level element:
	//
	//
                         <- Container
	//
                         <- Block
	//
	//          Hello World      <- Base
	//
	//

	//

	if block := getParentBlock(chunk.Base); block != nil {
		chunk.Block = block
	} else {
		return nil, errors.New("no block found")
	}

	// If there happens to be no block-level element after the block's parent,
	// use block as container as well. This ensures that the container field
	// is never nil and we avoid nil pointer handling in our code.
	if container := getParentBlock(chunk.Block.Parent); container != nil {
		chunk.Container = container
	} else {
		chunk.Container = chunk.Block
	}

	// Remember the ancestors in our chunk.
	chunk.Ancestors = doc.ancestors

	// Calculate the ratio between text inside links and text outside links
	// for the current element's block node. This is useful to determine the
	// quality of a link. Links used as cross references inside the article
	// content have a small link text to text ratio,
	//
	//
Long text .... short text ...

	//
	// whereas related content / navigation links have a high link text
	// to text ratio:
	//
	//
See also: ...

	//
	linkText := doc.linkText[chunk.Block]
	normText := doc.normText[chunk.Block]
	if normText == 0 && linkText == 0 {
		chunk.LinkText = 0.0
	} else {
		chunk.LinkText = float32(linkText) / float32(linkText+normText)
	}

	// Detect the classes of the current node. We use the good old class
	// attribute and the new HTML5 microdata (itemprop attribute) to determine
	// the content class. Most IDs aren't really meaningful, so no IDs here.
	chunk.Classes = make([]string, 0)

	// Ascend parent nodes until we found a class attribute and some
	// microdata.
	haveClass := false
	haveMicro := false
	for prev := chunk.Base; prev != nil; prev = prev.Parent {
		if prev.Type != html.ElementNode {
			continue
		}
		for _, attr := range prev.Attr {
			switch {
			case !haveClass && attr.Key == "class":
				haveClass = true
			case !haveMicro && attr.Key == "itemprop":
				haveMicro = true
			default:
				continue
			}
			// The default: continue case keeps us from reaching this for values
			// we are not interested in.
			for _, val := range strings.Fields(attr.Val) {
				chunk.Classes = append(chunk.Classes, val)
			}
		}
		if haveClass && haveMicro {
			break
		}
	}
	return chunk, nil
}

// Add all text from a html.Node to our chunk.
func (ch *Chunk) addText(n *html.Node) {
	switch n.Type {
	case html.TextNode:
		ch.Text.WriteString(n.Data)
	case html.ElementNode:
		for c := n.FirstChild; c != nil; c = c.NextSibling {
			ch.addText(c)
		}
	}
}

// Return the types of the base node's siblings.
func (ch *Chunk) GetSiblingTypes() []string {
	result := make([]string, 0, 8)
	for s := ch.Base.PrevSibling; s != nil; s = s.PrevSibling {
		if s.Type == html.ElementNode {
			result = append(result, s.Data)
		}
	}
	for s := ch.Base.NextSibling; s != nil; s = s.NextSibling {
		if s.Type == html.ElementNode {
			result = append(result, s.Data)
		}
	}
	return result
}

// Return the types of the base node's children.
func (ch *Chunk) GetChildTypes() []string {
	result := make([]string, 0, 8)
	for s := ch.Base.FirstChild; s != nil; s = s.NextSibling {
		if s.Type == html.ElementNode {
			result = append(result, s.Data)
		}
	}
	return result
}
<|endoftext|>


<commit_before>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of getgauge/html-report.

// getgauge/html-report is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// getgauge/html-report is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with getgauge/html-report.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/getgauge/common"
	"github.com/getgauge/html-report/gauge_messages"
	"github.com/getgauge/html-report/generator"
	"github.com/getgauge/html-report/listener"
)

const (
	reportTemplateDir           = "report-template"
	defaultReportsDir           = "reports"
	gaugeReportsDirEnvName      = "gauge_reports_dir" // directory where reports are generated by plugins
	overwriteReportsEnvProperty = "overwrite_reports"
	resultJsFile                = "result.js"
	htmlReport                  = "html-report"
	SETUP_ACTION                = "setup"
	EXECUTION_ACTION            = "execution"
	GAUGE_HOST                  = "localhost"
	GAUGE_PORT_ENV              = "plugin_connection_port"
	PLUGIN_ACTION_ENV           = "html-report_action"
	timeFormat                  = "2006-01-02 15.04.05"
)

var projectRoot string
var pluginDir string

type nameGenerator interface {
	randomName() string
}

type timeStampedNameGenerator struct {
}

func (T timeStampedNameGenerator) randomName() string {
	return time.Now().Format(timeFormat)
}

func findPluginAndProjectRoot() {
	projectRoot = os.Getenv(common.GaugeProjectRootEnv)
	if projectRoot == "" {
		fmt.Printf("Environment variable '%s' is not set. \n", common.GaugeProjectRootEnv)
		os.Exit(1)
	}

	var err error
	pluginDir, err = os.Getwd()
	if err != nil {
		fmt.Printf("Error finding current working directory: %s \n", err)
		os.Exit(1)
	}
}

func createExecutionReport() {
	os.Chdir(projectRoot)
	listener, err := listener.NewGaugeListener(GAUGE_HOST, os.Getenv(GAUGE_PORT_ENV))
	if err != nil {
		fmt.Println("Could not create the gauge listener")
		os.Exit(1)
	}
	listener.OnSuiteResult(createReport)
	listener.Start()
}

func addDefaultPropertiesToProject() {
	defaultPropertiesFile := getDefaultPropertiesFile()

	reportsDirProperty := &(common.Property{
		Comment:      "The path to the gauge reports directory. Should be either relative to the project directory or an absolute path",
		Name:         gaugeReportsDirEnvName,
		DefaultValue: defaultReportsDir})

	overwriteReportProperty := &(common.Property{
		Comment:      "Set as false if gauge reports should not be overwritten on each execution. A new time-stamped directory will be created on each execution.",
		Name:         overwriteReportsEnvProperty,
		DefaultValue: "true"})

	if !common.FileExists(defaultPropertiesFile) {
		fmt.Printf("Failed to setup html report plugin in project. Default properties file does not exist at %s. \n", defaultPropertiesFile)
		return
	}
	if err := common.AppendProperties(defaultPropertiesFile, reportsDirProperty, overwriteReportProperty); err != nil {
		fmt.Printf("Failed to setup html report plugin in project: %s \n", err)
		return
	}
	fmt.Println("Succesfully added configurations for html-report to env/default/default.properties")
}

func getDefaultPropertiesFile() string {
	return filepath.Join(projectRoot, "env", "default", "default.properties")
}

func createReport(suiteResult *gauge_messages.SuiteExecutionResult) {
	reportsDir := getReportsDirectory(getNameGen())
	err := generator.GenerateReports(suiteResult.GetSuiteResult(), reportsDir)
	if err != nil {
		fmt.Errorf("Failed to generate reports: %s", err.Error())
		os.Exit(1)
	}
	err = copyReportTemplateFiles(reportsDir)
	if err != nil {
		fmt.Errorf("Error copying template directory :%s\n", err.Error())
		os.Exit(1)
	}
	fmt.Printf("Successfully generated html-report to => %s\n", reportsDir)
}

func getNameGen() nameGenerator {
	var nameGen nameGenerator
	if shouldOverwriteReports() {
		nameGen = nil
	} else {
		nameGen = timeStampedNameGenerator{}
	}
	return nameGen
}

func getReportsDirectory(nameGen nameGenerator) string {
	reportsDir, err := filepath.Abs(os.Getenv(gaugeReportsDirEnvName))
	if reportsDir == "" || err != nil {
		reportsDir = defaultReportsDir
	}
	createDirectory(reportsDir)
	var currentReportDir string
	if nameGen != nil {
		currentReportDir = filepath.Join(reportsDir, htmlReport, nameGen.randomName())
	} else {
		currentReportDir = filepath.Join(reportsDir, htmlReport)
	}
	createDirectory(currentReportDir)
	return currentReportDir
}

func copyReportTemplateFiles(reportDir string) error {
	reportTemplateDir := filepath.Join(pluginDir, reportTemplateDir)
	_, err := common.MirrorDir(reportTemplateDir, reportDir)
	return err
}

func shouldOverwriteReports() bool {
	envValue := os.Getenv(overwriteReportsEnvProperty)
	if strings.ToLower(envValue) == "true" {
		return true
	}
	return false
}

func createDirectory(dir string) {
	if common.DirExists(dir) {
		return
	}
	if err := os.MkdirAll(dir, common.NewDirectoryPermissions); err != nil {
		fmt.Printf("Failed to create directory %s: %s\n", defaultReportsDir, err)
		os.Exit(1)
	}
}
<commit_msg>Using fmt.Printf instead of fmt.Errorf | Ref #86<commit_after>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of getgauge/html-report.

// getgauge/html-report is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// getgauge/html-report is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with getgauge/html-report.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/getgauge/common"
	"github.com/getgauge/html-report/gauge_messages"
	"github.com/getgauge/html-report/generator"
	"github.com/getgauge/html-report/listener"
)

const (
	reportTemplateDir           = "report-template"
	defaultReportsDir           = "reports"
	gaugeReportsDirEnvName      = "gauge_reports_dir" // directory where reports are generated by plugins
	overwriteReportsEnvProperty = "overwrite_reports"
	resultJsFile                = "result.js"
	htmlReport                  = "html-report"
	SETUP_ACTION                = "setup"
	EXECUTION_ACTION            = "execution"
	GAUGE_HOST                  = "localhost"
	GAUGE_PORT_ENV              = "plugin_connection_port"
	PLUGIN_ACTION_ENV           = "html-report_action"
	timeFormat                  = "2006-01-02 15.04.05"
)

var projectRoot string
var pluginDir string

type nameGenerator interface {
	randomName() string
}

type timeStampedNameGenerator struct {
}

func (T timeStampedNameGenerator) randomName() string {
	return time.Now().Format(timeFormat)
}

func findPluginAndProjectRoot() {
	projectRoot = os.Getenv(common.GaugeProjectRootEnv)
	if projectRoot == "" {
		fmt.Printf("Environment variable '%s' is not set. \n", common.GaugeProjectRootEnv)
		os.Exit(1)
	}

	var err error
	pluginDir, err = os.Getwd()
	if err != nil {
		fmt.Printf("Error finding current working directory: %s \n", err)
		os.Exit(1)
	}
}

func createExecutionReport() {
	os.Chdir(projectRoot)
	listener, err := listener.NewGaugeListener(GAUGE_HOST, os.Getenv(GAUGE_PORT_ENV))
	if err != nil {
		fmt.Println("Could not create the gauge listener")
		os.Exit(1)
	}
	listener.OnSuiteResult(createReport)
	listener.Start()
}

func addDefaultPropertiesToProject() {
	defaultPropertiesFile := getDefaultPropertiesFile()

	reportsDirProperty := &(common.Property{
		Comment:      "The path to the gauge reports directory. Should be either relative to the project directory or an absolute path",
		Name:         gaugeReportsDirEnvName,
		DefaultValue: defaultReportsDir})

	overwriteReportProperty := &(common.Property{
		Comment:      "Set as false if gauge reports should not be overwritten on each execution. A new time-stamped directory will be created on each execution.",
		Name:         overwriteReportsEnvProperty,
		DefaultValue: "true"})

	if !common.FileExists(defaultPropertiesFile) {
		fmt.Printf("Failed to setup html report plugin in project. Default properties file does not exist at %s. \n", defaultPropertiesFile)
		return
	}
	if err := common.AppendProperties(defaultPropertiesFile, reportsDirProperty, overwriteReportProperty); err != nil {
		fmt.Printf("Failed to setup html report plugin in project: %s \n", err)
		return
	}
	fmt.Println("Succesfully added configurations for html-report to env/default/default.properties")
}

func getDefaultPropertiesFile() string {
	return filepath.Join(projectRoot, "env", "default", "default.properties")
}

func createReport(suiteResult *gauge_messages.SuiteExecutionResult) {
	reportsDir := getReportsDirectory(getNameGen())
	err := generator.GenerateReports(suiteResult.GetSuiteResult(), reportsDir)
	if err != nil {
		fmt.Printf("Failed to generate reports: %s", err.Error())
		os.Exit(1)
	}
	err = copyReportTemplateFiles(reportsDir)
	if err != nil {
		fmt.Printf("Error copying template directory :%s\n", err.Error())
		os.Exit(1)
	}
	fmt.Printf("Successfully generated html-report to => %s\n", reportsDir)
}

func getNameGen() nameGenerator {
	var nameGen nameGenerator
	if shouldOverwriteReports() {
		nameGen = nil
	} else {
		nameGen = timeStampedNameGenerator{}
	}
	return nameGen
}

func getReportsDirectory(nameGen nameGenerator) string {
	reportsDir, err := filepath.Abs(os.Getenv(gaugeReportsDirEnvName))
	if reportsDir == "" || err != nil {
		reportsDir = defaultReportsDir
	}
	createDirectory(reportsDir)
	var currentReportDir string
	if nameGen != nil {
		currentReportDir = filepath.Join(reportsDir, htmlReport, nameGen.randomName())
	} else {
		currentReportDir = filepath.Join(reportsDir, htmlReport)
	}
	createDirectory(currentReportDir)
	return currentReportDir
}

func copyReportTemplateFiles(reportDir string) error {
	reportTemplateDir := filepath.Join(pluginDir, reportTemplateDir)
	_, err := common.MirrorDir(reportTemplateDir, reportDir)
	return err
}

func shouldOverwriteReports() bool {
	envValue := os.Getenv(overwriteReportsEnvProperty)
	if strings.ToLower(envValue) == "true" {
		return true
	}
	return false
}

func createDirectory(dir string) {
	if common.DirExists(dir) {
		return
	}
	if err := os.MkdirAll(dir, common.NewDirectoryPermissions); err != nil {
		fmt.Printf("Failed to create directory %s: %s\n", defaultReportsDir, err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package command_registry

import (
	"fmt"
	"os"
	"strings"
	"unicode/utf8"

	"github.com/cloudfoundry/cli/cf"
	"github.com/cloudfoundry/cli/cf/configuration/config_helpers"
	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	. "github.com/cloudfoundry/cli/cf/i18n"
	"github.com/cloudfoundry/cli/cf/i18n/detection"
	. "github.com/cloudfoundry/cli/cf/terminal"
	"github.com/simonleung8/flags"
)

var _ = initI18nFunc()
var Commands = NewRegistry()

func initI18nFunc() bool {
	errorHandler := func(err error) {
		if err != nil {
			fmt.Println(FailureColor("FAILED"))
			fmt.Println("Error read/writing config: ", err.Error())
			os.Exit(1)
		}
	}
	T = Init(core_config.NewRepositoryFromFilepath(config_helpers.DefaultFilePath(), errorHandler), &detection.JibberJabberDetector{})
	return true
}

type registry struct {
	cmd   map[string]Command
	alias map[string]string
}

func NewRegistry() *registry {
	return &registry{
		cmd:   make(map[string]Command),
		alias: make(map[string]string),
	}
}

func Register(cmd Command) {
	m := cmd.MetaData()
	Commands.cmd[m.Name] = cmd

	Commands.alias[m.ShortName] = m.Name
}

func (r *registry) FindCommand(name string) Command {
	if _, ok := r.cmd[name]; ok {
		return r.cmd[name]
	}

	if alias, exists := r.alias[name]; exists {
		return r.cmd[alias]
	}

	return nil
}

func (r *registry) CommandExists(name string) bool {
	if strings.TrimSpace(name) == "" {
		return false
	}

	var ok bool

	if _, ok = r.cmd[name]; !ok {
		alias, exists := r.alias[name]

		if exists {
			_, ok = r.cmd[alias]
		}
	}

	return ok
}

func (r *registry) SetCommand(cmd Command) {
	r.cmd[cmd.MetaData().Name] = cmd
}

func (r *registry) RemoveCommand(cmdName string) {
	delete(r.cmd, cmdName)
}

func (r *registry) TotalCommands() int {
	return len(r.cmd)
}

func (r *registry) MaxCommandNameLength() int {
	maxNameLen := 0
	for name, _ := range r.cmd {
		if utf8.RuneCountInString(name) > maxNameLen {
			maxNameLen = len(name)
		}
	}
	return maxNameLen
}

func (r *registry) Metadatas() []CommandMetadata {
	var m []CommandMetadata

	for _, c := range r.cmd {
		m = append(m, c.MetaData())
	}

	return m
}

func (r *registry) CommandUsage(cmdName string) string {
	output := ""
	cmd := r.FindCommand(cmdName)

	output = T("NAME") + ":" + "\n"
	output += "   " + cmd.MetaData().Name + " - " + cmd.MetaData().Description + "\n\n"

	output += T("USAGE") + ":" + "\n"
	output += "   " + strings.Replace(cmd.MetaData().Usage, "CF_NAME", cf.Name(), -1) + "\n"

	if cmd.MetaData().ShortName != "" {
		output += "\n" + T("ALIAS") + ":" + "\n"
		output += "   " + cmd.MetaData().ShortName + "\n"
	}

	if cmd.MetaData().Flags != nil {
		output += "\n" + T("OPTIONS") + ":" + "\n"
		output += flags.NewFlagContext(cmd.MetaData().Flags).ShowUsage(3)
	}

	return output
}
<commit_msg>use RuneCountInString() instead of len()<commit_after>package command_registry

import (
	"fmt"
	"os"
	"strings"
	"unicode/utf8"

	"github.com/cloudfoundry/cli/cf"
	"github.com/cloudfoundry/cli/cf/configuration/config_helpers"
	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	. "github.com/cloudfoundry/cli/cf/i18n"
	"github.com/cloudfoundry/cli/cf/i18n/detection"
	. "github.com/cloudfoundry/cli/cf/terminal"
	"github.com/simonleung8/flags"
)

var _ = initI18nFunc()
var Commands = NewRegistry()

func initI18nFunc() bool {
	errorHandler := func(err error) {
		if err != nil {
			fmt.Println(FailureColor("FAILED"))
			fmt.Println("Error read/writing config: ", err.Error())
			os.Exit(1)
		}
	}
	T = Init(core_config.NewRepositoryFromFilepath(config_helpers.DefaultFilePath(), errorHandler), &detection.JibberJabberDetector{})
	return true
}

type registry struct {
	cmd   map[string]Command
	alias map[string]string
}

func NewRegistry() *registry {
	return &registry{
		cmd:   make(map[string]Command),
		alias: make(map[string]string),
	}
}

func Register(cmd Command) {
	m := cmd.MetaData()
	Commands.cmd[m.Name] = cmd

	Commands.alias[m.ShortName] = m.Name
}

func (r *registry) FindCommand(name string) Command {
	if _, ok := r.cmd[name]; ok {
		return r.cmd[name]
	}

	if alias, exists := r.alias[name]; exists {
		return r.cmd[alias]
	}

	return nil
}

func (r *registry) CommandExists(name string) bool {
	if strings.TrimSpace(name) == "" {
		return false
	}

	var ok bool

	if _, ok = r.cmd[name]; !ok {
		alias, exists := r.alias[name]

		if exists {
			_, ok = r.cmd[alias]
		}
	}

	return ok
}

func (r *registry) SetCommand(cmd Command) {
	r.cmd[cmd.MetaData().Name] = cmd
}

func (r *registry) RemoveCommand(cmdName string) {
	delete(r.cmd, cmdName)
}

func (r *registry) TotalCommands() int {
	return len(r.cmd)
}

func (r *registry) MaxCommandNameLength() int {
	maxNameLen := 0
	for name, _ := range r.cmd {
		if nameLen := utf8.RuneCountInString(name); nameLen > maxNameLen {
			maxNameLen = nameLen
		}
	}
	return maxNameLen
}

func (r *registry) Metadatas() []CommandMetadata {
	var m []CommandMetadata

	for _, c := range r.cmd {
		m = append(m, c.MetaData())
	}

	return m
}

func (r *registry) CommandUsage(cmdName string) string {
	output := ""
	cmd := r.FindCommand(cmdName)

	output = T("NAME") + ":" + "\n"
	output += "   " + cmd.MetaData().Name + " - " + cmd.MetaData().Description + "\n\n"

	output += T("USAGE") + ":" + "\n"
	output += "   " + strings.Replace(cmd.MetaData().Usage, "CF_NAME", cf.Name(), -1) + "\n"

	if cmd.MetaData().ShortName != "" {
		output += "\n" + T("ALIAS") + ":" + "\n"
		output += "   " + cmd.MetaData().ShortName + "\n"
	}

	if cmd.MetaData().Flags != nil {
		output += "\n" + T("OPTIONS") + ":" + "\n"
		output += flags.NewFlagContext(cmd.MetaData().Flags).ShowUsage(3)
	}

	return output
}
<|endoftext|>