<commit_before>// Copyright 2013 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package id3

import (
	"errors"
	"fmt"
)

const (
	FrameHeaderSize = 10
)

// FrameType holds frame id metadata and constructor method
// A set number of these are created in the version specific files
type FrameType struct {
	id          string
	description string
	constructor func(FrameHead, []byte) Framer
}

// Framer provides a generic interface for frames
// This is the default type returned when creating frames
type Framer interface {
	Id() string
	Size() uint
	StatusFlags() byte
	FormatFlags() byte
	String() string
	Bytes() []byte
	setOwner(*Tag)
}

// FrameHead represents the header of each frame
// Additional metadata is kept through the embedded frame type
// These do not usually need to be manually created
type FrameHead struct {
	FrameType
	statusFlags byte
	formatFlags byte
	size        uint32
	owner       *Tag
}

func (h FrameHead) Id() string {
	return h.id
}

func (h FrameHead) Size() uint {
	return uint(h.size)
}

func (h FrameHead) changeSize(diff int) {
	if diff >= 0 {
		h.size += uint32(diff)
	} else {
		h.size -= uint32(-diff)
	}

	if h.owner != nil {
		h.owner.changeSize(diff)
	}
}

func (h FrameHead) StatusFlags() byte {
	return h.statusFlags
}

func (h FrameHead) FormatFlags() byte {
	return h.formatFlags
}

func (h *FrameHead) setOwner(t *Tag) {
	h.owner = t
}

// DataFrame is the default frame for binary data
type DataFrame struct {
	FrameHead
	data []byte
}

func NewDataFrame(ft FrameType, data []byte) *DataFrame {
	head := FrameHead{
		FrameType: ft,
		size:      uint32(len(data)),
	}

	return &DataFrame{head, data}
}

func ParseDataFrame(head FrameHead, data []byte) Framer {
	return &DataFrame{head, data}
}

func (f DataFrame) Data() []byte {
	return f.data
}

func (f *DataFrame) SetData(b []byte) {
	diff := len(b) - len(f.data)
	f.changeSize(diff)
	f.data = b
}

func (f DataFrame) String() string {
	return "<binary data>"
}

func (f DataFrame) Bytes() []byte {
	return f.data
}

// TextFramer represents frames that contain encoded text
type TextFramer interface {
	Framer
	Encoding() string
	SetEncoding(string) error
	Text() string
	SetText(string) error
}

// TextFrame represents frames that contain encoded text
type TextFrame struct {
	FrameHead
	encoding byte
	text     string
}

func ParseTextFrame(head FrameHead, data []byte) Framer {
	var err error
	f := &TextFrame{FrameHead: head}
	rd := newReader(data)

	if f.encoding, err = rd.readByte(); err != nil {
		return nil
	}

	if f.text, err = rd.readRestString(f.encoding); err != nil {
		return nil
	}

	return f
}

func (f TextFrame) Encoding() string {
	return encodingForIndex(f.encoding)
}

func (f *TextFrame) SetEncoding(encoding string) error {
	i := byte(indexForEncoding(encoding))
	if i < 0 {
		return errors.New("encoding: invalid encoding")
	}

	f.encoding = i
	return nil
}

func (f TextFrame) Text() string {
	return f.text
}

func (f *TextFrame) SetText(text string) error {
	diff, err := encodedDiff(f.encoding, text, f.encoding, f.text)
	if err != nil {
		return err
	}

	f.changeSize(diff)
	f.text = text
	return nil
}

func (f TextFrame) String() string {
	return f.text
}

func (f TextFrame) Bytes() []byte {
	var err error
	bytes := make([]byte, f.Size())
	wr := newWriter(bytes)

	if err = wr.writeByte(f.encoding); err != nil {
		return bytes
	}

	if err = wr.writeString(f.text, f.encoding); err != nil {
		return bytes
	}

	return bytes
}

type DescTextFrame struct {
	FrameHead
	TextFrame
	description string
}

// DescTextFrame represents frames that contain encoded text and descriptions
func ParseDescTextFrame(head FrameHead, data []byte) Framer {
	var err error
	f := &DescTextFrame{FrameHead: head}
	rd := newReader(data)

	if f.encoding, err = rd.readByte(); err != nil {
		return nil
	}

	if f.description, err = rd.readNullTermString(f.encoding); err != nil {
		return nil
	}

	if f.text, err = rd.readRestString(f.encoding); err != nil {
		return nil
	}

	return f
}

func (f DescTextFrame) Description() string {
	return f.description
}

func (f *DescTextFrame) SetDescription(description string) error {
	diff, err := encodedDiff(f.encoding, description, f.encoding, f.description)
	if err != nil {
		return err
	}

	f.changeSize(diff)
	f.description = description
	return nil
}

func (f DescTextFrame) String() string {
	return fmt.Sprintf("%s: %s", f.description, f.text)
}

func (f DescTextFrame) Bytes() []byte {
	var err error
	bytes := make([]byte, f.Size())
	wr := newWriter(bytes)

	if err = wr.writeByte(f.encoding); err != nil {
		return bytes
	}

	if err = wr.writeString(f.description, f.encoding); err != nil {
		return bytes
	}

	if err = wr.writeString(f.text, f.encoding); err != nil {
		return bytes
	}

	return bytes
}

// UnsynchTextFrame represents frames that contain unsynchronized text
type UnsynchTextFrame struct {
	FrameHead
	DescTextFrame
	language string
}

func ParseUnsynchTextFrame(head FrameHead, data []byte) Framer {
	var err error
	f := &UnsynchTextFrame{FrameHead: head}
	rd := newReader(data)

	if f.encoding, err = rd.readByte(); err != nil {
		return nil
	}

	if f.language, err = rd.readNumBytesString(3); err != nil {
		return nil
	}

	if f.description, err = rd.readNullTermString(f.encoding); err != nil {
		return nil
	}

	if f.text, err = rd.readRestString(f.encoding); err != nil {
		return nil
	}

	return f
}

func (f UnsynchTextFrame) Language() string {
	return f.language
}

func (f *UnsynchTextFrame) SetLanguage(language string) error {
	if len(language) != 3 {
		return errors.New("language: invalid language string")
	}

	f.language = language
	return nil
}

func (f UnsynchTextFrame) String() string {
	return fmt.Sprintf("%s\t%s:\n%s", f.language, f.description, f.text)
}

func (f UnsynchTextFrame) Bytes() []byte {
	var err error
	bytes := make([]byte, f.Size())
	wr := newWriter(bytes)

	if err = wr.writeByte(f.encoding); err != nil {
		return bytes
	}

	if err = wr.writeString(f.language, NativeEncoding); err != nil {
		return bytes
	}

	if err = wr.writeString(f.description, f.encoding); err != nil {
		return bytes
	}

	if err = wr.writeString(f.text, f.encoding); err != nil {
		return bytes
	}

	return bytes
}

// ImageFrame represent frames that have media attached
type ImageFrame struct {
	FrameHead
	DataFrame
	encoding    byte
	mimeType    string
	pictureType byte
	description string
}

func ParseImageFrame(head FrameHead, data []byte) Framer {
	var err error
	f := &ImageFrame{FrameHead: head}
	rd := newReader(data)

	if f.encoding, err = rd.readByte(); err != nil {
		return nil
	}

	if f.mimeType, err = rd.readNullTermString(NativeEncoding); err != nil {
		return nil
	}

	if f.pictureType, err = rd.readByte(); err != nil {
		return nil
	}

	if f.description, err = rd.readNullTermString(f.encoding); err != nil {
		return nil
	}

	if f.data, err = rd.readRest(); err != nil {
		return nil
	}

	return f
}

func (f ImageFrame) Encoding() string {
	return encodingForIndex(f.encoding)
}

func (f *ImageFrame) SetEncoding(encoding string) error {
	i := byte(indexForEncoding(encoding))
	if i < 0 {
		return errors.New("encoding: invalid encoding")
	}

	f.encoding = i
	return nil
}

func (f ImageFrame) MIMEType() string {
	return f.mimeType
}

func (f *ImageFrame) SetMIMEType(mimeType string) {
	diff := len(mimeType) - len(f.mimeType)
	if mimeType[len(mimeType)-1] != 0 {
		nullTermBytes := append([]byte(mimeType), 0x00)
		f.mimeType = string(nullTermBytes)
		diff += 1
	} else {
		f.mimeType = mimeType
	}

	f.changeSize(diff)
}

func (f ImageFrame) String() string {
	return fmt.Sprintf("%s\t%s: <binary data>", f.mimeType, f.description)
}

func (f ImageFrame) Bytes() []byte {
	var err error
	bytes := make([]byte, f.Size())
	wr := newWriter(bytes)

	if err = wr.writeByte(f.encoding); err != nil {
		return bytes
	}

	if err = wr.writeString(f.mimeType, NativeEncoding); err != nil {
		return bytes
	}

	if err = wr.writeByte(f.pictureType); err != nil {
		return bytes
	}

	if err = wr.writeString(f.description, f.encoding); err != nil {
		return bytes
	}

	if n, err := wr.write(f.data); n < len(f.data) || err != nil {
		return bytes
	}

	return bytes
}
<commit_msg>Fix SetEncoding size changes<commit_after>// Copyright 2013 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package id3

import (
	"errors"
	"fmt"
)

const (
	FrameHeaderSize = 10
)

// FrameType holds frame id metadata and constructor method
// A set number of these are created in the version specific files
type FrameType struct {
	id          string
	description string
	constructor func(FrameHead, []byte) Framer
}

// Framer provides a generic interface for frames
// This is the default type returned when creating frames
type Framer interface {
	Id() string
	Size() uint
	StatusFlags() byte
	FormatFlags() byte
	String() string
	Bytes() []byte
	setOwner(*Tag)
}

// FrameHead represents the header of each frame
// Additional metadata is kept through the embedded frame type
// These do not usually need to be manually created
type FrameHead struct {
	FrameType
	statusFlags byte
	formatFlags byte
	size        uint32
	owner       *Tag
}

func (h FrameHead) Id() string {
	return h.id
}

func (h FrameHead) Size() uint {
	return uint(h.size)
}

func (h FrameHead) changeSize(diff int) {
	if diff >= 0 {
		h.size += uint32(diff)
	} else {
		h.size -= uint32(-diff)
	}

	if h.owner != nil {
		h.owner.changeSize(diff)
	}
}

func (h FrameHead) StatusFlags() byte {
	return h.statusFlags
}

func (h FrameHead) FormatFlags() byte {
	return h.formatFlags
}

func (h *FrameHead) setOwner(t *Tag) {
	h.owner = t
}

// DataFrame is the default frame for binary data
type DataFrame struct {
	FrameHead
	data []byte
}

func NewDataFrame(ft FrameType, data []byte) *DataFrame {
	head := FrameHead{
		FrameType: ft,
		size:      uint32(len(data)),
	}

	return &DataFrame{head, data}
}

func ParseDataFrame(head FrameHead, data []byte) Framer {
	return &DataFrame{head, data}
}

func (f DataFrame) Data() []byte {
	return f.data
}

func (f *DataFrame) SetData(b []byte) {
	diff := len(b) - len(f.data)
	f.changeSize(diff)
	f.data = b
}

func (f DataFrame) String() string {
	return "<binary data>"
}

func (f DataFrame) Bytes() []byte {
	return f.data
}

