<commit_before>// This package provides a simple LRU cache. It is based on the
// LRU implementation in groupcache:
// https://github.com/golang/groupcache/tree/master/lru
package lru

import (
	"sync"

	"github.com/hashicorp/golang-lru/simplelru"
)

// Cache is a thread-safe fixed size LRU cache.
type Cache struct {
	lru  *simplelru.LRU
	lock sync.RWMutex
}

// New creates an LRU of the given size
func New(size int) (*Cache, error) {
	return NewWithEvict(size, nil)
}

// NewWithEvict constructs a fixed size cache with the given eviction
// callback.
func NewWithEvict(size int, onEvicted func(key interface{}, value interface{})) (*Cache, error) {
	lru, err := simplelru.NewLRU(size, simplelru.EvictCallback(onEvicted))
	if err != nil {
		return nil, err
	}
	c := &Cache{
		lru: lru,
	}
	return c, nil
}

// Purge is used to completely clear the cache
func (c *Cache) Purge() {
	c.lock.Lock()
	c.lru.Purge()
	c.lock.Unlock()
}

// Add adds a value to the cache.  Returns true if an eviction occurred.
func (c *Cache) Add(key, value interface{}) bool {
	c.lock.Lock()
	defer c.lock.Unlock()
	return c.lru.Add(key, value)
}

// Get looks up a key's value from the cache.
func (c *Cache) Get(key interface{}) (interface{}, bool) {
	c.lock.Lock()
	defer c.lock.Unlock()
	return c.lru.Get(key)
}

// Check if a key is in the cache, without updating the recent-ness
// or deleting it for being stale.
func (c *Cache) Contains(key interface{}) bool {
	c.lock.RLock()
	defer c.lock.RUnlock()
	return c.lru.Contains(key)
}

// Returns the key value (or undefined if not found) without updating
// the "recently used"-ness of the key.
func (c *Cache) Peek(key interface{}) (interface{}, bool) {
	c.lock.RLock()
	defer c.lock.RUnlock()
	return c.lru.Peek(key)
}

// ContainsOrAdd checks if a key is in the cache  without updating the
// recent-ness or deleting it for being stale,  and if not, adds the value.
// Returns whether found and whether an eviction occurred.
func (c *Cache) ContainsOrAdd(key, value interface{}) (ok, evict bool) {
	c.lock.Lock()
	defer c.lock.Unlock()

	if c.lru.Contains(key) {
		return true, false
	} else {
		evict := c.lru.Add(key, value)
		return false, evict
	}
}

// Remove removes the provided key from the cache.
func (c *Cache) Remove(key interface{}) {
	c.lock.Lock()
	c.lru.Remove(key)
	c.lock.Unlock()
}

// RemoveOldest removes the oldest item from the cache.
func (c *Cache) RemoveOldest() {
	c.lock.Lock()
	c.lru.RemoveOldest()
	c.lock.Unlock()
}

// Keys returns a slice of the keys in the cache, from oldest to newest.
func (c *Cache) Keys() []interface{} {
	c.lock.RLock()
	defer c.lock.RUnlock()
	return c.lru.Keys()
}

// Len returns the number of items in the cache.
func (c *Cache) Len() int {
	c.lock.RLock()
	defer c.lock.RUnlock()
	return c.lru.Len()
}
<commit_msg>make documentation and code more idiomatic<commit_after>// Package lru provides a simple LRU cache. It is based on the
// LRU implementation in groupcache:
// https://github.com/golang/groupcache/tree/master/lru
package lru

import (
	"sync"

	"github.com/hashicorp/golang-lru/simplelru"
)

// Cache is a thread-safe fixed size LRU cache.
type Cache struct {
	lru  *simplelru.LRU
	lock sync.RWMutex
}

// New creates an LRU of the given size
func New(size int) (*Cache, error) {
	return NewWithEvict(size, nil)
}

// NewWithEvict constructs a fixed size cache with the given eviction
// callback.
func NewWithEvict(size int, onEvicted func(key interface{}, value interface{})) (*Cache, error) {
	lru, err := simplelru.NewLRU(size, simplelru.EvictCallback(onEvicted))
	if err != nil {
		return nil, err
	}
	c := &Cache{
		lru: lru,
	}
	return c, nil
}

// Purge is used to completely clear the cache
func (c *Cache) Purge() {
	c.lock.Lock()
	c.lru.Purge()
	c.lock.Unlock()
}

// Add adds a value to the cache.  Returns true if an eviction occurred.
func (c *Cache) Add(key, value interface{}) bool {
	c.lock.Lock()
	defer c.lock.Unlock()
	return c.lru.Add(key, value)
}

// Get looks up a key's value from the cache.
func (c *Cache) Get(key interface{}) (interface{}, bool) {
	c.lock.Lock()
	defer c.lock.Unlock()
	return c.lru.Get(key)
}

// Contains checks if a key is in the cache, without updating the
// recent-ness or deleting it for being stale.
func (c *Cache) Contains(key interface{}) bool {
	c.lock.RLock()
	defer c.lock.RUnlock()
	return c.lru.Contains(key)
}

// Peek returns the key value (or undefined if not found) without updating
// the "recently used"-ness of the key.
func (c *Cache) Peek(key interface{}) (interface{}, bool) {
	c.lock.RLock()
	defer c.lock.RUnlock()
	return c.lru.Peek(key)
}

// ContainsOrAdd checks if a key is in the cache  without updating the
// recent-ness or deleting it for being stale,  and if not, adds the value.
// Returns whether found and whether an eviction occurred.
func (c *Cache) ContainsOrAdd(key, value interface{}) (ok, evict bool) {
	c.lock.Lock()
	defer c.lock.Unlock()

	if c.lru.Contains(key) {
		return true, false
	}
	evict = c.lru.Add(key, value)
	return false, evict
}

// Remove removes the provided key from the cache.
func (c *Cache) Remove(key interface{}) {
	c.lock.Lock()
	c.lru.Remove(key)
	c.lock.Unlock()
}

// RemoveOldest removes the oldest item from the cache.
func (c *Cache) RemoveOldest() {
	c.lock.Lock()
	c.lru.RemoveOldest()
	c.lock.Unlock()
}

// Keys returns a slice of the keys in the cache, from oldest to newest.
func (c *Cache) Keys() []interface{} {
	c.lock.RLock()
	defer c.lock.RUnlock()
	return c.lru.Keys()
}

// Len returns the number of items in the cache.
func (c *Cache) Len() int {
	c.lock.RLock()
	defer c.lock.RUnlock()
	return c.lru.Len()
}
<|endoftext|>


<commit_before>package mpo

import (
	"image"
	"image/jpeg"
	"io"
)

// GIF represents the likely multiple images stored in a GIF file.
type MPO struct {
	Image []image.Image
}

const (
	mpojpgMKR = 0xFF
	mpojpgSOI = 0xD8
	mpojpgEOI = 0xD9
)

type MpoReader interface {
	io.Reader
	io.ReaderAt
}

// DecodeAll reads an MPO image from r and returns the sequential frames
func DecodeAll(r MpoReader) (*MPO, error) {
	sectReaders := make([]*io.SectionReader, 0)
	readData := make([]byte, 1)

	var depth uint8 = 0
	var imgStart int64 = 0
	var loc int64 = 0
	for {
		i1, err := r.Read(readData)
		if err == io.EOF {
			break
		} else if err != nil {
			return nil, err
		}
		loc += int64(i1)

		if readData[0] == mpojpgMKR {
			i2, err := r.Read(readData)
			if err == io.EOF {
				break
			} else if err != nil {
				return nil, err
			}
			loc += int64(i2)

			if readData[0] == mpojpgSOI {
				if depth == 0 {
					imgStart = loc - 2
				}

				depth++
			} else if readData[0] == mpojpgEOI {
				depth--
				if depth == 0 {
					sectReaders = append(sectReaders, io.NewSectionReader(r, imgStart, loc))
				}

			}
		}
	}

	m := &MPO{
		Image: make([]image.Image, 0),
	}

	for _, s := range sectReaders {
		img, err := jpeg.Decode(s)
		if err != nil {
			return nil, err
		}

		m.Image = append(m.Image, img)
	}

	return m, nil
}
<commit_msg>Doc corrections<commit_after>package mpo

import (
	"image"
	"image/jpeg"
	"io"
)

// MPO represents the likely multiple images stored in a MPO file.
type MPO struct {
	Image []image.Image
}

const (
	mpojpgMKR = 0xFF
	mpojpgSOI = 0xD8
	mpojpgEOI = 0xD9
)

type MpoReader interface {
	io.Reader
	io.ReaderAt
}

// DecodeAll reads an MPO image from r and returns the sequential frames
func DecodeAll(r MpoReader) (*MPO, error) {
	sectReaders := make([]*io.SectionReader, 0)
	readData := make([]byte, 1)

	var depth uint8 = 0
	var imgStart int64 = 0
	var loc int64 = 0
	for {
		i1, err := r.Read(readData)
		if err == io.EOF {
			break
		} else if err != nil {
			return nil, err
		}
		loc += int64(i1)

		if readData[0] == mpojpgMKR {
			i2, err := r.Read(readData)
			if err == io.EOF {
				break
			} else if err != nil {
				return nil, err
			}
			loc += int64(i2)

			if readData[0] == mpojpgSOI {
				if depth == 0 {
					imgStart = loc - 2
				}

				depth++
			} else if readData[0] == mpojpgEOI {
				depth--
				if depth == 0 {
					sectReaders = append(sectReaders, io.NewSectionReader(r, imgStart, loc))
				}

			}
		}
	}

	m := &MPO{
		Image: make([]image.Image, 0),
	}

	for _, s := range sectReaders {
		img, err := jpeg.Decode(s)
		if err != nil {
			return nil, err
		}

		m.Image = append(m.Image, img)
	}

	return m, nil
}
<|endoftext|>


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

package tinynet

import (
	"fmt"

	log "github.com/sirupsen/logrus"
)

// AddHost will add a host to topology. set docker to true can enable docker container as a host
func AddHost(name string, addr string, docker bool) (*Host, error) {
	var h *Host
	var err error
	if docker {
		// Create a docker container
		h, err = NewContainer(name, "library/busybox")
		if err != nil {
			log.Fatal("failed to NewContainer: ", err)
		}
	} else {
		// Create a network namespace
		h, err = NewHost(name)
		if err != nil {
			log.Fatal("failed to NewHost: ", err)
		}
	}
	// setup a veth pair
	_, err = h.setupVeth("eth2", 1500)
	if err != nil {
		log.Fatal("failed to setup veth pair: ", err)
	}
	// setup a IP for host
	h.setIfaceIP(addr)
	if err != nil {
		log.Fatalf("failed to setIfaceIP for %s: %v", h.Name, err)
		return nil, err
	}
	return h, nil
}

// AddSwitch will add a switch to topology.
func AddSwitch(params ...string) (*OVSSwitch, error) {
	// params[0] for brName
	// params[1] for controller remote IP and port
	// Create a Open vSwitch bridge
	sw, err := NewOVSSwitch(params[0])
	if err != nil {
		log.Fatal("failed to NewOVSSwitch: ", err)
	}
	if len(params) == 2 {
		if err := sw.setCtrl(params[1]); err != nil {
			log.Warnf("failed to setCtrl for %s: %v", sw.BridgeName, err)
			return nil, err
		}
	} else if len(params) > 2 {
		return nil, fmt.Errorf("Too many arguments")
	}
	return sw, nil
}

// AddLink will add a link between switch to switch or host to switch.
func AddLink(n1, n2 interface{}) error {
	// log.Info(n1.(*OVSSwitch).nodeType)
	// log.Info(n2.(*Host).nodeType)
	var err error
	switch n1.(type) {
	case *OVSSwitch:
		switch n2.(type) {
		case *OVSSwitch:
			tap0, tap1, err := makeVethPair("tap0", "tap1")
			if err != nil {
				log.Fatalf("failed to makeVethPair: %v", err)
			}
			err = n1.(*OVSSwitch).addPort(tap0.Name)
			if err != nil {
				log.Fatalf("failed to addPortswitch - switch: %v", err)
			}
			err = n2.(*OVSSwitch).addPort(tap1.Name)
			if err != nil {
				log.Fatalf("failed to addPort switch - switch: %v", err)
			}
			log.Infof("Adding a link: (%s, %s)", n1.(*OVSSwitch).BridgeName, n2.(*OVSSwitch).BridgeName)
		case *Host:
			err = n1.(*OVSSwitch).addPort(n2.(*Host).vethName)
			if err != nil {
				log.Fatalf("failed to addPort switch - host: %v", err)
			}
			log.Infof("Adding a link: (%s, %s)", n1.(*OVSSwitch).BridgeName, n2.(*Host).Name)
		default:
			log.Fatalf("Type Error")
		}
	case *Host:
		switch n2.(type) {
		case *OVSSwitch:
			err = n2.(*OVSSwitch).addPort(n1.(*Host).vethName)
			if err != nil {
				log.Fatalf("failed to addPort host - switch : %v", err)
			}
			log.Infof("Adding a link: (%s, %s)", n1.(*Host).Name, n2.(*OVSSwitch).BridgeName)
		case *Host:
			log.Fatalf("Type Error: host can not connect to host")
		default:
			log.Fatalf("Type Error")
		}
	default:
		log.Fatalf("Type Error")
	}
	return nil
}

