<commit_before>// Copyright © 2017 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package handler

import (
	"testing"

	pb_broker "github.com/TheThingsNetwork/ttn/api/broker"
	pb_protocol "github.com/TheThingsNetwork/ttn/api/protocol"
	pb_lorawan "github.com/TheThingsNetwork/ttn/api/protocol/lorawan"
	"github.com/TheThingsNetwork/ttn/core/component"
	"github.com/TheThingsNetwork/ttn/core/handler/device"
	"github.com/TheThingsNetwork/ttn/core/types"
	. "github.com/TheThingsNetwork/ttn/utils/testing"
	. "github.com/smartystreets/assertions"
)

func buildLorawanUplink(payload []byte) (*pb_broker.DeduplicatedUplinkMessage, *types.UplinkMessage) {
	ttnUp := &pb_broker.DeduplicatedUplinkMessage{
		DevId:   "devid",
		AppId:   "appid",
		Payload: payload,
		ProtocolMetadata: &pb_protocol.RxMetadata{Protocol: &pb_protocol.RxMetadata_Lorawan{
			Lorawan: &pb_lorawan.Metadata{
				FCnt: 1,
			},
		}},
	}
	appUp := &types.UplinkMessage{}
	return ttnUp, appUp
}

func TestConvertFromLoRaWAN(t *testing.T) {
	a := New(t)
	var wg WaitGroup
	h := &handler{
		Component: &component.Component{Ctx: GetLogger(t, "TestConvertFromLoRaWAN")},
		devices:   device.NewRedisDeviceStore(GetRedisClient(), "handler-test-convert-from-lorawan"),
		qEvent:    make(chan *types.DeviceEvent, 10),
	}
	device := &device.Device{
		DevID:           "devid",
		AppID:           "appid",
		CurrentDownlink: &types.DownlinkMessage{},
	}
	ttnUp, appUp := buildLorawanUplink([]byte{0x40, 0x04, 0x03, 0x02, 0x01, 0x20, 0x01, 0x00, 0x0A, 0x46, 0x55, 0x96, 0x42, 0x92, 0xF2})
	err := h.ConvertFromLoRaWAN(h.Ctx, ttnUp, appUp, device)
	a.So(err, ShouldBeNil)
	a.So(appUp.PayloadRaw, ShouldResemble, []byte{0xaa, 0xbc})
	a.So(appUp.FCnt, ShouldEqual, 1)
	a.So(device.CurrentDownlink, ShouldBeNil)

	device.CurrentDownlink = &types.DownlinkMessage{Confirmed: true}

	ttnUp.UnmarshalPayload()
	ttnUp.Message.GetLorawan().MType = pb_lorawan.MType_CONFIRMED_UP
	ttnUp.Message.GetLorawan().GetMacPayload().FCnt++
	ttnUp.GetProtocolMetadata().GetLorawan().FCnt = ttnUp.Message.GetLorawan().GetMacPayload().FCnt
	ttnUp.Message.GetLorawan().GetMacPayload().Ack = false
	ttnUp.Message.GetLorawan().SetMIC(device.NwkSKey)
	ttnUp.Payload = ttnUp.Message.GetLorawan().PHYPayloadBytes()

	err = h.ConvertFromLoRaWAN(h.Ctx, ttnUp, appUp, device)
	a.So(err, ShouldBeNil)
	a.So(appUp.Confirmed, ShouldBeTrue)
	a.So(device.CurrentDownlink, ShouldNotBeNil)

	device.CurrentDownlink = &types.DownlinkMessage{Confirmed: true}

	wg.Add(1)
	go func() {
		<-h.qEvent
		wg.Done()
	}()

	ttnUp.UnmarshalPayload()
	ttnUp.Message.GetLorawan().MType = pb_lorawan.MType_CONFIRMED_UP
	ttnUp.Message.GetLorawan().GetMacPayload().FCnt++
	ttnUp.GetProtocolMetadata().GetLorawan().FCnt = ttnUp.Message.GetLorawan().GetMacPayload().FCnt
	ttnUp.Message.GetLorawan().GetMacPayload().Ack = true
	ttnUp.Message.GetLorawan().SetMIC(device.NwkSKey)
	ttnUp.Payload = ttnUp.Message.GetLorawan().PHYPayloadBytes()

	err = h.ConvertFromLoRaWAN(h.Ctx, ttnUp, appUp, device)
	a.So(err, ShouldBeNil)
	a.So(appUp.Confirmed, ShouldBeTrue)

	wg.Wait()
}

func buildLorawanDownlink(payload []byte) (*types.DownlinkMessage, *pb_broker.DownlinkMessage) {
	appDown := &types.DownlinkMessage{
		DevID:      "devid",
		AppID:      "appid",
		PayloadRaw: []byte{0xaa, 0xbc},
	}
	ttnDown := &pb_broker.DownlinkMessage{
		Payload: []byte{96, 4, 3, 2, 1, 0, 1, 0, 1, 0, 0, 0, 0},
		DownlinkOption: &pb_broker.DownlinkOption{
			ProtocolConfig: &pb_protocol.TxConfiguration{Protocol: &pb_protocol.TxConfiguration_Lorawan{
				Lorawan: &pb_lorawan.TxConfiguration{
					FCnt: 1,
				},
			}},
		},
	}
	return appDown, ttnDown
}

func TestConvertToLoRaWAN(t *testing.T) {
	a := New(t)
	h := &handler{
		Component: &component.Component{Ctx: GetLogger(t, "TestConvertToLoRaWAN")},
		devices:   device.NewRedisDeviceStore(GetRedisClient(), "handler-test-convert-to-lorawan"),
	}
	device := &device.Device{
		DevID: "devid",
		AppID: "appid",
	}
	appDown, ttnDown := buildLorawanDownlink([]byte{0xaa, 0xbc})
	err := h.ConvertToLoRaWAN(h.Ctx, appDown, ttnDown, device)
	a.So(err, ShouldBeNil)
	a.So(ttnDown.Payload, ShouldResemble, []byte{0x60, 0x04, 0x03, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0xa1, 0x33, 0x68, 0x0A, 0x08, 0xBD})

	appDown, ttnDown = buildLorawanDownlink([]byte{0xaa, 0xbc})
	appDown.FPort = 8
	err = h.ConvertToLoRaWAN(h.Ctx, appDown, ttnDown, device)
	a.So(err, ShouldBeNil)
	a.So(ttnDown.Payload, ShouldResemble, []byte{0x60, 0x04, 0x03, 0x02, 0x01, 0x00, 0x01, 0x00, 0x08, 0xa1, 0x33, 0x41, 0xA9, 0xFA, 0x03})
}
<commit_msg>Fix buildLorawanDownlink<commit_after>// Copyright © 2017 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package handler

import (
	"testing"

	pb_broker "github.com/TheThingsNetwork/ttn/api/broker"
	pb_protocol "github.com/TheThingsNetwork/ttn/api/protocol"
	pb_lorawan "github.com/TheThingsNetwork/ttn/api/protocol/lorawan"
	"github.com/TheThingsNetwork/ttn/core/component"
	"github.com/TheThingsNetwork/ttn/core/handler/device"
	"github.com/TheThingsNetwork/ttn/core/types"
	. "github.com/TheThingsNetwork/ttn/utils/testing"
	. "github.com/smartystreets/assertions"
)

func buildLorawanUplink(payload []byte) (*pb_broker.DeduplicatedUplinkMessage, *types.UplinkMessage) {
	ttnUp := &pb_broker.DeduplicatedUplinkMessage{
		DevId:   "devid",
		AppId:   "appid",
		Payload: payload,
		ProtocolMetadata: &pb_protocol.RxMetadata{Protocol: &pb_protocol.RxMetadata_Lorawan{
			Lorawan: &pb_lorawan.Metadata{
				FCnt: 1,
			},
		}},
	}
	appUp := &types.UplinkMessage{}
	return ttnUp, appUp
}

func TestConvertFromLoRaWAN(t *testing.T) {
	a := New(t)
	var wg WaitGroup
	h := &handler{
		Component: &component.Component{Ctx: GetLogger(t, "TestConvertFromLoRaWAN")},
		devices:   device.NewRedisDeviceStore(GetRedisClient(), "handler-test-convert-from-lorawan"),
		qEvent:    make(chan *types.DeviceEvent, 10),
	}
	device := &device.Device{
		DevID:           "devid",
		AppID:           "appid",
		CurrentDownlink: &types.DownlinkMessage{},
	}
	ttnUp, appUp := buildLorawanUplink([]byte{0x40, 0x04, 0x03, 0x02, 0x01, 0x20, 0x01, 0x00, 0x0A, 0x46, 0x55, 0x96, 0x42, 0x92, 0xF2})
	err := h.ConvertFromLoRaWAN(h.Ctx, ttnUp, appUp, device)
	a.So(err, ShouldBeNil)
	a.So(appUp.PayloadRaw, ShouldResemble, []byte{0xaa, 0xbc})
	a.So(appUp.FCnt, ShouldEqual, 1)
	a.So(device.CurrentDownlink, ShouldBeNil)

	device.CurrentDownlink = &types.DownlinkMessage{Confirmed: true}

	ttnUp.UnmarshalPayload()
	ttnUp.Message.GetLorawan().MType = pb_lorawan.MType_CONFIRMED_UP
	ttnUp.Message.GetLorawan().GetMacPayload().FCnt++
	ttnUp.GetProtocolMetadata().GetLorawan().FCnt = ttnUp.Message.GetLorawan().GetMacPayload().FCnt
	ttnUp.Message.GetLorawan().GetMacPayload().Ack = false
	ttnUp.Message.GetLorawan().SetMIC(device.NwkSKey)
	ttnUp.Payload = ttnUp.Message.GetLorawan().PHYPayloadBytes()

	err = h.ConvertFromLoRaWAN(h.Ctx, ttnUp, appUp, device)
	a.So(err, ShouldBeNil)
	a.So(appUp.Confirmed, ShouldBeTrue)
	a.So(device.CurrentDownlink, ShouldNotBeNil)

	device.CurrentDownlink = &types.DownlinkMessage{Confirmed: true}

	wg.Add(1)
	go func() {
		<-h.qEvent
		wg.Done()
	}()

	ttnUp.UnmarshalPayload()
	ttnUp.Message.GetLorawan().MType = pb_lorawan.MType_CONFIRMED_UP
	ttnUp.Message.GetLorawan().GetMacPayload().FCnt++
	ttnUp.GetProtocolMetadata().GetLorawan().FCnt = ttnUp.Message.GetLorawan().GetMacPayload().FCnt
	ttnUp.Message.GetLorawan().GetMacPayload().Ack = true
	ttnUp.Message.GetLorawan().SetMIC(device.NwkSKey)
	ttnUp.Payload = ttnUp.Message.GetLorawan().PHYPayloadBytes()

	err = h.ConvertFromLoRaWAN(h.Ctx, ttnUp, appUp, device)
	a.So(err, ShouldBeNil)
	a.So(appUp.Confirmed, ShouldBeTrue)

	wg.Wait()
}

func buildLorawanDownlink(payload []byte) (*types.DownlinkMessage, *pb_broker.DownlinkMessage) {
	appDown := &types.DownlinkMessage{
		DevID:      "devid",
		AppID:      "appid",
		PayloadRaw: payload,
	}
	ttnDown := &pb_broker.DownlinkMessage{
		Payload: []byte{96, 4, 3, 2, 1, 0, 1, 0, 1, 0, 0, 0, 0},
		DownlinkOption: &pb_broker.DownlinkOption{
			ProtocolConfig: &pb_protocol.TxConfiguration{Protocol: &pb_protocol.TxConfiguration_Lorawan{
				Lorawan: &pb_lorawan.TxConfiguration{
					FCnt: 1,
				},
			}},
		},
	}
	return appDown, ttnDown
}