// TextFramer represents frames that contain encoded text
type TextFramer interface {
	Framer
	Encoding() string
	SetEncoding(string) error
	Text() string
	SetText(string) error
}

// TextFrame represents frames that contain encoded text
type TextFrame struct {
	FrameHead
	encoding byte
	text     string
}

func ParseTextFrame(head FrameHead, data []byte) Framer {
	var err error
	f := &TextFrame{FrameHead: head}
	rd := newReader(data)

	if f.encoding, err = rd.readByte(); err != nil {
		return nil
	}

	if f.text, err = rd.readRestString(f.encoding); err != nil {
		return nil
	}

	return f
}

func (f TextFrame) Encoding() string {
	return encodingForIndex(f.encoding)
}

func (f *TextFrame) SetEncoding(encoding string) error {
	i := byte(indexForEncoding(encoding))
	if i < 0 {
		return errors.New("encoding: invalid encoding")
	}

	diff, err := encodedDiff(f.encoding, f.text, i, f.text)
	if err != nil {
		return err
	}

	f.changeSize(diff)
	f.encoding = i
	return nil
}

func (f TextFrame) Text() string {
	return f.text
}

func (f *TextFrame) SetText(text string) error {
	diff, err := encodedDiff(f.encoding, text, f.encoding, f.text)
	if err != nil {
		return err
	}

	f.changeSize(diff)
	f.text = text
	return nil
}

func (f TextFrame) String() string {
	return f.text
}

func (f TextFrame) Bytes() []byte {
	var err error
	bytes := make([]byte, f.Size())
	wr := newWriter(bytes)

	if err = wr.writeByte(f.encoding); err != nil {
		return bytes
	}

	if err = wr.writeString(f.text, f.encoding); err != nil {
		return bytes
	}

	return bytes
}

type DescTextFrame struct {
	FrameHead
	TextFrame
	description string
}

// DescTextFrame represents frames that contain encoded text and descriptions
func ParseDescTextFrame(head FrameHead, data []byte) Framer {
	var err error
	f := &DescTextFrame{FrameHead: head}
	rd := newReader(data)

	if f.encoding, err = rd.readByte(); err != nil {
		return nil
	}

	if f.description, err = rd.readNullTermString(f.encoding); err != nil {
		return nil
	}

	if f.text, err = rd.readRestString(f.encoding); err != nil {
		return nil
	}

	return f
}

func (f DescTextFrame) Description() string {
	return f.description
}

func (f *DescTextFrame) SetDescription(description string) error {
	diff, err := encodedDiff(f.encoding, description, f.encoding, f.description)
	if err != nil {
		return err
	}

	f.changeSize(diff)
	f.description = description
	return nil
}

func (f *DescTextFrame) SetEncoding(encoding string) error {
	i := byte(indexForEncoding(encoding))
	if i < 0 {
		return errors.New("encoding: invalid encoding")
	}

	descDiff, err := encodedDiff(f.encoding, f.text, i, f.text)
	if err != nil {
		return err
	}

	textDiff, err := encodedDiff(f.encoding, f.description, i, f.description)
	if err != nil {
		return err
	}

	f.changeSize(descDiff + textDiff)
	f.encoding = i
	return nil
}

func (f DescTextFrame) String() string {
	return fmt.Sprintf("%s: %s", f.description, f.text)
}

func (f DescTextFrame) Bytes() []byte {
	var err error
	bytes := make([]byte, f.Size())
	wr := newWriter(bytes)

	if err = wr.writeByte(f.encoding); err != nil {
		return bytes
	}

	if err = wr.writeString(f.description, f.encoding); err != nil {
		return bytes
	}

	if err = wr.writeString(f.text, f.encoding); err != nil {
		return bytes
	}

	return bytes
}

// UnsynchTextFrame represents frames that contain unsynchronized text
type UnsynchTextFrame struct {
	FrameHead
	DescTextFrame
	language string
}

func ParseUnsynchTextFrame(head FrameHead, data []byte) Framer {
	var err error
	f := &UnsynchTextFrame{FrameHead: head}
	rd := newReader(data)

	if f.encoding, err = rd.readByte(); err != nil {
		return nil
	}

	if f.language, err = rd.readNumBytesString(3); err != nil {
		return nil
	}

	if f.description, err = rd.readNullTermString(f.encoding); err != nil {
		return nil
	}

	if f.text, err = rd.readRestString(f.encoding); err != nil {
		return nil
	}

	return f
}

func (f UnsynchTextFrame) Language() string {
	return f.language
}

func (f *UnsynchTextFrame) SetLanguage(language string) error {
	if len(language) != 3 {
		return errors.New("language: invalid language string")
	}

	f.language = language
	return nil
}

func (f UnsynchTextFrame) String() string {
	return fmt.Sprintf("%s\t%s:\n%s", f.language, f.description, f.text)
}

func (f UnsynchTextFrame) Bytes() []byte {
	var err error
	bytes := make([]byte, f.Size())
	wr := newWriter(bytes)

	if err = wr.writeByte(f.encoding); err != nil {
		return bytes
	}

	if err = wr.writeString(f.language, NativeEncoding); err != nil {
		return bytes
	}

	if err = wr.writeString(f.description, f.encoding); err != nil {
		return bytes
	}

	if err = wr.writeString(f.text, f.encoding); err != nil {
		return bytes
	}

	return bytes
}

// ImageFrame represent frames that have media attached
type ImageFrame struct {
	FrameHead
	DataFrame
	encoding    byte
	mimeType    string
	pictureType byte
	description string
}

func ParseImageFrame(head FrameHead, data []byte) Framer {
	var err error
	f := &ImageFrame{FrameHead: head}
	rd := newReader(data)

	if f.encoding, err = rd.readByte(); err != nil {
		return nil
	}

	if f.mimeType, err = rd.readNullTermString(NativeEncoding); err != nil {
		return nil
	}

	if f.pictureType, err = rd.readByte(); err != nil {
		return nil
	}

	if f.description, err = rd.readNullTermString(f.encoding); err != nil {
		return nil
	}

	if f.data, err = rd.readRest(); err != nil {
		return nil
	}

	return f
}

func (f ImageFrame) Encoding() string {
	return encodingForIndex(f.encoding)
}

func (f *ImageFrame) SetEncoding(encoding string) error {
	i := byte(indexForEncoding(encoding))
	if i < 0 {
		return errors.New("encoding: invalid encoding")
	}

	diff, err := encodedDiff(f.encoding, f.description, i, f.description)
	if err != nil {
		return err
	}

	f.changeSize(diff)
	f.encoding = i
	return nil
}

func (f ImageFrame) MIMEType() string {
	return f.mimeType
}

func (f *ImageFrame) SetMIMEType(mimeType string) {
	diff := len(mimeType) - len(f.mimeType)
	if mimeType[len(mimeType)-1] != 0 {
		nullTermBytes := append([]byte(mimeType), 0x00)
		f.mimeType = string(nullTermBytes)
		diff += 1
	} else {
		f.mimeType = mimeType
	}

	f.changeSize(diff)
}

func (f ImageFrame) String() string {
	return fmt.Sprintf("%s\t%s: <binary data>", f.mimeType, f.description)
}

func (f ImageFrame) Bytes() []byte {
	var err error
	bytes := make([]byte, f.Size())
	wr := newWriter(bytes)

	if err = wr.writeByte(f.encoding); err != nil {
		return bytes
	}

	if err = wr.writeString(f.mimeType, NativeEncoding); err != nil {
		return bytes
	}

	if err = wr.writeByte(f.pictureType); err != nil {
		return bytes
	}

	if err = wr.writeString(f.description, f.encoding); err != nil {
		return bytes
	}

	if n, err := wr.write(f.data); n < len(f.data) || err != nil {
		return bytes
	}

	return bytes
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"strings"
	"github.com/breunigs/frank/frank"
	irc "github.com/fluffle/goirc/client"
	"log"
)

//~ const instaJoin = "#chaos-hd"
const instaJoin = "#test"

const nickServPass = ""

const ircServer = "irc.twice-irc.de"

func main() {
	flag.Parse() // parses the logging flags. TODO

	c := irc.SimpleClient("frank", "frank", "Frank Böterrich der Zweite")
	c.SSL = true

	// connect
	c.AddHandler(irc.CONNECTED,
		func(conn *irc.Conn, line *irc.Line) {
			log.Printf("Connected as: %s\n", conn.Me.Nick)
			conn.Privmsg("nickserv", "identify " + nickServPass)
			for _, cn := range(strings.Split(instaJoin, " ")) {
				if cn != "" {
					conn.Join(cn)
				}
			}
		})

	// react
	c.AddHandler("PRIVMSG",
		func(conn *irc.Conn, line *irc.Line) {
			//~ tgt := line.Args[0]
			//~ msg := line.Args[1]

			go func() { frank.RaumBang(conn, line) }()
			go func() { frank.UriFind(conn, line) }()

			//~ log.Printf("      Debug: tgt: %s, msg: %s\n", tgt, msg)
		})

	// auto follow invites
	c.AddHandler("INVITE",
		func(conn *irc.Conn, line *irc.Line) {
			tgt := line.Args[0]
			cnnl := line.Args[1]
			if conn.Me.Nick != tgt {
				log.Printf("WTF: received invite for %s but target was %s\n")
				return
			}

			log.Printf("Following invite for channel: %s\n", cnnl)
			conn.Join(cnnl)
		})

	// auto deop frank
	c.AddHandler("MODE",
		func(conn *irc.Conn, line *irc.Line) {
			if len(line.Args) != 3 {
				// mode statement cannot be not in a channel, so ignore
				return
			}

			if line.Args[2] != conn.Me.Nick {
				// not referring to us
				return
			}

			if line.Args[1] != "+o" {
				// not relevant
				return
			}

			cn := line.Args[0]
			conn.Mode(cn, "+v", conn.Me.Nick)
			conn.Mode(cn, "-o", conn.Me.Nick)
			conn.Privmsg(cn, line.Nick + ": SKYNET® Protection activated")
		})

	// disconnect
	quit := make(chan bool)
	c.AddHandler(irc.DISCONNECTED,
		func(conn *irc.Conn, line *irc.Line) { quit <- true })

	// go go GO!
	if err := c.Connect(ircServer); err != nil {
		log.Printf("Connection error: %s\n", err)
	}

	log.Printf("Frank has booted\n")

	// Wait for disconnect
	<-quit
}
<commit_msg>go fmt<commit_after>package main

import (
	"flag"
	"github.com/breunigs/frank/frank"
	irc "github.com/fluffle/goirc/client"
	"log"
	"strings"
)

//~ const instaJoin = "#chaos-hd"
const instaJoin = "#test"

const nickServPass = "k6CA9b9cfrLAPKmjlJGTIDO2bRyTN6"

const ircServer = "irc.twice-irc.de"