// GetIPs will get IP address from a CIDR notation
// Return an array with IP address. negative num for getting all IP addresses
// (network address and broadcast address are not included)
func GetIPs(cidr string, num int) ([]string, error) {
	ips, err := getAllIPsfromCIDR(cidr)
	if err != nil {
		return nil, err
	}
	if num < 0 {
		return ips, nil
	}
	return ips[0:num], nil
}
<commit_msg>use constructor to give host network configuration<commit_after>// Copyright (c) 2017 Che Wei, Lin
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package tinynet

import (
	"fmt"

	log "github.com/sirupsen/logrus"
)

// HostConfig is a host network configuration
type HostConfig struct {
	name      string
	address   string
	docker    bool
	ifaceName string
	imageRef  string
	mtu       int
}

// NewHostConfig is a constructor to initial host network configuration.
func NewHostConfig(name, addr, ifaceName string, mtu int, docker bool, imageRef string) HostConfig {
	hostConfig := HostConfig{}
	if name == "" {
		panic("Host name is required")
	}
	if addr == "" {
		panic("Host address is required")
	}
	hostConfig.name = name
	hostConfig.address = addr
	hostConfig.docker = docker
	hostConfig.ifaceName = ifaceName
	if ifaceName == "" {
		hostConfig.ifaceName = "eth1"
	}
	hostConfig.imageRef = imageRef
	if imageRef == "" {
		hostConfig.imageRef = "library/busybox"
	}
	hostConfig.mtu = mtu
	if mtu == 0 {
		hostConfig.mtu = 1500
	}
	return hostConfig
}

// AddHostWithConf will add a host to topology.
func AddHostWithConf(hc hostConfig) (*Host, error) {
	var h *Host
	var err error
	if hc.docker {
		// Create a docker container
		h, err = NewContainer(hc.name, hc.imageRef)
		if err != nil {
			log.Fatal("failed to NewContainer: ", err)
		}
	} else {
		// Create a network namespace
		h, err = NewHost(hc.name)
		if err != nil {
			log.Fatal("failed to NewHost: ", err)
		}
	}
	// setup a veth pair
	_, err = h.setupVeth(hc.ifaceName, hc.mtu)
	if err != nil {
		log.Fatal("failed to setup veth pair: ", err)
	}
	// setup a IP for host
	h.setIfaceIP(hc.address)
	if err != nil {
		log.Fatalf("failed to setIfaceIP for %s: %v", h.Name, err)
		return nil, err
	}
	return h, nil
}

// AddHost will add a host to topology. set docker to true can enable docker container as a host
func AddHost(name string, addr string, docker bool) (*Host, error) {
	log.Warnf("Will be deprecated: use AddHostWithConf instead")
	var h *Host
	var err error
	if docker {
		// Create a docker container
		h, err = NewContainer(name, "library/busybox")
		if err != nil {
			log.Fatal("failed to NewContainer: ", err)
		}
	} else {
		// Create a network namespace
		h, err = NewHost(name)
		if err != nil {
			log.Fatal("failed to NewHost: ", err)
		}
	}
	// setup a veth pair
	_, err = h.setupVeth("eth2", 1500)
	if err != nil {
		log.Fatal("failed to setup veth pair: ", err)
	}
	// setup a IP for host
	h.setIfaceIP(addr)
	if err != nil {
		log.Fatalf("failed to setIfaceIP for %s: %v", h.Name, err)
		return nil, err
	}
	return h, nil
}

// AddSwitch will add a switch to topology.
func AddSwitch(params ...string) (*OVSSwitch, error) {
	// params[0] for brName
	// params[1] for controller remote IP and port
	// Create a Open vSwitch bridge
	sw, err := NewOVSSwitch(params[0])
	if err != nil {
		log.Fatal("failed to NewOVSSwitch: ", err)
	}
	if len(params) == 2 {
		if err := sw.setCtrl(params[1]); err != nil {
			log.Warnf("failed to setCtrl for %s: %v", sw.BridgeName, err)
			return nil, err
		}
	} else if len(params) > 2 {
		return nil, fmt.Errorf("Too many arguments")
	}
	return sw, nil
}

// AddLink will add a link between switch to switch or host to switch.
func AddLink(n1, n2 interface{}) error {
	// log.Info(n1.(*OVSSwitch).nodeType)
	// log.Info(n2.(*Host).nodeType)
	var err error
	switch n1.(type) {
	case *OVSSwitch:
		switch n2.(type) {
		case *OVSSwitch:
			tap0, tap1, err := makeVethPair("tap0", "tap1")
			if err != nil {
				log.Fatalf("failed to makeVethPair: %v", err)
			}
			err = n1.(*OVSSwitch).addPort(tap0.Name)
			if err != nil {
				log.Fatalf("failed to addPortswitch - switch: %v", err)
			}
			err = n2.(*OVSSwitch).addPort(tap1.Name)
			if err != nil {
				log.Fatalf("failed to addPort switch - switch: %v", err)
			}
			log.Infof("Adding a link: (%s, %s)", n1.(*OVSSwitch).BridgeName, n2.(*OVSSwitch).BridgeName)
		case *Host:
			err = n1.(*OVSSwitch).addPort(n2.(*Host).vethName)
			if err != nil {
				log.Fatalf("failed to addPort switch - host: %v", err)
			}
			log.Infof("Adding a link: (%s, %s)", n1.(*OVSSwitch).BridgeName, n2.(*Host).Name)
		default:
			log.Fatalf("Type Error")
		}
	case *Host:
		switch n2.(type) {
		case *OVSSwitch:
			err = n2.(*OVSSwitch).addPort(n1.(*Host).vethName)
			if err != nil {
				log.Fatalf("failed to addPort host - switch : %v", err)
			}
			log.Infof("Adding a link: (%s, %s)", n1.(*Host).Name, n2.(*OVSSwitch).BridgeName)
		case *Host:
			log.Fatalf("Type Error: host can not connect to host")
		default:
			log.Fatalf("Type Error")
		}
	default:
		log.Fatalf("Type Error")
	}
	return nil
}

// GetIPs will get IP address from a CIDR notation
// Return an array with IP address. negative num for getting all IP addresses
// (network address and broadcast address are not included)
func GetIPs(cidr string, num int) ([]string, error) {
	ips, err := getAllIPsfromCIDR(cidr)
	if err != nil {
		return nil, err
	}
	if num < 0 {
		return ips, nil
	}
	return ips[0:num], nil
}
<|endoftext|>


<commit_before>package main

import (
	"http"
	"io/ioutil"
	"log"
	"os"
	"regexp"
	"sort"
	"strconv"
	"template"
)

const lenPath = len("/view/")

type Page struct {
	Id   string
	Body []byte
}

func (p *Page) save() os.Error {
	filename := "pastes/" + p.Id
	return ioutil.WriteFile(filename, p.Body, 0600)
}

func loadPage(title string) (*Page, os.Error) {
	filename := "pastes/" + title
	body, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return &Page{Id: title, Body: body}, nil
}

func main() {
	http.HandleFunc("/", pasteHandler)
	http.HandleFunc("/view/", makeHandler(viewHandler))
	http.HandleFunc("/save/", saveHandler)
	http.ListenAndServe(":8080", nil)
}

func pasteHandler(w http.ResponseWriter, r *http.Request) {
	p := &Page{Id: "0", Body: make([]byte, 0)}
	renderTemplate(w, "paste", p)
}

func nextid() string {
	nxt := curid
	curid++
	return strconv.Itoa(nxt)
}

func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		title := r.URL.Path[lenPath:]
		if !titleValidator.MatchString(title) {
			http.NotFound(w, r)
			return
		}
		fn(w, r, title)
	}
}

func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
	p, err := loadPage(title)
	if err != nil {
		http.NotFound(w, r)
		return
	}
	renderTemplate(w, "view", p)
}

func saveHandler(w http.ResponseWriter, r *http.Request) {
	body := r.FormValue("body")
	id := nextid()
	p := &Page{Id: id, Body: []byte(body)}
	err := p.save()
	if err != nil {
		log.Printf("Error saving paste %s\n", id)
		http.Error(w, err.String(), http.StatusInternalServerError)
		return
	}
	log.Printf("Saving paste %s\n", id)
	http.Redirect(w, r, "/view/"+id, http.StatusFound)
}

func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
	err := templates[tmpl].Execute(w, p)
	if err != nil {
		http.Error(w, err.String(), http.StatusInternalServerError)
		return
	}
}

var templates = make(map[string]*template.Template)
var curid int

func init() {
	for _, tmpl := range []string{"paste", "view"} {
		templates[tmpl] = template.MustParseFile(tmpl+".html", nil)
	}
	os.Mkdir("pastes", 0755)

	curid = getlastid() + 1
}

func getlastid() int {
	p, err := os.Open("pastes")
	if err != nil {
		panic(err)
	}
	defer p.Close()

	names, err := p.Readdirnames(-1)
	if err != nil {
		panic(err)
	}

	nc := len(names)
	if nc == 0 {
		return 0
	}

	ids := make([]int, nc)
	for i := 0; i < nc; i++ {
		ids[i], err = strconv.Atoi(names[i])
		if err != nil {
			panic(err)
		}
	}
	sort.SortInts(ids)
	return ids[nc-1]
}

var titleValidator = regexp.MustCompile("^[0-9]+$")

func getId(w http.ResponseWriter, r *http.Request) (title string, err os.Error) {
	title = r.URL.Path[lenPath:]
	if !titleValidator.MatchString(title) {
		http.NotFound(w, r)
		err = os.NewError("Invalid Page Id")
	}
	return
}
<commit_msg>Make sure it actually starts up.<commit_after>package main

import (
	"http"
	"io/ioutil"
	"log"
	"os"
	"regexp"
	"sort"
	"strconv"
	"template"
)

const lenPath = len("/view/")

type Page struct {
	Id   string
	Body []byte
}

func (p *Page) save() os.Error {
	filename := "pastes/" + p.Id
	return ioutil.WriteFile(filename, p.Body, 0600)
}

func loadPage(title string) (*Page, os.Error) {
	filename := "pastes/" + title
	body, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return &Page{Id: title, Body: body}, nil
}

func main() {
	http.HandleFunc("/", pasteHandler)
	http.HandleFunc("/view/", makeHandler(viewHandler))
	http.HandleFunc("/save/", saveHandler)
	http.ListenAndServe(":8080", nil)
}

func pasteHandler(w http.ResponseWriter, r *http.Request) {
	p := &Page{Id: "0", Body: make([]byte, 0)}
	renderTemplate(w, "paste", p)
}

func nextid() string {
	nxt := curid
	curid++
	return strconv.Itoa(nxt)
}

func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		title := r.URL.Path[lenPath:]
		if !titleValidator.MatchString(title) {
			http.NotFound(w, r)
			return
		}
		fn(w, r, title)
	}
}

func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
	p, err := loadPage(title)
	if err != nil {
		http.NotFound(w, r)
		return
	}
	renderTemplate(w, "view", p)
}

func saveHandler(w http.ResponseWriter, r *http.Request) {
	body := r.FormValue("body")
	id := nextid()
	p := &Page{Id: id, Body: []byte(body)}
	err := p.save()
	if err != nil {
		log.Printf("Error saving paste %s\n", id)
		http.Error(w, err.String(), http.StatusInternalServerError)
		return
	}
	log.Printf("Saving paste %s\n", id)
	http.Redirect(w, r, "/view/"+id, http.StatusFound)
}

func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
	err := templates[tmpl].Execute(w, p)
	if err != nil {
		http.Error(w, err.String(), http.StatusInternalServerError)
		return
	}
}

var templates = make(map[string]*template.Template)
var curid int

func init() {
	log.Println("Starting up")
	for _, tmpl := range []string{"paste", "view"} {
		templates[tmpl] = template.MustParseFile(tmpl+".html", nil)
	}
	os.Mkdir("pastes", 0755)

	curid = getlastid() + 1
	log.Println("Ready to serve")
}