func TestConvertToLoRaWAN(t *testing.T) {
	a := New(t)
	h := &handler{
		Component: &component.Component{Ctx: GetLogger(t, "TestConvertToLoRaWAN")},
		devices:   device.NewRedisDeviceStore(GetRedisClient(), "handler-test-convert-to-lorawan"),
	}
	device := &device.Device{
		DevID: "devid",
		AppID: "appid",
	}
	appDown, ttnDown := buildLorawanDownlink([]byte{0xaa, 0xbc})
	err := h.ConvertToLoRaWAN(h.Ctx, appDown, ttnDown, device)
	a.So(err, ShouldBeNil)
	a.So(ttnDown.Payload, ShouldResemble, []byte{0x60, 0x04, 0x03, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0xa1, 0x33, 0x68, 0x0A, 0x08, 0xBD})

	appDown, ttnDown = buildLorawanDownlink([]byte{0xaa, 0xbc})
	appDown.FPort = 8
	err = h.ConvertToLoRaWAN(h.Ctx, appDown, ttnDown, device)
	a.So(err, ShouldBeNil)
	a.So(ttnDown.Payload, ShouldResemble, []byte{0x60, 0x04, 0x03, 0x02, 0x01, 0x00, 0x01, 0x00, 0x08, 0xa1, 0x33, 0x41, 0xA9, 0xFA, 0x03})
}
<|endoftext|>


<commit_before>// Copyright © 2015-2016 River Yang <comicme_yanghe@nanoframework.org>
//
// 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 version

import (
	"fmt"
	"io"
	"os"
)

var (
	Package = "github.com/nano-projects/nanogo"
	Version = "0.1.0"
)

func FprintVersion(w io.Writer) {
	fmt.Fprintln(w, os.Args[0], Package, Version)
}

func PrintVersion() {
	FprintVersion(os.Stdout)
}
<commit_msg>#41 update:   version number to 0.1.1<commit_after>// Copyright © 2015-2016 River Yang <comicme_yanghe@nanoframework.org>
//
// 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 version

import (
	"fmt"
	"io"
	"os"
)

var (
	Package = "github.com/nano-projects/nanogo"
	Version = "0.1.1"
)

func FprintVersion(w io.Writer) {
	fmt.Fprintln(w, os.Args[0], Package, Version)
}

func PrintVersion() {
	FprintVersion(os.Stdout)
}
<|endoftext|>


<commit_before>// Copyright 2015, 2016 Eris Industries (UK) Ltd.
// This file is part of Eris-RT

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

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

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

package version

const TENDERMINT_VERSION = "0.5.0"
// IMPORTANT: Eris-DB version must be on the last line of this file for
// the deployment script DOCKER/build.sh to pick up the right label.
const VERSION = "0.12.0"
<commit_msg>Update version.go<commit_after>// Copyright 2015, 2016 Eris Industries (UK) Ltd.
// This file is part of Eris-RT

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

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

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

package version

const TENDERMINT_VERSION = "0.5.0"
// IMPORTANT: Eris-DB version must be on the last line of this file for
// the deployment script DOCKER/build.sh to pick up the right label.
const VERSION = "0.12.0-rc2"
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"strconv"
	"text/template"
)

// serverTmpl stores templates for the web interface.
var serverTmpl = new(template.Template)

func init() {
	serverTmpl.Funcs(template.FuncMap{
		"format": func(num int64, base int) string {
			return strconv.FormatInt(num, base)
		},

		"shortlen": func() string {
			return flags.short.String()
		},
	})

	template.Must(serverTmpl.New("main").Parse(`

		<title>{{.Title}} :: Main</title>

Loading...

Excluding short sessions:

Current average:

Calculated from  logouts.

					A session is short if it lasts less than {{shortlen}}.

Including short sessions:

Current average:

Calculated from  logouts.

					Tracker runtime: .

`))
}

// logHandler returns an http.Handler that logs every request that
// gets sent to h.
func logHandler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		log.Printf("Got %q request for %q", req.Method, req.URL)

		h.ServeHTTP(rw, req)
	})
}

// tmplHandler returns a handler that serves the template t in
// serverTmpl.
func tmplHandler(t string) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		err := serverTmpl.ExecuteTemplate(rw, t, map[string]interface{}{
			"Req":   req,
			"Title": "PS2 Average Login Times",
		})
		if err != nil {
			log.Printf("Failed to execute %q: %v", t, err)
		}
	})
}

// serveAverage serves the current session as JSON.
func serveAverage(rw http.ResponseWriter, req *http.Request) {
	e := json.NewEncoder(rw)
	err := e.Encode(<-session)
	if err != nil {
		log.Printf("Failed to write average: %v", err)
	}
}

// serveJS serves the javascript for the web interface.
func serveJS(rw http.ResponseWriter, req *http.Request) {
	_, err := io.WriteString(rw, `$(document).ready(function() {
	var loading = $('#loading');
	var main = $('#main');

	var noshort = {
		"average": $('#noshort .average'),
		"num": $('#noshort .num'),
	};
	var total = {
		"average": $('#total .average'),
		"num": $('#total .num'),
	};

	var runtime = $('#runtime');

	function getAverage() {
		$.getJSON('/average', function(data) {
			loading.hide();
			main.show();

			noshort.average.html(data.noshort.cur);
			noshort.num.html(data.noshort.num);
			total.average.html(data.total.cur);
			total.num.html(data.total.num);

			runtime.html(data.runtime);
		});
	};

	getAverage();
	setInterval(getAverage, 5000);
});`)
	if err != nil {
		log.Printf("Failed to write JS: %v", err)
	}
}

// server runs the web interface.
func server() {
	http.Handle("/average", logHandler(http.HandlerFunc(serveAverage)))
	http.Handle("/ps2avglogin.js", logHandler(http.HandlerFunc(serveJS)))
	http.Handle("/", logHandler(tmplHandler("main")))

	log.Printf("Starting server at %q...", flags.addr)
	err := http.ListenAndServe(flags.addr, nil)
	if err != nil {
		log.Fatalf("Failed to start server: %v", err)
	}
}
<commit_msg>Rename /average to /session.<commit_after>package main

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"strconv"
	"text/template"
)

// serverTmpl stores templates for the web interface.
var serverTmpl = new(template.Template)

func init() {
	serverTmpl.Funcs(template.FuncMap{
		"format": func(num int64, base int) string {
			return strconv.FormatInt(num, base)
		},

		"shortlen": func() string {
			return flags.short.String()
		},
	})

	template.Must(serverTmpl.New("main").Parse(`

		<title>{{.Title}} :: Main</title>

Loading...

Excluding short sessions:

Current average:

Calculated from  logouts.

					A session is short if it lasts less than {{shortlen}}.

Including short sessions:

Current average:

Calculated from  logouts.

					Tracker runtime: .

`))
}

// logHandler returns an http.Handler that logs every request that
// gets sent to h.
func logHandler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		log.Printf("Got %q request for %q", req.Method, req.URL)

		h.ServeHTTP(rw, req)
	})
}

// tmplHandler returns a handler that serves the template t in
// serverTmpl.
func tmplHandler(t string) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		err := serverTmpl.ExecuteTemplate(rw, t, map[string]interface{}{
			"Req":   req,
			"Title": "PS2 Average Login Times",
		})
		if err != nil {
			log.Printf("Failed to execute %q: %v", t, err)
		}
	})
}

// serveSession serves the current session as JSON.
func serveSession(rw http.ResponseWriter, req *http.Request) {
	e := json.NewEncoder(rw)
	err := e.Encode(<-session)
	if err != nil {
		log.Printf("Failed to write session: %v", err)
	}
}

// serveJS serves the javascript for the web interface.
func serveJS(rw http.ResponseWriter, req *http.Request) {
	_, err := io.WriteString(rw, `$(document).ready(function() {
	var loading = $('#loading');
	var main = $('#main');

	var noshort = {
		"average": $('#noshort .average'),
		"num": $('#noshort .num'),
	};
	var total = {
		"average": $('#total .average'),
		"num": $('#total .num'),
	};

	var runtime = $('#runtime');

	function getSession() {
		$.getJSON('/session', function(data) {
			loading.hide();
			main.show();

			noshort.average.html(data.noshort.cur);
			noshort.num.html(data.noshort.num);
			total.average.html(data.total.cur);
			total.num.html(data.total.num);

			runtime.html(data.runtime);
		});
	};

	getSession();
	setInterval(getSession, 5000);
});`)
	if err != nil {
		log.Printf("Failed to write JS: %v", err)
	}
}

// server runs the web interface.
func server() {
	http.Handle("/session", logHandler(http.HandlerFunc(serveSession)))
	http.Handle("/ps2avglogin.js", logHandler(http.HandlerFunc(serveJS)))
	http.Handle("/", logHandler(tmplHandler("main")))

	log.Printf("Starting server at %q...", flags.addr)
	err := http.ListenAndServe(flags.addr, nil)
	if err != nil {
		log.Fatalf("Failed to start server: %v", err)
	}
}
<|endoftext|>


<commit_before>package apns

import (
	"crypto/tls"
	"encoding/binary"
	"log"
	"strings"
	"net"
	"time"
)

//ResponseQueueSize indicates how many APNS responses may be buffered.
var ResponseQueueSize = 10000

//SentBufferSize is the maximum number of sent notifications which may be buffered.
var SentBufferSize = 10000

var maxBackoff = 20 * time.Second

//Connection represents a single connection to APNS.
type Connection struct {
	Client
	id              int
	conn            *tls.Conn
	connAux         net.Conn
	queue           chan PushNotification
	errors          chan BadPushNotification
	responses       chan Response
	shouldReconnect chan bool
	stopping        chan bool
	stopped         chan bool
	senderFinished  chan bool
	ackFinished     chan bool

}

//NewConnection initializes an APNS connection. Use Connection.Start() to actually start sending notifications.
func NewConnection(client *Client, id int, errorQueue chan BadPushNotification) *Connection {
	c := new(Connection)
	c.Client = *client
	c.id = id
	c.queue = make(chan PushNotification, 10000)
	c.errors = errorQueue
	c.responses = make(chan Response, ResponseQueueSize)
	c.shouldReconnect = make(chan bool)
	c.stopping = make(chan bool)
	c.stopped = make(chan bool)

	c.senderFinished = make(chan bool)
	c.ackFinished = make(chan bool)

	return c
}

//Response is a reply from APNS - see apns.ApplePushResponses.
type Response struct {
	Status     uint8
	Identifier uint32
}

func newResponse() Response {
	r := Response{}
	return r
}

//BadPushNotification represents a notification which APNS didn't like.
type BadPushNotification struct {
	PushNotification
	Status uint8
}

type timedPushNotification struct {
	PushNotification
	time.Time
}

func (pn PushNotification) timed() timedPushNotification {
	return timedPushNotification{PushNotification: pn, Time: time.Now()}
}

//Enqueue adds a push notification to the end of the "sending" queue.
func (conn *Connection) Enqueue(pn *PushNotification) {
	conn.queue <- *pn
}

//Errors gives you a channel of the push notifications Apple rejected.
func (conn *Connection) Errors() (errors <-chan BadPushNotification) {
	return conn.errors
}

//Start initiates a connection to APNS and asnchronously sends notifications which have been queued.
func (conn *Connection) Start() error {
	//Connect to APNS. The reason this is here as well as in sender is that this probably catches any unavoidable errors in a synchronous fashion, while in sender it can reconnect after temporary errors (which should work most of the time.)
	err := conn.connect()
	if err != nil {
		log.Fatalf("CONN #%d - Failed to connect due to: %+v\n", conn.id, err)
		return err
	}
	//Start sender goroutine
	sent := make(chan PushNotification, 10000)
	go conn.sender(conn.queue, sent)
	//Start limbo goroutine
	go conn.limbo(sent, conn.responses, conn.errors, conn.queue)
	return nil
}

//Stop gracefully closes the connection - it waits for the sending queue to clear, and then shuts down.
func (conn *Connection) Stop() chan bool {
	log.Printf("CONN #%d - apns: shutting down.\n", conn.id)
	conn.stopping <- true
	return conn.stopped
	//Thought: Don't necessarily need a channel here. Could signal finishing by closing errors?
}