func main() {
	flag.Parse() // parses the logging flags. TODO

	c := irc.SimpleClient("frank", "frank", "Frank Böterrich der Zweite")
	c.SSL = true

	// connect
	c.AddHandler(irc.CONNECTED,
		func(conn *irc.Conn, line *irc.Line) {
			log.Printf("Connected as: %s\n", conn.Me.Nick)
			conn.Privmsg("nickserv", "identify "+nickServPass)
			for _, cn := range strings.Split(instaJoin, " ") {
				if cn != "" {
					conn.Join(cn)
				}
			}
		})

	// react
	c.AddHandler("PRIVMSG",
		func(conn *irc.Conn, line *irc.Line) {
			//~ tgt := line.Args[0]
			//~ msg := line.Args[1]

			go func() { frank.RaumBang(conn, line) }()
			go func() { frank.UriFind(conn, line) }()

			//~ log.Printf("      Debug: tgt: %s, msg: %s\n", tgt, msg)
		})

	// auto follow invites
	c.AddHandler("INVITE",
		func(conn *irc.Conn, line *irc.Line) {
			tgt := line.Args[0]
			cnnl := line.Args[1]
			if conn.Me.Nick != tgt {
				log.Printf("WTF: received invite for %s but target was %s\n")
				return
			}

			log.Printf("Following invite for channel: %s\n", cnnl)
			conn.Join(cnnl)
		})

	// auto deop frank
	c.AddHandler("MODE",
		func(conn *irc.Conn, line *irc.Line) {
			if len(line.Args) != 3 {
				// mode statement cannot be not in a channel, so ignore
				return
			}

			if line.Args[2] != conn.Me.Nick {
				// not referring to us
				return
			}

			if line.Args[1] != "+o" {
				// not relevant
				return
			}

			cn := line.Args[0]
			conn.Mode(cn, "+v", conn.Me.Nick)
			conn.Mode(cn, "-o", conn.Me.Nick)
			conn.Privmsg(cn, line.Nick+": SKYNET® Protection activated")
		})

	// disconnect
	quit := make(chan bool)
	c.AddHandler(irc.DISCONNECTED,
		func(conn *irc.Conn, line *irc.Line) { quit <- true })

	// go go GO!
	if err := c.Connect(ircServer); err != nil {
		log.Printf("Connection error: %s\n", err)
	}

	log.Printf("Frank has booted\n")

	// Wait for disconnect
	<-quit
}
<|endoftext|>


<commit_before>package php

import (
	"fmt"
	"strings"
	"unicode"

	"stephensearles.com/php/token"
)

const shortPHPBegin = "<?"
const longPHPBegin = "<?php"
const phpEnd = "?>"

const eof = -1

// lexHTML consumes and emits an html t until it
// finds a php begin
func lexHTML(l *lexer) stateFn {
	for {
		if strings.HasPrefix(l.input[l.pos:], shortPHPBegin) {
			if l.pos > l.start {
				l.emit(token.HTML)
			}
			return lexPHPBegin
		}
		if l.next() == eof {
			break
		}
	}
	if l.pos > l.start {
		l.emit(token.HTML)
	}
	l.emit(token.EOF)
	return nil
}

func lexPHPBegin(l *lexer) stateFn {
	if strings.HasPrefix(l.input[l.pos:], longPHPBegin) {
		l.pos += len(longPHPBegin)
	}
	if strings.HasPrefix(l.input[l.pos:], shortPHPBegin) {
		l.pos += len(shortPHPBegin)
	}
	l.emit(token.PHPBegin)
	return lexPHP
}

func lexPHP(l *lexer) stateFn {
	l.skipSpace()

	if r := l.peek(); unicode.IsDigit(r) {
		return lexNumberLiteral
	} else if r == '.' {
		l.next() // must advance because we only peeked before
		secondR := l.peek()
		l.backup()
		if unicode.IsDigit(secondR) {
			return lexNumberLiteral
		}
	}

	if strings.HasPrefix(l.input[l.pos:], "<<<") {
		return lexDoc
	}

	if strings.HasPrefix(l.input[l.pos:], "?>") {
		return lexPHPEnd
	}

	if strings.HasPrefix(l.input[l.pos:], "#") {
		return lexLineComment
	}

	if strings.HasPrefix(l.input[l.pos:], "//") {
		return lexLineComment
	}

	if strings.HasPrefix(l.input[l.pos:], "/*") {
		return lexBlockComment
	}

	if l.peek() == eof {
		l.emit(token.EOF)
		return nil
	}

	if l.peek() == '`' {
		return lexShellCommand
	}

	if l.peek() == '\'' {
		return lexSingleQuotedStringLiteral
	}

	if l.peek() == '"' {
		return lexDoubleQuotedStringLiteral
	}

	for _, tokenString := range token.TokenList {
		t := token.TokenMap[tokenString]
		potentialToken := l.input[l.pos:]
		if len(potentialToken) > len(tokenString) {
			potentialToken = potentialToken[:len(tokenString)]
		}
		if strings.HasPrefix(strings.ToLower(potentialToken), tokenString) {
			l.pos += len(tokenString)
			if isKeyword(t, tokenString) && l.accept(alphabet+underscore+digits) {
				l.backup() // to account for the character consumed by accept
				l.pos -= len(tokenString)
				break
			}
			l.emit(t)
			return lexPHP
		}
	}

	l.acceptRun(alphabet + underscore + digits + "\\")
	l.emit(token.Identifier)
	return lexPHP
}

func lexNumberLiteral(l *lexer) stateFn {
	if l.accept("0") {
		if l.accept("x") {
			// hexadecimal
			l.acceptRun(digits + "abcdef")
			l.emit(token.NumberLiteral)
			return lexPHP
		}
	}
	// is decimal?
	l.acceptRun(digits)
	if l.accept(".") {
		l.acceptRun(digits)
	}

	l.emit(token.NumberLiteral)
	return lexPHP
}

func lexShellCommand(l *lexer) stateFn {
	l.next()
	for {
		switch l.next() {
		case '`':
			l.emit(token.ShellCommand)
			return lexPHP
		case eof:
			l.emit(token.ShellCommand)
			return nil
		}
	}
}

func lexSingleQuotedStringLiteral(l *lexer) stateFn {
	l.next()
	for {
		switch l.next() {
		case '\\':
			l.next()
			continue
		case '\'':
			l.emit(token.StringLiteral)
			return lexPHP
		}
	}
}

func lexDoubleQuotedStringLiteral(l *lexer) stateFn {
	l.next()
	for {
		switch l.next() {
		case '\\':
			l.next()
			continue
		case '"':
			l.emit(token.StringLiteral)
			return lexPHP
		}
	}
}

const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const digits = "0123456789"
const underscore = "_"

func lexIdentifier(l *lexer) stateFn {
	l.accept("$")
	l.accept(underscore + alphabet)
	l.acceptRun(underscore + alphabet + digits)
	l.emit(token.VariableOperator)
	return lexPHP
}

// lexPHPEnd lexes the end of a PHP section returning the context to HTML
func lexPHPEnd(l *lexer) stateFn {
	l.pos += len(phpEnd)
	l.emit(token.PHPEnd)
	return lexHTML
}

func lexLineComment(l *lexer) stateFn {
	lineLength := strings.Index(l.input[l.pos:], "\n") + 1
	if lineLength == 0 {
		// this is the last line, so lex until the end
		lineLength = len(l.input[l.pos:])
	}
	// don't lex php end
	if phpEndLength := strings.Index(l.input[l.pos:l.pos+lineLength], phpEnd); phpEndLength >= 0 && phpEndLength < lineLength {
		lineLength = phpEndLength
	}
	l.pos += lineLength
	l.ignore()
	return lexPHP
}

func lexBlockComment(l *lexer) stateFn {
	commentLength := strings.Index(l.input[l.pos:], "*/") + 2
	if commentLength == 1 {
		// the file ends before we find */
		commentLength = len(l.input[l.pos:])
	}
	if phpEndLength := strings.Index(l.input[l.pos:l.pos+commentLength], phpEnd); phpEndLength >= 0 {
		commentLength = phpEndLength
	}
	l.pos += commentLength
	l.ignore()
	return lexPHP
}

func lexDoc(l *lexer) stateFn {
	var nowDoc bool
	l.pos += len("<<<")
	if strings.HasPrefix(l.input[l.pos:], "'") {
		nowDoc = true
	}
	labelPos := l.pos
	l.accept(underscore + alphabet)
	l.acceptRun(underscore + alphabet + digits)
	endMarker := fmt.Sprintf("\n%s", l.input[labelPos:l.pos])
	if nowDoc {
		l.accept("'")
	}
	l.accept("\n")
	for !strings.HasPrefix(l.input[l.pos:], endMarker) {
		l.next()
	}
	l.pos += len(endMarker)
	l.emit(token.StringLiteral)
	return lexPHP
}
<commit_msg>Ignoring PHP End Tags inside block comments<commit_after>package php

import (
	"fmt"
	"strings"
	"unicode"

	"stephensearles.com/php/token"
)

const shortPHPBegin = "<?"
const longPHPBegin = "<?php"
const phpEnd = "?>"

const eof = -1

// lexHTML consumes and emits an html t until it
// finds a php begin
func lexHTML(l *lexer) stateFn {
	for {
		if strings.HasPrefix(l.input[l.pos:], shortPHPBegin) {
			if l.pos > l.start {
				l.emit(token.HTML)
			}
			return lexPHPBegin
		}
		if l.next() == eof {
			break
		}
	}
	if l.pos > l.start {
		l.emit(token.HTML)
	}
	l.emit(token.EOF)
	return nil
}

func lexPHPBegin(l *lexer) stateFn {
	if strings.HasPrefix(l.input[l.pos:], longPHPBegin) {
		l.pos += len(longPHPBegin)
	}
	if strings.HasPrefix(l.input[l.pos:], shortPHPBegin) {
		l.pos += len(shortPHPBegin)
	}
	l.emit(token.PHPBegin)
	return lexPHP
}

func lexPHP(l *lexer) stateFn {
	l.skipSpace()

	if r := l.peek(); unicode.IsDigit(r) {
		return lexNumberLiteral
	} else if r == '.' {
		l.next() // must advance because we only peeked before
		secondR := l.peek()
		l.backup()
		if unicode.IsDigit(secondR) {
			return lexNumberLiteral
		}
	}

	if strings.HasPrefix(l.input[l.pos:], "<<<") {
		return lexDoc
	}

	if strings.HasPrefix(l.input[l.pos:], "?>") {
		return lexPHPEnd
	}

	if strings.HasPrefix(l.input[l.pos:], "#") {
		return lexLineComment
	}

	if strings.HasPrefix(l.input[l.pos:], "//") {
		return lexLineComment
	}

	if strings.HasPrefix(l.input[l.pos:], "/*") {
		return lexBlockComment
	}

	if l.peek() == eof {
		l.emit(token.EOF)
		return nil
	}

	if l.peek() == '`' {
		return lexShellCommand
	}

	if l.peek() == '\'' {
		return lexSingleQuotedStringLiteral
	}

	if l.peek() == '"' {
		return lexDoubleQuotedStringLiteral
	}

	for _, tokenString := range token.TokenList {
		t := token.TokenMap[tokenString]
		potentialToken := l.input[l.pos:]
		if len(potentialToken) > len(tokenString) {
			potentialToken = potentialToken[:len(tokenString)]
		}
		if strings.HasPrefix(strings.ToLower(potentialToken), tokenString) {
			l.pos += len(tokenString)
			if isKeyword(t, tokenString) && l.accept(alphabet+underscore+digits) {
				l.backup() // to account for the character consumed by accept
				l.pos -= len(tokenString)
				break
			}
			l.emit(t)
			return lexPHP
		}
	}

	l.acceptRun(alphabet + underscore + digits + "\\")
	l.emit(token.Identifier)
	return lexPHP
}