func getlastid() int {
	p, err := os.Open("pastes")
	if err != nil {
		panic(err)
	}
	defer p.Close()

	names, err := p.Readdirnames(-1)
	if err != nil {
		panic(err)
	}

	nc := len(names)
	if nc == 0 {
		return 0
	}

	ids := make([]int, nc)
	for i := 0; i < nc; i++ {
		ids[i], err = strconv.Atoi(names[i])
		if err != nil {
			panic(err)
		}
	}
	sort.SortInts(ids)
	return ids[nc-1]
}

var titleValidator = regexp.MustCompile("^[0-9]+$")

func getId(w http.ResponseWriter, r *http.Request) (title string, err os.Error) {
	title = r.URL.Path[lenPath:]
	if !titleValidator.MatchString(title) {
		http.NotFound(w, r)
		err = os.NewError("Invalid Page Id")
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

const (
	AppName    = "Pingo"
	APIName    = "FindMyiphone"
	APIVertion = "2.0.2"
)

const (
	ExitOK = 0 + iota

	ExitError = 9 + iota
	ExitParseArgsError
	ExitRequestDeviceError
	ExitRequestSoundError
)

var HEADER_MAP = map[string][]string{
	"Content-Type":          {"application/json; charset=utf-8"},
	"X-Apple-Find-Api-Ver":  {"2.0"},
	"X-Apple-Authscheme":    {"UserIdGuest"},
	"X-Apple-Realm-Support": {"1.0"},
	"Accept-Language":       {"en-us"},
	"userAgent":             {"Pingo"},
	"Connection":            {"keep-alive"},
}

type ClientContext struct {
	AppName      string `json:"appName"`
	AppVersion   string `json:"appVersion"`
	ShouldLocate bool   `json:"shouldLocate"`
}

type SoundParams struct {
	ClientContext `json:"clientContext"`
	Device        string `json:"device"`
	Subject       string `json:"subject"`
}

type Container struct {
	Content []struct {
		DeviceName string `json:"deviceDisplayName"`
		DeviceId   string `json:"id"`
	} `json:"content"`
}

func main() {
	os.Exit(NewCLI().Run(os.Args))
}

type CLI struct {
	outStream, errStream io.Writer
}

func NewCLI() *CLI {
	return &CLI{
		outStream: os.Stdout,
		errStream: os.Stderr,
	}
}

func (cli *CLI) PutOutStream(format string, args ...interface{}) {
	fmt.Fprintf(cli.outStream, format, args...)
}

func (cli *CLI) PutErrStream(format string, args ...interface{}) {
	fmt.Fprintf(cli.errStream, format, args...)
}

func (cli *CLI) Run(args []string) int {
	appleAccount, err := cli.parseArgs(args)
	if err != nil {
		cli.PutErrStream("Failed to parse args:\n %s\n", err)
		return ExitParseArgsError
	}

	client := &Client{AppleAccount: appleAccount}

	deviceID, err := client.RequestDeviceID()
	if err != nil {
		cli.PutErrStream("Failed to request device id:\n %s\n", err)
		return ExitRequestDeviceError
	}

	if err = client.RequestSound(deviceID); err != nil {
		cli.PutErrStream("Failed to request sound:\n %s\n", err)
		return ExitRequestSoundError
	}

	return ExitOK
}

type AppleAccount struct {
	ID        string
	Pass      string
	ModelName string
}

func (cli *CLI) parseArgs(args []string) (*AppleAccount, error) {
	appleID := os.Getenv("APPLE_ID")
	applePass := os.Getenv("APPLE_PASSWORD")

	flags := flag.NewFlagSet(AppName, flag.ContinueOnError)

	flags.StringVar(&appleID, "apple-id", appleID, "apple id to use")
	flags.StringVar(&appleID, "i", appleID, "apple id to use (short)")
	flags.StringVar(&applePass, "apple-password", applePass, "apple passwaord to to")
	flags.StringVar(&applePass, "p", applePass, "apple passwaord to to (short)")

	if err := flags.Parse(args[1:]); err != nil {
		return nil, errors.New("Faild to parse flag")
	}

	if appleID == "" || applePass == "" {
		return nil, errors.New("APPLE ID or APPLE PASSWORD are empty")
	}

	modelName := flags.Arg(0)

	if modelName == "" {
		return nil, errors.New("Device model name is empty")
	}

	return &AppleAccount{ID: appleID, Pass: applePass, ModelName: modelName}, nil
}

type Client struct {
	*AppleAccount
	debug bool
}

func (c *Client) requestDeviceIDURL() string {
	return fmt.Sprintf("https://fmipmobile.icloud.com/fmipservice/device/%s/initClient", c.ModelName)
}

func (c *Client) requestSoundURL() string {
	return fmt.Sprintf("https://fmipmobile.icloud.com/fmipservice/device/%s/playSound", c.ModelName)
}

func (c *Client) RequestDeviceID() (string, error) {
	body, err := c.getBody("POST", c.requestDeviceIDURL(), nil)
	if err != nil {
		return "", errors.New("getBody: " + err.Error())
	}

	deviceID, err := c.parseDeviceID(body)
	if err != nil {
		return "", errors.New("parseDeviceID: " + err.Error())
	}

	return deviceID, nil
}

func (c *Client) getBody(method string, url string, params io.Reader) ([]byte, error) {
	resp, err := c.httpExecute(method, url, params)
	if err != nil {
		return nil, errors.New("httpExecute: " + err.Error())
	}

	bodyBytes, err := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()
	if err != nil {
		return nil, errors.New("ReadAll: " + err.Error())
	}

	if c.debug {
		fmt.Printf("STATUS: %s\n", resp.Status)
		fmt.Println("BODY RESPONSE: " + string(bodyBytes))
	}

	return bodyBytes, nil
}

type HTTPExecuteError struct {
	RequestHeaders    string
	ResponseBodyBytes []byte
	Status            string
	StatusCode        int
}

func (e HTTPExecuteError) Error() string {
	return "HTTP response is not 200/OK as expected. Actual response: \n" +
		"\tResponse Status: '" + e.Status + "'\n" +
		"\tResponse Code: " + strconv.Itoa(e.StatusCode) + "\n" +
		"\tRequest Headers: " + e.RequestHeaders + "\n" +
		"\tResponse Body: " + string(e.ResponseBodyBytes)
}

func (c *Client) httpExecute(method string, url string, body io.Reader) (*http.Response, error) {
	req, err := http.NewRequest(method, url, body)
	if err != nil {
		return nil, errors.New("NewRequest: " + err.Error())
	}

	req.Header = http.Header(HEADER_MAP)
	req.SetBasicAuth(c.ID, c.Pass)

	client := &http.Client{Timeout: time.Duration(10 * time.Second)}

	if c.debug {
		fmt.Printf("Request: %v\n", req)
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, errors.New("Do: " + err.Error())
	}

	if resp.StatusCode != 200 {
		defer resp.Body.Close()
		bytes, _ := ioutil.ReadAll(resp.Body)

		debugHeader := ""
		for k, vals := range req.Header {
			for _, val := range vals {
				debugHeader += "[key: " + k + ", val: " + val + "]"
			}
		}

		return resp, HTTPExecuteError{
			RequestHeaders:    debugHeader,
			ResponseBodyBytes: bytes,
			Status:            resp.Status,
			StatusCode:        resp.StatusCode,
		}
	}

	return resp, nil
}

func (c *Client) parseDeviceID(body []byte) (string, error) {

	var cont Container
	if err := json.Unmarshal(body, &cont); err != nil {
		return "", errors.New("Unmarshal: " + err.Error())
	}

	var deviceId string
	for _, v := range cont.Content {
		if strings.HasSuffix(v.DeviceName, c.ModelName) {
			deviceId = v.DeviceId
			break
		}
	}

	if deviceId == "" {
		return "", errors.New("Not found device id")
	}

	return deviceId, nil
}

func (c *Client) RequestSound(deviceId string) error {
	input, err := json.Marshal(SoundParams{
		ClientContext: ClientContext{AppName: APIName, AppVersion: APIVertion},
		Device:        deviceId,
		Subject:       AppName,
	})

	if err != nil {
		return errors.New("json.Marshal: " + err.Error())
	}

	if _, err := c.getBody("POST", c.requestSoundURL(), bytes.NewBuffer(input)); err != nil {
		return errors.New("getBody: " + err.Error())
	}

	return nil
}
<commit_msg>Add success message<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

const (
	AppName    = "Pingo"
	APIName    = "FindMyiphone"
	APIVertion = "2.0.2"
)

const (
	ExitOK = 0 + iota

	ExitError = 9 + iota
	ExitParseArgsError
	ExitRequestDeviceError
	ExitRequestSoundError
)

var HEADER_MAP = map[string][]string{
	"Content-Type":          {"application/json; charset=utf-8"},
	"X-Apple-Find-Api-Ver":  {"2.0"},
	"X-Apple-Authscheme":    {"UserIdGuest"},
	"X-Apple-Realm-Support": {"1.0"},
	"Accept-Language":       {"en-us"},
	"userAgent":             {"Pingo"},
	"Connection":            {"keep-alive"},
}

type ClientContext struct {
	AppName      string `json:"appName"`
	AppVersion   string `json:"appVersion"`
	ShouldLocate bool   `json:"shouldLocate"`
}

type SoundParams struct {
	ClientContext `json:"clientContext"`
	Device        string `json:"device"`
	Subject       string `json:"subject"`
}

type Container struct {
	Content []struct {
		DeviceName string `json:"deviceDisplayName"`
		DeviceId   string `json:"id"`
	} `json:"content"`
}

func main() {
	os.Exit(NewCLI().Run(os.Args))
}

type CLI struct {
	outStream, errStream io.Writer
}

func NewCLI() *CLI {
	return &CLI{
		outStream: os.Stdout,
		errStream: os.Stderr,
	}
}

func (cli *CLI) PutOutStream(format string, args ...interface{}) {
	fmt.Fprintf(cli.outStream, format, args...)
}

func (cli *CLI) PutErrStream(format string, args ...interface{}) {
	fmt.Fprintf(cli.errStream, format, args...)
}

func (cli *CLI) Run(args []string) int {
	appleAccount, err := cli.parseArgs(args)
	if err != nil {
		cli.PutErrStream("Failed to parse args:\n %s\n", err)
		return ExitParseArgsError
	}

	client := &Client{AppleAccount: appleAccount}

	deviceID, err := client.RequestDeviceID()
	if err != nil {
		cli.PutErrStream("Failed to request device id:\n %s\n", err)
		return ExitRequestDeviceError
	}

	if err = client.RequestSound(deviceID); err != nil {
		cli.PutErrStream("Failed to request sound:\n %s\n", err)
		return ExitRequestSoundError
	}

	cli.PrintSuccessMessage()

	return ExitOK
}

type AppleAccount struct {
	ID        string
	Pass      string
	ModelName string
}

func (cli *CLI) parseArgs(args []string) (*AppleAccount, error) {
	appleID := os.Getenv("APPLE_ID")
	applePass := os.Getenv("APPLE_PASSWORD")

	flags := flag.NewFlagSet(AppName, flag.ContinueOnError)

	flags.StringVar(&appleID, "apple-id", appleID, "apple id to use")
	flags.StringVar(&appleID, "i", appleID, "apple id to use (short)")
	flags.StringVar(&applePass, "apple-password", applePass, "apple passwaord to to")
	flags.StringVar(&applePass, "p", applePass, "apple passwaord to to (short)")

	if err := flags.Parse(args[1:]); err != nil {
		return nil, errors.New("Faild to parse flag")
	}

	if appleID == "" || applePass == "" {
		return nil, errors.New("APPLE ID or APPLE PASSWORD are empty")
	}

	modelName := flags.Arg(0)

	if modelName == "" {
		return nil, errors.New("Device model name is empty")
	}

	return &AppleAccount{ID: appleID, Pass: applePass, ModelName: modelName}, nil
}

func (c *CLI) PrintSuccessMessage() {
	fmt.Println(`
	    888888ba  oo
	    88    8b
	   a88aaaa8P  dP 88d888b. .d8888b. .d8888b.
	    88        88 88    88 88    88 88    88
	    88        88 88    88 88.  .88 88.  .88
	    dP        dP dP    dP .8888P88  88888P
	                               .88
	                           d8888P
	`)
	return
}

type Client struct {
	*AppleAccount
	debug bool
}

func (c *Client) requestDeviceIDURL() string {
	return fmt.Sprintf("https://fmipmobile.icloud.com/fmipservice/device/%s/initClient", c.ModelName)
}

func (c *Client) requestSoundURL() string {
	return fmt.Sprintf("https://fmipmobile.icloud.com/fmipservice/device/%s/playSound", c.ModelName)
}

func (c *Client) RequestDeviceID() (string, error) {
	body, err := c.getBody("POST", c.requestDeviceIDURL(), nil)
	if err != nil {
		return "", errors.New("getBody: " + err.Error())
	}

	deviceID, err := c.parseDeviceID(body)
	if err != nil {
		return "", errors.New("parseDeviceID: " + err.Error())
	}

	return deviceID, nil
}

func (c *Client) getBody(method string, url string, params io.Reader) ([]byte, error) {
	resp, err := c.httpExecute(method, url, params)
	if err != nil {
		return nil, errors.New("httpExecute: " + err.Error())
	}

	bodyBytes, err := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()
	if err != nil {
		return nil, errors.New("ReadAll: " + err.Error())
	}

	if c.debug {
		fmt.Printf("STATUS: %s\n", resp.Status)
		fmt.Println("BODY RESPONSE: " + string(bodyBytes))
	}

	return bodyBytes, nil
}

type HTTPExecuteError struct {
	RequestHeaders    string
	ResponseBodyBytes []byte
	Status            string
	StatusCode        int
}

func (e HTTPExecuteError) Error() string {
	return "HTTP response is not 200/OK as expected. Actual response: \n" +
		"\tResponse Status: '" + e.Status + "'\n" +
		"\tResponse Code: " + strconv.Itoa(e.StatusCode) + "\n" +
		"\tRequest Headers: " + e.RequestHeaders + "\n" +
		"\tResponse Body: " + string(e.ResponseBodyBytes)
}

func (c *Client) httpExecute(method string, url string, body io.Reader) (*http.Response, error) {
	req, err := http.NewRequest(method, url, body)
	if err != nil {
		return nil, errors.New("NewRequest: " + err.Error())
	}

	req.Header = http.Header(HEADER_MAP)
	req.SetBasicAuth(c.ID, c.Pass)

	client := &http.Client{Timeout: time.Duration(10 * time.Second)}

	if c.debug {
		fmt.Printf("Request: %v\n", req)
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, errors.New("Do: " + err.Error())
	}

	if resp.StatusCode != 200 {
		defer resp.Body.Close()
		bytes, _ := ioutil.ReadAll(resp.Body)

		debugHeader := ""
		for k, vals := range req.Header {
			for _, val := range vals {
				debugHeader += "[key: " + k + ", val: " + val + "]"
			}
		}

		return resp, HTTPExecuteError{
			RequestHeaders:    debugHeader,
			ResponseBodyBytes: bytes,
			Status:            resp.Status,
			StatusCode:        resp.StatusCode,
		}
	}

	return resp, nil
}

func (c *Client) parseDeviceID(body []byte) (string, error) {

	var cont Container
	if err := json.Unmarshal(body, &cont); err != nil {
		return "", errors.New("Unmarshal: " + err.Error())
	}

	var deviceId string
	for _, v := range cont.Content {
		if strings.HasSuffix(v.DeviceName, c.ModelName) {
			deviceId = v.DeviceId
			break
		}
	}

	if deviceId == "" {
		return "", errors.New("Not found device id")
	}

	return deviceId, nil
}

func (c *Client) RequestSound(deviceId string) error {
	input, err := json.Marshal(SoundParams{
		ClientContext: ClientContext{AppName: APIName, AppVersion: APIVertion},
		Device:        deviceId,
		Subject:       AppName,
	})

	if err != nil {
		return errors.New("json.Marshal: " + err.Error())
	}

	if _, err := c.getBody("POST", c.requestSoundURL(), bytes.NewBuffer(input)); err != nil {
		return errors.New("getBody: " + err.Error())
	}

	return nil
}
<|endoftext|>


<commit_before>package log

import (
	"context"
	"fmt"
	"runtime"
)

var (
	_logger *logger
)

func init() {
	_logger = new()
}

// RegisterHandler adds a new Log Handler and specifies what log levels
// the handler will be passed log entries for
func RegisterHandler(handler Handler, levels ...Level) {
	_logger.RegisterHandler(handler, levels...)
}

// Debug level formatted message.
func Debug(v ...interface{}) {
	e := _logger.newEntry(DebugLevel, fmt.Sprint(v...), nil, skipLevel)
	_logger.handleEntry(e)
}

// Debugf level formatted message.
func Debugf(msg string, v ...interface{}) {
	e := _logger.newEntry(DebugLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	_logger.handleEntry(e)
}

// Info level formatted message.
func Info(v ...interface{}) {
	e := _logger.newEntry(InfoLevel, fmt.Sprint(v...), nil, skipLevel)
	_logger.handleEntry(e)
}

// Infof level formatted message.
func Infof(msg string, v ...interface{}) {
	e := _logger.newEntry(InfoLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	_logger.handleEntry(e)
}

// Warn level formatted message.
func Warn(v ...interface{}) {
	e := _logger.newEntry(WarnLevel, fmt.Sprint(v...), nil, skipLevel)
	_logger.handleEntry(e)
}

// Warnf level formatted message.
func Warnf(msg string, v ...interface{}) {
	e := _logger.newEntry(WarnLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	_logger.handleEntry(e)
}

// Error level formatted message
func Error(v ...interface{}) {
	e := _logger.newEntry(ErrorLevel, fmt.Sprint(v...), nil, skipLevel)
	_logger.handleEntry(e)
}

// Errorf level formatted message
func Errorf(msg string, v ...interface{}) {
	e := _logger.newEntry(ErrorLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	_logger.handleEntry(e)
}

// Panic level formatted message
func Panic(v ...interface{}) {
	s := fmt.Sprint(v...)
	e := _logger.newEntry(PanicLevel, s, nil, skipLevel)
	_logger.handleEntry(e)
	panic(s)
}

// Panicf level formatted message
func Panicf(msg string, v ...interface{}) {
	s := fmt.Sprintf(msg, v...)
	e := _logger.newEntry(PanicLevel, s, nil, skipLevel)
	_logger.handleEntry(e)
	panic(s)
}

// Fatal level formatted message, followed by an exit.
func Fatal(v ...interface{}) {
	e := _logger.newEntry(FatalLevel, fmt.Sprint(v...), nil, skipLevel)
	_logger.handleEntry(e)
	exitFunc(1)
}

// Fatalf level formatted message, followed by an exit.
func Fatalf(msg string, v ...interface{}) {
	e := _logger.newEntry(FatalLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	_logger.handleEntry(e)
	exitFunc(1)
}

// WithFields returns a log Entry with fields set
func WithFields(fields Fields) Logger {
	e := _logger.newEntry(InfoLevel, "", fields, skipLevel)
	return e
}

// StackTrace creates a new log Entry with pre-populated field with stack trace.
func StackTrace() Logger {
	trace := make([]byte, 4096)
	runtime.Stack(trace, true)
	customFields := Fields{
		"stack_trace": string(trace) + "\n",
	}
	return _logger.newEntry(DebugLevel, "", customFields, skipLevel)
}

// SetAppID set a constant application key
// that will be set on all log Entry objects
func SetAppID(id string) {
	_logger.appID = id
}

// AppID return an application key
func AppID() string {
	return _logger.appID
}

const (
	requestIdKey = "log_requestIdKey"
)

// NewContext return a new context with a logger value
func NewContext(ctx context.Context, logger Logger) context.Context {
	return context.WithValue(ctx, requestIdKey, logger)
}

// FromContext return a logger from the context
func FromContext(ctx context.Context) Logger {
	val, ok := ctx.Value(requestIdKey).(*Entry)
	if ok {
		return val
	}
	return _logger
}
<commit_msg>change stacktrace to error level<commit_after>package log

import (
	"context"
	"fmt"
	"runtime"
)

var (
	_logger *logger
)

func init() {
	_logger = new()
}

// RegisterHandler adds a new Log Handler and specifies what log levels
// the handler will be passed log entries for
func RegisterHandler(handler Handler, levels ...Level) {
	_logger.RegisterHandler(handler, levels...)
}

// Debug level formatted message.
func Debug(v ...interface{}) {
	e := _logger.newEntry(DebugLevel, fmt.Sprint(v...), nil, skipLevel)
	_logger.handleEntry(e)
}

// Debugf level formatted message.
func Debugf(msg string, v ...interface{}) {
	e := _logger.newEntry(DebugLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	_logger.handleEntry(e)
}

// Info level formatted message.
func Info(v ...interface{}) {
	e := _logger.newEntry(InfoLevel, fmt.Sprint(v...), nil, skipLevel)
	_logger.handleEntry(e)
}

// Infof level formatted message.
func Infof(msg string, v ...interface{}) {
	e := _logger.newEntry(InfoLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	_logger.handleEntry(e)
}

// Warn level formatted message.
func Warn(v ...interface{}) {
	e := _logger.newEntry(WarnLevel, fmt.Sprint(v...), nil, skipLevel)
	_logger.handleEntry(e)
}

// Warnf level formatted message.
func Warnf(msg string, v ...interface{}) {
	e := _logger.newEntry(WarnLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	_logger.handleEntry(e)
}

// Error level formatted message
func Error(v ...interface{}) {
	e := _logger.newEntry(ErrorLevel, fmt.Sprint(v...), nil, skipLevel)
	_logger.handleEntry(e)
}

// Errorf level formatted message
func Errorf(msg string, v ...interface{}) {
	e := _logger.newEntry(ErrorLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	_logger.handleEntry(e)
}

// Panic level formatted message
func Panic(v ...interface{}) {
	s := fmt.Sprint(v...)
	e := _logger.newEntry(PanicLevel, s, nil, skipLevel)
	_logger.handleEntry(e)
	panic(s)
}

// Panicf level formatted message
func Panicf(msg string, v ...interface{}) {
	s := fmt.Sprintf(msg, v...)
	e := _logger.newEntry(PanicLevel, s, nil, skipLevel)
	_logger.handleEntry(e)
	panic(s)
}

// Fatal level formatted message, followed by an exit.
func Fatal(v ...interface{}) {
	e := _logger.newEntry(FatalLevel, fmt.Sprint(v...), nil, skipLevel)
	_logger.handleEntry(e)
	exitFunc(1)
}

// Fatalf level formatted message, followed by an exit.
func Fatalf(msg string, v ...interface{}) {
	e := _logger.newEntry(FatalLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	_logger.handleEntry(e)
	exitFunc(1)
}

// WithFields returns a log Entry with fields set
func WithFields(fields Fields) Logger {
	e := _logger.newEntry(InfoLevel, "", fields, skipLevel)
	return e
}

// StackTrace creates a new log Entry with pre-populated field with stack trace.
func StackTrace() Logger {
	trace := make([]byte, 4096)
	runtime.Stack(trace, true)
	customFields := Fields{
		"stack_trace": string(trace) + "\n",
	}
	return _logger.newEntry(ErrorLevel, "", customFields, skipLevel)
}

// SetAppID set a constant application key
// that will be set on all log Entry objects
func SetAppID(id string) {
	_logger.appID = id
}

// AppID return an application key
func AppID() string {
	return _logger.appID
}

const (
	requestIdKey = "log_requestIdKey"
)

// NewContext return a new context with a logger value
func NewContext(ctx context.Context, logger Logger) context.Context {
	return context.WithValue(ctx, requestIdKey, logger)
}

// FromContext return a logger from the context
func FromContext(ctx context.Context) Logger {
	val, ok := ctx.Value(requestIdKey).(*Entry)
	if ok {
		return val
	}
	return _logger
}
<|endoftext|>


<commit_before>package pos

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"runtime"
	"strings"
)

// https://www.ling.upenn.edu/courses/Fall_2003/ling001/penn_treebank_pos.html
var Descriptions map[string]string = map[string]string{
	"CC":   "Coordinating conjunction",
	"CD":   "Cardinal number",
	"DT":   "Determiner",
	"EX":   "Existential there",
	"FW":   "Foreign word",
	"IN":   "Preposition or subordinating conjunction",
	"JJ":   "Adjective",
	"JJR":  "Adjective, comparative",
	"JJS":  "Adjective, superlative",
	"LS":   "List item marker",
	"MD":   "Modal",
	"NN":   "Noun, singular or mass",
	"NNS":  "Noun, plural",
	"NNP":  "Proper noun, singular",
	"NNPS": "Proper noun, plural",
	"PDT":  "Predeterminer",
	"POS":  "Possessive ending",
	"PRP":  "Personal pronoun",
	"PRP$": "Possessive pronoun",
	"RB":   "Adverb",
	"RBR":  "Adverb, comparative",
	"RBS":  "Adverb, superlative",
	"RP":   "Particle",
	"SYM":  "Symbol",
	"TO":   "to",
	"UH":   "Interjection",
	"VB":   "Verb, base form",
	"VBD":  "Verb, past tense",
	"VBG":  "Verb, gerund or present participle",
	"VBN":  "Verb, past participle",
	"VBP":  "Verb, non-3rd person singular present",
	"VBZ":  "Verb, 3rd person singular present",
	"WDT":  "Wh-determiner",
	"WP":   "Wh-pronoun",
	"WP$":  "Possessive wh-pronoun",
	"WRB":  "Wh-adverb",
}

type POSTagger struct {
	model     string
	tagger    string
	java      string
	opts      []string
	separator string
	encoding  string
}

type Result struct {
	Word string
	TAG  string
}

func (r *Result) Description() string {
	if _, exists := Descriptions[r.TAG]; !exists {
		return ""
	}
	return Descriptions[r.TAG]
}

func NewPOSTagger(m, t string) (*POSTagger, error) {
	separator := ":"
	if runtime.GOOS == "windows" {
		separator = ";"
	}

	pos := &POSTagger{
		java:      "java",
		encoding:  "utf8",
		opts:      []string{"-mx300m"},
		separator: separator,
	}

	if err := pos.SetModel(m); err != nil {
		return nil, err
	}
	if err := pos.SetTagger(t); err != nil {
		return nil, err
	}

	return pos, nil
}

func (p *POSTagger) SetModel(m string) error {
	if _, err := os.Stat(m); err != nil {
		return errors.New("Model not exists!")
	}
	p.model = m

	return nil
}

func (p *POSTagger) SetTagger(t string) error {
	if _, err := os.Stat(t); err != nil {
		return errors.New("Tagger not exists!")
	}
	p.tagger = t

	return nil
}

func (p *POSTagger) SetJavaPath(j string) {
	p.java = j
}

func (p *POSTagger) SetJavaOpts(opts []string) {
	p.opts = opts
}

func (p *POSTagger) SetEncoding(e string) {
	p.encoding = e
}

func (p *POSTagger) parse(out string) []*Result {
	words := strings.Split(out, " ")

	res := make([]*Result, len(words))
	for i, word := range words {
		split := strings.Split(word, "_")
		res[i] = &Result{
			Word: split[0],
			TAG:  split[1],
		}
	}

	return res
}

func (p *POSTagger) Tag(input string) ([]*Result, error) {
	var (
		tmp  *os.File
		err  error
		args []string
	)

	if tmp, err = ioutil.TempFile("", "nlptemp"); err != nil {
		return nil, err
	}
	defer os.Remove(tmp.Name())
	if _, err = tmp.WriteString(input); err != nil {
		return nil, err
	}

	args = append(p.opts, []string{
		"-cp",
		p.tagger + p.separator,
		"edu.stanford.nlp.tagger.maxent.MaxentTagger",
		"-model",
		p.model,
		"-textFile",
		tmp.Name(),
		"-encoding",
		p.encoding,
	}...)

	cmd := exec.Command(p.java, args...)

	var out bytes.Buffer
	var stderr bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &stderr

	if err = cmd.Run(); err != nil {
		return nil, fmt.Errorf("%s: %s", err, stderr.String())
	}

	return p.parse(out.String()), nil
}
<commit_msg>added comments; POSTagger renamed to Tagger<commit_after>package pos

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"runtime"
	"strings"
)

// Descriptions - word tags description
// https://www.ling.upenn.edu/courses/Fall_2003/ling001/penn_treebank_pos.html
var Descriptions = map[string]string{
	"CC":   "Coordinating conjunction",
	"CD":   "Cardinal number",
	"DT":   "Determiner",
	"EX":   "Existential there",
	"FW":   "Foreign word",
	"IN":   "Preposition or subordinating conjunction",
	"JJ":   "Adjective",
	"JJR":  "Adjective, comparative",
	"JJS":  "Adjective, superlative",
	"LS":   "List item marker",
	"MD":   "Modal",
	"NN":   "Noun, singular or mass",
	"NNS":  "Noun, plural",
	"NNP":  "Proper noun, singular",
	"NNPS": "Proper noun, plural",
	"PDT":  "Predeterminer",
	"POS":  "Possessive ending",
	"PRP":  "Personal pronoun",
	"PRP$": "Possessive pronoun",
	"RB":   "Adverb",
	"RBR":  "Adverb, comparative",
	"RBS":  "Adverb, superlative",
	"RP":   "Particle",
	"SYM":  "Symbol",
	"TO":   "to",
	"UH":   "Interjection",
	"VB":   "Verb, base form",
	"VBD":  "Verb, past tense",
	"VBG":  "Verb, gerund or present participle",
	"VBN":  "Verb, past participle",
	"VBP":  "Verb, non-3rd person singular present",
	"VBZ":  "Verb, 3rd person singular present",
	"WDT":  "Wh-determiner",
	"WP":   "Wh-pronoun",
	"WP$":  "Possessive wh-pronoun",
	"WRB":  "Wh-adverb",
}

// Tagger struct
type Tagger struct {
	model     string
	tagger    string
	java      string
	opts      []string
	separator string
	encoding  string
}

// Result struct
type Result struct {
	Word string
	TAG  string
}

// Description - returns tag description
func (r *Result) Description() string {
	if _, exists := Descriptions[r.TAG]; !exists {
		return ""
	}
	return Descriptions[r.TAG]
}

// NewTagger - returns Tagger pointer
func NewTagger(m, t string) (*Tagger, error) {
	separator := ":"
	if runtime.GOOS == "windows" {
		separator = ";"
	}

	pos := &Tagger{
		java:      "java",
		encoding:  "utf8",
		opts:      []string{"-mx300m"},
		separator: separator,
	}

	if err := pos.SetModel(m); err != nil {
		return nil, err
	}
	if err := pos.SetTagger(t); err != nil {
		return nil, err
	}

	return pos, nil
}

// SetModel - set stanford pos tagger model
func (p *Tagger) SetModel(m string) error {
	if _, err := os.Stat(m); err != nil {
		return errors.New("Model not exists!")
	}
	p.model = m

	return nil
}

// SetTagger - set stanford pos tagger jar file
func (p *Tagger) SetTagger(t string) error {
	if _, err := os.Stat(t); err != nil {
		return errors.New("Tagger not exists!")
	}
	p.tagger = t

	return nil
}

// SetJavaPath - set path to java executable file
func (p *Tagger) SetJavaPath(j string) {
	p.java = j
}

// SetJavaOpts - set java options (default: [mx300m])
func (p *Tagger) SetJavaOpts(opts []string) {
	p.opts = opts
}

// SetEncoding - set outupt encoding (default: utf8)
func (p *Tagger) SetEncoding(e string) {
	p.encoding = e
}

func (p *Tagger) parse(out string) []*Result {
	words := strings.Split(out, " ")

	res := make([]*Result, len(words))
	for i, word := range words {
		split := strings.Split(word, "_")
		res[i] = &Result{
			Word: split[0],
			TAG:  split[1],
		}
	}

	return res
}

// Tag - use stanford pos tagger to tag input sentence
func (p *Tagger) Tag(input string) ([]*Result, error) {
	var (
		tmp  *os.File
		err  error
		args []string
	)

	if tmp, err = ioutil.TempFile("", "nlptemp"); err != nil {
		return nil, err
	}
	defer os.Remove(tmp.Name())
	if _, err = tmp.WriteString(input); err != nil {
		return nil, err
	}

	args = append(p.opts, []string{
		"-cp",
		p.tagger + p.separator,
		"edu.stanford.nlp.tagger.maxent.MaxentTagger",
		"-model",
		p.model,
		"-textFile",
		tmp.Name(),
		"-encoding",
		p.encoding,
	}...)

	cmd := exec.Command(p.java, args...)

	var out bytes.Buffer
	var stderr bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &stderr

	if err = cmd.Run(); err != nil {
		return nil, fmt.Errorf("%s: %s", err, stderr.String())
	}

	return p.parse(out.String()), nil
}
<|endoftext|>


<commit_before>/*
Package pwd is a thin wrapper of C library <pwd.h>.
This is designed as thin as possible, but aimed to be thread-safe.
*/
package pwd

/*
#include <sys/types.h>
#include <pwd.h>
#include <stdlib.h>

// While getpwuid requires "uid_t" according to man page, it actually requires
// "__uit_t" in the source code, that causes cgo compile error ("uid_t" is
// actually aliased to __uid_t).
// Unlike Linux, getpwuid on Mac OS X requires uid_t properly. For compatibility,
// we use a C function as a bridge here.
struct passwd *getpwuid_aux(unsigned int uid) {
	return getpwuid((uid_t)uid);
}
*/
import "C"
import (
	"sync"
	"unsafe"
)

// Passwd represents an entry of the user database defined in <pwd.h>
type Passwd struct {
	Name  string
	UID   uint32
	GID   uint32
	Dir   string
	Shell string
}

func cpasswd2go(cpw *C.struct_passwd) *Passwd {
	return &Passwd{
		Name:  C.GoString(cpw.pw_name),
		UID:   uint32(cpw.pw_uid),
		GID:   uint32(cpw.pw_uid),
		Dir:   C.GoString(cpw.pw_dir),
		Shell: C.GoString(cpw.pw_shell),
	}
}

// Getpwnam searches the user database for an entry with a matching name.
func Getpwnam(name string) *Passwd {
	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))
	cpw := C.getpwnam(cname)
	if cpw == nil {
		return nil
	}
	return cpasswd2go(cpw)
}

// Getpwuid searches the user database for an entry with a matching uid.
func Getpwuid(uid uint32) *Passwd {
	cpw := C.getpwuid_aux(C.uint(uid))
	if cpw == nil {
		return nil
	}
	return cpasswd2go(cpw)
}

// Getpwents returns all entries in the user databases.
// This is aimed to be thread-safe, that is, if a goroutine is executing this
// function, another goroutine is blocked until it completes.
func Getpwents() []*Passwd {
	pwentMutex.Lock()
	defer pwentMutex.Unlock()
	C.setpwent()
	defer C.endpwent()
	ents := make([]*Passwd, 0, 10)
	for {
		cpw := C.getpwent()
		if cpw == nil {
			break
		}
		ents = append(ents, cpasswd2go(cpw))
	}
	return ents
}

var pwentMutex = sync.Mutex{}
<commit_msg>Add Gecos field<commit_after>/*
Package pwd is a thin wrapper of C library <pwd.h>.
This is designed as thin as possible, but aimed to be thread-safe.
*/
package pwd

/*
#include <sys/types.h>
#include <pwd.h>
#include <stdlib.h>

// While getpwuid requires "uid_t" according to man page, it actually requires
// "__uit_t" in the source code, that causes cgo compile error ("uid_t" is
// actually aliased to __uid_t).
// Unlike Linux, getpwuid on Mac OS X requires uid_t properly. For compatibility,
// we use a C function as a bridge here.
struct passwd *getpwuid_aux(unsigned int uid) {
	return getpwuid((uid_t)uid);
}
*/
import "C"
import (
	"sync"
	"unsafe"
)

// Passwd represents an entry of the user database defined in <pwd.h>
type Passwd struct {
	Name  string
	UID   uint32
	GID   uint32
	Gecos string
	Dir   string
	Shell string
}

func cpasswd2go(cpw *C.struct_passwd) *Passwd {
	return &Passwd{
		Name:  C.GoString(cpw.pw_name),
		UID:   uint32(cpw.pw_uid),
		GID:   uint32(cpw.pw_uid),
		Gecos: C.GoString(cpw.pw_gecos),
		Dir:   C.GoString(cpw.pw_dir),
		Shell: C.GoString(cpw.pw_shell),
	}
}

// Getpwnam searches the user database for an entry with a matching name.
func Getpwnam(name string) *Passwd {
	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))
	cpw := C.getpwnam(cname)
	if cpw == nil {
		return nil
	}
	return cpasswd2go(cpw)
}

// Getpwuid searches the user database for an entry with a matching uid.
func Getpwuid(uid uint32) *Passwd {
	cpw := C.getpwuid_aux(C.uint(uid))
	if cpw == nil {
		return nil
	}
	return cpasswd2go(cpw)
}

// Getpwents returns all entries in the user databases.
// This is aimed to be thread-safe, that is, if a goroutine is executing this
// function, another goroutine is blocked until it completes.
func Getpwents() []*Passwd {
	pwentMutex.Lock()
	defer pwentMutex.Unlock()
	C.setpwent()
	defer C.endpwent()
	ents := make([]*Passwd, 0, 10)
	for {
		cpw := C.getpwent()
		if cpw == nil {
			break
		}
		ents = append(ents, cpasswd2go(cpw))
	}
	return ents
}

var pwentMutex = sync.Mutex{}
<|endoftext|>


<commit_before>package main
import "fmt"

// func p(m variant) {
//   fmt.Println(m)
// }

// for i from 0 to 255
//     S[i] := i
// endfor
// j := 0
// for i from 0 to 255
//     j := (j + S[i] + key[i mod keylength]) mod 256
//     swap values of S[i] and S[j]
// endfor

func ksa(keystring string) {
  var key = []byte(keystring)
  var s [256]byte
  var j, newj, newi byte

  for i := 0; i < 255; i++ {
    s[i] = byte(i)
  }
  for i := 0; i < 255; i++ {
    j = (j + s[byte(i)] + key[i % len(key)]) % 255
    fmt.Println("i: ", i)
    fmt.Println("j: ", j)
    newi++
    newj++
    // newi = s[j]
    // newj = s[i]
    // s[i] = newj
    // s[j] = newi
  }
}

func main() {
  ksa("coconuts")
}

<commit_msg>sort of working version<commit_after>    package main
    import "fmt"

    func ksa(keystring string) ([256]byte) {
      var key = []byte(keystring)

      var s [256]byte
      var j byte

      for i := 0; i <= 255; i++ {
        s[i] = byte(i)
      }
      for i := 0; i <= 255; i++ {
        j = (j + s[byte(i)] + key[i % len(key)]) % 255
        s[j], s[i] = s[i], s[j]
      }
      return s
    }

    func rc4(bufferstring string, key [256]byte) ([]byte) {
      buffer := []byte(bufferstring)
      res := make([]byte, len(buffer))
      var x, y, k, r byte = 0, 0, 0, 0

      for i, b := range(buffer) {
        x = (x + 1) % 255
        y = (y + key[x] % 255)
        y, x = x, y
        k = key[(key[x] + key[y]) % 255]
        r = b ^ k

        fmt.Printf("i: %d, b: %c, x: %#X, y: %#X, k: %#X, r: %#X  \n", i, b, x, y, k, r)
        res[i] = r
      }
      return res
    }

    func main() {
      keystring := "Secret"
      plaintext := "Attack at dawn"
      key := ksa(keystring)

      encrypted := rc4(plaintext, key)

      unencrypted := rc4(string(encrypted), key)

      fmt.Println("Encrypted")
      fmt.Printf("hex: %#X\n", string(encrypted))
      fmt.Printf("string: %s\n", string(encrypted))

      fmt.Println("Un-Encrypted")
      fmt.Printf("hex: %#X\n", string(unencrypted))
      fmt.Printf("string: %s\n", string(unencrypted))
    }

<|endoftext|>


<commit_before>package raft

import (
  "net/http"
  "fmt"
  "time"
  "io/ioutil"
  "strconv"
  "encoding/json"
  "net/url"
  "bytes"
  "log"
)

// Used to store any field to interact with the RPC
// functions
type RPC struct {
  Server *http.Server
  StateMachine *StateMachine
}

// Start the RPC server
func (rpc *RPC) Start() error {
  // TODO: test the server
  go func() {
  }()

  err := rpc.Server.ListenAndServe()

  return err
}

func (rpc *RPC) StartElection() {
  sm := rpc.StateMachine

  if sm.State.Is() != CANDIDATE {
    return
  }

  sm.State.SyncTerm <- struct{}{}
  defer func() {
    <- sm.State.SyncTerm
  }()

  sm.Timer.Stop();

  oldTerm := sm.State.CurrentTerm
  newTerm := sm.State.CurrentTerm + 1

  sm.State.CurrentTerm = newTerm
  sm.Exec("term::changed", oldTerm, newTerm)

  sm.State.VotedFor = sm.State.MyId

  timer := time.NewTimer(300 * time.Millisecond)

  done := make(chan struct{}, 0)
  go func() {
    for nodeName, _ := range sm.Cluster.Nodes {
      if nodeName == sm.State.MyId {
        continue
      }

      client := &http.Client{}
      form := url.Values{}
      form.Set("term", strconv.FormatUint(sm.State.CurrentTerm, 10))
      form.Set("candidateId", sm.State.MyId)
      req, err := http.NewRequest("POST", fmt.Sprintf("http://%s/request-vote", nodeName), bytes.NewBufferString(form.Encode()))
      if err != nil {
        return
      }
      req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
      resp, err := client.Do(req)
      if err != nil {
        return
      }

      switch statusCode := resp.StatusCode; statusCode {
        case 200:
          done <- struct{}{}
        default:
          return
      }
    }
  }()

  LOOP: for {
    select {
      case <- timer.C:
        timer.Stop()
        return
      case <- done:
        break LOOP
    }
  }

  sm.Timer.Stop()
  sm.State.Switch(LEADER)
  go func() {
    defer func() {
      sm.Timer.Start()
    }()

    for state := sm.State.Is(); state == LEADER; state = sm.State.Is() {
      for nodeName, _ := range sm.Cluster.Nodes {
        if nodeName == sm.State.MyId {
          continue
        }

        log.Println("AppendEntry RPC started for: ", sm.State.MyId)
        client := &http.Client{}
        form := url.Values{}
        form.Set("term", strconv.FormatUint(sm.State.CurrentTerm, 10))
        req, err := http.NewRequest("POST", fmt.Sprintf("http://%s/append-entry?%s", nodeName, form.Encode()), bytes.NewBufferString("[]"))
        if err != nil {
          return
        }
        req.Header.Add("Content-Type", "application/json")
        _, err = client.Do(req)
        if err != nil {
          return
        }
      }
      <- time.Tick(50 * time.Millisecond)
    }
  }()
}

// Create RPC connection
// TODO: create error object for http responses
func NewRPC(sm *StateMachine) (*RPC, error) {
  mux := http.NewServeMux()

  addr := fmt.Sprintf("%s:%d", sm.Configuration.RPCHost, sm.Configuration.RPCPort)

  server := &http.Server{
    Addr: addr,
    Handler: mux,
  }

  mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World!")
  })
  mux.HandleFunc("/append-entry", func(w http.ResponseWriter, r *http.Request) {
    // Declare a variable that will be used to be the statusCode of the response
    // because WriteHeader actually writes header, it is not possible to play
    // with the header in a defer function's call
    statusCode := 200

    // Acquire the lock since we'll write and we don't want dirty reads
    sm.State.SyncTerm <- struct{}{}
    defer func() {
      // Send back the Current-Term in the response
      w.Header().Add("X-Current-Term", strconv.FormatUint(sm.State.CurrentTerm, 10))
      w.WriteHeader(statusCode)

      // Unlock
      <- sm.State.SyncTerm
    }()

    oldTerm := sm.State.CurrentTerm

    err := r.ParseForm()
    if err != nil {
      statusCode = 422
      return
    }

    // start parsing term
    term, ok := r.Form["term"]
    if !ok || term[0] == "" {
      statusCode = 422
      return
    }

    newTerm, err := strconv.ParseUint(term[0], 10, 0)
    if err != nil {
      statusCode = 422
      return
    }

    if newTerm < sm.State.CurrentTerm {
      statusCode = 422
      return
    }
    // end parsing term

    //// start parsing leaderCommit
    //leaderCommitValue, ok := r.Form["leaderCommit"]
    //if !ok || leaderCommitValue[0] == "" {
      //statusCode = 422
      //return
    //}

    //leaderCommit, err := strconv.ParseInt(leaderCommitValue[0], 10, 0)
    //if err != nil {
      //statusCode = 422
      //return
    //}
    //// end parsing leaderCommit

    //// start parsing prevLogTerm
    //prevLogTerm, ok := r.Form["prevLogTerm"]
    //if !ok || prevLogTerm[0] == "" {
      //statusCode = 422
      //return
    //}

    //prevTerm, err := strconv.ParseUint(prevLogTerm[0], 10, 0)
    //if err != nil {
      //statusCode = 422
      //return
    //}
    //// end parsing prevLogTerm

    //// start parsing prevLogIndex
    //prevLogIndex, ok := r.Form["prevLogIndex"]
    //if !ok || prevLogIndex[0] == "" {
      //statusCode = 422
      //return
    //}

    //prevIndex, err := strconv.ParseInt(prevLogIndex[0], 10, 0)
    //if err != nil {
      //statusCode = 422
      //return
    //}

    //// Acquire the lock
    //sm.Storage.C <- struct{}{}
    //defer func() {
      //<- sm.Storage.C
    //}()

    //// end parsing prevLogTerm

    // start parsing body
    body, err := ioutil.ReadAll(r.Body)
    if err != nil {
      statusCode = 400
      return
    }

    switch contentType := r.Header.Get("Content-Type"); contentType {
      case "application/json":
        var logs Logs

        err := json.Unmarshal(body, &logs)
        if err != nil {
          statusCode = 400
          return
        }

        if sm.State.Is() != FOLLOWER {
          sm.State.Switch(FOLLOWER)
        }

        if len(logs) == 0 && newTerm != sm.State.CurrentTerm {
          sm.State.CurrentTerm = newTerm
          sm.Exec("term::changed", oldTerm, newTerm)
        }

        // TODO: stop the timer after added all logs
        sm.Timer.Stop();
        for ok := false; !ok; {
          ok = sm.Timer.Start()
        }
      default:
        statusCode = 415
        return
    }
    // end parsing body

  })

  mux.HandleFunc("/request-vote", func(w http.ResponseWriter, r *http.Request) {
    // Declare a variable that will be used to be the statusCode of the response
    // because WriteHeader actually writes header, it is not possible to play
    // with the header in a defer function's call
    statusCode := 200

    // Acquire the lock since we'll write and we don't want dirty reads
    sm.State.SyncTerm <- struct{}{}

    defer func() {
      // Send back the Current-Term in the response
      w.Header().Add("X-Current-Term", strconv.FormatUint(sm.State.CurrentTerm, 10))
      w.WriteHeader(statusCode)

      // Unlock
      <- sm.State.SyncTerm
    }()

    err := r.ParseForm()
    if err != nil {
      statusCode = 422
      return
    }

    // start parsing term
    term, ok := r.Form["term"]
    if !ok || term[0] == "" {
      statusCode = 422
      return
    }

    newTerm, err := strconv.ParseUint(term[0], 10, 0)
    if err != nil {
      statusCode = 422
      return
    }

    if newTerm < sm.State.CurrentTerm {
      statusCode = 422
      return
    }
    // end parsing term

    // start parsing candidateId
    candidateId, ok := r.Form["candidateId"]
    if !ok || candidateId[0] == "" {
      statusCode = 422
      return
    }

    candidate := candidateId[0]

    // If the name of the candidate cannot be found in the
    // cluster configuration then tell him to gtfo
    if ok := sm.Cluster. Find(candidate); ok == false {
      statusCode = 422
      return
    }

    // If the candidate's term is the same as the CurrentTerm
    // We need to check if VotedFor is not null AND VotedFor is not the same candidate's ID
    // Otherwise since there is only one VotedFor per term and at start up the VotedFor is null
    // respond to false.
    log.Println(sm.State.MyId, "receive vote: ", r.Form, "votedFor :", sm.State.VotedFor, "myterm :", sm.State.CurrentTerm)
    if newTerm == sm.State.CurrentTerm {
      if sm.State.VotedFor != "" && sm.State.VotedFor != candidate {
        statusCode = 422
        return
      }
    }
    // end parsing candidateId

    // if Voted yes, convert to follower and vote for him
    if sm.State.Is() != FOLLOWER {
      sm.State.Switch(FOLLOWER)
      sm.Timer.Start()
    }

    sm.State.CurrentTerm = newTerm
    sm.State.VotedFor = candidate

  })

  rpc := &RPC{
    Server: server,
    StateMachine: sm,
  }

  return rpc, nil
}
<commit_msg>Added support for multi node clustering > 2 :p<commit_after>package raft

import (
  "net/http"
  "fmt"
  "time"
  "io/ioutil"
  "strconv"
  "encoding/json"
  "net/url"
  "bytes"
  "log"
)

// Used to store any field to interact with the RPC
// functions
type RPC struct {
  Server *http.Server
  StateMachine *StateMachine
}

// Start the RPC server
func (rpc *RPC) Start() error {
  // TODO: test the server
  go func() {
  }()

  err := rpc.Server.ListenAndServe()

  return err
}

func (rpc *RPC) StartElection() {
  sm := rpc.StateMachine

  if sm.State.Is() != CANDIDATE {
    return
  }

  sm.State.SyncTerm <- struct{}{}
  defer func() {
    <- sm.State.SyncTerm
  }()

  sm.Timer.Stop();

  oldTerm := sm.State.CurrentTerm
  newTerm := sm.State.CurrentTerm + 1

  sm.State.CurrentTerm = newTerm
  sm.Exec("term::changed", oldTerm, newTerm)

  sm.State.VotedFor = sm.State.MyId

  timer := time.NewTimer(300 * time.Millisecond)

  addOkNode := make(chan struct{}, len(sm.Cluster.Nodes))
  // we start at one because we implicitly count this statemachine
  okNode := 1
  done := make(chan struct{}, 0)

  // counter of node who positivly responded to request-vote
  go func() {
    for ; okNode != len(sm.Cluster.Nodes); okNode++ {
      <- addOkNode
    }

    done <- struct{}{}
  }()

  go func() {
    for nodeName, _ := range sm.Cluster.Nodes {
      if nodeName == sm.State.MyId {
        continue
      }

      client := &http.Client{}
      form := url.Values{}
      form.Set("term", strconv.FormatUint(sm.State.CurrentTerm, 10))
      form.Set("candidateId", sm.State.MyId)
      req, err := http.NewRequest("POST", fmt.Sprintf("http://%s/request-vote", nodeName), bytes.NewBufferString(form.Encode()))
      if err != nil {
        return
      }
      req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
      resp, err := client.Do(req)
      if err != nil {
        return
      }

      switch statusCode := resp.StatusCode; statusCode {
        case 200:
          addOkNode <- struct{}{}
        default:
          return
      }
    }
  }()

  LOOP: for {
    select {
      case <- timer.C:
        timer.Stop()

        // if the majority has been reached, break the loop and become leader
        if uint(okNode) >= sm.Cluster.Majority {
          break LOOP
        }

        return
      case <- done:
        break LOOP
    }
  }

  sm.Timer.Stop()
  sm.State.Switch(LEADER)
  go func() {
    defer func() {
      sm.Timer.Start()
    }()

    for state := sm.State.Is(); state == LEADER; state = sm.State.Is() {
      timer = time.NewTimer(50 * time.Millisecond)

      addOkNode = make(chan struct{}, len(sm.Cluster.Nodes))
      // we start at one because we implicitly count this statemachine
      okNode = 1
      done = make(chan struct{}, 0)

      // counter of node who positivly responded to request-vote
      go func() {
        for ; okNode != len(sm.Cluster.Nodes); okNode++ {
          <- addOkNode
        }

        done <- struct{}{}
      }()

      for nodeName, _ := range sm.Cluster.Nodes {
        if nodeName == sm.State.MyId {
          continue
        }

        go func(nodeName string) {
          defer func() {
            addOkNode <- struct{}{}
          }()

          log.Println("AppendEntry RPC started for: ", sm.State.MyId, " to: ", nodeName)
          client := &http.Client{}
          form := url.Values{}
          form.Set("term", strconv.FormatUint(sm.State.CurrentTerm, 10))
          req, err := http.NewRequest("POST", fmt.Sprintf("http://%s/append-entry?%s", nodeName, form.Encode()), bytes.NewBufferString("[]"))
          if err != nil {
            return
          }
          req.Header.Add("Content-Type", "application/json")
          _, err = client.Do(req)
          if err != nil {
            return
          }
        }(nodeName)
      }

      LOOP: for {
        select {
          case <- timer.C:
            timer.Stop()
            break LOOP
          case <- done:
            <- time.Tick(50 * time.Millisecond)
            break LOOP
        }
      }

    }
  }()
}

// Create RPC connection
// TODO: create error object for http responses
func NewRPC(sm *StateMachine) (*RPC, error) {
  mux := http.NewServeMux()

  addr := fmt.Sprintf("%s:%d", sm.Configuration.RPCHost, sm.Configuration.RPCPort)

  server := &http.Server{
    Addr: addr,
    Handler: mux,
  }

  mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World!")
  })
  mux.HandleFunc("/append-entry", func(w http.ResponseWriter, r *http.Request) {
    // Declare a variable that will be used to be the statusCode of the response
    // because WriteHeader actually writes header, it is not possible to play
    // with the header in a defer function's call
    statusCode := 200

    // Acquire the lock since we'll write and we don't want dirty reads
    sm.State.SyncTerm <- struct{}{}
    defer func() {
      // Send back the Current-Term in the response
      w.Header().Add("X-Current-Term", strconv.FormatUint(sm.State.CurrentTerm, 10))
      w.WriteHeader(statusCode)

      // Unlock
      <- sm.State.SyncTerm
    }()

    oldTerm := sm.State.CurrentTerm

    err := r.ParseForm()
    if err != nil {
      statusCode = 422
      return
    }

    // start parsing term
    term, ok := r.Form["term"]
    if !ok || term[0] == "" {
      statusCode = 422
      return
    }

    newTerm, err := strconv.ParseUint(term[0], 10, 0)
    if err != nil {
      statusCode = 422
      return
    }

    if newTerm < sm.State.CurrentTerm {
      statusCode = 422
      return
    }
    // end parsing term

    //// start parsing leaderCommit
    //leaderCommitValue, ok := r.Form["leaderCommit"]
    //if !ok || leaderCommitValue[0] == "" {
      //statusCode = 422
      //return
    //}

    //leaderCommit, err := strconv.ParseInt(leaderCommitValue[0], 10, 0)
    //if err != nil {
      //statusCode = 422
      //return
    //}
    //// end parsing leaderCommit

    //// start parsing prevLogTerm
    //prevLogTerm, ok := r.Form["prevLogTerm"]
    //if !ok || prevLogTerm[0] == "" {
      //statusCode = 422
      //return
    //}

    //prevTerm, err := strconv.ParseUint(prevLogTerm[0], 10, 0)
    //if err != nil {
      //statusCode = 422
      //return
    //}
    //// end parsing prevLogTerm

    //// start parsing prevLogIndex
    //prevLogIndex, ok := r.Form["prevLogIndex"]
    //if !ok || prevLogIndex[0] == "" {
      //statusCode = 422
      //return
    //}

    //prevIndex, err := strconv.ParseInt(prevLogIndex[0], 10, 0)
    //if err != nil {
      //statusCode = 422
      //return
    //}

    //// Acquire the lock
    //sm.Storage.C <- struct{}{}
    //defer func() {
      //<- sm.Storage.C
    //}()

    //// end parsing prevLogTerm

    // start parsing body
    body, err := ioutil.ReadAll(r.Body)
    if err != nil {
      statusCode = 400
      return
    }

    switch contentType := r.Header.Get("Content-Type"); contentType {
      case "application/json":
        var logs Logs

        err := json.Unmarshal(body, &logs)
        if err != nil {
          statusCode = 400
          return
        }

        if sm.State.Is() != FOLLOWER {
          sm.State.Switch(FOLLOWER)
        }

        if len(logs) == 0 && newTerm != sm.State.CurrentTerm {
          sm.State.CurrentTerm = newTerm
          sm.Exec("term::changed", oldTerm, newTerm)
        }

        // TODO: stop the timer after added all logs
        sm.Timer.Stop();
        for ok := false; !ok; {
          ok = sm.Timer.Start()
        }
      default:
        statusCode = 415
        return
    }
    // end parsing body

  })

  mux.HandleFunc("/request-vote", func(w http.ResponseWriter, r *http.Request) {
    // Declare a variable that will be used to be the statusCode of the response
    // because WriteHeader actually writes header, it is not possible to play
    // with the header in a defer function's call
    statusCode := 200

    // Acquire the lock since we'll write and we don't want dirty reads
    sm.State.SyncTerm <- struct{}{}

    defer func() {
      // Send back the Current-Term in the response
      w.Header().Add("X-Current-Term", strconv.FormatUint(sm.State.CurrentTerm, 10))
      w.WriteHeader(statusCode)

      // Unlock
      <- sm.State.SyncTerm
    }()

    err := r.ParseForm()
    if err != nil {
      statusCode = 422
      return
    }

    // start parsing term
    term, ok := r.Form["term"]
    if !ok || term[0] == "" {
      statusCode = 422
      return
    }

    newTerm, err := strconv.ParseUint(term[0], 10, 0)
    if err != nil {
      statusCode = 422
      return
    }

    if newTerm < sm.State.CurrentTerm {
      statusCode = 422
      return
    }
    // end parsing term

    // start parsing candidateId
    candidateId, ok := r.Form["candidateId"]
    if !ok || candidateId[0] == "" {
      statusCode = 422
      return
    }

    candidate := candidateId[0]

    // If the name of the candidate cannot be found in the
    // cluster configuration then tell him to gtfo
    if ok := sm.Cluster. Find(candidate); ok == false {
      statusCode = 422
      return
    }

    // If the candidate's term is the same as the CurrentTerm
    // We need to check if VotedFor is not null AND VotedFor is not the same candidate's ID
    // Otherwise since there is only one VotedFor per term and at start up the VotedFor is null
    // respond to false.
    log.Println(sm.State.MyId, "receive vote: ", r.Form, "votedFor :", sm.State.VotedFor, "myterm :", sm.State.CurrentTerm)
    if newTerm == sm.State.CurrentTerm {
      if sm.State.VotedFor != "" && sm.State.VotedFor != candidate {
        statusCode = 422
        return
      }
    }
    // end parsing candidateId

    // if Voted yes, convert to follower and vote for him
    if sm.State.Is() != FOLLOWER {
      sm.State.Switch(FOLLOWER)
      sm.Timer.Start()
    }

    sm.State.CurrentTerm = newTerm
    sm.State.VotedFor = candidate

  })

  rpc := &RPC{
    Server: server,
    StateMachine: sm,
  }

  return rpc, nil
}
<|endoftext|>


<commit_before>package feeds

// rss support
// validation done according to spec here:
//    http://cyber.law.harvard.edu/rss/rss.html

import (
	"encoding/xml"
	"fmt"
	"strconv"
)

// private wrapper around the RssFeed which gives us the <rss>..</rss> xml
type rssFeedXml struct {
	XMLName xml.Name `xml:"rss"`
	Version string   `xml:"version,attr"`
	Channel *RssFeed
}

type RssImage struct {
	XMLName xml.Name `xml:"image"`
	Url     string   `xml:"url"`
	Title   string   `xml:"title"`
	Link    string   `xml:"link"`
	Width   int      `xml:"width,omitempty"`
	Height  int      `xml:"height,omitempty"`
}

type RssTextInput struct {
	XMLName     xml.Name `xml:"textInput"`
	Title       string   `xml:"title"`
	Description string   `xml:"description"`
	Name        string   `xml:"name"`
	Link        string   `xml:"link"`
}

type RssFeed struct {
	XMLName        xml.Name `xml:"channel"`
	Title          string   `xml:"title"`       // required
	Link           string   `xml:"link"`        // required
	Description    string   `xml:"description"` // required
	Language       string   `xml:"language,omitempty"`
	Copyright      string   `xml:"copyright,omitempty"`
	ManagingEditor string   `xml:"managingEditor,omitempty"` // Author used
	WebMaster      string   `xml:"webMaster,omitempty"`
	PubDate        string   `xml:"pubDate,omitempty"`       // created or updated
	LastBuildDate  string   `xml:"lastBuildDate,omitempty"` // updated used
	Category       string   `xml:"category,omitempty"`
	Generator      string   `xml:"generator,omitempty"`
	Docs           string   `xml:"docs,omitempty"`
	Cloud          string   `xml:"cloud,omitempty"`
	Ttl            int      `xml:"ttl,omitempty"`
	Rating         string   `xml:"rating,omitempty"`
	SkipHours      string   `xml:"skipHours,omitempty"`
	SkipDays       string   `xml:"skipDays,omitempty"`
	Image          *RssImage
	TextInput      *RssTextInput
	Items          []*RssItem
}

type RssItem struct {
	XMLName     xml.Name `xml:"item"`
	Title       string   `xml:"title"`       // required
	Link        string   `xml:"link"`        // required
	Description string   `xml:"description"` // required
	Author      string   `xml:"author,omitempty"`
	Category    string   `xml:"category,omitempty"`
	Comments    string   `xml:"comments,omitempty"`
	Enclosure   *RssEnclosure
	Guid        string `xml:"guid,omitempty"`    // Id used
	PubDate     string `xml:"pubDate,omitempty"` // created or updated
	Source      string `xml:"source,omitempty"`
}

type RssEnclosure struct {
	//RSS 2.0 <enclosure url="http://example.com/file.mp3" length="123456789" type="audio/mpeg" />
	XMLName xml.Name `xml:"enclosure"`
	Url     string   `xml:"url,attr"`
	Length  string   `xml:"length,attr"`
	Type    string   `xml:"type,attr"`
}

type Rss struct {
	*Feed
}

// create a new RssItem with a generic Item struct's data
func newRssItem(i *Item) *RssItem {
	item := &RssItem{
		Title:       i.Title,
		Link:        i.Link.Href,
		Description: i.Description,
		Guid:        i.Id,
		PubDate:     anyTimeFormat("2006-01-02T15:04:05-07:00", i.Created, i.Updated),
	}

	intLength, err := strconv.ParseInt(i.Link.Length, 10, 64)

	if err == nil && (intLength > 0 || i.Link.Type != "") {
		item.Enclosure = &RssEnclosure{Url: i.Link.Href, Type: i.Link.Type, Length: i.Link.Length}
	}
	if i.Author != nil {
		item.Author = i.Author.Name
	}
	return item
}

// create a new RssFeed with a generic Feed struct's data
func (r *Rss) RssFeed() *RssFeed {
	pub := anyTimeFormat("2006-01-02T15:04:05-07:00", r.Created, r.Updated)
	build := anyTimeFormat("2006-01-02T15:04:05-07:00", r.Updated)
	author := ""
	if r.Author != nil {
		author = r.Author.Email
		if len(r.Author.Name) > 0 {
			author = fmt.Sprintf("%s (%s)", r.Author.Email, r.Author.Name)
		}
	}

	channel := &RssFeed{
		Title:          r.Title,
		Link:           r.Link.Href,
		Description:    r.Description,
		ManagingEditor: author,
		PubDate:        pub,
		LastBuildDate:  build,
		Copyright:      r.Copyright,
	}
	for _, i := range r.Items {
		channel.Items = append(channel.Items, newRssItem(i))
	}
	return channel
}

// return an XML-Ready object for an Rss object
func (r *Rss) FeedXml() interface{} {
	// only generate version 2.0 feeds for now
	return r.RssFeed().FeedXml()

}

// return an XML-ready object for an RssFeed object
func (r *RssFeed) FeedXml() interface{} {
	return &rssFeedXml{Version: "2.0", Channel: r}
}
<commit_msg>Update time format RFC1123<commit_after>package feeds

// rss support
// validation done according to spec here:
//    http://cyber.law.harvard.edu/rss/rss.html

import (
	"encoding/xml"
	"fmt"
	"strconv"
	"time"
)

// private wrapper around the RssFeed which gives us the <rss>..</rss> xml
type rssFeedXml struct {
	XMLName xml.Name `xml:"rss"`
	Version string   `xml:"version,attr"`
	Channel *RssFeed
}

type RssImage struct {
	XMLName xml.Name `xml:"image"`
	Url     string   `xml:"url"`
	Title   string   `xml:"title"`
	Link    string   `xml:"link"`
	Width   int      `xml:"width,omitempty"`
	Height  int      `xml:"height,omitempty"`
}

type RssTextInput struct {
	XMLName     xml.Name `xml:"textInput"`
	Title       string   `xml:"title"`
	Description string   `xml:"description"`
	Name        string   `xml:"name"`
	Link        string   `xml:"link"`
}

type RssFeed struct {
	XMLName        xml.Name `xml:"channel"`
	Title          string   `xml:"title"`       // required
	Link           string   `xml:"link"`        // required
	Description    string   `xml:"description"` // required
	Language       string   `xml:"language,omitempty"`
	Copyright      string   `xml:"copyright,omitempty"`
	ManagingEditor string   `xml:"managingEditor,omitempty"` // Author used
	WebMaster      string   `xml:"webMaster,omitempty"`
	PubDate        string   `xml:"pubDate,omitempty"`       // created or updated
	LastBuildDate  string   `xml:"lastBuildDate,omitempty"` // updated used
	Category       string   `xml:"category,omitempty"`
	Generator      string   `xml:"generator,omitempty"`
	Docs           string   `xml:"docs,omitempty"`
	Cloud          string   `xml:"cloud,omitempty"`
	Ttl            int      `xml:"ttl,omitempty"`
	Rating         string   `xml:"rating,omitempty"`
	SkipHours      string   `xml:"skipHours,omitempty"`
	SkipDays       string   `xml:"skipDays,omitempty"`
	Image          *RssImage
	TextInput      *RssTextInput
	Items          []*RssItem
}

type RssItem struct {
	XMLName     xml.Name `xml:"item"`
	Title       string   `xml:"title"`       // required
	Link        string   `xml:"link"`        // required
	Description string   `xml:"description"` // required
	Author      string   `xml:"author,omitempty"`
	Category    string   `xml:"category,omitempty"`
	Comments    string   `xml:"comments,omitempty"`
	Enclosure   *RssEnclosure
	Guid        string `xml:"guid,omitempty"`    // Id used
	PubDate     string `xml:"pubDate,omitempty"` // created or updated
	Source      string `xml:"source,omitempty"`
}

type RssEnclosure struct {
	//RSS 2.0 <enclosure url="http://example.com/file.mp3" length="123456789" type="audio/mpeg" />
	XMLName xml.Name `xml:"enclosure"`
	Url     string   `xml:"url,attr"`
	Length  string   `xml:"length,attr"`
	Type    string   `xml:"type,attr"`
}

type Rss struct {
	*Feed
}

// create a new RssItem with a generic Item struct's data
func newRssItem(i *Item) *RssItem {
	item := &RssItem{
		Title:       i.Title,
		Link:        i.Link.Href,
		Description: i.Description,
		Guid:        i.Id,
		PubDate:     anyTimeFormat(time.RFC1123, i.Created, i.Updated),
	}

	intLength, err := strconv.ParseInt(i.Link.Length, 10, 64)

	if err == nil && (intLength > 0 || i.Link.Type != "") {
		item.Enclosure = &RssEnclosure{Url: i.Link.Href, Type: i.Link.Type, Length: i.Link.Length}
	}
	if i.Author != nil {
		item.Author = i.Author.Name
	}
	return item
}

// create a new RssFeed with a generic Feed struct's data
func (r *Rss) RssFeed() *RssFeed {
	pub := anyTimeFormat(time.RFC1123, r.Created, r.Updated)
	build := anyTimeFormat(time.RFC1123, r.Updated)
	author := ""
	if r.Author != nil {
		author = r.Author.Email
		if len(r.Author.Name) > 0 {
			author = fmt.Sprintf("%s (%s)", r.Author.Email, r.Author.Name)
		}
	}

	channel := &RssFeed{
		Title:          r.Title,
		Link:           r.Link.Href,
		Description:    r.Description,
		ManagingEditor: author,
		PubDate:        pub,
		LastBuildDate:  build,
		Copyright:      r.Copyright,
	}
	for _, i := range r.Items {
		channel.Items = append(channel.Items, newRssItem(i))
	}
	return channel
}

// return an XML-Ready object for an Rss object
func (r *Rss) FeedXml() interface{} {
	// only generate version 2.0 feeds for now
	return r.RssFeed().FeedXml()

}

// return an XML-ready object for an RssFeed object
func (r *RssFeed) FeedXml() interface{} {
	return &rssFeedXml{Version: "2.0", Channel: r}
}
<|endoftext|>


<commit_before>//Stupidly simple package for parsing XML RSS from a byte slice.
package easyrss

import (
	"bytes"
	"encoding/xml"
)

type RSS struct {
	XMLname  xml.Name   `xml:"rss"`
	Channels []*Channel `xml:"channel"` //Slice of the channels
}

type Channel struct {
	XMLname         xml.Name    `xml:"channel"`
	Title           string      `xml:"title"`           //Channel title
	Link            string      `xml:"link"`            //Channel link
	Generator       string      `xmlL"generator"`       //Channel Generator
	Description     string      `xml:"description"`     //Channel description
	Language        string      `xml:"language"`        //Channel language
	Copyright       string      `xml:"copyright"`       //Channel Copyright
	Categories      []string    `xml:"category"`        //Channel Categories
	Items           []*Item     `xml:"item"`            //Slice of the items in the channel
	MediaCategories []string    `xml:"media:category"`  //Slice of media tag categories
	MediaCopyright  string      `xml:"media:copyright"` //Media Copyright
	MediaRating     string      `xml:"media:rating"`    //Media Rating
	MediaThumbnail  Image       `xml:"media:thumbnail"` //Media Thumbnail
	ItunesCategory  string      `xml:"itunes:category"` //Itunes Podcast Category
	ItunesOwner     ItunesOwner `xml:"itunes:owner"`    //Itunes Podcast Owner Contact Info
	ItunesKeywords  string      `xml:"itunes:keywords"` //Itunes Podcast Keywords

}

type ItunesOwner struct {
	Name  string `xml:"itunes:name"`
	Email string `xml:"itunes:email"`
}
type RSSEnclosure struct {
	URL       string `xml:"url,attr"`
	MediaType string `xml:"type,attr"`
	Size      string `xml:"fileSize,attr"`
}
type Image struct {
	URL    string `xml:"url,attr"`
	Width  string `xml:"width,attr"`
	Height string `xml:"height,attr"`
}
type Item struct {
	XMLname        xml.Name     `xml:"item"`
	Title          string       `xml:"title"`       //Item title
	Link           string       `xml:"link"`        //Item link
	Content        string       `xml:"encoded"`     //Item content
	Description    string       `xml:"description"` //Item description
	Category       []string     `xml:"category"`    //Item categories
	Enclosure      RSSEnclosure `xml"enclosure"`    //Optional RSS Media Enclosure
	Date           string       `xml:"pubDate"`     //Last date of item publication
	GUID           string       `xml:"guid"`
	ItunesAuthor   string       `xml:"itunes:author"`   //Itunes Episode Author
	ItunesImage    Image        `xml:"itunes:image"`    //Itunes Episode Th
	ItunesSubtitle string       `xml:"itunes:subtitle"` //Itunes Episode Subtitle
	ItunesSummary  string       `xml"itunes:summary"`   //Itunes Episode Summary
	MediaContent   RSSEnclosure `xml:"media:content"`   //Media Payload
	MediaThumbnail Image        `xml:"media:thumbnail"` //Media Thumbnail
}

//Pass in a byte slice containing the feed, get an RSS struct back, with stuff populated.
func Decode(data []byte) (*RSS, error) {
	r := bytes.NewReader(data)
	decoder := xml.NewDecoder(r)
	rss := &RSS{}
	return rss, decoder.Decode(rss)
}
<commit_msg>Add iTunes duration<commit_after>//Stupidly simple package for parsing XML RSS from a byte slice.
package easyrss

import (
	"bytes"
	"encoding/xml"
)

type RSS struct {
	XMLname  xml.Name   `xml:"rss"`
	Channels []*Channel `xml:"channel"` //Slice of the channels
}

type Channel struct {
	XMLname         xml.Name    `xml:"channel"`
	Title           string      `xml:"title"`           //Channel title
	Link            string      `xml:"link"`            //Channel link
	Generator       string      `xmlL"generator"`       //Channel Generator
	Description     string      `xml:"description"`     //Channel description
	Language        string      `xml:"language"`        //Channel language
	Copyright       string      `xml:"copyright"`       //Channel Copyright
	Categories      []string    `xml:"category"`        //Channel Categories
	Items           []*Item     `xml:"item"`            //Slice of the items in the channel
	MediaCategories []string    `xml:"media:category"`  //Slice of media tag categories
	MediaCopyright  string      `xml:"media:copyright"` //Media Copyright
	MediaRating     string      `xml:"media:rating"`    //Media Rating
	MediaThumbnail  Image       `xml:"media:thumbnail"` //Media Thumbnail
	ItunesCategory  string      `xml:"itunes:category"` //Itunes Podcast Category
	ItunesOwner     ItunesOwner `xml:"itunes:owner"`    //Itunes Podcast Owner Contact Info
	ItunesKeywords  string      `xml:"itunes:keywords"` //Itunes Podcast Keywords

}

type ItunesOwner struct {
	Name  string `xml:"itunes:name"`
	Email string `xml:"itunes:email"`
}
type RSSEnclosure struct {
	URL       string `xml:"url,attr"`
	MediaType string `xml:"type,attr"`
	Size      string `xml:"fileSize,attr"`
}
type Image struct {
	URL    string `xml:"url,attr"`
	Width  string `xml:"width,attr"`
	Height string `xml:"height,attr"`
}
type Item struct {
	XMLname        xml.Name     `xml:"item"`
	Title          string       `xml:"title"`       //Item title
	Link           string       `xml:"link"`        //Item link
	Content        string       `xml:"encoded"`     //Item content
	Description    string       `xml:"description"` //Item description
	Category       []string     `xml:"category"`    //Item categories
	Enclosure      RSSEnclosure `xml"enclosure"`    //Optional RSS Media Enclosure
	Date           string       `xml:"pubDate"`     //Last date of item publication
	GUID           string       `xml:"guid"`
	ItunesAuthor   string       `xml:"itunes:author"`   //Itunes Episode Author
	ItunesDuration string       `xml:"itunes:duration"` //Itunes Episode Duration
	ItunesImage    Image        `xml:"itunes:image"`    //Itunes Episode Th
	ItunesSubtitle string       `xml:"itunes:subtitle"` //Itunes Episode Subtitle
	ItunesSummary  string       `xml"itunes:summary"`   //Itunes Episode Summary
	MediaContent   RSSEnclosure `xml:"media:content"`   //Media Payload
	MediaThumbnail Image        `xml:"media:thumbnail"` //Media Thumbnail
}

//Pass in a byte slice containing the feed, get an RSS struct back, with stuff populated.
func Decode(data []byte) (*RSS, error) {
	r := bytes.NewReader(data)
	decoder := xml.NewDecoder(r)
	rss := &RSS{}
	return rss, decoder.Decode(rss)
}
<|endoftext|>