func (conn *Connection) sender(queue <-chan PushNotification, sent chan PushNotification) {
	i := 0
	stopping := false
	defer conn.conn.Close()
	defer conn.connAux.Close()
	log.Printf("CONN #%d - Starting sender", conn.id)
	for {
		select {
		case pn, ok := <-conn.queue:
			if !ok {
				log.Printf("CONN %d - Not okay; queue closed.", conn.id)
				//That means the Connection is stopped
				//close sent?
				return
			}
			//This means we saw a response; connection is over.
			select {
			case <-conn.shouldReconnect:
				conn.conn.Close()
				conn.conn = nil
				conn.connAux.Close()
				conn.connAux = nil
				conn.spinUntilReconnect()
			default:
			}
			//Then send the push notification
			pn.Priority = 10
			payload, err := pn.ToBytes()
			if err != nil {
				log.Printf("CONN #%d - %+v\n",conn.id,err)
				//Should report this on the bad notifications channel probably
			} else {
				if conn.conn == nil {
					conn.spinUntilReconnect()
				}
				_, err := conn.conn.Write(payload)
				if err != nil {
					go func() {
						conn.shouldReconnect <- true
					}()
					//Disconnect?
				} else {
					i++
					sent <- pn
					if stopping && len(queue) == 0 {
						conn.senderFinished <- true
					}
				}
			}
		case <-conn.stopping:
			log.Printf("CONN #%d - sender: Got a stop message!\n", conn.id)
			stopping = true
			if len(queue) == 0 {
				log.Printf("CONN #%d - sender: I'm stopping and I've run out of things to send. Let's see if limbo is empty.", conn.id)
				conn.senderFinished <- true
			}
		case <-conn.ackFinished:
			log.Printf("CONN #%d - sender: limbo is empty!", conn.id)
			if len(queue) == 0 {
				log.Printf("CONN #%d - sender: limbo is empty and so am I!", conn.id)
				close(sent)
				return
			}
		}
	}
}

func (conn *Connection) reader(responses chan<- Response) {
	buffer := make([]byte, 6)
	for {
		n, err := conn.conn.Read(buffer)
		if err != nil && n < 6 {
			log.Printf("CONN #%d - APNS: Error before reading complete response %d %+v\n", conn.id, n, err)
			conn.shouldReconnect <- true
			return
		}
		command := uint8(buffer[0])
		if command != 8 {
			log.Printf("CONN #%d - Something went wrong: command should have been 8; it was actually %+v\n",conn.id, command)
		}
		resp := newResponse()
		resp.Identifier = binary.BigEndian.Uint32(buffer[2:6])
		resp.Status = uint8(buffer[1])
		responses <- resp
		conn.shouldReconnect <- true
		return
	}
}

func (conn *Connection) limbo(sent <-chan PushNotification, responses chan Response, errors chan BadPushNotification, queue chan PushNotification) {
	stopping := false
	limbo := make([]timedPushNotification, 0, SentBufferSize)
	ticker := time.NewTicker(1 * time.Second)
	for {
		select {
		case pn, ok := <-sent:
			limbo = append(limbo, pn.timed())
			stopping = false
			if !ok {
				log.Printf("CONN #%d - limbo: sent is closed, so sender is done. So am I, then!", conn.id)
				close(errors)
				conn.stopped <- true
				return
			}
		case <-conn.senderFinished:
			//senderFinished means the sender thinks it's done.
			//However, sender might not be - limbo could resend some, if there are any left here.
			//So we just take note of this until limbo is empty too.
			stopping = true
		case resp, ok := <-responses:
			if !ok {
				//If the responses channel is closed,
				//that means we're shutting down the connection.
			}
			for i, pn := range limbo {
				if pn.Identifier == resp.Identifier {
					if resp.Status != 10 {
						//It was an error, we should report this on the error channel
						bad := BadPushNotification{PushNotification: pn.PushNotification, Status: resp.Status}
						errors <- bad
					}
					if len(limbo) > i {
						toRequeue := len(limbo) - (i + 1)
						if toRequeue > 0 {
							conn.requeue(limbo[i+1:])
							//We resent some notifications: that means we should wait for sender to tell us it's done, again.
							stopping = false
						}
					}
				}
			}
			limbo = make([]timedPushNotification, 0, SentBufferSize)
		case <-ticker.C:
			flushed := false
			for i := range limbo {
				if limbo[i].After(time.Now().Add(-TimeoutSeconds * time.Second)) {
					if i > 0 {
						newLimbo := make([]timedPushNotification, len(limbo[i:]), SentBufferSize)
						copy(newLimbo, limbo[i:])
						limbo = newLimbo
						flushed = true
						break
					}
				}
			}
			if !flushed {
				limbo = make([]timedPushNotification, 0, SentBufferSize)
			}
			if stopping && len(limbo) == 0 {
				//sender() is finished and so is limbo - so the connection is done.
				log.Printf("CONN #%d - limbo: I've flushed all my notifications. Tell sender I'm done.\n", conn.id)
				conn.ackFinished <- true
			}
		}
	}
}

func (conn *Connection) requeue(queue []timedPushNotification) {
	for _, pn := range queue {
		conn.Enqueue(&pn.PushNotification)
	}
}

func (conn *Connection) connect() error {
	if conn.conn != nil {
		conn.conn.Close()
	}
	if conn.connAux != nil {
		conn.connAux.Close()
	}

	var cert tls.Certificate
	var err error
	if len(conn.CertificateBase64) == 0 && len(conn.KeyBase64) == 0 {
		// The user did not specify raw block contents, so check the filesystem.
		cert, err = tls.LoadX509KeyPair(conn.CertificateFile, conn.KeyFile)
	} else {
		// The user provided the raw block contents, so use that.
		cert, err = tls.X509KeyPair([]byte(conn.CertificateBase64), []byte(conn.KeyBase64))
	}

	if err != nil {
		log.Fatal("Failed to obtain cert: %+v\n", err)
		return err
	}

	conf := &tls.Config{
		Certificates: []tls.Certificate{cert},
		ServerName: strings.Split(conn.Gateway, ":")[0],
	}

	connAux, err := net.Dial("tcp", conn.Gateway)
	if err != nil {
		log.Fatal("Failed while dialing %s with error: %+v\n", conn.Gateway, err)
		return err
	}
	tlsConn := tls.Client(connAux, conf)
	err = tlsConn.Handshake()
	if err != nil {
		log.Fatal("Failed while handshaking %+v...\n", err)
		_ = tlsConn.Close()
		return err
	}
	conn.conn = tlsConn
	conn.connAux = connAux
	//Start reader goroutine
	go conn.reader(conn.responses)
	return nil
}

func (c *Connection) spinUntilReconnect() {
	var backoff = time.Duration(100)
	for {
		log.Printf("CONN #%d - Connection lost; reconnecting.", c.id)
		err := c.connect()
		if err != nil {
			//Exponential backoff up to a limit
			log.Printf("CONN #%d - APNS: Error connecting to server: ", c.id, err)
			backoff = backoff * 2
			if backoff > maxBackoff {
				backoff = maxBackoff
			}
			time.Sleep(backoff)
		} else {
			backoff = 100
			log.Printf("CONN #%d - Connected...", c.id)
			break
		}
	}
}
<commit_msg>Ultimate logging to identify not sent notifications<commit_after>package apns

import (
	"crypto/tls"
	"encoding/binary"
	"log"
	"strings"
	"net"
	"time"
)

//ResponseQueueSize indicates how many APNS responses may be buffered.
var ResponseQueueSize = 10000

//SentBufferSize is the maximum number of sent notifications which may be buffered.
var SentBufferSize = 10000

var maxBackoff = 20 * time.Second

//Connection represents a single connection to APNS.
type Connection struct {
	Client
	id              int
	conn            *tls.Conn
	connAux         net.Conn
	queue           chan PushNotification
	errors          chan BadPushNotification
	responses       chan Response
	shouldReconnect chan bool
	stopping        chan bool
	stopped         chan bool
	senderFinished  chan bool
	ackFinished     chan bool

}

//NewConnection initializes an APNS connection. Use Connection.Start() to actually start sending notifications.
func NewConnection(client *Client, id int, errorQueue chan BadPushNotification) *Connection {
	c := new(Connection)
	c.Client = *client
	c.id = id
	c.queue = make(chan PushNotification, 10000)
	c.errors = errorQueue
	c.responses = make(chan Response, ResponseQueueSize)
	c.shouldReconnect = make(chan bool)
	c.stopping = make(chan bool)
	c.stopped = make(chan bool)

	c.senderFinished = make(chan bool)
	c.ackFinished = make(chan bool)

	return c
}

//Response is a reply from APNS - see apns.ApplePushResponses.
type Response struct {
	Status     uint8
	Identifier uint32
}

func newResponse() Response {
	r := Response{}
	return r
}

//BadPushNotification represents a notification which APNS didn't like.
type BadPushNotification struct {
	PushNotification
	Status uint8
}

type timedPushNotification struct {
	PushNotification
	time.Time
}

func (pn PushNotification) timed() timedPushNotification {
	return timedPushNotification{PushNotification: pn, Time: time.Now()}
}

//Enqueue adds a push notification to the end of the "sending" queue.
func (conn *Connection) Enqueue(pn *PushNotification) {
	conn.queue <- *pn
}

//Errors gives you a channel of the push notifications Apple rejected.
func (conn *Connection) Errors() (errors <-chan BadPushNotification) {
	return conn.errors
}

//Start initiates a connection to APNS and asnchronously sends notifications which have been queued.
func (conn *Connection) Start() error {
	//Connect to APNS. The reason this is here as well as in sender is that this probably catches any unavoidable errors in a synchronous fashion, while in sender it can reconnect after temporary errors (which should work most of the time.)
	err := conn.connect()
	if err != nil {
		log.Fatalf("CONN #%d - Failed to connect due to: %+v\n", conn.id, err)
		return err
	}
	//Start sender goroutine
	sent := make(chan PushNotification, 10000)
	go conn.sender(conn.queue, sent)
	//Start limbo goroutine
	go conn.limbo(sent, conn.responses, conn.errors, conn.queue)
	return nil
}

//Stop gracefully closes the connection - it waits for the sending queue to clear, and then shuts down.
func (conn *Connection) Stop() chan bool {
	log.Printf("CONN #%d - apns: shutting down.\n", conn.id)
	conn.stopping <- true
	return conn.stopped
	//Thought: Don't necessarily need a channel here. Could signal finishing by closing errors?
}

func (conn *Connection) sender(queue <-chan PushNotification, sent chan PushNotification) {
	i := 0
	stopping := false
	defer conn.conn.Close()
	defer conn.connAux.Close()
	log.Printf("CONN #%d - Starting sender", conn.id)
	for {
		select {
		case pn, ok := <-conn.queue:
			if !ok {
				log.Printf("CONN %d - Not okay; queue closed.", conn.id)
				//That means the Connection is stopped
				//close sent?
				return
			}
			//This means we saw a response; connection is over.
			select {
			case <-conn.shouldReconnect:
				conn.conn.Close()
				conn.conn = nil
				conn.connAux.Close()
				conn.connAux = nil
				conn.spinUntilReconnect()
			default:
			}
			//Then send the push notification
			pn.Priority = 10
			payload, err := pn.ToBytes()
			if err != nil {
				log.Printf("CONN #%d - %+v\n",conn.id,err)
				//Should report this on the bad notifications channel probably
			} else {
				if conn.conn == nil {
					conn.spinUntilReconnect()
				}
				pStr, err := pn.PayloadString()
				if err != nil {
					log.Printf("Err is: %+v\n", err)
				}
				log.Printf("Not is: %s\n", pStr)
				_, err = conn.conn.Write(payload)
				if err != nil {
					go func() {
						conn.shouldReconnect <- true
					}()
					//Disconnect?
				} else {
					i++
					sent <- pn
					if stopping && len(queue) == 0 {
						conn.senderFinished <- true
					}
				}
			}
		case <-conn.stopping:
			log.Printf("CONN #%d - sender: Got a stop message!\n", conn.id)
			stopping = true
			if len(queue) == 0 {
				log.Printf("CONN #%d - sender: I'm stopping and I've run out of things to send. Let's see if limbo is empty.", conn.id)
				conn.senderFinished <- true
			}
		case <-conn.ackFinished:
			log.Printf("CONN #%d - sender: limbo is empty!", conn.id)
			if len(queue) == 0 {
				log.Printf("CONN #%d - sender: limbo is empty and so am I!", conn.id)
				close(sent)
				return
			}
		}
	}
}

func (conn *Connection) reader(responses chan<- Response) {
	buffer := make([]byte, 6)
	for {
		n, err := conn.conn.Read(buffer)
		if err != nil && n < 6 {
			log.Printf("CONN #%d - APNS: Error before reading complete response %d %+v\n", conn.id, n, err)
			conn.shouldReconnect <- true
			return
		}
		command := uint8(buffer[0])
		if command != 8 {
			log.Printf("CONN #%d - Something went wrong: command should have been 8; it was actually %+v\n",conn.id, command)
		}
		resp := newResponse()
		resp.Identifier = binary.BigEndian.Uint32(buffer[2:6])
		resp.Status = uint8(buffer[1])
		responses <- resp
		conn.shouldReconnect <- true
		return
	}
}