func lexNumberLiteral(l *lexer) stateFn {
	if l.accept("0") {
		if l.accept("x") {
			// hexadecimal
			l.acceptRun(digits + "abcdef")
			l.emit(token.NumberLiteral)
			return lexPHP
		}
	}
	// is decimal?
	l.acceptRun(digits)
	if l.accept(".") {
		l.acceptRun(digits)
	}

	l.emit(token.NumberLiteral)
	return lexPHP
}

func lexShellCommand(l *lexer) stateFn {
	l.next()
	for {
		switch l.next() {
		case '`':
			l.emit(token.ShellCommand)
			return lexPHP
		case eof:
			l.emit(token.ShellCommand)
			return nil
		}
	}
}

func lexSingleQuotedStringLiteral(l *lexer) stateFn {
	l.next()
	for {
		switch l.next() {
		case '\\':
			l.next()
			continue
		case '\'':
			l.emit(token.StringLiteral)
			return lexPHP
		}
	}
}

func lexDoubleQuotedStringLiteral(l *lexer) stateFn {
	l.next()
	for {
		switch l.next() {
		case '\\':
			l.next()
			continue
		case '"':
			l.emit(token.StringLiteral)
			return lexPHP
		}
	}
}

const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const digits = "0123456789"
const underscore = "_"

func lexIdentifier(l *lexer) stateFn {
	l.accept("$")
	l.accept(underscore + alphabet)
	l.acceptRun(underscore + alphabet + digits)
	l.emit(token.VariableOperator)
	return lexPHP
}

// lexPHPEnd lexes the end of a PHP section returning the context to HTML
func lexPHPEnd(l *lexer) stateFn {
	l.pos += len(phpEnd)
	l.emit(token.PHPEnd)
	return lexHTML
}

func lexLineComment(l *lexer) stateFn {
	lineLength := strings.Index(l.input[l.pos:], "\n") + 1
	if lineLength == 0 {
		// this is the last line, so lex until the end
		lineLength = len(l.input[l.pos:])
	}
	// don't lex php end
	if phpEndLength := strings.Index(l.input[l.pos:l.pos+lineLength], phpEnd); phpEndLength >= 0 && phpEndLength < lineLength {
		lineLength = phpEndLength
	}
	l.pos += lineLength
	l.ignore()
	return lexPHP
}

func lexBlockComment(l *lexer) stateFn {
	commentLength := strings.Index(l.input[l.pos:], "*/") + 2
	if commentLength == 1 {
		// the file ends before we find */
		commentLength = len(l.input[l.pos:])
	}
	l.pos += commentLength
	l.ignore()
	return lexPHP
}

func lexDoc(l *lexer) stateFn {
	var nowDoc bool
	l.pos += len("<<<")
	if strings.HasPrefix(l.input[l.pos:], "'") {
		nowDoc = true
	}
	labelPos := l.pos
	l.accept(underscore + alphabet)
	l.acceptRun(underscore + alphabet + digits)
	endMarker := fmt.Sprintf("\n%s", l.input[labelPos:l.pos])
	if nowDoc {
		l.accept("'")
	}
	l.accept("\n")
	for !strings.HasPrefix(l.input[l.pos:], endMarker) {
		l.next()
	}
	l.pos += len(endMarker)
	l.emit(token.StringLiteral)
	return lexPHP
}
<|endoftext|>


<commit_before>package main

import "strings"
import "strconv"
import "fmt"
import "errors"
import "net/http"
import "net/url"
import "time"
import "html"
import "log"
import "io"
import "bufio"
import "bytes"
import "encoding/xml"
import "golang.org/x/tools/blog/atom"

// TODO that shouldn't be a constant. Parse as argument?
// Maximum size a request for a bug-xml is read in byte.
var maxBugRequestRead int64 = 1 * 1024 * 1024 // 1MiB per default

// TODO that shouldn't be a constant. Parse as argument?
// Maximum number of requests per second. Set to something negative to disable
var maxRequestsPerSecond int = 5

const bugzillaDateFormat = "2006-01-02 15:04:05 -0700"

// Channel to block on during too many requests in a second
var tooManyRequestsBlocker chan bool = make(chan bool)

// returns the minimum of the given values
func min(a int, b int) int {
    if a <= b {
        return a
    } else {
        return b
    }
}

// Read from r until given string is found. Appends toAppend afterwards if string
// is found and in any case returns the result
func readUntilString(r io.Reader, until string, toAppend string) (string, error) {
    var buffer bytes.Buffer
    eofReached := false
    rs := bufio.NewReader(io.LimitReader(r, maxBugRequestRead))

    for !eofReached {
        str, err := rs.ReadString('\n')

        if err == io.EOF {
            eofReached = true
        } else if err != nil {
            log.Printf("Error during reading from url: %s\n", err)
            return "", err
        }

        index := strings.Index(str, until)

        if index == -1 {
            buffer.WriteString(str)
        } else {
            buffer.WriteString(str[:index])
            buffer.WriteString(toAppend)
            break
        }
    }

    return buffer.String(), nil
}

// Requests the bug from given url
func doRequest(target string) (string, error) {
    resp, err := http.Get(target)

    if err != nil {
        log.Printf("Error during GET to url \"%s\": %s\n", target, err)
        return "", err
    }

    defer resp.Body.Close()

    // TODO: maybe we should search for something more clever to abort. <attachment could be given by a user in a report
    return readUntilString(resp.Body, "<attachment", "</bug></bugzilla>")
}

// converts the given xml string into an atom feed
func convertXmlToAtom(inXml string) (string, error) {
    type Who struct {
        Name string `xml:",chardata"`
        RealName string `xml:"name,attr"`
    }

    getFormatedName := func(w Who) string {
        if w.RealName == "" {
            return w.Name
        } else {
            return w.RealName + " (" + w.Name + ")"
        }
    }

    type Comment struct {
        CommentId int `xml:"commentid"`
        CommentCount int `xml:"comment_count"`
        AttachmentID int `xml:"attachid"`
        Who Who `xml:"who"`
        When string `xml:"bug_when"`
        Text string `xml:"thetext"`
        // TODO: add attachments?
    }

    type InResult struct {
        Urlbase string `xml:"urlbase,attr"`
        BugId int `xml:"bug>bug_id"`
        Description string `xml:"bug>short_desc"`
        Comments []Comment `xml:"bug>long_desc"`
    }

    inResult := InResult{}
    err := xml.Unmarshal([]byte(inXml), &inResult)
    if err != nil {
        log.Printf("Error during unmarshalling the xml: %s\n", err)
        return "", err
    } else if len(inResult.Comments) == 0 {
        // One comment, the initial one, should always be available
        err := errors.New("Zero comments in bug. There should be at least the initial one.")
        log.Printf("Error after unmarshalling the xml: %s\n", err)
        return "", err
    }

    updateTime, err := time.Parse(bugzillaDateFormat, inResult.Comments[len(inResult.Comments)-1].When)
    if err != nil {
        log.Printf("Couldn't parse updateTime in initial comment: %s\n", err)
        return "", err
    }

    inUrl := fmt.Sprintf("%s/show_bug.cgi?id=%d", inResult.Urlbase, inResult.BugId)
    attachmentUrl := fmt.Sprintf("%s/attachment.cgi?id=", inResult.Urlbase)

    feed := &atom.Feed{
        Title: inResult.Description,
        ID: inUrl,
        Link: []atom.Link{atom.Link{Href: inUrl, Rel: "alternate"}},
        Updated: atom.Time(updateTime),
        Author: &atom.Person{Name: getFormatedName(inResult.Comments[0].Who)},
        Entry: make([]*atom.Entry, 0, len(inResult.Comments)),
    }

    for i, comment := range inResult.Comments {
        creationTime, err := time.Parse(bugzillaDateFormat, comment.When)
        if err != nil {
            log.Printf("Couldn't parse updateTime in comment %d: %s\n", i, err)
            return "", err
        }

        links := []atom.Link{atom.Link{Href: inUrl + "#c" + strconv.Itoa(comment.CommentCount), Rel: "alternate"}}
        if comment.AttachmentID != 0 {
            links = append(links, atom.Link{Href: attachmentUrl + strconv.Itoa(comment.AttachmentID), Rel: "enclosure"})
        }

        entry := &atom.Entry{
            Title: getFormatedName(comment.Who) + ": " + comment.Text[:min(100, len(comment.Text))],
            ID: inUrl + "#c" + strconv.Itoa(comment.CommentCount),
            Link: links,
            Published: atom.Time(creationTime),
            Author: &atom.Person{Name: getFormatedName(comment.Who)},
            Content: &atom.Text{Type: "html", Body: strings.Replace(html.EscapeString(comment.Text), "\n", "
", -1)},
        }

        feed.Entry = append(feed.Entry, entry)
    }

    atom, err := xml.MarshalIndent(feed, "", "\t")
    if err != nil {
        log.Printf("Error during creating the atom feed: %s\n", err)
        return "", err
    }

    return xml.Header + string(atom), nil
}

func handleConvert(w http.ResponseWriter, r *http.Request) {
    // TODO: do some security: What about local domains, etc... Test for this stuff!

    // Block during too many requests in the last second
    if maxRequestsPerSecond >= 0 {
        <-tooManyRequestsBlocker
    }

    formValueUrl := r.FormValue("url")

    // if the user didn't give a protocol simply assume http
    if !(strings.HasPrefix(formValueUrl, "http://") || strings.HasPrefix(formValueUrl, "https://")) {
        formValueUrl = "http://" + formValueUrl
    }

    target, err := url.Parse(formValueUrl)

    if err != nil {
        errStr := fmt.Sprintf("Error occurred during parsing the url \"%s\": %s\nAre you sure the url is correct?", r.FormValue("url"), err.Error())
        http.Error(w, errStr, http.StatusInternalServerError)
        return
    }

    parsedQuery := target.Query()
    parsedQuery.Set("ctype", "xml")
    target.RawQuery = parsedQuery.Encode()
    target.Fragment = ""

    if target.Host == "" {
        errStr := fmt.Sprintf("Error occurred during parsing the url \"%s\": No host recognized.\nAre you sure the url is correct?", formValueUrl)
        http.Error(w, errStr, http.StatusInternalServerError)
        return
    }

    inXml, err := doRequest(target.String())
    if err != nil {
        errStr := fmt.Sprintf("Error occurred during fetching the url \"%s\": %s\nAre you sure the url is correct?", target.String(), err.Error())
        http.Error(w, errStr, http.StatusInternalServerError)
        return
    }

    atom, err := convertXmlToAtom(inXml)
    if err != nil {
        errStr := fmt.Sprintf("Error occurred during conversion of the url \"%s\" to atom: %s\nAre you sure the url is correct?", target.String(), err.Error())
        http.Error(w, errStr, http.StatusInternalServerError)
        return
    }

    fmt.Fprintf(w, "%s", atom)
}

func handleMain(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "%s", `

<title>bugzillatoatom</title>

<form action=convert>
    Convert a Bugzilla bug entry into an Atom feed. Enter an url:
    <input type="text" name="url">

`)
    // TODO: do some pretty gui stuff
}

func main() {
    // Add a timeout for the default http.Get() in case something goes wrong
    // on the oher side.
    http.DefaultClient = &http.Client{Timeout: time.Second * 30}

    for i := 0; i < maxRequestsPerSecond; i++ {
        go func() {
            for {
                tooManyRequestsBlocker <- true
                time.Sleep(time.Second)
            }
        }()
    }

    http.HandleFunc("/convert", handleConvert)
    http.HandleFunc("/", handleMain)

    http.ListenAndServe(":9080", nil)
}<commit_msg>We don't need a fancier GUI for this dummy<commit_after>package main

import "strings"
import "strconv"
import "fmt"
import "errors"
import "net/http"
import "net/url"
import "time"
import "html"
import "log"
import "io"
import "bufio"
import "bytes"
import "encoding/xml"
import "golang.org/x/tools/blog/atom"

// TODO that shouldn't be a constant. Parse as argument?
// Maximum size a request for a bug-xml is read in byte.
var maxBugRequestRead int64 = 1 * 1024 * 1024 // 1MiB per default

// TODO that shouldn't be a constant. Parse as argument?
// Maximum number of requests per second. Set to something negative to disable
var maxRequestsPerSecond int = 5

const bugzillaDateFormat = "2006-01-02 15:04:05 -0700"

// Channel to block on during too many requests in a second
var tooManyRequestsBlocker chan bool = make(chan bool)

// returns the minimum of the given values
func min(a int, b int) int {
    if a <= b {
        return a
    } else {
        return b
    }
}

// Read from r until given string is found. Appends toAppend afterwards if string
// is found and in any case returns the result
func readUntilString(r io.Reader, until string, toAppend string) (string, error) {
    var buffer bytes.Buffer
    eofReached := false
    rs := bufio.NewReader(io.LimitReader(r, maxBugRequestRead))

    for !eofReached {
        str, err := rs.ReadString('\n')

        if err == io.EOF {
            eofReached = true
        } else if err != nil {
            log.Printf("Error during reading from url: %s\n", err)
            return "", err
        }

        index := strings.Index(str, until)

        if index == -1 {
            buffer.WriteString(str)
        } else {
            buffer.WriteString(str[:index])
            buffer.WriteString(toAppend)
            break
        }
    }

    return buffer.String(), nil
}

// Requests the bug from given url
func doRequest(target string) (string, error) {
    resp, err := http.Get(target)

    if err != nil {
        log.Printf("Error during GET to url \"%s\": %s\n", target, err)
        return "", err
    }

    defer resp.Body.Close()

    // TODO: maybe we should search for something more clever to abort. <attachment could be given by a user in a report
    return readUntilString(resp.Body, "<attachment", "</bug></bugzilla>")
}

// converts the given xml string into an atom feed
func convertXmlToAtom(inXml string) (string, error) {
    type Who struct {
        Name string `xml:",chardata"`
        RealName string `xml:"name,attr"`
    }

    getFormatedName := func(w Who) string {
        if w.RealName == "" {
            return w.Name
        } else {
            return w.RealName + " (" + w.Name + ")"
        }
    }

    type Comment struct {
        CommentId int `xml:"commentid"`
        CommentCount int `xml:"comment_count"`
        AttachmentID int `xml:"attachid"`
        Who Who `xml:"who"`
        When string `xml:"bug_when"`
        Text string `xml:"thetext"`
        // TODO: add attachments?
    }

    type InResult struct {
        Urlbase string `xml:"urlbase,attr"`
        BugId int `xml:"bug>bug_id"`
        Description string `xml:"bug>short_desc"`
        Comments []Comment `xml:"bug>long_desc"`
    }

    inResult := InResult{}
    err := xml.Unmarshal([]byte(inXml), &inResult)
    if err != nil {
        log.Printf("Error during unmarshalling the xml: %s\n", err)
        return "", err
    } else if len(inResult.Comments) == 0 {
        // One comment, the initial one, should always be available
        err := errors.New("Zero comments in bug. There should be at least the initial one.")
        log.Printf("Error after unmarshalling the xml: %s\n", err)
        return "", err
    }

    updateTime, err := time.Parse(bugzillaDateFormat, inResult.Comments[len(inResult.Comments)-1].When)
    if err != nil {
        log.Printf("Couldn't parse updateTime in initial comment: %s\n", err)
        return "", err
    }

    inUrl := fmt.Sprintf("%s/show_bug.cgi?id=%d", inResult.Urlbase, inResult.BugId)
    attachmentUrl := fmt.Sprintf("%s/attachment.cgi?id=", inResult.Urlbase)

    feed := &atom.Feed{
        Title: inResult.Description,
        ID: inUrl,
        Link: []atom.Link{atom.Link{Href: inUrl, Rel: "alternate"}},
        Updated: atom.Time(updateTime),
        Author: &atom.Person{Name: getFormatedName(inResult.Comments[0].Who)},
        Entry: make([]*atom.Entry, 0, len(inResult.Comments)),
    }

    for i, comment := range inResult.Comments {
        creationTime, err := time.Parse(bugzillaDateFormat, comment.When)
        if err != nil {
            log.Printf("Couldn't parse updateTime in comment %d: %s\n", i, err)
            return "", err
        }

        links := []atom.Link{atom.Link{Href: inUrl + "#c" + strconv.Itoa(comment.CommentCount), Rel: "alternate"}}
        if comment.AttachmentID != 0 {
            links = append(links, atom.Link{Href: attachmentUrl + strconv.Itoa(comment.AttachmentID), Rel: "enclosure"})
        }

        entry := &atom.Entry{
            Title: getFormatedName(comment.Who) + ": " + comment.Text[:min(100, len(comment.Text))],
            ID: inUrl + "#c" + strconv.Itoa(comment.CommentCount),
            Link: links,
            Published: atom.Time(creationTime),
            Author: &atom.Person{Name: getFormatedName(comment.Who)},
            Content: &atom.Text{Type: "html", Body: strings.Replace(html.EscapeString(comment.Text), "\n", "
", -1)},
        }

        feed.Entry = append(feed.Entry, entry)
    }

    atom, err := xml.MarshalIndent(feed, "", "\t")
    if err != nil {
        log.Printf("Error during creating the atom feed: %s\n", err)
        return "", err
    }

    return xml.Header + string(atom), nil
}

func handleConvert(w http.ResponseWriter, r *http.Request) {
    // TODO: do some security: What about local domains, etc... Test for this stuff!

    // Block during too many requests in the last second
    if maxRequestsPerSecond >= 0 {
        <-tooManyRequestsBlocker
    }

    formValueUrl := r.FormValue("url")

    // if the user didn't give a protocol simply assume http
    if !(strings.HasPrefix(formValueUrl, "http://") || strings.HasPrefix(formValueUrl, "https://")) {
        formValueUrl = "http://" + formValueUrl
    }

    target, err := url.Parse(formValueUrl)

    if err != nil {
        errStr := fmt.Sprintf("Error occurred during parsing the url \"%s\": %s\nAre you sure the url is correct?", r.FormValue("url"), err.Error())
        http.Error(w, errStr, http.StatusInternalServerError)
        return
    }

    parsedQuery := target.Query()
    parsedQuery.Set("ctype", "xml")
    target.RawQuery = parsedQuery.Encode()
    target.Fragment = ""

    if target.Host == "" {
        errStr := fmt.Sprintf("Error occurred during parsing the url \"%s\": No host recognized.\nAre you sure the url is correct?", formValueUrl)
        http.Error(w, errStr, http.StatusInternalServerError)
        return
    }

    inXml, err := doRequest(target.String())
    if err != nil {
        errStr := fmt.Sprintf("Error occurred during fetching the url \"%s\": %s\nAre you sure the url is correct?", target.String(), err.Error())
        http.Error(w, errStr, http.StatusInternalServerError)
        return
    }

    atom, err := convertXmlToAtom(inXml)
    if err != nil {
        errStr := fmt.Sprintf("Error occurred during conversion of the url \"%s\" to atom: %s\nAre you sure the url is correct?", target.String(), err.Error())
        http.Error(w, errStr, http.StatusInternalServerError)
        return
    }

    fmt.Fprintf(w, "%s", atom)
}

func handleMain(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "%s", `

<title>bugzillatoatom</title>

<form action=convert>
    Convert a Bugzilla bug entry into an Atom feed. Enter an url:
    <input type="text" name="url">

`)
}

func main() {
    // Add a timeout for the default http.Get() in case something goes wrong
    // on the oher side.
    http.DefaultClient = &http.Client{Timeout: time.Second * 30}

    for i := 0; i < maxRequestsPerSecond; i++ {
        go func() {
            for {
                tooManyRequestsBlocker <- true
                time.Sleep(time.Second)
            }
        }()
    }

    http.HandleFunc("/convert", handleConvert)
    http.HandleFunc("/", handleMain)

    http.ListenAndServe(":9080", nil)
}<|endoftext|>


<commit_before>// File system interface

package fs

import (
	"fmt"
	"io"
	"log"
	"path/filepath"
	"regexp"
	"time"
)

// Constants
const (
	// User agent for Fs which can set it
	UserAgent = "rclone/" + Version
)

// Globals
var (
	// Filesystem registry
	fsRegistry []*FsInfo
	// Error returned by NewFs if not found in config file
	NotFoundInConfigFile = fmt.Errorf("Didn't find section in config file")
)

// Filesystem info
type FsInfo struct {
	// Name of this fs
	Name string
	// Create a new file system.  If root refers to an existing
	// object, then it should return a Fs which only returns that
	// object.
	NewFs func(name string, root string) (Fs, error)
	// Function to call to help with config
	Config func(string)
	// Options for the Fs configuration
	Options []Option
}

// An options for a Fs
type Option struct {
	Name     string
	Help     string
	Optional bool
	Examples []OptionExample
}

// An example for an option
type OptionExample struct {
	Value string
	Help  string
}

// Register a filesystem
//
// Fs modules  should use this in an init() function
func Register(info *FsInfo) {
	fsRegistry = append(fsRegistry, info)
}

// A Filesystem, describes the local filesystem and the remote object store
type Fs interface {
	// String returns a description of the FS
	String() string

	// List the Fs into a channel
	List() ObjectsChan

	// List the Fs directories/buckets/containers into a channel
	ListDir() DirChan

	// Find the Object at remote.  Returns nil if can't be found
	NewFsObject(remote string) Object

	// Put in to the remote path with the modTime given of the given size
	//
	// May create the object even if it returns an error - if so
	// will return the object and the error, otherwise will return
	// nil and the error
	Put(in io.Reader, remote string, modTime time.Time, size int64) (Object, error)

	// Make the directory (container, bucket)
	//
	// Shouldn't return an error if it already exists
	Mkdir() error

	// Remove the directory (container, bucket) if empty
	//
	// Return an error if it doesn't exist or isn't empty
	Rmdir() error

	// Precision of the ModTimes in this Fs
	Precision() time.Duration
}

// A filesystem like object which can either be a remote object or a
// local file/directory
type Object interface {
	// String returns a description of the Object
	String() string

	// Fs returns the Fs that this object is part of
	Fs() Fs

	// Remote returns the remote path
	Remote() string

	// Md5sum returns the md5 checksum of the file
	Md5sum() (string, error)

	// ModTime returns the modification date of the file
	ModTime() time.Time

	// SetModTime sets the metadata on the object to set the modification date
	SetModTime(time.Time)

	// Size returns the size of the file
	Size() int64

	// Open opens the file for read.  Call Close() on the returned io.ReadCloser
	Open() (io.ReadCloser, error)

	// Update in to the object with the modTime given of the given size
	Update(in io.Reader, modTime time.Time, size int64) error

	// Storable says whether this object can be stored
	Storable() bool

	// Removes this object
	Remove() error
}

// Optional interfaces
type Purger interface {
	// Purge all files in the root and the root directory
	//
	// Implement this if you have a way of deleting all the files
	// quicker than just running Remove() on the result of List()
	//
	// Return an error if it doesn't exist
	Purge() error
}

// An optional interface for error as to whether the operation should be retried
//
// This should be returned from Update or Put methods as required
type Retry interface {
	error
	Retry() bool
}

// A type of error
type retryError string

// Error interface
func (r retryError) Error() string {
	return string(r)
}

// Retry interface
func (r retryError) Retry() bool {
	return true
}

// Check interface
var _ Retry = retryError("")

// RetryErrorf makes an error which indicates it would like to be retried
func RetryErrorf(format string, a ...interface{}) error {
	return retryError(fmt.Sprintf(format, a...))
}

// A channel of Objects
type ObjectsChan chan Object

// A slice of Objects
type Objects []Object

// A pair of Objects
type ObjectPair struct {
	src, dst Object
}

// A channel of ObjectPair
type ObjectPairChan chan ObjectPair

// A structure of directory/container/bucket lists
type Dir struct {
	Name  string    // name of the directory
	When  time.Time // modification or creation time - IsZero for unknown
	Bytes int64     // size of directory and contents -1 for unknown
	Count int64     // number of objects -1 for unknown
}

// A channel of Dir objects
type DirChan chan *Dir

// Finds a FsInfo object for the name passed in
//
// Services are looked up in the config file
func Find(name string) (*FsInfo, error) {
	for _, item := range fsRegistry {
		if item.Name == name {
			return item, nil
		}
	}
	return nil, fmt.Errorf("Didn't find filing system for %q", name)
}

// Pattern to match an rclone url
var matcher = regexp.MustCompile(`^([\w_-]+):(.*)$`)

// NewFs makes a new Fs object from the path
//
// The path is of the form remote:path
//
// Remotes are looked up in the config file.  If the remote isn't
// found then NotFoundInConfigFile will be returned.
//
// On Windows avoid single character remote names as they can be mixed
// up with drive letters.
func NewFs(path string) (Fs, error) {
	parts := matcher.FindStringSubmatch(path)
	fsName, configName, fsPath := "local", "local", path
	if parts != nil && !isDriveLetter(parts[1]) {
		configName, fsPath = parts[1], parts[2]
		var err error
		fsName, err = ConfigFile.GetValue(configName, "type")
		if err != nil {
			return nil, NotFoundInConfigFile
		}
	}
	fs, err := Find(fsName)
	if err != nil {
		return nil, err
	}
	// change native directory separators to / if there are any
	fsPath = filepath.ToSlash(fsPath)
	return fs.NewFs(configName, fsPath)
}

// Outputs log for object
func OutputLog(o interface{}, text string, args ...interface{}) {
	description := ""
	if x, ok := o.(fmt.Stringer); ok {
		description = x.String() + ": "
	}
	out := fmt.Sprintf(text, args...)
	log.Print(description + out)
}

// Write debuging output for this Object or Fs
func Debug(o interface{}, text string, args ...interface{}) {
	if Config.Verbose {
		OutputLog(o, text, args...)
	}
}

// Write log output for this Object or Fs
func Log(o interface{}, text string, args ...interface{}) {
	if !Config.Quiet {
		OutputLog(o, text, args...)
	}
}

// checkClose is a utility function used to check the return from
// Close in a defer statement.
func checkClose(c io.Closer, err *error) {
	cerr := c.Close()
	if *err == nil {
		*err = cerr
	}
}
<commit_msg>Log all objects more informatively<commit_after>// File system interface

package fs

import (
	"fmt"
	"io"
	"log"
	"path/filepath"
	"regexp"
	"time"
)

// Constants
const (
	// User agent for Fs which can set it
	UserAgent = "rclone/" + Version
)

// Globals
var (
	// Filesystem registry
	fsRegistry []*FsInfo
	// Error returned by NewFs if not found in config file
	NotFoundInConfigFile = fmt.Errorf("Didn't find section in config file")
)

// Filesystem info
type FsInfo struct {
	// Name of this fs
	Name string
	// Create a new file system.  If root refers to an existing
	// object, then it should return a Fs which only returns that
	// object.
	NewFs func(name string, root string) (Fs, error)
	// Function to call to help with config
	Config func(string)
	// Options for the Fs configuration
	Options []Option
}

// An options for a Fs
type Option struct {
	Name     string
	Help     string
	Optional bool
	Examples []OptionExample
}

// An example for an option
type OptionExample struct {
	Value string
	Help  string
}

// Register a filesystem
//
// Fs modules  should use this in an init() function
func Register(info *FsInfo) {
	fsRegistry = append(fsRegistry, info)
}

// A Filesystem, describes the local filesystem and the remote object store
type Fs interface {
	// String returns a description of the FS
	String() string

	// List the Fs into a channel
	List() ObjectsChan

	// List the Fs directories/buckets/containers into a channel
	ListDir() DirChan

	// Find the Object at remote.  Returns nil if can't be found
	NewFsObject(remote string) Object

	// Put in to the remote path with the modTime given of the given size
	//
	// May create the object even if it returns an error - if so
	// will return the object and the error, otherwise will return
	// nil and the error
	Put(in io.Reader, remote string, modTime time.Time, size int64) (Object, error)

	// Make the directory (container, bucket)
	//
	// Shouldn't return an error if it already exists
	Mkdir() error

	// Remove the directory (container, bucket) if empty
	//
	// Return an error if it doesn't exist or isn't empty
	Rmdir() error

	// Precision of the ModTimes in this Fs
	Precision() time.Duration
}

// A filesystem like object which can either be a remote object or a
// local file/directory
type Object interface {
	// String returns a description of the Object
	String() string

	// Fs returns the Fs that this object is part of
	Fs() Fs

	// Remote returns the remote path
	Remote() string

	// Md5sum returns the md5 checksum of the file
	Md5sum() (string, error)

	// ModTime returns the modification date of the file
	ModTime() time.Time

	// SetModTime sets the metadata on the object to set the modification date
	SetModTime(time.Time)

	// Size returns the size of the file
	Size() int64

	// Open opens the file for read.  Call Close() on the returned io.ReadCloser
	Open() (io.ReadCloser, error)

	// Update in to the object with the modTime given of the given size
	Update(in io.Reader, modTime time.Time, size int64) error

	// Storable says whether this object can be stored
	Storable() bool

	// Removes this object
	Remove() error
}

// Optional interfaces
type Purger interface {
	// Purge all files in the root and the root directory
	//
	// Implement this if you have a way of deleting all the files
	// quicker than just running Remove() on the result of List()
	//
	// Return an error if it doesn't exist
	Purge() error
}

// An optional interface for error as to whether the operation should be retried
//
// This should be returned from Update or Put methods as required
type Retry interface {
	error
	Retry() bool
}

// A type of error
type retryError string

// Error interface
func (r retryError) Error() string {
	return string(r)
}

// Retry interface
func (r retryError) Retry() bool {
	return true
}

// Check interface
var _ Retry = retryError("")

// RetryErrorf makes an error which indicates it would like to be retried
func RetryErrorf(format string, a ...interface{}) error {
	return retryError(fmt.Sprintf(format, a...))
}

// A channel of Objects
type ObjectsChan chan Object

// A slice of Objects
type Objects []Object

// A pair of Objects
type ObjectPair struct {
	src, dst Object
}

// A channel of ObjectPair
type ObjectPairChan chan ObjectPair

// A structure of directory/container/bucket lists
type Dir struct {
	Name  string    // name of the directory
	When  time.Time // modification or creation time - IsZero for unknown
	Bytes int64     // size of directory and contents -1 for unknown
	Count int64     // number of objects -1 for unknown
}

// A channel of Dir objects
type DirChan chan *Dir

// Finds a FsInfo object for the name passed in
//
// Services are looked up in the config file
func Find(name string) (*FsInfo, error) {
	for _, item := range fsRegistry {
		if item.Name == name {
			return item, nil
		}
	}
	return nil, fmt.Errorf("Didn't find filing system for %q", name)
}

// Pattern to match an rclone url
var matcher = regexp.MustCompile(`^([\w_-]+):(.*)$`)

// NewFs makes a new Fs object from the path
//
// The path is of the form remote:path
//
// Remotes are looked up in the config file.  If the remote isn't
// found then NotFoundInConfigFile will be returned.
//
// On Windows avoid single character remote names as they can be mixed
// up with drive letters.
func NewFs(path string) (Fs, error) {
	parts := matcher.FindStringSubmatch(path)
	fsName, configName, fsPath := "local", "local", path
	if parts != nil && !isDriveLetter(parts[1]) {
		configName, fsPath = parts[1], parts[2]
		var err error
		fsName, err = ConfigFile.GetValue(configName, "type")
		if err != nil {
			return nil, NotFoundInConfigFile
		}
	}
	fs, err := Find(fsName)
	if err != nil {
		return nil, err
	}
	// change native directory separators to / if there are any
	fsPath = filepath.ToSlash(fsPath)
	return fs.NewFs(configName, fsPath)
}

// Outputs log for object
func OutputLog(o interface{}, text string, args ...interface{}) {
	description := ""
	if o != nil {
		description = fmt.Sprintf("%v: ", o)
	}
	out := fmt.Sprintf(text, args...)
	log.Print(description + out)
}

// Write debuging output for this Object or Fs
func Debug(o interface{}, text string, args ...interface{}) {
	if Config.Verbose {
		OutputLog(o, text, args...)
	}
}

// Write log output for this Object or Fs
func Log(o interface{}, text string, args ...interface{}) {
	if !Config.Quiet {
		OutputLog(o, text, args...)
	}
}

// checkClose is a utility function used to check the return from
// Close in a defer statement.
func checkClose(c io.Closer, err *error) {
	cerr := c.Close()
	if *err == nil {
		*err = cerr
	}
}
<|endoftext|>


<commit_before>// fscan.go - display new rss feeds
package main

import (
	"fmt"
	"os"
	"strconv"
	"time"

	"code.google.com/p/go-sqlite/go1/sqlite3"
	"github.com/jehiah/go-strftime"
	"github.com/mattn/go-getopt"
)

// Default SQL Database
const (
	SQLDatabase = "feedme.db"
)

// A Args set getopt arguments
type Args struct {
	limit int
}

var cursor *sqlite3.Conn

func checkErr(err error) {
	if err != nil {
		panic(err)
	}
}

func checkFileExist(filename string) bool {
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		return false
	}

	return true
}

func initSQL() {
	if !checkFileExist(SQLDatabase) {
		fmt.Printf("%s not found, please run first ffetch\n", SQLDatabase)
	} else {
		cursor, _ = sqlite3.Open(SQLDatabase)
	}
}

func showSQL(limit int) {
	query := "SELECT * from feed ORDER BY date DESC LIMIT $limit;"
	sql := sqlite3.NamedArgs{"$limit": limit}
	row := make(sqlite3.RowMap)

	for s, err := cursor.Query(query, sql); err == nil; err = s.Next() {
		var symb string
		var rowid int64
		s.Scan(&rowid, row)

		date := strftime.Format("%Y-%m-%d %H:%M:%S", time.Unix(row["date"].(int64), 0))
		title := row["title"]
		author := row["site"]
		read := row["read"].(int64)

		// Use * for read
		if read == 0 {
			symb = " "
		} else {
			symb = "*"
		}

		fmt.Printf(" %3.d%s %s  %-21s  %s\n", rowid, symb, date, author, title)
	}
}

func usage() {
	fmt.Println("usage: fscan [options]")
	fmt.Println("   -l,  Show n new RSS feeds (default 10).")
	fmt.Println("   -h,  Show this help and exit.")
}

func main() {
	args := Args{10}
	var c int

	getopt.OptErr = 0
	for {
		if c = getopt.Getopt("l:h"); c == getopt.EOF {
			break
		}
		switch c {
		case 'l':
			args.limit, _ = strconv.Atoi(getopt.OptArg)
		case 'h':
			usage()
			os.Exit(0)
		}
	}

	initSQL()
	showSQL(args.limit)
}

/* vim: set noet sw=4 sts=4: */
<commit_msg>Remove unused function<commit_after>// fscan.go - display new rss feeds
package main

import (
	"fmt"
	"os"
	"strconv"
	"time"

	"code.google.com/p/go-sqlite/go1/sqlite3"
	"github.com/jehiah/go-strftime"
	"github.com/mattn/go-getopt"
)

// Default SQL Database
const (
	SQLDatabase = "feedme.db"
)

// A Args set getopt arguments
type Args struct {
	limit int
}

var cursor *sqlite3.Conn

func checkFileExist(filename string) bool {
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		return false
	}

	return true
}