func (conn *Connection) limbo(sent <-chan PushNotification, responses chan Response, errors chan BadPushNotification, queue chan PushNotification) {
	stopping := false
	limbo := make([]timedPushNotification, 0, SentBufferSize)
	ticker := time.NewTicker(1 * time.Second)
	for {
		select {
		case pn, ok := <-sent:
			limbo = append(limbo, pn.timed())
			stopping = false
			if !ok {
				log.Printf("CONN #%d - limbo: sent is closed, so sender is done. So am I, then!", conn.id)
				close(errors)
				conn.stopped <- true
				return
			}
		case <-conn.senderFinished:
			//senderFinished means the sender thinks it's done.
			//However, sender might not be - limbo could resend some, if there are any left here.
			//So we just take note of this until limbo is empty too.
			stopping = true
		case resp, ok := <-responses:
			if !ok {
				//If the responses channel is closed,
				//that means we're shutting down the connection.
			}
			for i, pn := range limbo {
				if pn.Identifier == resp.Identifier {
					if resp.Status != 10 {
						//It was an error, we should report this on the error channel
						bad := BadPushNotification{PushNotification: pn.PushNotification, Status: resp.Status}
						errors <- bad
					}
					if len(limbo) > i {
						toRequeue := len(limbo) - (i + 1)
						if toRequeue > 0 {
							conn.requeue(limbo[i+1:])
							//We resent some notifications: that means we should wait for sender to tell us it's done, again.
							stopping = false
						}
					}
				}
			}
			limbo = make([]timedPushNotification, 0, SentBufferSize)
		case <-ticker.C:
			flushed := false
			for i := range limbo {
				if limbo[i].After(time.Now().Add(-TimeoutSeconds * time.Second)) {
					if i > 0 {
						newLimbo := make([]timedPushNotification, len(limbo[i:]), SentBufferSize)
						copy(newLimbo, limbo[i:])
						limbo = newLimbo
						flushed = true
						break
					}
				}
			}
			if !flushed {
				limbo = make([]timedPushNotification, 0, SentBufferSize)
			}
			if stopping && len(limbo) == 0 {
				//sender() is finished and so is limbo - so the connection is done.
				log.Printf("CONN #%d - limbo: I've flushed all my notifications. Tell sender I'm done.\n", conn.id)
				conn.ackFinished <- true
			}
		}
	}
}

func (conn *Connection) requeue(queue []timedPushNotification) {
	for _, pn := range queue {
		conn.Enqueue(&pn.PushNotification)
	}
}

func (conn *Connection) connect() error {
	if conn.conn != nil {
		conn.conn.Close()
	}
	if conn.connAux != nil {
		conn.connAux.Close()
	}

	var cert tls.Certificate
	var err error
	if len(conn.CertificateBase64) == 0 && len(conn.KeyBase64) == 0 {
		// The user did not specify raw block contents, so check the filesystem.
		cert, err = tls.LoadX509KeyPair(conn.CertificateFile, conn.KeyFile)
	} else {
		// The user provided the raw block contents, so use that.
		cert, err = tls.X509KeyPair([]byte(conn.CertificateBase64), []byte(conn.KeyBase64))
	}

	if err != nil {
		log.Fatal("Failed to obtain cert: %+v\n", err)
		return err
	}

	conf := &tls.Config{
		Certificates: []tls.Certificate{cert},
		ServerName: strings.Split(conn.Gateway, ":")[0],
	}

	connAux, err := net.Dial("tcp", conn.Gateway)
	if err != nil {
		log.Fatal("Failed while dialing %s with error: %+v\n", conn.Gateway, err)
		return err
	}
	tlsConn := tls.Client(connAux, conf)
	err = tlsConn.Handshake()
	if err != nil {
		log.Fatal("Failed while handshaking %+v...\n", err)
		_ = tlsConn.Close()
		return err
	}
	conn.conn = tlsConn
	conn.connAux = connAux
	//Start reader goroutine
	go conn.reader(conn.responses)
	return nil
}

func (c *Connection) spinUntilReconnect() {
	var backoff = time.Duration(100)
	for {
		log.Printf("CONN #%d - Connection lost; reconnecting.", c.id)
		err := c.connect()
		if err != nil {
			//Exponential backoff up to a limit
			log.Printf("CONN #%d - APNS: Error connecting to server: ", c.id, err)
			backoff = backoff * 2
			if backoff > maxBackoff {
				backoff = maxBackoff
			}
			time.Sleep(backoff)
		} else {
			backoff = 100
			log.Printf("CONN #%d - Connected...", c.id)
			break
		}
	}
}
<|endoftext|>


<commit_before>// Copyright ©2014 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package stat

import (
	"github.com/gonum/matrix/mat64"
)

// CovarianceMatrix calculates a covariance matrix (also known as a
// variance-covariance matrix) from a matrix of data.
func CovarianceMatrix(x mat64.Matrix) *mat64.Dense {

	// matrix version of the two pass algorithm.  This doesn't use
	// the correction found in the Covariance and Variance functions.

	r, _ := x.Dims()
	b := ones(1, r)
	b.Mul(b, x)
	b.Scale(1/float64(r), b)

	// todo: avoid unneeded memory expansion here.
	mu := b.RowView(0)

	// this could also be done with a clone & row viewer
	xc := mat64.DenseCopyOf(x)
	for i := 0; i < r; i++ {
		rv := xc.RowView(i)
		for j, mean := range(mu) {
			rv[j] -= mean
		}
	}

	// todo: avoid matrix copy
	xt := new(mat64.Dense)
	xt.TCopy(xc)

	ss := new(mat64.Dense)
	ss.Mul(xt, xc)
	ss.Scale(1/float64(r-1), ss)
	return ss
}

// ones is a matrix of all ones.
func ones(r, c int) *mat64.Dense {
	x := make([]float64, r*c)
	for i := range x {
		x[i] = 1
	}
	return mat64.NewDense(r, c, x)
}
<commit_msg>improve comments<commit_after>// Copyright ©2014 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package stat

import (
	"github.com/gonum/matrix/mat64"
)

// CovarianceMatrix calculates a covariance matrix (also known as a
// variance-covariance matrix) from a matrix of data.
func CovarianceMatrix(x mat64.Matrix) *mat64.Dense {

	// matrix version of the two pass algorithm.  This doesn't use
	// the correction found in the Covariance and Variance functions.

	r, _ := x.Dims()

	// determine the mean of each of the columns
	b := ones(1, r)
	b.Mul(b, x)
	b.Scale(1/float64(r), b)
	mu := b.RowView(0)

	// subtract the mean from the data
	xc := mat64.DenseCopyOf(x)
	for i := 0; i < r; i++ {
		rv := xc.RowView(i)
		for j, mean := range mu {
			rv[j] -= mean
		}
	}

	// todo: avoid matrix copy?
	xt := new(mat64.Dense)
	xt.TCopy(xc)

	// It would be nice if we could indicate that this was a symmetric
	// matrix.
	ss := new(mat64.Dense)
	ss.Mul(xt, xc)
	ss.Scale(1/float64(r-1), ss)
	return ss
}

// ones is a matrix of all ones.
func ones(r, c int) *mat64.Dense {
	x := make([]float64, r*c)
	for i := range x {
		x[i] = 1
	}
	return mat64.NewDense(r, c, x)
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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 logging sets up and configures logging.
package logging

import (
	"context"
	"fmt"
	"sync"
	"time"

	"go.opencensus.io/trace"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

// contextKey is a private string type to prevent collisions in the context map.
type contextKey string

// loggerKey points to the value in the context where the logger is stored.
const loggerKey = contextKey("logger")

var (
	// defaultLogger is the default logger. It is initialized once per package
	// include upon calling DefaultLogger.
	defaultLogger     *zap.SugaredLogger
	defaultLoggerOnce sync.Once
)

// NewLogger creates a new logger with the given configuration.
func NewLogger(debug bool) *zap.SugaredLogger {
	config := &zap.Config{
		Level:            zap.NewAtomicLevelAt(zap.InfoLevel),
		Development:      false,
		Sampling:         samplingConfig,
		Encoding:         encodingJSON,
		EncoderConfig:    encoderConfig,
		OutputPaths:      outputStderr,
		ErrorOutputPaths: outputStderr,
	}

	// Add more details if logging is in debug mode.
	if debug {
		config.Level = zap.NewAtomicLevelAt(zap.DebugLevel)
		config.Development = true
		config.Sampling = nil
	}

	logger, err := config.Build()
	if err != nil {
		logger = zap.NewNop()
	}

	return logger.Sugar()
}

// DefaultLogger returns the default logger for the package.
func DefaultLogger() *zap.SugaredLogger {
	defaultLoggerOnce.Do(func() {
		defaultLogger = NewLogger(false)
	})
	return defaultLogger
}

// WithLogger creates a new context with the provided logger attached.
func WithLogger(ctx context.Context, logger *zap.SugaredLogger) context.Context {
	return context.WithValue(ctx, loggerKey, logger)
}

// FromContext returns the logger stored in the context. If no such logger
// exists, a default logger is returned.
func FromContext(ctx context.Context) *zap.SugaredLogger {
	if logger, ok := ctx.Value(loggerKey).(*zap.SugaredLogger); ok {
		return logger
	}
	return DefaultLogger()
}

const (
	timestamp  = "timestamp"
	severity   = "severity"
	logger     = "logger"
	caller     = "caller"
	message    = "message"
	stacktrace = "stacktrace"

	levelDebug     = "DEBUG"
	levelInfo      = "INFO"
	levelWarning   = "WARNING"
	levelError     = "ERROR"
	levelCritical  = "CRITICAL"
	levelAlert     = "ALERT"
	levelEmergency = "EMERGENCY"

	encodingJSON = "json"
)

var outputStderr = []string{"stderr"}

var encoderConfig = zapcore.EncoderConfig{
	TimeKey:        timestamp,
	LevelKey:       severity,
	NameKey:        logger,
	CallerKey:      caller,
	MessageKey:     message,
	StacktraceKey:  stacktrace,
	LineEnding:     zapcore.DefaultLineEnding,
	EncodeLevel:    levelEncoder(),
	EncodeTime:     timeEncoder(),
	EncodeDuration: zapcore.SecondsDurationEncoder,
	EncodeCaller:   zapcore.ShortCallerEncoder,
}

var samplingConfig = &zap.SamplingConfig{
	Initial:    250,
	Thereafter: 250,
}

// levelEncoder transforms a zap level to the associated stackdriver level.
func levelEncoder() zapcore.LevelEncoder {
	return func(l zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
		switch l {
		case zapcore.DebugLevel:
			enc.AppendString(levelDebug)
		case zapcore.InfoLevel:
			enc.AppendString(levelInfo)
		case zapcore.WarnLevel:
			enc.AppendString(levelWarning)
		case zapcore.ErrorLevel:
			enc.AppendString(levelError)
		case zapcore.DPanicLevel:
			enc.AppendString(levelCritical)
		case zapcore.PanicLevel:
			enc.AppendString(levelAlert)
		case zapcore.FatalLevel:
			enc.AppendString(levelEmergency)
		}
	}
}

// TraceFromContext adds the correct Stackdriver trace fields.
//
// see: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry
func TraceFromContext(ctx context.Context) []zap.Field {
	span := trace.FromContext(ctx)

	if span == nil {
		return nil
	}

	sc := span.SpanContext()

	return []zap.Field{
		// TODO(icco): Figure out how to add project ID to this.
		zap.String("trace", fmt.Sprintf("traces/%s", sc.TraceID)),
		zap.String("spanId", sc.SpanID.String()),
		zap.Bool("traceSampled", sc.IsSampled()),
	}
}

// timeEncoder encodes the time as RFC3339 nano
func timeEncoder() zapcore.TimeEncoder {
	return func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
		enc.AppendString(t.Format(time.RFC3339Nano))
	}
}
<commit_msg>Do not sample logs in production (#1252)<commit_after>// Copyright 2020 Google LLC
//
// 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 logging sets up and configures logging.
package logging

import (
	"context"
	"fmt"
	"sync"
	"time"

	"go.opencensus.io/trace"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

// contextKey is a private string type to prevent collisions in the context map.
type contextKey string

// loggerKey points to the value in the context where the logger is stored.
const loggerKey = contextKey("logger")

var (
	// defaultLogger is the default logger. It is initialized once per package
	// include upon calling DefaultLogger.
	defaultLogger     *zap.SugaredLogger
	defaultLoggerOnce sync.Once
)

// NewLogger creates a new logger with the given configuration.
func NewLogger(debug bool) *zap.SugaredLogger {
	config := &zap.Config{
		Level:            zap.NewAtomicLevelAt(zap.InfoLevel),
		Development:      false,
		Encoding:         encodingJSON,
		EncoderConfig:    encoderConfig,
		OutputPaths:      outputStderr,
		ErrorOutputPaths: outputStderr,
	}

	// Add more details if logging is in debug mode.
	if debug {
		config.Level = zap.NewAtomicLevelAt(zap.DebugLevel)
		config.Development = true
	}

	logger, err := config.Build()
	if err != nil {
		logger = zap.NewNop()
	}

	return logger.Sugar()
}

// DefaultLogger returns the default logger for the package.
func DefaultLogger() *zap.SugaredLogger {
	defaultLoggerOnce.Do(func() {
		defaultLogger = NewLogger(false)
	})
	return defaultLogger
}

// WithLogger creates a new context with the provided logger attached.
func WithLogger(ctx context.Context, logger *zap.SugaredLogger) context.Context {
	return context.WithValue(ctx, loggerKey, logger)
}

// FromContext returns the logger stored in the context. If no such logger
// exists, a default logger is returned.
func FromContext(ctx context.Context) *zap.SugaredLogger {
	if logger, ok := ctx.Value(loggerKey).(*zap.SugaredLogger); ok {
		return logger
	}
	return DefaultLogger()
}

const (
	timestamp  = "timestamp"
	severity   = "severity"
	logger     = "logger"
	caller     = "caller"
	message    = "message"
	stacktrace = "stacktrace"

	levelDebug     = "DEBUG"
	levelInfo      = "INFO"
	levelWarning   = "WARNING"
	levelError     = "ERROR"
	levelCritical  = "CRITICAL"
	levelAlert     = "ALERT"
	levelEmergency = "EMERGENCY"

	encodingJSON = "json"
)

var outputStderr = []string{"stderr"}

var encoderConfig = zapcore.EncoderConfig{
	TimeKey:        timestamp,
	LevelKey:       severity,
	NameKey:        logger,
	CallerKey:      caller,
	MessageKey:     message,
	StacktraceKey:  stacktrace,
	LineEnding:     zapcore.DefaultLineEnding,
	EncodeLevel:    levelEncoder(),
	EncodeTime:     timeEncoder(),
	EncodeDuration: zapcore.SecondsDurationEncoder,
	EncodeCaller:   zapcore.ShortCallerEncoder,
}

// levelEncoder transforms a zap level to the associated stackdriver level.
func levelEncoder() zapcore.LevelEncoder {
	return func(l zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
		switch l {
		case zapcore.DebugLevel:
			enc.AppendString(levelDebug)
		case zapcore.InfoLevel:
			enc.AppendString(levelInfo)
		case zapcore.WarnLevel:
			enc.AppendString(levelWarning)
		case zapcore.ErrorLevel:
			enc.AppendString(levelError)
		case zapcore.DPanicLevel:
			enc.AppendString(levelCritical)
		case zapcore.PanicLevel:
			enc.AppendString(levelAlert)
		case zapcore.FatalLevel:
			enc.AppendString(levelEmergency)
		}
	}
}

// TraceFromContext adds the correct Stackdriver trace fields.
//
// see: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry
func TraceFromContext(ctx context.Context) []zap.Field {
	span := trace.FromContext(ctx)

	if span == nil {
		return nil
	}

	sc := span.SpanContext()

	return []zap.Field{
		// TODO(icco): Figure out how to add project ID to this.
		zap.String("trace", fmt.Sprintf("traces/%s", sc.TraceID)),
		zap.String("spanId", sc.SpanID.String()),
		zap.Bool("traceSampled", sc.IsSampled()),
	}
}

// timeEncoder encodes the time as RFC3339 nano
func timeEncoder() zapcore.TimeEncoder {
	return func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
		enc.AppendString(t.Format(time.RFC3339Nano))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"io"
	"os"
	"regexp"
	"runtime"
	// "strconv"
	// "strings"
)

const (
	helpFlagUsage  = "Help and usage instructions"
	forceFlagUsage = "Force overwrite of destination file if it exists"
)

var helpPtr = flag.Bool("help", false, helpFlagUsage)
var forcePtr = flag.Bool("force", false, forceFlagUsage)
var counter int = 0
var lexer = regexp.MustCompile(`s:\d+:\\?\".*?\\?\";`)
var re = regexp.MustCompile(`(s:)(\d+)(:\\?\")(.*?)(\\?\";)`)
var esc = regexp.MustCompile(`(\\"|\\'|\\\\|\\a|\\b|\\n|\\r|\\s|\\t|\\v)`)

// var escstrs = []string{`\"`, `\'`, `\\`, `\a`, `\b`, `\n`, `\r`, `\s`, `\t`, `\v`}

func init() {
	// Short flags too
	flag.BoolVar(helpPtr, "h", false, helpFlagUsage)
	flag.BoolVar(forcePtr, "f", false, forceFlagUsage)
}

func main() {
	numCPU := runtime.NumCPU()
	runtime.GOMAXPROCS(numCPU)

	// Handle flags
	flag.Parse()

	args := flag.Args()

	if *helpPtr {
		printUsage()
		return
	}

	if len(args) > 0 {
		filename := fmt.Sprintf("%s", args[0])
		// Open provided file
		infile, err := os.Open(filename)
		if err != nil {
			fmt.Println(err)
			return
		}
		// close provided file on exit and check for its returned error
		defer infile.Close()

		newDestination := false
		outfilename := filename
		tempfilename := fmt.Sprintf("%s~", outfilename)
		if len(args) > 1 {
			newDestination = true
			outfilename = fmt.Sprintf("%s", args[1])
			tempfilename = fmt.Sprintf("%s~", outfilename)
			if !*forcePtr {
				if _, err := os.Stat(outfilename); err == nil {
					fmt.Println("Destination file already exists, aborting serfix.")
					return
				}
			}
		}

		// Open out file
		tempfile, err := os.Create(tempfilename)
		if err != nil {
			println(err)
		}
		// close out file
		defer tempfile.Close()

		r := bufio.NewReaderSize(infile, 2*1024*1024)

		line, err := r.ReadString('\n')
		for err == nil {
			tempfile.WriteString(lexer.ReplaceAllStringFunc(string(line), replace))

			line, err = r.ReadString('\n')
		}
		// if isPrefix {
		// 	fmt.Println(errors.New("buffer size too small"))
		// 	return
		// }
		if err != io.EOF {
			fmt.Println(err)
			return
		}

		// Close the in/out files
		if err := tempfile.Close(); err != nil {
			fmt.Println(err)
			return
		}
		if err := infile.Close(); err != nil {
			fmt.Println(err)
			return
		}

		if !newDestination {
			// Remove original file
			if err := os.Remove(filename); err != nil {
				fmt.Println(err)
				return
			}
		} else {
			// If destination exists and force flag is used, remove destination file
			if _, err := os.Stat(outfilename); err == nil {
				if !*forcePtr {
					if err := os.Remove(outfilename); err != nil {
						fmt.Println(err)
						return
					}
				}
			}
		}
		if err := os.Rename(tempfilename, outfilename); err != nil {
			fmt.Println(err)
			return
		}

	} else {
		r := bufio.NewReaderSize(os.Stdin, 2*1024*1024)

		line, isPrefix, err := r.ReadLine()
		for err == nil && !isPrefix {
			fmt.Println(lexer.ReplaceAllStringFunc(string(line), replace))

			line, isPrefix, err = r.ReadLine()
		}
		if isPrefix {
			fmt.Println(errors.New("buffer size too small"))
			return
		}
		if err != io.EOF {
			fmt.Println(err)
			return
		}
	}
}

func replace(matches string) string {
	parts := re.FindStringSubmatch(matches)

	str_len := len(parts[4]) - len(esc.FindAllString(parts[4], -1))
	// esc_len := 0
	// for _, escstr := range escstrs {
	// 	esc_len = esc_len + strings.Count(parts[4], escstr)
	// }

	return fmt.Sprintf("%s%d%s%s%s", parts[1], str_len, parts[3], parts[4], parts[5])
}

func printUsage() {
	fmt.Println("Usage: serfix [flags] filename [outfilename]")
	fmt.Println("Alt. Usage: cat filename | serfix")
	fmt.Println("")
	fmt.Println("\t -f, --force \t\t\t Force overwrite of destination file if it exists.")
	fmt.Println("\t -h, --help  \t\t\t Print serfix help.")
	fmt.Println("")
}
<commit_msg>removed leftover from failed optimization attempt<commit_after>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"io"
	"os"
	"regexp"
	"runtime"
)

const (
	helpFlagUsage  = "Help and usage instructions"
	forceFlagUsage = "Force overwrite of destination file if it exists"
)

var helpPtr = flag.Bool("help", false, helpFlagUsage)
var forcePtr = flag.Bool("force", false, forceFlagUsage)
var counter int = 0
var lexer = regexp.MustCompile(`s:\d+:\\?\".*?\\?\";`)
var re = regexp.MustCompile(`(s:)(\d+)(:\\?\")(.*?)(\\?\";)`)
var esc = regexp.MustCompile(`(\\"|\\'|\\\\|\\a|\\b|\\n|\\r|\\s|\\t|\\v)`)

func init() {
	// Short flags too
	flag.BoolVar(helpPtr, "h", false, helpFlagUsage)
	flag.BoolVar(forcePtr, "f", false, forceFlagUsage)
}

func main() {
	numCPU := runtime.NumCPU()
	runtime.GOMAXPROCS(numCPU)

	// Handle flags
	flag.Parse()

	args := flag.Args()

	if *helpPtr {
		printUsage()
		return
	}

	if len(args) > 0 {
		filename := fmt.Sprintf("%s", args[0])
		// Open provided file
		infile, err := os.Open(filename)
		if err != nil {
			fmt.Println(err)
			return
		}
		// close provided file on exit and check for its returned error
		defer infile.Close()

		newDestination := false
		outfilename := filename
		tempfilename := fmt.Sprintf("%s~", outfilename)
		if len(args) > 1 {
			newDestination = true
			outfilename = fmt.Sprintf("%s", args[1])
			tempfilename = fmt.Sprintf("%s~", outfilename)
			if !*forcePtr {
				if _, err := os.Stat(outfilename); err == nil {
					fmt.Println("Destination file already exists, aborting serfix.")
					return
				}
			}
		}

		// Open out file
		tempfile, err := os.Create(tempfilename)
		if err != nil {
			println(err)
		}
		// close out file
		defer tempfile.Close()

		r := bufio.NewReaderSize(infile, 2*1024*1024)

		line, err := r.ReadString('\n')
		for err == nil {
			tempfile.WriteString(lexer.ReplaceAllStringFunc(string(line), replace))

			line, err = r.ReadString('\n')
		}
		// if isPrefix {
		// 	fmt.Println(errors.New("buffer size too small"))
		// 	return
		// }
		if err != io.EOF {
			fmt.Println(err)
			return
		}

		// Close the in/out files
		if err := tempfile.Close(); err != nil {
			fmt.Println(err)
			return
		}
		if err := infile.Close(); err != nil {
			fmt.Println(err)
			return
		}

		if !newDestination {
			// Remove original file
			if err := os.Remove(filename); err != nil {
				fmt.Println(err)
				return
			}
		} else {
			// If destination exists and force flag is used, remove destination file
			if _, err := os.Stat(outfilename); err == nil {
				if !*forcePtr {
					if err := os.Remove(outfilename); err != nil {
						fmt.Println(err)
						return
					}
				}
			}
		}
		if err := os.Rename(tempfilename, outfilename); err != nil {
			fmt.Println(err)
			return
		}

	} else {
		r := bufio.NewReaderSize(os.Stdin, 2*1024*1024)

		line, isPrefix, err := r.ReadLine()
		for err == nil && !isPrefix {
			fmt.Println(lexer.ReplaceAllStringFunc(string(line), replace))

			line, isPrefix, err = r.ReadLine()
		}
		if isPrefix {
			fmt.Println(errors.New("buffer size too small"))
			return
		}
		if err != io.EOF {
			fmt.Println(err)
			return
		}
	}
}

func replace(matches string) string {
	parts := re.FindStringSubmatch(matches)
	str_len := len(parts[4]) - len(esc.FindAllString(parts[4], -1))
	return fmt.Sprintf("%s%d%s%s%s", parts[1], str_len, parts[3], parts[4], parts[5])
}

func printUsage() {
	fmt.Println("Usage: serfix [flags] filename [outfilename]")
	fmt.Println("Alt. Usage: cat filename | serfix")
	fmt.Println("")
	fmt.Println("\t -f, --force \t\t\t Force overwrite of destination file if it exists.")
	fmt.Println("\t -h, --help  \t\t\t Print serfix help.")
	fmt.Println("")
}
<|endoftext|>


<commit_before>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

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

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

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

package version

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

var CurrentGaugeVersion = &Version{0, 1, 3}

type Version struct {
	Major int
	Minor int
	Patch int
}

func ParseVersion(versionText string) (*Version, error) {
	splits := strings.Split(versionText, ".")
	if len(splits) != 3 {
		return nil, errors.New("Incorrect Version format. Version should be in the form 1.5.7")
	}
	Major, err := strconv.Atoi(splits[0])
	if err != nil {
		return nil, VersionError("major", splits[0], err)
	}
	Minor, err := strconv.Atoi(splits[1])
	if err != nil {
		return nil, VersionError("minor", splits[1], err)
	}
	Patch, err := strconv.Atoi(splits[2])
	if err != nil {
		return nil, VersionError("patch", splits[2], err)
	}

	return &Version{Major, Minor, Patch}, nil
}

func VersionError(level, text string, err error) error {
	return errors.New(fmt.Sprintf("Error parsing %s Version %s to integer. %s", level, text, err.Error()))
}

func (Version *Version) IsBetween(lower *Version, greater *Version) bool {
	return Version.IsGreaterThanEqualTo(lower) && Version.IsLesserThanEqualTo(greater)
}

func (Version *Version) IsLesserThan(version1 *Version) bool {
	return CompareVersions(Version, version1, LesserThanFunc)
}

func (Version *Version) IsGreaterThan(version1 *Version) bool {
	return CompareVersions(Version, version1, GreaterThanFunc)
}

func (Version *Version) IsLesserThanEqualTo(version1 *Version) bool {
	return Version.IsLesserThan(version1) || Version.IsEqualTo(version1)
}

func (Version *Version) IsGreaterThanEqualTo(version1 *Version) bool {
	return Version.IsGreaterThan(version1) || Version.IsEqualTo(version1)
}

func (Version *Version) IsEqualTo(version1 *Version) bool {
	return IsEqual(Version.Major, version1.Major) && IsEqual(Version.Minor, version1.Minor) && IsEqual(Version.Patch, version1.Patch)
}

func CompareVersions(first *Version, second *Version, compareFunc func(int, int) bool) bool {
	if compareFunc(first.Major, second.Major) {
		return true
	} else if IsEqual(first.Major, second.Major) {
		if compareFunc(first.Minor, second.Minor) {
			return true
		} else if IsEqual(first.Minor, second.Minor) {
			if compareFunc(first.Patch, second.Patch) {
				return true
			} else {
				return false
			}
		}
	}
	return false
}

func LesserThanFunc(first, second int) bool {
	return first < second
}

func GreaterThanFunc(first, second int) bool {
	return first > second
}

func IsEqual(first, second int) bool {
	return first == second
}

func (Version *Version) String() string {
	return fmt.Sprintf("%d.%d.%d", Version.Major, Version.Minor, Version.Patch)
}
<commit_msg>bumping verison to 0.1.4<commit_after>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

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

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

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

package version

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

var CurrentGaugeVersion = &Version{0, 1, 4}

type Version struct {
	Major int
	Minor int
	Patch int
}

func ParseVersion(versionText string) (*Version, error) {
	splits := strings.Split(versionText, ".")
	if len(splits) != 3 {
		return nil, errors.New("Incorrect Version format. Version should be in the form 1.5.7")
	}
	Major, err := strconv.Atoi(splits[0])
	if err != nil {
		return nil, VersionError("major", splits[0], err)
	}
	Minor, err := strconv.Atoi(splits[1])
	if err != nil {
		return nil, VersionError("minor", splits[1], err)
	}
	Patch, err := strconv.Atoi(splits[2])
	if err != nil {
		return nil, VersionError("patch", splits[2], err)
	}

	return &Version{Major, Minor, Patch}, nil
}

func VersionError(level, text string, err error) error {
	return errors.New(fmt.Sprintf("Error parsing %s Version %s to integer. %s", level, text, err.Error()))
}

func (Version *Version) IsBetween(lower *Version, greater *Version) bool {
	return Version.IsGreaterThanEqualTo(lower) && Version.IsLesserThanEqualTo(greater)
}

func (Version *Version) IsLesserThan(version1 *Version) bool {
	return CompareVersions(Version, version1, LesserThanFunc)
}

func (Version *Version) IsGreaterThan(version1 *Version) bool {
	return CompareVersions(Version, version1, GreaterThanFunc)
}

func (Version *Version) IsLesserThanEqualTo(version1 *Version) bool {
	return Version.IsLesserThan(version1) || Version.IsEqualTo(version1)
}

func (Version *Version) IsGreaterThanEqualTo(version1 *Version) bool {
	return Version.IsGreaterThan(version1) || Version.IsEqualTo(version1)
}

func (Version *Version) IsEqualTo(version1 *Version) bool {
	return IsEqual(Version.Major, version1.Major) && IsEqual(Version.Minor, version1.Minor) && IsEqual(Version.Patch, version1.Patch)
}

func CompareVersions(first *Version, second *Version, compareFunc func(int, int) bool) bool {
	if compareFunc(first.Major, second.Major) {
		return true
	} else if IsEqual(first.Major, second.Major) {
		if compareFunc(first.Minor, second.Minor) {
			return true
		} else if IsEqual(first.Minor, second.Minor) {
			if compareFunc(first.Patch, second.Patch) {
				return true
			} else {
				return false
			}
		}
	}
	return false
}

func LesserThanFunc(first, second int) bool {
	return first < second
}

func GreaterThanFunc(first, second int) bool {
	return first > second
}

func IsEqual(first, second int) bool {
	return first == second
}

func (Version *Version) String() string {
	return fmt.Sprintf("%d.%d.%d", Version.Major, Version.Minor, Version.Patch)
}
<|endoftext|>


<commit_before>// Copyright 2016 Marcel Gotsch. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package goserv

import (
	"fmt"
	"io"
	"net/http"
	"path"
)

type TLS struct {
	CertFile, KeyFile string
}

type Server struct {
	*Router
	Addr          string
	TLS           *TLS
	ViewRoot      string
	Renderer      Renderer
	PanicRecovery bool
}

func (s *Server) Listen(addr string) error {
	return http.ListenAndServe(addr, s)
}

func (s *Server) ListenTLS(addr, certFile, keyFile string) error {
	s.TLS = &TLS{certFile, keyFile}
	return http.ListenAndServeTLS(addr, certFile, keyFile, s)
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	res := newResponseWriter(w, s)
	req := newRequest(r)

	if s.PanicRecovery {
		defer s.handleRecovery(res, req)
	}

	s.Router.ServeHTTP(res, req)
}

func (s *Server) Static(prefix string, dir http.Dir) {
	s.Prefix(prefix, WrapHTTPHandler(http.StripPrefix(prefix, http.FileServer(dir))))
}

func (s *Server) renderView(w io.Writer, name string, locals interface{}) error {
	if s.Renderer == nil {
		panic("no renderer set")
	}

	filePath := path.Join(s.ViewRoot, name) + s.Renderer.Ext()
	return s.Renderer.RenderAndWrite(w, filePath, locals)
}

func (s *Server) handleRecovery(res ResponseWriter, req *Request) {
	if r := recover(); r != nil {
		s.ErrorHandler.ServeHTTP(res, req, fmt.Errorf("Panic: %v", r))
	}
}

func NewServer() *Server {
	s := &Server{NewRouter(), "", nil, "", nil, false}
	s.ErrorHandler = StdErrorHandler

	return s
}
<commit_msg>Improve NewServer() code readability<commit_after>// Copyright 2016 Marcel Gotsch. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package goserv

import (
	"fmt"
	"io"
	"net/http"
	"path"
)

type TLS struct {
	CertFile, KeyFile string
}

type Server struct {
	*Router
	Addr          string
	TLS           *TLS
	ViewRoot      string
	Renderer      Renderer
	PanicRecovery bool
}

func (s *Server) Listen(addr string) error {
	return http.ListenAndServe(addr, s)
}

func (s *Server) ListenTLS(addr, certFile, keyFile string) error {
	s.TLS = &TLS{certFile, keyFile}
	return http.ListenAndServeTLS(addr, certFile, keyFile, s)
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	res := newResponseWriter(w, s)
	req := newRequest(r)

	if s.PanicRecovery {
		defer s.handleRecovery(res, req)
	}

	s.Router.ServeHTTP(res, req)
}

func (s *Server) Static(prefix string, dir http.Dir) {
	s.Prefix(prefix, WrapHTTPHandler(http.StripPrefix(prefix, http.FileServer(dir))))
}

func (s *Server) renderView(w io.Writer, name string, locals interface{}) error {
	if s.Renderer == nil {
		panic("no renderer set")
	}

	filePath := path.Join(s.ViewRoot, name) + s.Renderer.Ext()
	return s.Renderer.RenderAndWrite(w, filePath, locals)
}

func (s *Server) handleRecovery(res ResponseWriter, req *Request) {
	if r := recover(); r != nil {
		s.ErrorHandler.ServeHTTP(res, req, fmt.Errorf("Panic: %v", r))
	}
}

func NewServer() *Server {
	s := &Server{
		Router:        NewRouter(),
		Addr:          "",
		TLS:           nil,
		ViewRoot:      "",
		Renderer:      nil,
		PanicRecovery: false,
	}

	s.ErrorHandler = StdErrorHandler

	return s
}
<|endoftext|>


<commit_before>package object

// Mutator receives an object, mutates it, or errors
type Mutator interface {
	Mutate(o *Object) error
}
<commit_msg>chore(object): remove unused mutator interface<commit_after><|endoftext|>


<commit_before>package main

import (
	"bytes"
	"io"
	"log"
	"os"
	"path/filepath"
	"time"

	"github.com/nictuku/stardew-rocks/parser"
	"github.com/nictuku/stardew-rocks/stardb"
	"github.com/nictuku/stardew-rocks/view"

	"github.com/streadway/amqp"
)

func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
	}
}