func initSQL() {
	if !checkFileExist(SQLDatabase) {
		fmt.Printf("%s not found, please run first ffetch\n", SQLDatabase)
	} else {
		cursor, _ = sqlite3.Open(SQLDatabase)
	}
}

func showSQL(limit int) {
	query := "SELECT * from feed ORDER BY date DESC LIMIT $limit;"
	sql := sqlite3.NamedArgs{"$limit": limit}
	row := make(sqlite3.RowMap)

	for s, err := cursor.Query(query, sql); err == nil; err = s.Next() {
		var symb string
		var rowid int64
		s.Scan(&rowid, row)

		date := strftime.Format("%Y-%m-%d %H:%M:%S", time.Unix(row["date"].(int64), 0))
		title := row["title"]
		author := row["site"]
		read := row["read"].(int64)

		// Use * for read
		if read == 0 {
			symb = " "
		} else {
			symb = "*"
		}

		fmt.Printf(" %3.d%s %s  %-21s  %s\n", rowid, symb, date, author, title)
	}
}

func usage() {
	fmt.Println("usage: fscan [options]")
	fmt.Println("   -l,  Show n new RSS feeds (default 10).")
	fmt.Println("   -h,  Show this help and exit.")
}

func main() {
	args := Args{10}
	var c int

	getopt.OptErr = 0
	for {
		if c = getopt.Getopt("l:h"); c == getopt.EOF {
			break
		}
		switch c {
		case 'l':
			args.limit, _ = strconv.Atoi(getopt.OptArg)
		case 'h':
			usage()
			os.Exit(0)
		}
	}

	initSQL()
	showSQL(args.limit)
}