func wwwDir() string {
	home := os.Getenv("HOME")
	if home == "" {
		home = string(filepath.Separator)
	}
	return filepath.Clean(filepath.Join(home, "www"))
}

func main() {
	conn, err := amqp.Dial("amqp://guest:guest@amqp.stardew.rocks:5672/")
	failOnError(err, "Failed to connect to RabbitMQ")
	defer conn.Close()

	ch, err := conn.Channel()
	failOnError(err, "Failed to open a channel")
	defer ch.Close()
	for _, exc := range []string{"SaveGameInfo-1", "OtherFiles-1"} {
		err = ch.ExchangeDeclare(
			exc,      // name
			"fanout", // type
			false,    // durable
			false,    // auto-deleted
			false,    // internal
			false,    // no-wait
			nil,      // arguments
		)

		failOnError(err, "Failed to declare an exchange")
	}
	q, err := ch.QueueDeclare(
		"",    // name
		false, // durable
		false, // delete when usused
		true,  // exclusive
		false, // no-wait
		nil,   // arguments
	)
	failOnError(err, "Failed to declare a queue")

	err = ch.QueueBind(
		q.Name,         // queue name
		"",             // routing key
		"OtherFiles-1", // exchange
		false,
		nil)
	failOnError(err, "Failed to bind a queue")

	msgs, err := ch.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto-ack
		false,  // exclusive
		false,  // no-local
		false,  // no-wait
		nil,    // args
	)
	failOnError(err, "Failed to register a consumer")

	count := 0

	farmMap := parser.LoadFarmMap()

	go func() {
		for d := range msgs {
			count++
			var reader io.Reader = bytes.NewReader(d.Body)
			// The content is usually gzip encoded by we don't have to worry about that.
			// Apparently rabbitMQ or the Go library will decompress it transparently.
			// d.ContentEncoding == "gzip" {
			saveGame, err := parser.ParseSaveGame(reader)
			if err != nil {
				log.Print("Error parsing saved game:", err)
				continue
			}
			if saveGame.Player.Name == "" {
				log.Print("Ignoring save with blank player name")
				continue
			}

			ts := time.Now()

			farm, _, err := stardb.FindOrCreateFarm(stardb.FarmCollection, saveGame.UniqueIDForThisGame, saveGame.Player.Name, saveGame.Player.FarmName)
			if err != nil {
				log.Print("Error fetching farm ID:", err)
				continue
			}
			// GridFs screenshot write. We write this first because as soon as we change
			// the save game (below) users of the site will be given that save's timestamp and
			// will try to open the screenshot. See issue #72.
			// But we treat this screenshot write as optional - just in case the
			// renderer is broken or something, we continue anyway because the most
			// valuable data are the save games.
			fs, err := stardb.NewScreenshotWriter(farm, ts)
			if err != nil {
				log.Print("Error writing grid screenshot:", err)
			} else {
				if err := view.WriteImage(farmMap, saveGame, fs); err != nil {
					log.Print(err)
				} else {
					log.Printf("Wrote grid map file %v", farm.ScreenshotPath())
				}
				fs.Close()
			}

			// GridFS XML save file write.
			// TODO: broken saves (length 0)
			if err := stardb.WriteSaveFile(farm, d.Body, ts); err != nil {
				log.Print("write save file:", err)
				continue
			}
			// The save file is the most critical and it's been updated, so we should be fine.
			if err := stardb.UpdateFarmTime(farm.InternalID, ts); err != nil {
				log.Print("update farm time:", err)
				continue
			}
			if fi, err := stardb.FarmInfoFromSaveGame(saveGame); err != nil {
				log.Print("farm info from save game:", err)
				continue
			} else {
				if err := stardb.UpdateFarmInfo(farm.InternalID, fi); err != nil {
					log.Print("update farm info:", err)
					continue
				}
			}

		}
		log.Printf("Total messages so far: %d", count)

	}()

	log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
	select {}
}
<commit_msg>Revert "Write the screenshot first, optionally. Should help with issue #72"<commit_after>package main