/* vim: set noet sw=4 sts=4: */
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"os"

	"github.com/hashicorp/terraform/helper/schema"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/s3"
)

func resourceAwsS3BucketObject() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsS3BucketObjectPut,
		Read:   resourceAwsS3BucketObjectRead,
		Update: resourceAwsS3BucketObjectPut,
		Delete: resourceAwsS3BucketObjectDelete,

		Schema: map[string]*schema.Schema{
			"bucket": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"cache_control": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},

			"content_disposition": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},

			"content_encoding": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},

			"content_language": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},

			"content_type": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},

			"key": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"source": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"etag": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceAwsS3BucketObjectPut(d *schema.ResourceData, meta interface{}) error {
	s3conn := meta.(*AWSClient).s3conn

	bucket := d.Get("bucket").(string)
	key := d.Get("key").(string)

	source := d.Get("source").(string)
	file, err := os.Open(source)

	if err != nil {
		return fmt.Errorf("Error opening S3 bucket object source (%s): %s", source, err)
	}
	putInput := &s3.PutObjectInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
		Body:   file,
	}

	if v, ok := d.GetOk("cache_control"); ok {
		putInput.CacheControl = aws.String(v.(string))
	}

	if v, ok := d.GetOk("content_type"); ok {
		putInput.ContentType = aws.String(v.(string))
	}

	if v, ok := d.GetOk("content_encoding"); ok {
		putInput.ContentEncoding = aws.String(v.(string))
	}

	if v, ok := d.GetOk("content_language"); ok {
		putInput.ContentLanguage = aws.String(v.(string))
	}

	if v, ok := d.GetOk("content_disposition"); ok {
		putInput.ContentDisposition = aws.String(v.(string))
	}

	resp, err := s3conn.PutObject(putInput)

	if err != nil {
		return fmt.Errorf("Error putting object in S3 bucket (%s): %s", bucket, err)
	}

	d.Set("etag", resp.ETag)
	d.SetId(key)
	return nil
}

func resourceAwsS3BucketObjectRead(d *schema.ResourceData, meta interface{}) error {
	s3conn := meta.(*AWSClient).s3conn

	bucket := d.Get("bucket").(string)
	key := d.Get("key").(string)
	etag := d.Get("etag").(string)

	resp, err := s3conn.HeadObject(
		&s3.HeadObjectInput{
			Bucket:  aws.String(bucket),
			Key:     aws.String(key),
			IfMatch: aws.String(etag),
		})

	if err != nil {
		// If S3 returns a 404 Request Failure, mark the object as destroyed
		if awsErr, ok := err.(awserr.RequestFailure); ok && awsErr.StatusCode() == 404 {
			d.SetId("")
			log.Printf("[WARN] Error Reading Object (%s), object not found (HTTP status 404)", key)
			return nil
		}
		return err
	}

	d.Set("cache_control", resp.CacheControl)
	d.Set("content_disposition", resp.ContentDisposition)
	d.Set("content_encoding", resp.ContentEncoding)
	d.Set("content_language", resp.ContentLanguage)
	d.Set("content_type", resp.ContentType)

	log.Printf("[DEBUG] Reading S3 Bucket Object meta: %s", resp)
	return nil
}

func resourceAwsS3BucketObjectDelete(d *schema.ResourceData, meta interface{}) error {
	s3conn := meta.(*AWSClient).s3conn

	bucket := d.Get("bucket").(string)
	key := d.Get("key").(string)

	_, err := s3conn.DeleteObject(
		&s3.DeleteObjectInput{
			Bucket: aws.String(bucket),
			Key:    aws.String(key),
		})
	if err != nil {
		return fmt.Errorf("Error deleting S3 bucket object: %s", err)
	}
	return nil
}
<commit_msg>Removing the S3 Bucket Object Update method. This was removed in master but seems to be broken in my branch<commit_after>package aws

import (
	"fmt"
	"log"
	"os"

	"github.com/hashicorp/terraform/helper/schema"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/s3"
)

func resourceAwsS3BucketObject() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsS3BucketObjectPut,
		Read:   resourceAwsS3BucketObjectRead,
		Delete: resourceAwsS3BucketObjectDelete,

		Schema: map[string]*schema.Schema{
			"bucket": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"cache_control": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},

			"content_disposition": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},

			"content_encoding": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},

			"content_language": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},

			"content_type": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},

			"key": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"source": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"etag": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceAwsS3BucketObjectPut(d *schema.ResourceData, meta interface{}) error {
	s3conn := meta.(*AWSClient).s3conn

	bucket := d.Get("bucket").(string)
	key := d.Get("key").(string)

	source := d.Get("source").(string)
	file, err := os.Open(source)

	if err != nil {
		return fmt.Errorf("Error opening S3 bucket object source (%s): %s", source, err)
	}
	putInput := &s3.PutObjectInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
		Body:   file,
	}

	if v, ok := d.GetOk("cache_control"); ok {
		putInput.CacheControl = aws.String(v.(string))
	}

	if v, ok := d.GetOk("content_type"); ok {
		putInput.ContentType = aws.String(v.(string))
	}

	if v, ok := d.GetOk("content_encoding"); ok {
		putInput.ContentEncoding = aws.String(v.(string))
	}

	if v, ok := d.GetOk("content_language"); ok {
		putInput.ContentLanguage = aws.String(v.(string))
	}

	if v, ok := d.GetOk("content_disposition"); ok {
		putInput.ContentDisposition = aws.String(v.(string))
	}

	resp, err := s3conn.PutObject(putInput)

	if err != nil {
		return fmt.Errorf("Error putting object in S3 bucket (%s): %s", bucket, err)
	}

	d.Set("etag", resp.ETag)
	d.SetId(key)
	return nil
}

func resourceAwsS3BucketObjectRead(d *schema.ResourceData, meta interface{}) error {
	s3conn := meta.(*AWSClient).s3conn

	bucket := d.Get("bucket").(string)
	key := d.Get("key").(string)
	etag := d.Get("etag").(string)

	resp, err := s3conn.HeadObject(
		&s3.HeadObjectInput{
			Bucket:  aws.String(bucket),
			Key:     aws.String(key),
			IfMatch: aws.String(etag),
		})

	if err != nil {
		// If S3 returns a 404 Request Failure, mark the object as destroyed
		if awsErr, ok := err.(awserr.RequestFailure); ok && awsErr.StatusCode() == 404 {
			d.SetId("")
			log.Printf("[WARN] Error Reading Object (%s), object not found (HTTP status 404)", key)
			return nil
		}
		return err
	}

	d.Set("cache_control", resp.CacheControl)
	d.Set("content_disposition", resp.ContentDisposition)
	d.Set("content_encoding", resp.ContentEncoding)
	d.Set("content_language", resp.ContentLanguage)
	d.Set("content_type", resp.ContentType)

	log.Printf("[DEBUG] Reading S3 Bucket Object meta: %s", resp)
	return nil
}

func resourceAwsS3BucketObjectDelete(d *schema.ResourceData, meta interface{}) error {
	s3conn := meta.(*AWSClient).s3conn

	bucket := d.Get("bucket").(string)
	key := d.Get("key").(string)

	_, err := s3conn.DeleteObject(
		&s3.DeleteObjectInput{
			Bucket: aws.String(bucket),
			Key:    aws.String(key),
		})
	if err != nil {
		return fmt.Errorf("Error deleting S3 bucket object: %s", err)
	}
	return nil
}
<|endoftext|>


<commit_before>package ga

import (
	"log"
	"math/rand"
	"sort"
	"strconv"
	"strings"
	"time"

	server "github.com/sunfish-shogi/sunfish4-ga/shogiserver"
)

type GAManager struct {
	Config Config

	server   server.ShogiServer
	lastID   int
	indMap   map[string]*individual
	normal   *individual
	allInds  []*individual
	currInds []*individual
}

func NewGAManager(config Config) *GAManager {
	validateConfig(config)
	return &GAManager{
		Config: config,
		indMap: make(map[string]*individual),
	}
}

func (ga *GAManager) Run() error {
	defer ga.Destroy()

	err := ga.Start()
	if err != nil {
		return err
	}

	for gn := 1; ; gn++ {
		ga.PrintGeneration(gn)

		time.Sleep(time.Hour * 4)

		err = ga.Next()
		if err != nil {
			log.Println(err)
		}
	}
}

func (ga *GAManager) Start() error {
	err := ga.server.Setup()
	if err != nil {
		return err
	}

	ga.normal = newIndividual(ga.nextID(), ga.Config)
	ga.normal.initParamNormal()

	ga.currInds = make([]*individual, 0, ga.Config.NumberOfIndividual)
	for i := 0; i < ga.Config.NumberOfIndividual; i++ {
		ind := newIndividual(ga.nextID(), ga.Config)
		ind.initParamByRandom()
		ga.currInds = append(ga.currInds, ind)
	}
	ga.updateIndMap()

	err = startIndividuals(append(ga.currInds, ga.normal))
	return err
}

type indsDescScoreOrder []*individual

func (inds indsDescScoreOrder) Len() int           { return len(inds) }
func (inds indsDescScoreOrder) Swap(i, j int)      { inds[i], inds[j] = inds[j], inds[i] }
func (inds indsDescScoreOrder) Less(i, j int) bool { return inds[i].score > inds[j].score }

func (ga *GAManager) Next() error {
	rate, err := ga.server.MakeRate()
	if err != nil {
		return err
	}

	for pi := range rate.Players {
		for _, player := range rate.Players[pi] {
			if ind, ok := ga.indMap[player.Name]; ok {
				ind.score = player.Rate
			}
		}
	}

	// Sort by Score
	sort.Stable(indsDescScoreOrder(ga.allInds))
	sort.Stable(indsDescScoreOrder(ga.currInds))

	// Print Scores
	log.Println("Score")
	for i := range ga.currInds {
		log.Printf("%s %0.3f", ga.currInds[i].id, ga.currInds[i].score)
	}
	log.Println()

	// New Generation
	inds := make([]*individual, 0, ga.Config.NumberOfIndividual)

	// Elitism
	log.Printf("elite: %s", ga.allInds[0].id)
	inds = append(inds, ga.allInds[0])

	// Random
	ind := newIndividual(ga.nextID(), ga.Config)
	ind.initParamByRandom()
	log.Printf("random: => %s", ind.id)
	inds = append(inds, ind)

	for {
		if len(inds) >= ga.Config.NumberOfIndividual {
			break
		}

		i1 := ga.selectIndividual("")
		i2 := ga.selectIndividual(i1.id)

		ind := ga.crossover(i1, i2)
		log.Printf("crossover: %s x %s => %s", i1.id, i2.id, ind.id)

		if rand.Intn(10) < 1 /* 1/10 */ {
			ga.mutate(ind)
			log.Printf("mutate: %s", ind.id)
		}

		inds = append(inds, ind)
	}
	log.Println()

	// Stop Previous Generation
	stopIndividuals(ga.currInds)

	// Replace to New Generation
	ga.currInds = inds
	ga.updateIndMap()

	// Start Next Generation
	startIndividuals(ga.currInds)

	return nil
}

func (ga *GAManager) selectIndividual(excludeID string) *individual {
	weight := make([]int, len(ga.currInds))
	var sum int
	for i := range weight {
		if ga.currInds[i].id != excludeID {
			if i == 0 {
				weight[0] = 1024
			} else {
				weight[i] = weight[i-1]*9/10 + 1
			}
			sum += weight[i]
		}
	}

	r := rand.Intn(sum)

	for i := range weight {
		r -= weight[i]
		if r <= 0 {
			return ga.currInds[i]
		}
	}
	return ga.currInds[0]
}

func (ga *GAManager) crossover(i1, i2 *individual) *individual {
	ind := newIndividual(ga.nextID(), ga.Config)
	values := make([]int32, len(ga.Config.Params))
	for i := range values {
		if rand.Intn(2) == 0 {
			values[i] = i1.values[i]
		} else {
			values[i] = i2.values[i]
		}
	}
	ind.initParam(values)
	return ind
}

func (ga *GAManager) mutate(ind *individual) {
	n := rand.Intn(2) + 1
	for ; n > 0; n-- {
		i := rand.Intn(len(ind.values))
		min := ga.Config.Params[i].MinimumValue
		max := ga.Config.Params[i].MaximumValue
		t := min + rand.Int31n(max-min+1)
		ind.values[i] = (ind.values[i] + t) / 2
	}
}

func (ga *GAManager) nextID() string {
	ga.lastID++
	return strconv.Itoa(ga.lastID)
}

func (ga *GAManager) PrintGeneration(gn int) {
	log.Printf("Generation: %d\n", gn)
	for i := range ga.currInds {
		ss := make([]string, len(ga.currInds[i].values))
		for vi, v := range ga.currInds[i].values {
			ss[vi] = strconv.Itoa(int(v))
		}
		log.Printf("%s [%s]\n", ga.currInds[i].id, strings.Join(ss, ","))
	}
	log.Println()
}

func (ga *GAManager) Destroy() {
	ga.normal.stopWithClean()
	for i := range ga.currInds {
		ga.currInds[i].stopWithClean()
	}
	ga.server.Stop()
}

func (ga *GAManager) updateIndMap() {
	for i := range ga.currInds {
		ga.indMap[ga.currInds[i].id] = ga.currInds[i]
	}

	ga.allInds = make([]*individual, len(ga.indMap))
	for _, ind := range ga.indMap {
		ga.allInds = append(ga.allInds, ind)
	}
}
<commit_msg>bugfix about slice's initialization<commit_after>package ga

import (
	"log"
	"math/rand"
	"sort"
	"strconv"
	"strings"
	"time"

	server "github.com/sunfish-shogi/sunfish4-ga/shogiserver"
)

type GAManager struct {
	Config Config

	server   server.ShogiServer
	lastID   int
	indMap   map[string]*individual
	normal   *individual
	allInds  []*individual
	currInds []*individual
}

func NewGAManager(config Config) *GAManager {
	validateConfig(config)
	return &GAManager{
		Config: config,
		indMap: make(map[string]*individual),
	}
}

func (ga *GAManager) Run() error {
	defer ga.Destroy()

	err := ga.Start()
	if err != nil {
		return err
	}

	for gn := 1; ; gn++ {
		ga.PrintGeneration(gn)

		time.Sleep(time.Hour * 4)

		err = ga.Next()
		if err != nil {
			log.Println(err)
		}
	}
}

func (ga *GAManager) Start() error {
	err := ga.server.Setup()
	if err != nil {
		return err
	}

	ga.normal = newIndividual(ga.nextID(), ga.Config)
	ga.normal.initParamNormal()

	ga.currInds = make([]*individual, 0, ga.Config.NumberOfIndividual)
	for i := 0; i < ga.Config.NumberOfIndividual; i++ {
		ind := newIndividual(ga.nextID(), ga.Config)
		ind.initParamByRandom()
		ga.currInds = append(ga.currInds, ind)
	}
	ga.updateIndMap()

	err = startIndividuals(append(ga.currInds, ga.normal))
	return err
}

type indsDescScoreOrder []*individual

func (inds indsDescScoreOrder) Len() int           { return len(inds) }
func (inds indsDescScoreOrder) Swap(i, j int)      { inds[i], inds[j] = inds[j], inds[i] }
func (inds indsDescScoreOrder) Less(i, j int) bool { return inds[i].score > inds[j].score }

func (ga *GAManager) Next() error {
	rate, err := ga.server.MakeRate()
	if err != nil {
		return err
	}

	for pi := range rate.Players {
		for _, player := range rate.Players[pi] {
			if ind, ok := ga.indMap[player.Name]; ok {
				ind.score = player.Rate
			}
		}
	}

	// Sort by Score
	sort.Stable(indsDescScoreOrder(ga.allInds))
	sort.Stable(indsDescScoreOrder(ga.currInds))

	// Print Scores
	log.Println("Score")
	for i := range ga.currInds {
		log.Printf("%s %0.3f", ga.currInds[i].id, ga.currInds[i].score)
	}
	log.Println()

	// New Generation
	inds := make([]*individual, 0, ga.Config.NumberOfIndividual)

	// Elitism
	log.Printf("elite: %s", ga.allInds[0].id)
	inds = append(inds, ga.allInds[0])

	// Random
	ind := newIndividual(ga.nextID(), ga.Config)
	ind.initParamByRandom()
	log.Printf("random: => %s", ind.id)
	inds = append(inds, ind)

	for {
		if len(inds) >= ga.Config.NumberOfIndividual {
			break
		}

		i1 := ga.selectIndividual("")
		i2 := ga.selectIndividual(i1.id)

		ind := ga.crossover(i1, i2)
		log.Printf("crossover: %s x %s => %s", i1.id, i2.id, ind.id)

		if rand.Intn(10) < 1 /* 1/10 */ {
			ga.mutate(ind)
			log.Printf("mutate: %s", ind.id)
		}

		inds = append(inds, ind)
	}
	log.Println()

	// Stop Previous Generation
	stopIndividuals(ga.currInds)

	// Replace to New Generation
	ga.currInds = inds
	ga.updateIndMap()

	// Start Next Generation
	startIndividuals(ga.currInds)

	return nil
}

func (ga *GAManager) selectIndividual(excludeID string) *individual {
	weight := make([]int, len(ga.currInds))
	var sum int
	for i := range weight {
		if ga.currInds[i].id != excludeID {
			if i == 0 {
				weight[0] = 1024
			} else {
				weight[i] = weight[i-1]*9/10 + 1
			}
			sum += weight[i]
		}
	}

	r := rand.Intn(sum)

	for i := range weight {
		r -= weight[i]
		if r <= 0 {
			return ga.currInds[i]
		}
	}
	return ga.currInds[0]
}

func (ga *GAManager) crossover(i1, i2 *individual) *individual {
	ind := newIndividual(ga.nextID(), ga.Config)
	values := make([]int32, len(ga.Config.Params))
	for i := range values {
		if rand.Intn(2) == 0 {
			values[i] = i1.values[i]
		} else {
			values[i] = i2.values[i]
		}
	}
	ind.initParam(values)
	return ind
}

func (ga *GAManager) mutate(ind *individual) {
	n := rand.Intn(2) + 1
	for ; n > 0; n-- {
		i := rand.Intn(len(ind.values))
		min := ga.Config.Params[i].MinimumValue
		max := ga.Config.Params[i].MaximumValue
		t := min + rand.Int31n(max-min+1)
		ind.values[i] = (ind.values[i] + t) / 2
	}
}

func (ga *GAManager) nextID() string {
	ga.lastID++
	return strconv.Itoa(ga.lastID)
}

func (ga *GAManager) PrintGeneration(gn int) {
	log.Printf("Generation: %d\n", gn)
	for i := range ga.currInds {
		ss := make([]string, len(ga.currInds[i].values))
		for vi, v := range ga.currInds[i].values {
			ss[vi] = strconv.Itoa(int(v))
		}
		log.Printf("%s [%s]\n", ga.currInds[i].id, strings.Join(ss, ","))
	}
	log.Println()
}

func (ga *GAManager) Destroy() {
	ga.normal.stopWithClean()
	for i := range ga.currInds {
		ga.currInds[i].stopWithClean()
	}
	ga.server.Stop()
}

func (ga *GAManager) updateIndMap() {
	for i := range ga.currInds {
		ga.indMap[ga.currInds[i].id] = ga.currInds[i]
	}

	ga.allInds = make([]*individual, 0, len(ga.indMap))
	for _, ind := range ga.indMap {
		ga.allInds = append(ga.allInds, ind)
	}
}
<|endoftext|>