import (
	"bytes"
	"io"
	"log"
	"os"
	"path/filepath"
	"time"

	"github.com/nictuku/stardew-rocks/parser"
	"github.com/nictuku/stardew-rocks/stardb"
	"github.com/nictuku/stardew-rocks/view"

	"github.com/streadway/amqp"
)

func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
	}
}

func wwwDir() string {
	home := os.Getenv("HOME")
	if home == "" {
		home = string(filepath.Separator)
	}
	return filepath.Clean(filepath.Join(home, "www"))
}

func main() {
	conn, err := amqp.Dial("amqp://guest:guest@amqp.stardew.rocks:5672/")
	failOnError(err, "Failed to connect to RabbitMQ")
	defer conn.Close()

	ch, err := conn.Channel()
	failOnError(err, "Failed to open a channel")
	defer ch.Close()
	for _, exc := range []string{"SaveGameInfo-1", "OtherFiles-1"} {
		err = ch.ExchangeDeclare(
			exc,      // name
			"fanout", // type
			false,    // durable
			false,    // auto-deleted
			false,    // internal
			false,    // no-wait
			nil,      // arguments
		)

		failOnError(err, "Failed to declare an exchange")
	}
	q, err := ch.QueueDeclare(
		"",    // name
		false, // durable
		false, // delete when usused
		true,  // exclusive
		false, // no-wait
		nil,   // arguments
	)
	failOnError(err, "Failed to declare a queue")

	err = ch.QueueBind(
		q.Name,         // queue name
		"",             // routing key
		"OtherFiles-1", // exchange
		false,
		nil)
	failOnError(err, "Failed to bind a queue")

	msgs, err := ch.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto-ack
		false,  // exclusive
		false,  // no-local
		false,  // no-wait
		nil,    // args
	)
	failOnError(err, "Failed to register a consumer")

	count := 0

	farmMap := parser.LoadFarmMap()

	go func() {
		for d := range msgs {
			count++
			var reader io.Reader = bytes.NewReader(d.Body)
			// The content is usually gzip encoded by we don't have to worry about that.
			// Apparently rabbitMQ or the Go library will decompress it transparently.
			// d.ContentEncoding == "gzip" {
			saveGame, err := parser.ParseSaveGame(reader)
			if err != nil {
				log.Print("Error parsing saved game:", err)
				continue
			}
			if saveGame.Player.Name == "" {
				log.Print("Ignoring save with blank player name")
				continue
			}

			ts := time.Now()

			farm, _, err := stardb.FindOrCreateFarm(stardb.FarmCollection, saveGame.UniqueIDForThisGame, saveGame.Player.Name, saveGame.Player.FarmName)
			if err != nil {
				log.Print("Error fetching farm ID:", err)
				continue
			}

			// GridFS XML save file write.
			// TODO: broken saves (length 0)
			if err := stardb.WriteSaveFile(farm, d.Body, ts); err != nil {
				log.Print("write save file:", err)
				continue
			}
			// The save file is the most critical and it's been updated, so we should be fine.
			if err := stardb.UpdateFarmTime(farm.InternalID, ts); err != nil {
				log.Print("update farm time:", err)
				continue
			}
			if fi, err := stardb.FarmInfoFromSaveGame(saveGame); err != nil {
				log.Print("farm info from save game:", err)
				continue
			} else {
				if err := stardb.UpdateFarmInfo(farm.InternalID, fi); err != nil {
					log.Print("update farm info:", err)
					continue
				}
			}

			// GridFs screenshot write.
			fs, err := stardb.NewScreenshotWriter(farm, ts)
			if err != nil {
				log.Print("Error writing grid screenshot:", err)
				continue
			}

			if err := view.WriteImage(farmMap, saveGame, fs); err != nil {
				log.Print(err)
				fs.Close()
				continue
			}
			fs.Close()
			log.Printf("Wrote grid map file %v", farm.ScreenshotPath())

		}
		log.Printf("Total messages so far: %d", count)

	}()

	log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
	select {}
}
<|endoftext|>


<commit_before>package version

// VERSION ...
const VERSION = "2.4.3"
<commit_msg>version bump to 2.4.4 (#149)<commit_after>package version

// VERSION ...
const VERSION = "2.4.4"
<|endoftext|>


<commit_before>package ingress

import (
	"regexp"
	"strings"

	"github.com/traefik/traefik/v2/pkg/config/dynamic"
	"github.com/traefik/traefik/v2/pkg/config/label"
)

const (
	// https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/#syntax-and-character-set
	annotationsPrefix = "traefik.ingress.kubernetes.io/"
)

// RouterConfig is the router's root configuration from annotations.
type RouterConfig struct {
	Router *RouterIng `json:"router,omitempty"`
}

// RouterIng is the router's configuration from annotations.
type RouterIng struct {
	PathMatcher string                   `json:"pathMatcher,omitempty"`
	EntryPoints []string                 `json:"entryPoints,omitempty"`
	Middlewares []string                 `json:"middlewares,omitempty"`
	Priority    int                      `json:"priority,omitempty"`
	TLS         *dynamic.RouterTLSConfig `json:"tls,omitempty" label:"allowEmpty"`
}

// SetDefaults sets the default values.
func (r *RouterIng) SetDefaults() {
	r.PathMatcher = defaultPathMatcher
}

// ServiceConfig is the service's root configuration from annotations.
type ServiceConfig struct {
	Service *ServiceIng `json:"service,omitempty"`
}

// ServiceIng is the service's configuration from annotations.
type ServiceIng struct {
	ServersScheme  string          `json:"serversScheme,omitempty"`
	PassHostHeader *bool           `json:"passHostHeader"`
	Sticky         *dynamic.Sticky `json:"sticky,omitempty" label:"allowEmpty"`
}

// SetDefaults sets the default values.
func (s *ServiceIng) SetDefaults() {
	s.PassHostHeader = func(v bool) *bool { return &v }(true)
}

func parseRouterConfig(annotations map[string]string) (*RouterConfig, error) {
	labels := convertAnnotations(annotations)
	if len(labels) == 0 {
		return nil, nil
	}

	cfg := &RouterConfig{}

	err := label.Decode(labels, cfg, "traefik.router.")
	if err != nil {
		return nil, err
	}

	return cfg, nil
}

func parseServiceConfig(annotations map[string]string) (*ServiceConfig, error) {
	labels := convertAnnotations(annotations)
	if len(labels) == 0 {
		return nil, nil
	}

	cfg := &ServiceConfig{}

	err := label.Decode(labels, cfg, "traefik.service.")
	if err != nil {
		return nil, err
	}

	return cfg, nil
}

func convertAnnotations(annotations map[string]string) map[string]string {
	if len(annotations) == 0 {
		return nil
	}

	exp := regexp.MustCompile(`(.+)\.(\w+)\.(\d+)\.(.+)`)

	result := make(map[string]string)

	for key, value := range annotations {
		if !strings.HasPrefix(key, annotationsPrefix) {
			continue
		}

		newKey := strings.ReplaceAll(key, "ingress.kubernetes.io/", "")

		if exp.MatchString(newKey) {
			newKey = exp.ReplaceAllString(newKey, "$1.$2[$3].$4")
		}

		result[newKey] = value
	}

	return result
}
<commit_msg>Compile kubernetes ingress annotation regex only once<commit_after>package ingress

import (
	"regexp"
	"strings"

	"github.com/traefik/traefik/v2/pkg/config/dynamic"
	"github.com/traefik/traefik/v2/pkg/config/label"
)

const (
	// https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/#syntax-and-character-set
	annotationsPrefix = "traefik.ingress.kubernetes.io/"
)

var annotationsRegex = regexp.MustCompile(`(.+)\.(\w+)\.(\d+)\.(.+)`)

// RouterConfig is the router's root configuration from annotations.
type RouterConfig struct {
	Router *RouterIng `json:"router,omitempty"`
}

// RouterIng is the router's configuration from annotations.
type RouterIng struct {
	PathMatcher string                   `json:"pathMatcher,omitempty"`
	EntryPoints []string                 `json:"entryPoints,omitempty"`
	Middlewares []string                 `json:"middlewares,omitempty"`
	Priority    int                      `json:"priority,omitempty"`
	TLS         *dynamic.RouterTLSConfig `json:"tls,omitempty" label:"allowEmpty"`
}

// SetDefaults sets the default values.
func (r *RouterIng) SetDefaults() {
	r.PathMatcher = defaultPathMatcher
}

// ServiceConfig is the service's root configuration from annotations.
type ServiceConfig struct {
	Service *ServiceIng `json:"service,omitempty"`
}

// ServiceIng is the service's configuration from annotations.
type ServiceIng struct {
	ServersScheme  string          `json:"serversScheme,omitempty"`
	PassHostHeader *bool           `json:"passHostHeader"`
	Sticky         *dynamic.Sticky `json:"sticky,omitempty" label:"allowEmpty"`
}

// SetDefaults sets the default values.
func (s *ServiceIng) SetDefaults() {
	s.PassHostHeader = func(v bool) *bool { return &v }(true)
}

func parseRouterConfig(annotations map[string]string) (*RouterConfig, error) {
	labels := convertAnnotations(annotations)
	if len(labels) == 0 {
		return nil, nil
	}

	cfg := &RouterConfig{}

	err := label.Decode(labels, cfg, "traefik.router.")
	if err != nil {
		return nil, err
	}

	return cfg, nil
}

func parseServiceConfig(annotations map[string]string) (*ServiceConfig, error) {
	labels := convertAnnotations(annotations)
	if len(labels) == 0 {
		return nil, nil
	}

	cfg := &ServiceConfig{}

	err := label.Decode(labels, cfg, "traefik.service.")
	if err != nil {
		return nil, err
	}

	return cfg, nil
}

func convertAnnotations(annotations map[string]string) map[string]string {
	if len(annotations) == 0 {
		return nil
	}

	result := make(map[string]string)

	for key, value := range annotations {
		if !strings.HasPrefix(key, annotationsPrefix) {
			continue
		}

		newKey := strings.ReplaceAll(key, "ingress.kubernetes.io/", "")

		if annotationsRegex.MatchString(newKey) {
			newKey = annotationsRegex.ReplaceAllString(newKey, "$1.$2[$3].$4")
		}

		result[newKey] = value
	}

	return result
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"io"
	"log"
	"os"
	"path/filepath"
	"time"

	"github.com/nictuku/stardew-rocks/parser"
	"github.com/nictuku/stardew-rocks/stardb"
	"github.com/nictuku/stardew-rocks/view"

	"github.com/streadway/amqp"
)

func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
	}
}

func wwwDir() string {
	home := os.Getenv("HOME")
	if home == "" {
		home = string(filepath.Separator)
	}
	return filepath.Clean(filepath.Join(home, "www"))
}

func main() {
	conn, err := amqp.Dial("amqp://guest:guest@amqp.stardew.rocks:5672/")
	failOnError(err, "Failed to connect to RabbitMQ")
	defer conn.Close()

	ch, err := conn.Channel()
	failOnError(err, "Failed to open a channel")
	defer ch.Close()
	for _, exc := range []string{"SaveGameInfo-1", "OtherFiles-1"} {
		err = ch.ExchangeDeclare(
			exc,      // name
			"fanout", // type
			false,    // durable
			false,    // auto-deleted
			false,    // internal
			false,    // no-wait
			nil,      // arguments
		)

		failOnError(err, "Failed to declare an exchange")
	}
	q, err := ch.QueueDeclare(
		"",    // name
		false, // durable
		false, // delete when usused
		true,  // exclusive
		false, // no-wait
		nil,   // arguments
	)
	failOnError(err, "Failed to declare a queue")

	err = ch.QueueBind(
		q.Name,         // queue name
		"",             // routing key
		"OtherFiles-1", // exchange
		false,
		nil)
	failOnError(err, "Failed to bind a queue")

	msgs, err := ch.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto-ack
		false,  // exclusive
		false,  // no-local
		false,  // no-wait
		nil,    // args
	)
	failOnError(err, "Failed to register a consumer")

	count := 0

	farmMap := parser.LoadFarmMap()

	go func() {
		for d := range msgs {
			count++
			var reader io.Reader = bytes.NewReader(d.Body)
			// The content is usually gzip encoded by we don't have to worry about that.
			// Apparently rabbitMQ or the Go library will decompress it transparently.
			// d.ContentEncoding == "gzip" {
			saveGame, err := parser.ParseSaveGame(reader)
			if err != nil {
				log.Print("Error parsing saved game:", err)
				continue
			}
			if saveGame.Player.Name == "" {
				log.Print("Ignoring save with blank player name")
				continue
			}

			ts := time.Now()

			farm, _, err := stardb.FindOrCreateFarm(stardb.FarmCollection, saveGame.UniqueIDForThisGame, saveGame.Player.Name, saveGame.Player.FarmName)
			if err != nil {
				log.Print("Error fetching farm ID:", err)
				continue
			}

			// GridFS XML save file write.
			// TODO: broken saves (length 0)
			if err := stardb.WriteSaveFile(farm, d.Body, ts); err != nil {
				log.Print("write save file:", err)
				continue
			}
			// The save file is the most critical and it's been updated, so we should be fine.
			if err := stardb.UpdateFarmTime(farm.InternalID, ts); err != nil {
				log.Print("update farm time:", err)
				continue
			}
			if fi, err := stardb.FarmInfoFromSaveGame(saveGame); err != nil {
				log.Print("farm info from save game:", err)
				continue
			} else {
				if err := stardb.UpdateFarmInfo(farm.InternalID, fi); err != nil {
					log.Print("update farm info:", err)
					continue
				}
			}
			if fi, err := stardb.FarmHistoryFromSaveGame(farm.InternalID, saveGame, ts); err != nil {
				log.Print("farm history from save game:", err)
				continue
			} else {
				if err := stardb.InsertFarmHistory(farm.InternalID, fi); err != nil {
					log.Print("update farm history failed:", err)
					continue
				}
				log.Println("Updated farm history")
			}

			// GridFs screenshot write.
			fs, err := stardb.NewScreenshotWriter(farm, ts)
			if err != nil {
				log.Print("Error writing grid screenshot:", err)
				continue
			}

			if err := view.WriteImage(farmMap, saveGame, fs); err != nil {
				log.Print(err)
				fs.Close()
				continue
			}
			fs.Close()
			log.Printf("Wrote grid map file %v", farm.ScreenshotPath())

		}
		log.Printf("Total messages so far: %d", count)

	}()

	log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
	select {}
}
<commit_msg>subscriber fix<commit_after>package main

import (
	"bytes"
	"io"
	"log"
	"os"
	"path/filepath"
	"time"

	"github.com/nictuku/stardew-rocks/parser"
	"github.com/nictuku/stardew-rocks/stardb"
	"github.com/nictuku/stardew-rocks/view"

	"github.com/streadway/amqp"
)

func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
	}
}

func wwwDir() string {
	home := os.Getenv("HOME")
	if home == "" {
		home = string(filepath.Separator)
	}
	return filepath.Clean(filepath.Join(home, "www"))
}

func main() {
	conn, err := amqp.Dial("amqp://guest:guest@amqp.stardew.rocks:5672/")
	failOnError(err, "Failed to connect to RabbitMQ")
	defer conn.Close()

	ch, err := conn.Channel()
	failOnError(err, "Failed to open a channel")
	defer ch.Close()
	for _, exc := range []string{"SaveGameInfo-1", "OtherFiles-1"} {
		err = ch.ExchangeDeclare(
			exc,      // name
			"fanout", // type
			false,    // durable
			false,    // auto-deleted
			false,    // internal
			false,    // no-wait
			nil,      // arguments
		)

		failOnError(err, "Failed to declare an exchange")
	}
	q, err := ch.QueueDeclare(
		"",    // name
		false, // durable
		false, // delete when usused
		true,  // exclusive
		false, // no-wait
		nil,   // arguments
	)
	failOnError(err, "Failed to declare a queue")

	err = ch.QueueBind(
		q.Name,         // queue name
		"",             // routing key
		"OtherFiles-1", // exchange
		false,
		nil)
	failOnError(err, "Failed to bind a queue")

	msgs, err := ch.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto-ack
		false,  // exclusive
		false,  // no-local
		false,  // no-wait
		nil,    // args
	)
	failOnError(err, "Failed to register a consumer")

	count := 0

	farmMap := parser.LoadFarmMap()

	go func() {
		for d := range msgs {
			count++
			var reader io.Reader = bytes.NewReader(d.Body)
			// The content is usually gzip encoded by we don't have to worry about that.
			// Apparently rabbitMQ or the Go library will decompress it transparently.
			// d.ContentEncoding == "gzip" {
			saveGame, err := parser.ParseSaveGame(reader)
			if err != nil {
				log.Print("Error parsing saved game:", err)
				continue
			}
			if saveGame.Player.Name == "" {
				log.Print("Ignoring save with blank player name")
				continue
			}

			ts := time.Now()

			farm, _, err := stardb.FindOrCreateFarm(stardb.FarmCollection, saveGame.UniqueIDForThisGame, saveGame.Player.Name, saveGame.Player.FarmName)
			if err != nil {
				log.Print("Error fetching farm ID:", err)
				continue
			}

			// GridFS XML save file write.
			// TODO: broken saves (length 0)
			if err := stardb.WriteSaveFile(farm, d.Body, ts); err != nil {
				log.Print("write save file:", err)
				continue
			}
			// The save file is the most critical and it's been updated, so we should be fine.
			if err := stardb.UpdateFarmTime(farm.InternalID, ts); err != nil {
				log.Print("update farm time:", err)
				continue
			}
			if fi, err := stardb.FarmInfoFromSaveGame(saveGame); err != nil {
				log.Print("farm info from save game:", err)
				continue
			} else {
				if err := stardb.UpdateFarmInfo(farm.InternalID, fi); err != nil {
					log.Print("update farm info:", err)
					continue
				}
			}
			if fi, err := stardb.FarmHistoryFromSaveGame(farm.InternalID, saveGame, int(ts.Unix())); err != nil {
				log.Print("farm history from save game:", err)
				continue
			} else {
				if err := stardb.InsertFarmHistory(farm.InternalID, fi); err != nil {
					log.Print("update farm history failed:", err)
					continue
				}
				log.Println("Updated farm history")
			}

			// GridFs screenshot write.
			fs, err := stardb.NewScreenshotWriter(farm, ts)
			if err != nil {
				log.Print("Error writing grid screenshot:", err)
				continue
			}

			if err := view.WriteImage(farmMap, saveGame, fs); err != nil {
				log.Print(err)
				fs.Close()
				continue
			}
			fs.Close()
			log.Printf("Wrote grid map file %v", farm.ScreenshotPath())

		}
		log.Printf("Total messages so far: %d", count)

	}()

	log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
	select {}
}
<|endoftext|>


<commit_before>package version

import (
	"fmt"

	"github.com/github/hub/git"
)

var Version = "2.11.0"

func FullVersion() (string, error) {
	gitVersion, err := git.Version()
	if err != nil {
		gitVersion = "git version (unavailable)"
	}
	return fmt.Sprintf("%s\nhub version %s", gitVersion, Version), err
}
<commit_msg>hub 2.11.1<commit_after>package version

import (
	"fmt"

	"github.com/github/hub/git"
)

var Version = "2.11.1"

func FullVersion() (string, error) {
	gitVersion, err := git.Version()
	if err != nil {
		gitVersion = "git version (unavailable)"
	}
	return fmt.Sprintf("%s\nhub version %s", gitVersion, Version), err
}
<|endoftext|>


<commit_before>package bamstats

import (
	log "github.com/Sirupsen/logrus"
	"github.com/brentp/irelate/interfaces"
	"github.com/brentp/irelate/parsers"
)

type location struct {
	chrom string
	start int
	end   int
}

func (s location) Chrom() string {
	return s.chrom
}
func (s location) Start() uint32 {
	return uint32(s.start)
}
func (s location) End() uint32 {
	return uint32(s.end)
}

func getElements(pos location, buf interfaces.RelatableIterator, elems map[string]uint8) {
	for {
		feature, err := buf.Next()
		if err != nil {
			break
		}
		start := max(pos.Start(), feature.Start())
		end := min(pos.End(), feature.End())
		if end <= start {
			continue
		}
		log.Debug(feature)
		if interval, ok := feature.(*parsers.Interval); ok {
			t := string(interval.Fields[3])
			if t != "gene" {
				elems[t]++
			}
		}
	}
}
<commit_msg>Update location.go<commit_after>package bamstats

import (
	log "github.com/Sirupsen/logrus"
	I "github.com/brentp/irelate/interfaces"
	"github.com/brentp/irelate/parsers"
)

type location struct {
	chrom string
	start int
	end   int
}

func (s location) Chrom() string {
	return s.chrom
}
func (s location) Start() uint32 {
	return uint32(s.start)
}
func (s location) End() uint32 {
	return uint32(s.end)
}

func getElements(pos I.IPosition, buf I.RelatableIterator, elems map[string]uint8) {
	for {
		feature, err := buf.Next()
		if err != nil {
			break
		}
		start := max(pos.Start(), feature.Start())
		end := min(pos.End(), feature.End())
		if end <= start {
			continue
		}
		log.Debug(feature)
		if interval, ok := feature.(*parsers.Interval); ok {
			t := string(interval.Fields[3])
			if t != "gene" {
				elems[t]++
			}
		}
	}
}

func getElements1(pos I.IPosition, buf []I.Relatable, elems map[string]uint8) {
	for _, feature := range buf {
		// start := max(pos.Start(), feature.Start())
		// end := min(pos.End(), feature.End())
		// if end <= start {
		// 	continue
		// }
		log.Debug(feature)
		if interval, ok := feature.(*parsers.Interval); ok {
			t := string(interval.Fields[3])
			if t != "gene" {
				elems[t]++
			}
		}
	}
}
<|endoftext|>