<commit_before>// Package gpx provides convenience types for reading and writing GPX
// documents.
// See http://www.topografix.com/gpx.asp.
package gpx

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

const timeLayout = "2006-01-02T15:04:05.999999999Z"

type BoundsType struct {
	MinLat float64 `xml:"minlat,attr"`
	MinLon float64 `xml:"minlon,attr"`
	MaxLat float64 `xml:"maxlat,attr"`
	MaxLon float64 `xml:"maxlon,attr"`
}

type CopyrightType struct {
	Author  string `xml:"author,attr"`
	Year    int    `xml:"year,omitempty"`
	License string `xml:"license,omitempty"`
}

type ExtensionsType struct {
	XML []byte `xml:",innerxml"`
}

type GPXType struct {
	XMLName    string          `xml:"gpx"`
	Version    string          `xml:"version,attr"`
	Creator    string          `xml:"creator,attr"`
	Metadata   *MetadataType   `xml:"metadata,omitempty"`
	Wpt        []*WptType      `xml:"wpt,omitempty"`
	Rte        []*RteType      `xml:"rte,omitempty"`
	Trk        []*TrkType      `xml:"trk,omitempty"`
	Extensions *ExtensionsType `xml:"extensions"`
}

type LinkType struct {
	HREF string `xml:"href,attr"`
	Text string `xml:"text,omitempty"`
	Type string `xml:"type,omitempty"`
}

type PersonType struct {
	Name  string    `xml:"name,omitempty"`
	Email string    `xml:"email,omitempty"`
	Link  *LinkType `xml:"link,omitempty"`
}

type MetadataType struct {
	Name       string          `xml:"name,omitempty"`
	Desc       string          `xml:"desc,omitempty"`
	Author     *PersonType     `xml:"author,omitempty"`
	Copyright  *CopyrightType  `xml:"copyright,omitempty"`
	Link       []*LinkType     `xml:"link,omitempty"`
	Time       time.Time       `xml:"time,omitempty"`
	Keywords   string          `xml:"keywords,omitempty"`
	Bounds     *BoundsType     `xml:"bounds,omitempty"`
	Extensions *ExtensionsType `xml:"extensions"`
}

type RteType struct {
	Name       string          `xml:"name,omitempty"`
	Cmt        string          `xml:"cmt,omitempty"`
	Desc       string          `xml:"desc,omitempty"`
	Src        string          `xml:"src,omitempty"`
	Link       []*LinkType     `xml:"link,omitempty"`
	Number     int             `xml:"number,omitempty"`
	Type       string          `xml:"type,omitempty"`
	Extensions *ExtensionsType `xml:"extensions"`
	RtePt      []*WptType      `xml:"rtept,omitempty"`
}

type TrkSegType struct {
	TrkPt      []*WptType      `xml:"trkpt,omitempty"`
	Extensions *ExtensionsType `xml:"extensions"`
}

type TrkType struct {
	Name       string          `xml:"name,omitempty"`
	Cmt        string          `xml:"cmt,omitempty"`
	Desc       string          `xml:"desc,omitempty"`
	Src        string          `xml:"src,omitempty"`
	Link       []*LinkType     `xml:"link,omitempty"`
	Number     int             `xml:"number,omitempty"`
	Type       string          `xml:"type,omitempty"`
	Extensions *ExtensionsType `xml:"extensions"`
	TrkSeg     []*TrkSegType   `xml:"trkseg,omitempty"`
}

type WptType struct {
	Lat          float64
	Lon          float64
	Ele          float64
	Time         time.Time
	MagVar       float64
	GeoidHeight  float64
	Name         string
	Cmt          string
	Desc         string
	Src          string
	Link         []*LinkType
	Sym          string
	Type         string
	Fix          string
	Sat          int
	HDOP         float64
	VDOP         float64
	PDOP         float64
	AgeOfGPSData float64
	DGPSID       []int
	Extensions   *ExtensionsType
}

func emitIntElement(e *xml.Encoder, localName string, value int) error {
	return emitStringElement(e, localName, strconv.FormatInt(int64(value), 10))
}

func emitStringElement(e *xml.Encoder, localName, value string) error {
	return e.EncodeElement(value, xml.StartElement{Name: xml.Name{Local: localName}})
}

func maybeEmitFloatElement(e *xml.Encoder, localName string, value float64) error {
	if value == 0.0 {
		return nil
	}
	return emitStringElement(e, localName, strconv.FormatFloat(value, 'f', -1, 64))
}

func maybeEmitIntElement(e *xml.Encoder, localName string, value int) error {
	if value == 0 {
		return nil
	}
	return emitIntElement(e, localName, value)
}

func maybeEmitStringElement(e *xml.Encoder, localName, value string) error {
	if value == "" {
		return nil
	}
	return emitStringElement(e, localName, value)
}

func (w *WptType) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	latAttr := xml.Attr{
		Name:  xml.Name{Local: "lat"},
		Value: strconv.FormatFloat(w.Lat, 'f', -1, 64),
	}
	lonAttr := xml.Attr{
		Name:  xml.Name{Local: "lon"},
		Value: strconv.FormatFloat(w.Lon, 'f', -1, 64),
	}
	start.Attr = append(start.Attr, latAttr, lonAttr)
	if err := e.EncodeToken(start); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "ele", w.Ele); err != nil {
		return err
	}
	if !w.Time.IsZero() {
		if err := maybeEmitStringElement(e, "time", w.Time.UTC().Format(timeLayout)); err != nil {
			return err
		}
	}
	if err := maybeEmitFloatElement(e, "magvar", w.MagVar); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "geoidheight", w.GeoidHeight); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "name", w.Name); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "cmt", w.Cmt); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "desc", w.Desc); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "src", w.Src); err != nil {
		return err
	}
	if w.Link != nil {
		if err := e.EncodeElement(w.Link, xml.StartElement{Name: xml.Name{Local: "link"}}); err != nil {
			return err
		}
	}
	if err := maybeEmitStringElement(e, "sym", w.Sym); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "type", w.Type); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "fix", w.Fix); err != nil {
		return err
	}
	if err := maybeEmitIntElement(e, "sat", w.Sat); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "hdop", w.HDOP); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "vdop", w.VDOP); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "pdop", w.PDOP); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "ageofgpsdata", w.AgeOfGPSData); err != nil {
		return err
	}
	for _, dgpsid := range w.DGPSID {
		if err := emitIntElement(e, "dgpsid", dgpsid); err != nil {
			return err
		}
	}
	// FIXME Encode extensions
	return e.EncodeToken(start.End())
}

func (g *GPXType) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	start = xml.StartElement{
		Name: xml.Name{Local: "gpx"},
		Attr: []xml.Attr{
			xml.Attr{
				Name:  xml.Name{Local: "version"},
				Value: g.Version,
			},
			xml.Attr{
				Name:  xml.Name{Local: "creator"},
				Value: g.Creator,
			},
			xml.Attr{
				Name:  xml.Name{Local: "xmlns:xsi"},
				Value: "http://www.w3.org/2001/XMLSchema-instance",
			},
			xml.Attr{
				Name:  xml.Name{Local: "xmlns"},
				Value: "http://www.topografix.com/GPX/1/0",
			},
			xml.Attr{
				Name:  xml.Name{Local: "xsi:schemaLocation"},
				Value: "http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd",
			},
		},
	}
	if err := e.EncodeToken(start); err != nil {
		return err
	}
	if err := e.EncodeElement(g.Wpt, xml.StartElement{Name: xml.Name{Local: "wpt"}}); err != nil {
		return err
	}
	if err := e.EncodeElement(g.Rte, xml.StartElement{Name: xml.Name{Local: "rte"}}); err != nil {
		return err
	}
	if err := e.EncodeElement(g.Trk, xml.StartElement{Name: xml.Name{Local: "trk"}}); err != nil {
		return err
	}
	return e.EncodeToken(start.End())
}

func (w *WptType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var e struct {
		Lat          float64         `xml:"lat,attr"`
		Lon          float64         `xml:"lon,attr"`
		Ele          float64         `xml:"ele"`
		Time         string          `xml:"time"`
		MagVar       float64         `xml:"magvar"`
		GeoidHeight  float64         `xml:"geoidheight"`
		Name         string          `xml:"name"`
		Cmt          string          `xml:"cmt"`
		Desc         string          `xml:"desc"`
		Src          string          `xml:"src"`
		Link         []*LinkType     `xml:"link"`
		Sym          string          `xml:"sym"`
		Type         string          `xml:"type"`
		Fix          string          `xml:"fix"`
		Sat          int             `xml:"sat"`
		HDOP         float64         `xml:"hdop"`
		VDOP         float64         `xml:"vdop"`
		PDOP         float64         `xml:"pdop"`
		AgeOfGPSData float64         `xml:"ageofgpsdata"`
		DGPSID       []int           `xml:"dgpsid"`
		Extensions   *ExtensionsType `xml:"extensions"`
	}
	if err := d.DecodeElement(&e, &start); err != nil {
		return err
	}
	*w = WptType{
		Lat:          e.Lat,
		Lon:          e.Lon,
		Ele:          e.Ele,
		MagVar:       e.MagVar,
		GeoidHeight:  e.GeoidHeight,
		Name:         e.Name,
		Cmt:          e.Cmt,
		Desc:         e.Desc,
		Src:          e.Src,
		Link:         e.Link,
		Sym:          e.Sym,
		Type:         e.Type,
		Fix:          e.Fix,
		Sat:          e.Sat,
		HDOP:         e.HDOP,
		VDOP:         e.VDOP,
		PDOP:         e.PDOP,
		AgeOfGPSData: e.AgeOfGPSData,
		DGPSID:       e.DGPSID,
		Extensions:   e.Extensions,
	}
	if e.Time != "" {
		t, err := time.ParseInLocation(timeLayout, e.Time, time.UTC)
		if err != nil {
			return err
		}
		w.Time = t
	}
	return nil
}
<commit_msg>Document exported types<commit_after>// Package gpx provides convenience types for reading and writing GPX
// documents.
// See http://www.topografix.com/gpx.asp.
package gpx

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

const timeLayout = "2006-01-02T15:04:05.999999999Z"

// A BoundsType is a boundsType.
type BoundsType struct {
	MinLat float64 `xml:"minlat,attr"`
	MinLon float64 `xml:"minlon,attr"`
	MaxLat float64 `xml:"maxlat,attr"`
	MaxLon float64 `xml:"maxlon,attr"`
}

// A CopyrightType is a copyrightType.
type CopyrightType struct {
	Author  string `xml:"author,attr"`
	Year    int    `xml:"year,omitempty"`
	License string `xml:"license,omitempty"`
}

// An ExtensionsType contains elements from another schema.
type ExtensionsType struct {
	XML []byte `xml:",innerxml"`
}

// A GPXType is a gpxType.
type GPXType struct {
	XMLName    string          `xml:"gpx"`
	Version    string          `xml:"version,attr"`
	Creator    string          `xml:"creator,attr"`
	Metadata   *MetadataType   `xml:"metadata,omitempty"`
	Wpt        []*WptType      `xml:"wpt,omitempty"`
	Rte        []*RteType      `xml:"rte,omitempty"`
	Trk        []*TrkType      `xml:"trk,omitempty"`
	Extensions *ExtensionsType `xml:"extensions"`
}

// A LinkType is a linkType.
type LinkType struct {
	HREF string `xml:"href,attr"`
	Text string `xml:"text,omitempty"`
	Type string `xml:"type,omitempty"`
}

// A PersonType is a personType.
type PersonType struct {
	Name  string    `xml:"name,omitempty"`
	Email string    `xml:"email,omitempty"`
	Link  *LinkType `xml:"link,omitempty"`
}

// A MetadataType is a metadataType.
type MetadataType struct {
	Name       string          `xml:"name,omitempty"`
	Desc       string          `xml:"desc,omitempty"`
	Author     *PersonType     `xml:"author,omitempty"`
	Copyright  *CopyrightType  `xml:"copyright,omitempty"`
	Link       []*LinkType     `xml:"link,omitempty"`
	Time       time.Time       `xml:"time,omitempty"`
	Keywords   string          `xml:"keywords,omitempty"`
	Bounds     *BoundsType     `xml:"bounds,omitempty"`
	Extensions *ExtensionsType `xml:"extensions"`
}

// A RteType is a rteType.
type RteType struct {
	Name       string          `xml:"name,omitempty"`
	Cmt        string          `xml:"cmt,omitempty"`
	Desc       string          `xml:"desc,omitempty"`
	Src        string          `xml:"src,omitempty"`
	Link       []*LinkType     `xml:"link,omitempty"`
	Number     int             `xml:"number,omitempty"`
	Type       string          `xml:"type,omitempty"`
	Extensions *ExtensionsType `xml:"extensions"`
	RtePt      []*WptType      `xml:"rtept,omitempty"`
}

// A TrkSegType is a trkSegType.
type TrkSegType struct {
	TrkPt      []*WptType      `xml:"trkpt,omitempty"`
	Extensions *ExtensionsType `xml:"extensions"`
}

// A TrkType is a trkType.
type TrkType struct {
	Name       string          `xml:"name,omitempty"`
	Cmt        string          `xml:"cmt,omitempty"`
	Desc       string          `xml:"desc,omitempty"`
	Src        string          `xml:"src,omitempty"`
	Link       []*LinkType     `xml:"link,omitempty"`
	Number     int             `xml:"number,omitempty"`
	Type       string          `xml:"type,omitempty"`
	Extensions *ExtensionsType `xml:"extensions"`
	TrkSeg     []*TrkSegType   `xml:"trkseg,omitempty"`
}

// A WptType is a wptType.
type WptType struct {
	Lat          float64
	Lon          float64
	Ele          float64
	Time         time.Time
	MagVar       float64
	GeoidHeight  float64
	Name         string
	Cmt          string
	Desc         string
	Src          string
	Link         []*LinkType
	Sym          string
	Type         string
	Fix          string
	Sat          int
	HDOP         float64
	VDOP         float64
	PDOP         float64
	AgeOfGPSData float64
	DGPSID       []int
	Extensions   *ExtensionsType
}

func emitIntElement(e *xml.Encoder, localName string, value int) error {
	return emitStringElement(e, localName, strconv.FormatInt(int64(value), 10))
}

func emitStringElement(e *xml.Encoder, localName, value string) error {
	return e.EncodeElement(value, xml.StartElement{Name: xml.Name{Local: localName}})
}

func maybeEmitFloatElement(e *xml.Encoder, localName string, value float64) error {
	if value == 0.0 {
		return nil
	}
	return emitStringElement(e, localName, strconv.FormatFloat(value, 'f', -1, 64))
}

func maybeEmitIntElement(e *xml.Encoder, localName string, value int) error {
	if value == 0 {
		return nil
	}
	return emitIntElement(e, localName, value)
}

func maybeEmitStringElement(e *xml.Encoder, localName, value string) error {
	if value == "" {
		return nil
	}
	return emitStringElement(e, localName, value)
}

// MarshalXML implements xml.Marshaler.MarshalXML.
func (w *WptType) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	latAttr := xml.Attr{
		Name:  xml.Name{Local: "lat"},
		Value: strconv.FormatFloat(w.Lat, 'f', -1, 64),
	}
	lonAttr := xml.Attr{
		Name:  xml.Name{Local: "lon"},
		Value: strconv.FormatFloat(w.Lon, 'f', -1, 64),
	}
	start.Attr = append(start.Attr, latAttr, lonAttr)
	if err := e.EncodeToken(start); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "ele", w.Ele); err != nil {
		return err
	}
	if !w.Time.IsZero() {
		if err := maybeEmitStringElement(e, "time", w.Time.UTC().Format(timeLayout)); err != nil {
			return err
		}
	}
	if err := maybeEmitFloatElement(e, "magvar", w.MagVar); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "geoidheight", w.GeoidHeight); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "name", w.Name); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "cmt", w.Cmt); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "desc", w.Desc); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "src", w.Src); err != nil {
		return err
	}
	if w.Link != nil {
		if err := e.EncodeElement(w.Link, xml.StartElement{Name: xml.Name{Local: "link"}}); err != nil {
			return err
		}
	}
	if err := maybeEmitStringElement(e, "sym", w.Sym); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "type", w.Type); err != nil {
		return err
	}
	if err := maybeEmitStringElement(e, "fix", w.Fix); err != nil {
		return err
	}
	if err := maybeEmitIntElement(e, "sat", w.Sat); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "hdop", w.HDOP); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "vdop", w.VDOP); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "pdop", w.PDOP); err != nil {
		return err
	}
	if err := maybeEmitFloatElement(e, "ageofgpsdata", w.AgeOfGPSData); err != nil {
		return err
	}
	for _, dgpsid := range w.DGPSID {
		if err := emitIntElement(e, "dgpsid", dgpsid); err != nil {
			return err
		}
	}
	// FIXME Encode extensions
	return e.EncodeToken(start.End())
}

// MarshalXML implements xml.Marshaler.MarshalXML.
func (g *GPXType) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	start = xml.StartElement{
		Name: xml.Name{Local: "gpx"},
		Attr: []xml.Attr{
			xml.Attr{
				Name:  xml.Name{Local: "version"},
				Value: g.Version,
			},
			xml.Attr{
				Name:  xml.Name{Local: "creator"},
				Value: g.Creator,
			},
			xml.Attr{
				Name:  xml.Name{Local: "xmlns:xsi"},
				Value: "http://www.w3.org/2001/XMLSchema-instance",
			},
			xml.Attr{
				Name:  xml.Name{Local: "xmlns"},
				Value: "http://www.topografix.com/GPX/1/0",
			},
			xml.Attr{
				Name:  xml.Name{Local: "xsi:schemaLocation"},
				Value: "http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd",
			},
		},
	}
	if err := e.EncodeToken(start); err != nil {
		return err
	}
	if err := e.EncodeElement(g.Wpt, xml.StartElement{Name: xml.Name{Local: "wpt"}}); err != nil {
		return err
	}
	if err := e.EncodeElement(g.Rte, xml.StartElement{Name: xml.Name{Local: "rte"}}); err != nil {
		return err
	}
	if err := e.EncodeElement(g.Trk, xml.StartElement{Name: xml.Name{Local: "trk"}}); err != nil {
		return err
	}
	return e.EncodeToken(start.End())
}

// UnmarshalXML implements xml.Unmarshaler.UnmarshalXML.
func (w *WptType) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var e struct {
		Lat          float64         `xml:"lat,attr"`
		Lon          float64         `xml:"lon,attr"`
		Ele          float64         `xml:"ele"`
		Time         string          `xml:"time"`
		MagVar       float64         `xml:"magvar"`
		GeoidHeight  float64         `xml:"geoidheight"`
		Name         string          `xml:"name"`
		Cmt          string          `xml:"cmt"`
		Desc         string          `xml:"desc"`
		Src          string          `xml:"src"`
		Link         []*LinkType     `xml:"link"`
		Sym          string          `xml:"sym"`
		Type         string          `xml:"type"`
		Fix          string          `xml:"fix"`
		Sat          int             `xml:"sat"`
		HDOP         float64         `xml:"hdop"`
		VDOP         float64         `xml:"vdop"`
		PDOP         float64         `xml:"pdop"`
		AgeOfGPSData float64         `xml:"ageofgpsdata"`
		DGPSID       []int           `xml:"dgpsid"`
		Extensions   *ExtensionsType `xml:"extensions"`
	}
	if err := d.DecodeElement(&e, &start); err != nil {
		return err
	}
	*w = WptType{
		Lat:          e.Lat,
		Lon:          e.Lon,
		Ele:          e.Ele,
		MagVar:       e.MagVar,
		GeoidHeight:  e.GeoidHeight,
		Name:         e.Name,
		Cmt:          e.Cmt,
		Desc:         e.Desc,
		Src:          e.Src,
		Link:         e.Link,
		Sym:          e.Sym,
		Type:         e.Type,
		Fix:          e.Fix,
		Sat:          e.Sat,
		HDOP:         e.HDOP,
		VDOP:         e.VDOP,
		PDOP:         e.PDOP,
		AgeOfGPSData: e.AgeOfGPSData,
		DGPSID:       e.DGPSID,
		Extensions:   e.Extensions,
	}
	if e.Time != "" {
		t, err := time.ParseInLocation(timeLayout, e.Time, time.UTC)
		if err != nil {
			return err
		}
		w.Time = t
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"io"
	"net"
	"os"
)

const VERSION = "v0.0.2"

func main() {
	port := flag.Int("p", 0, "")
	ip := flag.String("i", "127.0.0.1", "")
	originPort := flag.Int("P", 0, "")
	originHost := flag.String("H", "", "")
	certPath := flag.String("c", "", "")
	keyPath := flag.String("k", "", "")
	version := flag.Bool("version", false, "")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS]\n\n", os.Args[0])
		fmt.Println("Options:")
		fmt.Println("  -p:        Port. (Default: 443)")
		fmt.Println("  -i:        IP Address. (Default: 127.0.0.1)")
		fmt.Println("  -P:        Origin port.")
		fmt.Println("  -H:        Origin host.")
		fmt.Println("  -c:        Certificate file.")
		fmt.Println("  -k:        Certificate key file.")
		fmt.Println("  --version: Display version information and exit.")
		fmt.Println("  --help:    Display this help and exit.")
		os.Exit(1)
	}

	flag.Parse()

	if *version {
		fmt.Fprintf(os.Stderr, "h2analyzer %s\n", VERSION)
		os.Exit(0)
	}

	if *port == 0 {
		*port = 443
	}
	addr := fmt.Sprintf("%s:%d", *ip, *port)

	if *originPort == 0 {
		fmt.Fprintf(os.Stderr, "Origin port is not specified\n")
		os.Exit(1)
	}
	if *originHost == "" {
		fmt.Fprintf(os.Stderr, "Origin host is not specified\n")
		os.Exit(1)
	}
	origin := fmt.Sprintf("%s:%d", *originHost, *originPort)

	cert, err := tls.LoadX509KeyPair(*certPath, *keyPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Invalid certificate file\n")
		os.Exit(1)
	}

	config := &tls.Config{}
	config.Certificates = []tls.Certificate{cert}
	config.NextProtos = append(config.NextProtos, "h2-14", "h2-15", "h2-16", "h2")

	server, err := tls.Listen("tcp", addr, config)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Could not bind address - %s\n", addr)
		os.Exit(1)
	}

	defer server.Close()

	for {
		remoteConn, err := server.Accept()
		if err != nil {
			fmt.Fprintf(os.Stderr, "Unable to accept: %s", err)
			continue
		}

		go handlePeer(remoteConn, origin)
	}
}

func handlePeer(remoteConn net.Conn, originAddr string) {
	var originConn net.Conn
	var err error

	defer remoteConn.Close()

	dumper := NewFrameDumper(remoteConn.RemoteAddr())
	defer dumper.Close()

	remoteID := remoteConn.RemoteAddr().String()

	remoteCh, remoteErrCh := handleConnection(remoteConn)

	select {
	case chunk := <-remoteCh:
		connState := remoteConn.(*tls.Conn).ConnectionState()
		dumper.DumpConnectionState(connState)

		config := &tls.Config{}
		config.NextProtos = append(config.NextProtos, connState.NegotiatedProtocol)
		config.CipherSuites = []uint16{connState.CipherSuite}
		config.ServerName = connState.ServerName
		config.InsecureSkipVerify = true

		dialer := new(net.Dialer)
		originConn, err = tls.DialWithDialer(dialer, "tcp", originAddr, config)
		if err != nil {
			logger.LogFrame(true, remoteID, 0, "Unable to connect to the origin: %s", err)
			return
		}

		defer originConn.Close()

		_, err = originConn.Write(chunk)
		if err != nil {
			logger.LogFrame(true, remoteID, 0, "Unable to proxy data: %s", err)
			return
		}

		dumper.DumpFrame(chunk, true)

	case err := <-remoteErrCh:
		if err != io.EOF {
			logger.LogFrame(true, remoteID, 0, "Error: %s", err)
		}
		return
	}

	originCh, originErrCh := handleConnection(originConn)

	for {
		select {
		case chunk := <-remoteCh:
			_, err := originConn.Write(chunk)
			//fmt.Printf("Write to origin: %x byte\n", chunk)
			if err != nil {
				logger.LogFrame(true, remoteID, 0, "Unable to proxy data: %s", err)
				return
			}
			dumper.DumpFrame(chunk, true)

		case err := <-remoteErrCh:
			if err != io.EOF {
				logger.LogFrame(true, remoteID, 0, "Error: %s", err)
			}
			return

		case chunk := <-originCh:
			_, err := remoteConn.Write(chunk)
			//fmt.Printf("Write to remote: %x byte\n", chunk)
			if err != nil {
				logger.LogFrame(false, remoteID, 0, "Unable to proxy data: %s", err)
				return
			}
			dumper.DumpFrame(chunk, false)

		case err := <-originErrCh:
			if err != io.EOF {
				logger.LogFrame(false, remoteID, 0, "Error: %s", err)
			}
			return
		}
	}
}

func handleConnection(conn net.Conn) (<-chan []byte, <-chan error) {
	dataCh := make(chan []byte)
	errCh := make(chan error, 1)

	go func() {
		for {
			buf := make([]byte, 16384)

			n, err := conn.Read(buf)
			//fmt.Printf("Read: %d byte\n", n)
			if err != nil {
				errCh <- err
				break
			}

			dataCh <- buf[:n]
		}
	}()

	return dataCh, errCh
}
<commit_msg>Use dafault logger to output error<commit_after>package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
)

const VERSION = "v0.0.2"

var logger = log.New(os.Stderr, "", 0)

func main() {
	port := flag.Int("p", 0, "")
	ip := flag.String("i", "127.0.0.1", "")
	originPort := flag.Int("P", 0, "")
	originHost := flag.String("H", "", "")
	certPath := flag.String("c", "", "")
	keyPath := flag.String("k", "", "")
	version := flag.Bool("version", false, "")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS]\n\n", os.Args[0])
		fmt.Println("Options:")
		fmt.Println("  -p:        Port. (Default: 443)")
		fmt.Println("  -i:        IP Address. (Default: 127.0.0.1)")
		fmt.Println("  -P:        Origin port.")
		fmt.Println("  -H:        Origin host.")
		fmt.Println("  -c:        Certificate file.")
		fmt.Println("  -k:        Certificate key file.")
		fmt.Println("  --version: Display version information and exit.")
		fmt.Println("  --help:    Display this help and exit.")
		os.Exit(1)
	}

	flag.Parse()

	if *version {
		logger.Printf("h2analyzer %s\n", VERSION)
		os.Exit(0)
	}

	if *port == 0 {
		*port = 443
	}
	addr := fmt.Sprintf("%s:%d", *ip, *port)

	if *originPort == 0 {
		logger.Fatalln("Origin port is not specified")
	}
	if *originHost == "" {
		logger.Fatalln("Origin host is not specified")
	}
	origin := fmt.Sprintf("%s:%d", *originHost, *originPort)

	cert, err := tls.LoadX509KeyPair(*certPath, *keyPath)
	if err != nil {
		logger.Fatalln("Invalid certificate file")
	}

	config := &tls.Config{}
	config.Certificates = []tls.Certificate{cert}
	config.NextProtos = append(config.NextProtos, "h2", "h2-16", "h2-15", "h2-14")

	server, err := tls.Listen("tcp", addr, config)
	if err != nil {
		logger.Fatalf("Could not bind address - %s\n", addr)
	}

	defer server.Close()

	for {
		remoteConn, err := server.Accept()
		if err != nil {
			logger.Printf("Unable to accept: %s", err)
			continue
		}

		go handlePeer(remoteConn, origin)
	}
}

func handlePeer(remoteConn net.Conn, originAddr string) {
	var originConn net.Conn
	var err error

	defer remoteConn.Close()

	dumper := NewFrameDumper(remoteConn.RemoteAddr())
	defer dumper.Close()

	remoteCh, remoteErrCh := handleConnection(remoteConn)

	select {
	case chunk := <-remoteCh:
		connState := remoteConn.(*tls.Conn).ConnectionState()
		dumper.DumpConnectionState(connState)

		config := &tls.Config{}
		config.NextProtos = append(config.NextProtos, connState.NegotiatedProtocol)
		config.CipherSuites = []uint16{connState.CipherSuite}
		config.ServerName = connState.ServerName
		config.InsecureSkipVerify = true

		dialer := new(net.Dialer)
		originConn, err = tls.DialWithDialer(dialer, "tcp", originAddr, config)
		if err != nil {
			logger.Printf("Unable to connect to the origin: %s", err)
			return
		}

		defer originConn.Close()

		_, err = originConn.Write(chunk)
		if err != nil {
			logger.Printf("Unable to write data to the origin: %s", err)
			return
		}

		dumper.DumpFrame(chunk, true)

	case err := <-remoteErrCh:
		if err != io.EOF {
			logger.Printf("Connection error: %s", err)
		}
		return
	}

	originCh, originErrCh := handleConnection(originConn)

	for {
		select {
		case chunk := <-remoteCh:
			_, err := originConn.Write(chunk)
			if err != nil {
				logger.Printf("Unable to write data to the origin: %s", err)
				return
			}
			dumper.DumpFrame(chunk, true)

		case err := <-remoteErrCh:
			if err != io.EOF {
				logger.Printf("Connection error: %s", err)
			}
			return

		case chunk := <-originCh:
			_, err := remoteConn.Write(chunk)
			if err != nil {
				logger.Printf("Unable to write data to the connection: %s", err)
				return
			}
			dumper.DumpFrame(chunk, false)

		case err := <-originErrCh:
			if err != io.EOF {
				logger.Printf("Origin error: %s", err)
			}
			return
		}
	}
}

func handleConnection(conn net.Conn) (<-chan []byte, <-chan error) {
	dataCh := make(chan []byte)
	errCh := make(chan error, 1)

	go func() {
		for {
			buf := make([]byte, 16384)

			n, err := conn.Read(buf)
			if err != nil {
				errCh <- err
				break
			}

			dataCh <- buf[:n]
		}
	}()

	return dataCh, errCh
}
<|endoftext|>


<commit_before>package hof

import "reflect"

func _map(in []reflect.Value) []reflect.Value {
	f := in[0]
	args := in[1]

	outType := reflect.SliceOf(f.Type().Out(0))

	out := reflect.MakeSlice(outType, args.Len(), args.Len())
	for i := 0; i < args.Len(); i++ {
		ret := f.Call([]reflect.Value{args.Index(i)})
		out.Index(i).Set(ret[0])
	}

	return []reflect.Value{out}
}

func filter(in []reflect.Value) []reflect.Value {
	f := in[0]
	args := in[1]

	out := reflect.MakeSlice(args.Type(), 0, args.Len())
	for i := 0; i < args.Len(); i++ {
		val := args.Index(i)
		shouldInclude := f.Call([]reflect.Value{val})[0]

		if shouldInclude.Bool() {
			out = reflect.Append(out, val)
		}
	}

	return []reflect.Value{out}
}

func reduce(in []reflect.Value) []reflect.Value {
	f := in[0]
	args := in[1]

	outType := f.Type().Out(0)
	out := reflect.Zero(outType)

	haveInit := false
	if len(in) > 2 {
		out = in[2]
		haveInit = true
	}

	for i := 0; i < args.Len(); i++ {
		if !haveInit && i == 0 {
			out = args.Index(i)
		} else {
			out = f.Call([]reflect.Value{out, args.Index(i)})[0]
		}
	}

	return []reflect.Value{out}
}

func MakeMapFunc(mapFnPtr interface{}) {
	f := reflect.ValueOf(mapFnPtr).Elem()
	f.Set(reflect.MakeFunc(f.Type(), _map))
}

func MakeFilterFunc(filterFnPtr interface{}) {
	f := reflect.ValueOf(filterFnPtr).Elem()
	f.Set(reflect.MakeFunc(f.Type(), filter))
}

func MakeReduceFunc(reduceFnPtr interface{}) {
	f := reflect.ValueOf(reduceFnPtr).Elem()
	f.Set(reflect.MakeFunc(f.Type(), reduce))
}
<commit_msg>add go doc comments.<commit_after>// Package hof is an experimental implementation of common higher-order functions in Go.
// This package requires a version of Go that includes reflect.MakeFunc and reflect.MakeSlice.
package hof

import "reflect"

func _map(in []reflect.Value) []reflect.Value {
	f := in[0]
	args := in[1]

	outType := reflect.SliceOf(f.Type().Out(0))

	out := reflect.MakeSlice(outType, args.Len(), args.Len())
	for i := 0; i < args.Len(); i++ {
		ret := f.Call([]reflect.Value{args.Index(i)})
		out.Index(i).Set(ret[0])
	}

	return []reflect.Value{out}
}

func filter(in []reflect.Value) []reflect.Value {
	f := in[0]
	args := in[1]

	out := reflect.MakeSlice(args.Type(), 0, args.Len())
	for i := 0; i < args.Len(); i++ {
		val := args.Index(i)
		shouldInclude := f.Call([]reflect.Value{val})[0]

		if shouldInclude.Bool() {
			out = reflect.Append(out, val)
		}
	}

	return []reflect.Value{out}
}

func reduce(in []reflect.Value) []reflect.Value {
	f := in[0]
	args := in[1]

	outType := f.Type().Out(0)
	out := reflect.Zero(outType)

	haveInit := false
	if len(in) > 2 {
		out = in[2]
		haveInit = true
	}

	for i := 0; i < args.Len(); i++ {
		if !haveInit && i == 0 {
			out = args.Index(i)
		} else {
			out = f.Call([]reflect.Value{out, args.Index(i)})[0]
		}
	}

	return []reflect.Value{out}
}

/*
MakeMapFunc takes pointer to a map function zero value and substitutes in the appropriate implementation.
Generally, such a function will take the following form:
    var mapper func (func (A) B, []A) []B
*/
func MakeMapFunc(mapFnPtr interface{}) {
	f := reflect.ValueOf(mapFnPtr).Elem()
	f.Set(reflect.MakeFunc(f.Type(), _map))
}

/*
MakeFilterFunc takes pointer to a filter function zero value and substitutes in the appropriate implementation.
Generally, such a function will take the following form:
    var filter func (func (A) bool, []A) []A
*/
func MakeFilterFunc(filterFnPtr interface{}) {
	f := reflect.ValueOf(filterFnPtr).Elem()
	f.Set(reflect.MakeFunc(f.Type(), filter))
}

/*
MakeFilterFunc takes pointer to a filter function zero value and substitutes in the appropriate implementation.
Generally, such a function will take one of the following forms:
    var reduce func (func (A, A) A, []A) A // takes two args: the reducer and the slice

    var reduce func (func (A, B) A, []B, A) A // takes three args: the reducer, the slice, and an initial value
*/
func MakeReduceFunc(reduceFnPtr interface{}) {
	f := reflect.ValueOf(reduceFnPtr).Elem()
	f.Set(reflect.MakeFunc(f.Type(), reduce))
}
<|endoftext|>


<commit_before>package peco

import (
	"sync"
	"time"
)

// Hub acts as the messaging hub between components -- that is,
// it controls how the communication that goes through channels
// are handled.
type Hub struct {
	isSync        bool
	mutex         *sync.Mutex
	loopCh        chan struct{}
	queryCh       chan HubReq
	drawCh        chan HubReq
	statusMsgCh   chan HubReq
	clearStatusCh chan HubReq
	pagingCh      chan HubReq
}

// HubReq is a wrapper around the actual requst value that needs
// to be passed. It contains an optional channel field which can
// be filled to force synchronous communication between the
// sender and receiver
type HubReq struct {
	data    interface{}
	replyCh chan struct{}
}

// DataInterface returns the underlying data as interface{}
func (hr HubReq) DataInterface() interface{} {
	return hr.data
}

// DataString returns the underlying data as a string. Panics
// if type conversion fails.
func (hr HubReq) DataString() string {
	return hr.data.(string)
}

// Done marks the request as done. If Hub is operating in
// asynchronous mode (default), it's a no op. Otherwise it
// sends a message back the reply channel to finish up the
// synchronous communication
func (hr HubReq) Done() {
	if hr.replyCh == nil {
		return
	}
	hr.replyCh <- struct{}{}
}

// NewHub creates a new Hub struct
func NewHub() *Hub {
	return &Hub{
		false,
		&sync.Mutex{},
		make(chan struct{}),  // loopCh. You never send messages to this. no point in buffering
		make(chan HubReq, 5), // queryCh.
		make(chan HubReq, 5), // drawCh.
		make(chan HubReq, 5), // statusMsgCh
		make(chan HubReq, 5), // clearStatusCh
		make(chan HubReq, 5), // pagingCh
	}
}

// Batch allows you to synchronously send messages during the
// scope of f() being executed.
func (h *Hub) Batch(f func()) {
	// lock during this operation
	h.mutex.Lock()
	defer h.mutex.Unlock()

	// temporarily set isSync = true
	o := h.isSync
	h.isSync = true
	defer func() { h.isSync = o }()

	// ignore panics
	defer func() { recover() }()

	f()
}

// low-level utility
func send(ch chan HubReq, r HubReq, needReply bool) {
	if needReply {
		r.replyCh = make(chan struct{})
		defer func() { <-r.replyCh }()
	}

	ch <- r
}

// QueryCh returns the underlying channel for queries
func (h *Hub) QueryCh() chan HubReq {
	return h.queryCh
}

// SendQuery sends the query string to be processed by the Filter
func (h *Hub) SendQuery(q string) {
	send(h.QueryCh(), HubReq{q, nil}, h.isSync)
}

// LoopCh returns the channel to control the main execution loop.
// Nothing should ever be sent through this channel. The only way
// the channel communicates anything to its receivers is when
// it is closed -- which is when peco is done.
func (h *Hub) LoopCh() chan struct{} {
	return h.loopCh
}

// DrawCh returns the channel to redraw the terminal display
func (h *Hub) DrawCh() chan HubReq {
	return h.drawCh
}

// SendDraw sends a request to redraw the terminal display
func (h *Hub) SendDraw(matches []Match) {
	send(h.DrawCh(), HubReq{matches, nil}, h.isSync)
}

// StatusMsgCh returns the channel to update the status message
func (h *Hub) StatusMsgCh() chan HubReq {
	return h.statusMsgCh
}

// SendStatusMsg sends a string to be displayed in the status message
func (h *Hub) SendStatusMsg(q string) {
	send(h.StatusMsgCh(), HubReq{q, nil}, h.isSync)
}

func (h *Hub) ClearStatusCh() chan HubReq {
	return h.clearStatusCh
}

// SendClearStatus sends a request to clear the status message in
// `d` duration. If a new status message is sent before the clear
// request is executed, the clear instruction will be canceled
func (h *Hub) SendClearStatus(d time.Duration) {
	send(h.ClearStatusCh(), HubReq{d, nil}, h.isSync)
}

// PagingCh returns the channel to page through the results
func (h *Hub) PagingCh() chan HubReq {
	return h.pagingCh
}

// SendPaging sends a request to move the cursor around
func (h *Hub) SendPaging(x PagingRequest) {
	send(h.PagingCh(), HubReq{x, nil}, h.isSync)
}

// Stop closes the LoopCh so that peco shutsdown
func (h *Hub) Stop() {
	close(h.LoopCh())
}
<commit_msg>Try very hard to keep data == nil when it's nil<commit_after>package peco

import (
	"sync"
	"time"
)

// Hub acts as the messaging hub between components -- that is,
// it controls how the communication that goes through channels
// are handled.
type Hub struct {
	isSync        bool
	mutex         *sync.Mutex
	loopCh        chan struct{}
	queryCh       chan HubReq
	drawCh        chan HubReq
	statusMsgCh   chan HubReq
	clearStatusCh chan HubReq
	pagingCh      chan HubReq
}

// HubReq is a wrapper around the actual requst value that needs
// to be passed. It contains an optional channel field which can
// be filled to force synchronous communication between the
// sender and receiver
type HubReq struct {
	data    interface{}
	replyCh chan struct{}
}

// DataInterface returns the underlying data as interface{}
func (hr HubReq) DataInterface() interface{} {
	if hr.data == nil {
		return nil
	}
	return hr.data
}

// DataString returns the underlying data as a string. Panics
// if type conversion fails.
func (hr HubReq) DataString() string {
	return hr.data.(string)
}

// Done marks the request as done. If Hub is operating in
// asynchronous mode (default), it's a no op. Otherwise it
// sends a message back the reply channel to finish up the
// synchronous communication
func (hr HubReq) Done() {
	if hr.replyCh == nil {
		return
	}
	hr.replyCh <- struct{}{}
}

// NewHub creates a new Hub struct
func NewHub() *Hub {
	return &Hub{
		false,
		&sync.Mutex{},
		make(chan struct{}),  // loopCh. You never send messages to this. no point in buffering
		make(chan HubReq, 5), // queryCh.
		make(chan HubReq, 5), // drawCh.
		make(chan HubReq, 5), // statusMsgCh
		make(chan HubReq, 5), // clearStatusCh
		make(chan HubReq, 5), // pagingCh
	}
}

// Batch allows you to synchronously send messages during the
// scope of f() being executed.
func (h *Hub) Batch(f func()) {
	// lock during this operation
	h.mutex.Lock()
	defer h.mutex.Unlock()

	// temporarily set isSync = true
	o := h.isSync
	h.isSync = true
	defer func() { h.isSync = o }()

	// ignore panics
	defer func() { recover() }()

	f()
}

// low-level utility
func send(ch chan HubReq, r HubReq, needReply bool) {
	if needReply {
		r.replyCh = make(chan struct{})
		defer func() { <-r.replyCh }()
	}

	ch <- r
}

// QueryCh returns the underlying channel for queries
func (h *Hub) QueryCh() chan HubReq {
	return h.queryCh
}

// SendQuery sends the query string to be processed by the Filter
func (h *Hub) SendQuery(q string) {
	send(h.QueryCh(), HubReq{q, nil}, h.isSync)
}

// LoopCh returns the channel to control the main execution loop.
// Nothing should ever be sent through this channel. The only way
// the channel communicates anything to its receivers is when
// it is closed -- which is when peco is done.
func (h *Hub) LoopCh() chan struct{} {
	return h.loopCh
}

// DrawCh returns the channel to redraw the terminal display
func (h *Hub) DrawCh() chan HubReq {
	return h.drawCh
}

// SendDraw sends a request to redraw the terminal display
func (h *Hub) SendDraw(matches []Match) {
	// to make sure interface is nil, I need to EXPLICITLY set nil
	req := HubReq{nil, nil}
	if matches != nil {
		req.data = matches
	}
	send(h.DrawCh(), req, h.isSync)
}

// StatusMsgCh returns the channel to update the status message
func (h *Hub) StatusMsgCh() chan HubReq {
	return h.statusMsgCh
}

// SendStatusMsg sends a string to be displayed in the status message
func (h *Hub) SendStatusMsg(q string) {
	send(h.StatusMsgCh(), HubReq{q, nil}, h.isSync)
}

func (h *Hub) ClearStatusCh() chan HubReq {
	return h.clearStatusCh
}

// SendClearStatus sends a request to clear the status message in
// `d` duration. If a new status message is sent before the clear
// request is executed, the clear instruction will be canceled
func (h *Hub) SendClearStatus(d time.Duration) {
	send(h.ClearStatusCh(), HubReq{d, nil}, h.isSync)
}

// PagingCh returns the channel to page through the results
func (h *Hub) PagingCh() chan HubReq {
	return h.pagingCh
}

// SendPaging sends a request to move the cursor around
func (h *Hub) SendPaging(x PagingRequest) {
	send(h.PagingCh(), HubReq{x, nil}, h.isSync)
}

// Stop closes the LoopCh so that peco shutsdown
func (h *Hub) Stop() {
	close(h.LoopCh())
}
<|endoftext|>


<commit_before>package protocol

import (
	"fmt"
	"log"
	"time"
)

type Message struct {
	Type    string      `json:"type"`
	Date    time.Time   `json:"time"`
	Payload interface{} `json:"payload"`
}

type Conn interface {
	ReadJSON(interface{}) error
	WriteJSON(interface{}) error
	Close() error
}

type Hub struct {
	connections      map[Conn]bool
	globalBroadcasts chan *Message
	processors       map[string]ProcessorFn
}

type ProcessorFn func(*Hub, *Message) (*Message, error)

func GenericHub() *Hub {
	return &Hub{
		connections:      make(map[Conn]bool),
		globalBroadcasts: make(chan *Message),
		processors:       make(map[string]ProcessorFn),
	}
}

func (hub *Hub) Run() {
	for {
		message := <-hub.globalBroadcasts
		for connection := range hub.connections {
			go func(connnection Conn, message *Message) {
				err := connection.WriteJSON(message)
				if err != nil {
					log.Println(err)
				}
			}(connection, message)
		}
	}
}

func (hub *Hub) RegisterProcessor(messageName string, fn ProcessorFn) error {
	_, exists := hub.processors[messageName]
	if exists {
		return fmt.Errorf("Processor already exists with the name %d", messageName)
	}

	hub.processors[messageName] = fn
	return nil
}

func (hub *Hub) GlobalBroadcast(message *Message) {
	hub.globalBroadcasts <- message
}

func (hub *Hub) Attach(connection Conn) {
	hub.connections[connection] = true
	go hub.listen(connection)
}

func (hub *Hub) CloseConnection(connection Conn) {
	err := connection.Close()
	if err != nil {
		log.Println("Error closing connection", err)
	} else {
		delete(hub.connections, connection)
	}
}

func (hub *Hub) listen(connection Conn) {
	for {
		request := &Message{}
		err := connection.ReadJSON(request)
		if err != nil {
			hub.CloseConnection(connection)
			log.Println(err)
			return
		}

		fn, exists := hub.processors[request.Type]
		var response *Message
		if exists {
		}
	}
}
<commit_msg>Finish first pass of Hub<commit_after>package protocol

import (
	"fmt"
	"log"
	"time"
)

type Message struct {
	Type    string      `json:"type"`
	Date    time.Time   `json:"time"`
	Payload interface{} `json:"payload"`
}

type Conn interface {
	ReadJSON(interface{}) error
	WriteJSON(interface{}) error
	Close() error
}

type Hub struct {
	connections      map[Conn]bool
	globalBroadcasts chan *Message
	processors       map[string]ProcessorFn
	running          bool
}

type ProcessorFn func(*Hub, *Message) (*Message, error)

func GenericHub() *Hub {
	return &Hub{
		connections:      make(map[Conn]bool),
		globalBroadcasts: make(chan *Message),
		processors:       make(map[string]ProcessorFn),
		running:          false,
	}
}

func (hub *Hub) Run() {
	hub.running = true
	for conn, _ := range hub.connections {
		go hub.listen(conn)
	}

	for {
		message := <-hub.globalBroadcasts
		for connection := range hub.connections {
			go func(connnection Conn, message *Message) {
				err := connection.WriteJSON(message)
				if err != nil {
					log.Println(err)
				}
			}(connection, message)
		}
	}
}

func (hub *Hub) RegisterProcessor(messageName string, fn ProcessorFn) error {
	_, exists := hub.processors[messageName]
	if exists {
		return fmt.Errorf("Processor already exists with the name %d", messageName)
	}

	hub.processors[messageName] = fn
	return nil
}

func (hub *Hub) GlobalBroadcast(message *Message) {
	hub.globalBroadcasts <- message
}

func (hub *Hub) Attach(connection Conn) {
	hub.connections[connection] = true
	if hub.running {
		go hub.listen(connection)
	}
}

func (hub *Hub) CloseConnection(connection Conn) {
	err := connection.Close()
	if err != nil {
		log.Println("Error closing connection", err)
	} else {
		delete(hub.connections, connection)
	}
}

func (hub *Hub) listen(conn Conn) {
	for {
		request := &Message{}
		err := conn.ReadJSON(request)
		if err != nil {
			log.Println("Error reading JSON")
			hub.CloseConnection(conn)
			log.Println(err)
			return
		}

		fn, exists := hub.processors[request.Type]
		var response *Message
		if exists {
			response, err = fn(hub, request)
			if err != nil {
				response = &Message{
					Type:    "error",
					Payload: err.Error(),
				}
			}
		} else {
			response = &Message{
				Type:    "error",
				Payload: "unknown message type",
			}
		}

		response.stamp()
		err = conn.WriteJSON(response)
		if err != nil {
			hub.CloseConnection(conn)
			log.Println("Closed connection")
			log.Println(err)
			return
		}
	}
}

func (message *Message) stamp() {
	if message.Date.IsZero() {
		message.Date = time.Now()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	log "github.com/Sirupsen/logrus"
	"github.com/kardianos/osext"
	//"os"
	"os/exec"
	//"path"
	//"path/filepath"
	//"runtime"
	//"debug"
	"encoding/json"
	"io"
	"os"
	"runtime"
	"runtime/debug"
	"strconv"
	"strings"
)

type hub struct {
	// Registered connections.
	connections map[*connection]bool

	// Inbound messages from the connections.
	broadcast chan []byte

	// Inbound messages from the system
	broadcastSys chan []byte

	// Register requests from the connections.
	register chan *connection

	// Unregister requests from connections.
	unregister chan *connection
}

var h = hub{
	// buffered. go with 1000 cuz should never surpass that
	broadcast:    make(chan []byte, 1000),
	broadcastSys: make(chan []byte, 1000),
	// non-buffered
	//broadcast:    make(chan []byte),
	//broadcastSys: make(chan []byte),
	register:    make(chan *connection),
	unregister:  make(chan *connection),
	connections: make(map[*connection]bool),
}

func (h *hub) run() {
	for {
		select {
		case c := <-h.register:
			h.connections[c] = true
			// send supported commands
			c.send <- []byte("{\"Version\" : \"" + version + "\"} ")
			c.send <- []byte("{\"Commands\" : [\"list\", \"open [portName] [baud] [bufferAlgorithm (optional)]\", \"send [portName] [cmd]\", \"sendnobuf [portName] [cmd]\", \"close [portName]\", \"bufferalgorithms\", \"baudrates\", \"restart\", \"exit\", \"program [portName] [board:name] [$path/to/filename/without/extension]\", \"programfromurl [portName] [board:name] [urlToHexFile]\"]} ")
			c.send <- []byte("{\"Hostname\" : \"" + *hostname + "\"} ")
			c.send <- []byte("{\"OS\" : \"" + runtime.GOOS + "\"} ")
		case c := <-h.unregister:
			delete(h.connections, c)
			// put close in func cuz it was creating panics and want
			// to isolate
			func() {
				// this method can panic if websocket gets disconnected
				// from users browser and we see we need to unregister a couple
				// of times, i.e. perhaps from incoming data from serial triggering
				// an unregister. (NOT 100% sure why seeing c.send be closed twice here)
				defer func() {
					if e := recover(); e != nil {
						log.Println("Got panic: ", e)
					}
				}()
				close(c.send)
			}()
		case m := <-h.broadcast:
			if len(m) > 0 {
				//log.Print(string(m))
				//log.Print(h.broadcast)
				checkCmd(m)
				//log.Print("-----")

				for c := range h.connections {
					select {
					case c.send <- m:
						//log.Print("did broadcast to ")
						//log.Print(c.ws.RemoteAddr())
						//c.send <- []byte("hello world")
					default:
						delete(h.connections, c)
						close(c.send)
					}
				}
			}
		case m := <-h.broadcastSys:
			for c := range h.connections {
				select {
				case c.send <- m:
					//log.Print("did broadcast to ")
					//log.Print(c.ws.RemoteAddr())
					//c.send <- []byte("hello world")
				default:
					delete(h.connections, c)
					close(c.send)
				}
			}
		}
	}
}

func checkCmd(m []byte) {
	//log.Print("Inside checkCmd")
	s := string(m[:])

	sl := strings.ToLower(strings.Trim(s, "\n"))

	if *hibernate == true {
		//do nothing
		return
	}

	if strings.HasPrefix(sl, "open") {

		// check if user wants to open this port as a secondary port
		// this doesn't mean much other than allowing the UI to show
		// a port as primary and make other ports sort of act less important
		isSecondary := false
		if strings.HasPrefix(s, "open secondary") {
			isSecondary = true
			// swap out the word secondary
			s = strings.Replace(s, "open secondary", "open", 1)
		}

		args := strings.Split(s, " ")
		if len(args) < 3 {
			go spErr("You did not specify a port and baud rate in your open cmd")
			return
		}
		if len(args[1]) < 1 {
			go spErr("You did not specify a serial port")
			return
		}

		baudStr := strings.Replace(args[2], "\n", "", -1)
		baud, err := strconv.Atoi(baudStr)
		if err != nil {
			go spErr("Problem converting baud rate " + args[2])
			return
		}
		// pass in buffer type now as string. if user does not
		// ask for a buffer type pass in empty string
		bufferAlgorithm := ""
		if len(args) > 3 {
			// cool. we got a buffer type request
			buftype := strings.Replace(args[3], "\n", "", -1)
			bufferAlgorithm = buftype
		}
		go spHandlerOpen(args[1], baud, bufferAlgorithm, isSecondary)

	} else if strings.HasPrefix(sl, "close") {

		args := strings.Split(s, " ")
		if len(args) > 1 {
			go spClose(args[1])
		} else {
			go spErr("You did not specify a port to close")
		}

	} else if strings.HasPrefix(sl, "killprogrammer") {
		// kill the running process (assumes singleton for now)
		go spHandlerProgramKill()

	} else if strings.HasPrefix(sl, "sendjsonraw") {
		// will catch sendjsonraw
		go spWriteJsonRaw(s)

	} else if strings.HasPrefix(sl, "sendjson") {
		// will catch sendjson
		go spWriteJson(s)

	} else if strings.HasPrefix(sl, "send") {
		// will catch send and sendnobuf

		//args := strings.Split(s, "send ")
		go spWrite(s)

	} else if strings.HasPrefix(sl, "list") {
		go spList(false)
		go spList(true)
	} else if strings.HasPrefix(sl, "downloadtool") {
		go func() {
			args := strings.Split(s, " ")
			var tool, toolVersion, behaviour string
			toolVersion = "latest"
			behaviour = "keep"
			if len(args) < 1 {
				mapD := map[string]string{"DownloadStatus": "Error", "Msg": "Not enough arguments"}
				mapB, _ := json.Marshal(mapD)
				h.broadcastSys <- mapB
			}
			if len(args) > 1 {
				tool = args[1]
			}
			if len(args) > 2 {
				toolVersion = args[2]
			}
			if len(args) > 3 {
				behaviour = args[3]
			}

			err := Tools.Download(tool, toolVersion, behaviour)
			if err != nil {
				mapD := map[string]string{"DownloadStatus": "Error", "Msg": err.Error()}
				mapB, _ := json.Marshal(mapD)
				h.broadcastSys <- mapB
			} else {
				mapD := map[string]string{"DownloadStatus": "Success", "Msg": "Map Updated"}
				mapB, _ := json.Marshal(mapD)
				h.broadcastSys <- mapB
			}
		}()
	} else if strings.HasPrefix(sl, "bufferalgorithm") {
		go spBufferAlgorithms()
	} else if strings.HasPrefix(sl, "log") {
		go logAction(sl)
	} else if strings.HasPrefix(sl, "baudrate") {
		go spBaudRates()
	} else if strings.HasPrefix(sl, "broadcast") {
		go broadcast(s)
	} else if strings.HasPrefix(sl, "restart") {
		log.Println("Received restart from the daemon. Why? Boh")
		restart("")
	} else if strings.HasPrefix(sl, "exit") {
		exit()
	} else if strings.HasPrefix(sl, "memstats") {
		memoryStats()
	} else if strings.HasPrefix(sl, "gc") {
		garbageCollection()
	} else if strings.HasPrefix(sl, "hostname") {
		getHostname()
	} else if strings.HasPrefix(sl, "version") {
		getVersion()
	} else {
		go spErr("Could not understand command.")
	}

	//log.Print("Done with checkCmd")
}

func logAction(sl string) {
	if strings.HasPrefix(sl, "log on") {
		*logDump = "on"
		multi_writer := io.MultiWriter(&logger_ws, os.Stderr)
		log.SetOutput(multi_writer)
	} else if strings.HasPrefix(sl, "log off") {
		*logDump = "off"
		log.SetOutput(os.Stderr)
	} else if strings.HasPrefix(sl, "log show") {
		// TODO: send all the saved log to websocket
		//h.broadcastSys <- []byte("{\"BufFlowDebug\" : \"" + *logDump + "\"}")
	}
}

func memoryStats() {
	var memStats runtime.MemStats
	runtime.ReadMemStats(&memStats)
	json, _ := json.Marshal(memStats)
	log.Printf("memStats:%v\n", string(json))
	h.broadcastSys <- json
}

func getHostname() {
	h.broadcastSys <- []byte("{\"Hostname\" : \"" + *hostname + "\"}")
}

func getVersion() {
	h.broadcastSys <- []byte("{\"Version\" : \"" + version + "\"}")
}

func garbageCollection() {
	log.Printf("Starting garbageCollection()\n")
	h.broadcastSys <- []byte("{\"gc\":\"starting\"}")
	memoryStats()
	debug.SetGCPercent(100)
	debug.FreeOSMemory()
	debug.SetGCPercent(-1)
	log.Printf("Done with garbageCollection()\n")
	h.broadcastSys <- []byte("{\"gc\":\"done\"}")
	memoryStats()
}

func exit() {
	log.Println("Starting new spjs process")
	h.broadcastSys <- []byte("{\"Exiting\" : true}")
	log.Fatal("Exited current spjs cuz asked to")

}

func restart(path string) {
	log.Println("called restart", path)
	// relaunch ourself and exit
	// the relaunch works because we pass a cmdline in
	// that has serial-port-json-server only initialize 5 seconds later
	// which gives us time to exit and unbind from serial ports and TCP/IP
	// sockets like :8989
	log.Println("Starting new spjs process")
	h.broadcastSys <- []byte("{\"Restarting\" : true}")

	// figure out current path of executable so we know how to restart
	// this process
	/*
		dir, err2 := filepath.Abs(filepath.Dir(os.Args[0]))
		if err2 != nil {
			//log.Fatal(err2)
			fmt.Printf("Error getting executable file path. err: %v\n", err2)
		}
		fmt.Printf("The path to this exe is: %v\n", dir)

		// alternate approach
		_, filename, _, _ := runtime.Caller(1)
		f, _ := os.Open(path.Join(path.Dir(filename), "serial-port-json-server"))
		fmt.Println(f)
	*/

	// using osext
	exePath, err3 := osext.Executable()
	if err3 != nil {
		log.Printf("Error getting exe path using osext lib. err: %v\n", err3)
	}

	if path == "" {
		log.Printf("exePath using osext: %v\n", exePath)
	} else {
		exePath = path
	}

	exePath = strings.Trim(exePath, "\n")
	// figure out garbageCollection flag
	//isGcFlag := "false"

	var cmd *exec.Cmd

	/*if *isGC {
		//isGcFlag = "true"
		cmd = exec.Command(exePath, "-ls", "-addr", *addr, "-regex", *regExpFilter, "-gc")
	} else {
		cmd = exec.Command(exePath, "-ls", "-addr", *addr, "-regex", *regExpFilter)

	}*/

	hiberString := ""
	if *hibernate == true {
		hiberString = "-hibernate"
	}

	cmd = exec.Command(exePath, "-ls", "-regex", *regExpFilter, "-gc", *gcType, hiberString)

	fmt.Println(cmd)

	//cmd := exec.Command("./serial-port-json-server", "ls")
	err := cmd.Start()
	if err != nil {
		log.Printf("Got err restarting spjs: %v\n", err)
		h.broadcastSys <- []byte("{\"Error\" : \"" + fmt.Sprintf("%v", err) + "\"}")
	} else {
		h.broadcastSys <- []byte("{\"Restarted\" : true}")
	}
	log.Fatal("Exited current spjs for restart")
	//log.Printf("Waiting for command to finish...")
	//err = cmd.Wait()
	//log.Printf("Command finished with error: %v", err)
}

type CmdBroadcast struct {
	Cmd string
	Msg string
}

func broadcast(arg string) {
	// we will get a string of broadcast asdf asdf asdf
	log.Println("Inside broadcast arg: " + arg)
	arg = strings.TrimPrefix(arg, " ")
	//log.Println("arg after trim: " + arg)
	args := strings.SplitN(arg, " ", 2)
	if len(args) != 2 {
		errstr := "Could not parse broadcast command: " + arg
		log.Println(errstr)
		spErr(errstr)
		return
	}
	broadcastcmd := strings.Trim(args[1], " ")
	log.Println("The broadcast cmd is:" + broadcastcmd + "---")

	bcmd := CmdBroadcast{
		Cmd: "Broadcast",
		Msg: broadcastcmd,
	}
	json, _ := json.Marshal(bcmd)
	log.Printf("bcmd:%v\n", string(json))
	h.broadcastSys <- json
}
<commit_msg>Fix error management for downloadtool<commit_after>package main

import (
	"fmt"

	log "github.com/Sirupsen/logrus"
	"github.com/kardianos/osext"
	//"os"
	"os/exec"
	//"path"
	//"path/filepath"
	//"runtime"
	//"debug"
	"encoding/json"
	"io"
	"os"
	"runtime"
	"runtime/debug"
	"strconv"
	"strings"
)

type hub struct {
	// Registered connections.
	connections map[*connection]bool

	// Inbound messages from the connections.
	broadcast chan []byte

	// Inbound messages from the system
	broadcastSys chan []byte

	// Register requests from the connections.
	register chan *connection

	// Unregister requests from connections.
	unregister chan *connection
}

var h = hub{
	// buffered. go with 1000 cuz should never surpass that
	broadcast:    make(chan []byte, 1000),
	broadcastSys: make(chan []byte, 1000),
	// non-buffered
	//broadcast:    make(chan []byte),
	//broadcastSys: make(chan []byte),
	register:    make(chan *connection),
	unregister:  make(chan *connection),
	connections: make(map[*connection]bool),
}

func (h *hub) run() {
	for {
		select {
		case c := <-h.register:
			h.connections[c] = true
			// send supported commands
			c.send <- []byte("{\"Version\" : \"" + version + "\"} ")
			c.send <- []byte("{\"Commands\" : [\"list\", \"open [portName] [baud] [bufferAlgorithm (optional)]\", \"send [portName] [cmd]\", \"sendnobuf [portName] [cmd]\", \"close [portName]\", \"bufferalgorithms\", \"baudrates\", \"restart\", \"exit\", \"program [portName] [board:name] [$path/to/filename/without/extension]\", \"programfromurl [portName] [board:name] [urlToHexFile]\"]} ")
			c.send <- []byte("{\"Hostname\" : \"" + *hostname + "\"} ")
			c.send <- []byte("{\"OS\" : \"" + runtime.GOOS + "\"} ")
		case c := <-h.unregister:
			delete(h.connections, c)
			// put close in func cuz it was creating panics and want
			// to isolate
			func() {
				// this method can panic if websocket gets disconnected
				// from users browser and we see we need to unregister a couple
				// of times, i.e. perhaps from incoming data from serial triggering
				// an unregister. (NOT 100% sure why seeing c.send be closed twice here)
				defer func() {
					if e := recover(); e != nil {
						log.Println("Got panic: ", e)
					}
				}()
				close(c.send)
			}()
		case m := <-h.broadcast:
			if len(m) > 0 {
				//log.Print(string(m))
				//log.Print(h.broadcast)
				checkCmd(m)
				//log.Print("-----")

				for c := range h.connections {
					select {
					case c.send <- m:
						//log.Print("did broadcast to ")
						//log.Print(c.ws.RemoteAddr())
						//c.send <- []byte("hello world")
					default:
						delete(h.connections, c)
						close(c.send)
					}
				}
			}
		case m := <-h.broadcastSys:
			for c := range h.connections {
				select {
				case c.send <- m:
					//log.Print("did broadcast to ")
					//log.Print(c.ws.RemoteAddr())
					//c.send <- []byte("hello world")
				default:
					delete(h.connections, c)
					close(c.send)
				}
			}
		}
	}
}

func checkCmd(m []byte) {
	//log.Print("Inside checkCmd")
	s := string(m[:])

	sl := strings.ToLower(strings.Trim(s, "\n"))

	if *hibernate == true {
		//do nothing
		return
	}

	if strings.HasPrefix(sl, "open") {

		// check if user wants to open this port as a secondary port
		// this doesn't mean much other than allowing the UI to show
		// a port as primary and make other ports sort of act less important
		isSecondary := false
		if strings.HasPrefix(s, "open secondary") {
			isSecondary = true
			// swap out the word secondary
			s = strings.Replace(s, "open secondary", "open", 1)
		}

		args := strings.Split(s, " ")
		if len(args) < 3 {
			go spErr("You did not specify a port and baud rate in your open cmd")
			return
		}
		if len(args[1]) < 1 {
			go spErr("You did not specify a serial port")
			return
		}

		baudStr := strings.Replace(args[2], "\n", "", -1)
		baud, err := strconv.Atoi(baudStr)
		if err != nil {
			go spErr("Problem converting baud rate " + args[2])
			return
		}
		// pass in buffer type now as string. if user does not
		// ask for a buffer type pass in empty string
		bufferAlgorithm := ""
		if len(args) > 3 {
			// cool. we got a buffer type request
			buftype := strings.Replace(args[3], "\n", "", -1)
			bufferAlgorithm = buftype
		}
		go spHandlerOpen(args[1], baud, bufferAlgorithm, isSecondary)

	} else if strings.HasPrefix(sl, "close") {

		args := strings.Split(s, " ")
		if len(args) > 1 {
			go spClose(args[1])
		} else {
			go spErr("You did not specify a port to close")
		}

	} else if strings.HasPrefix(sl, "killprogrammer") {
		// kill the running process (assumes singleton for now)
		go spHandlerProgramKill()

	} else if strings.HasPrefix(sl, "sendjsonraw") {
		// will catch sendjsonraw
		go spWriteJsonRaw(s)

	} else if strings.HasPrefix(sl, "sendjson") {
		// will catch sendjson
		go spWriteJson(s)

	} else if strings.HasPrefix(sl, "send") {
		// will catch send and sendnobuf

		//args := strings.Split(s, "send ")
		go spWrite(s)

	} else if strings.HasPrefix(sl, "list") {
		go spList(false)
		go spList(true)
	} else if strings.HasPrefix(sl, "downloadtool") {
		go func() {
			args := strings.Split(s, " ")
			var tool, toolVersion, behaviour string
			toolVersion = "latest"
			behaviour = "keep"
			if len(args) <= 1 {
				mapD := map[string]string{"DownloadStatus": "Error", "Msg": "Not enough arguments"}
				mapB, _ := json.Marshal(mapD)
				h.broadcastSys <- mapB
				return
			}
			if len(args) > 1 {
				tool = args[1]
			}
			if len(args) > 2 {
				toolVersion = args[2]
			}
			if len(args) > 3 {
				behaviour = args[3]
			}

			err := Tools.Download(tool, toolVersion, behaviour)
			if err != nil {
				mapD := map[string]string{"DownloadStatus": "Error", "Msg": err.Error()}
				mapB, _ := json.Marshal(mapD)
				h.broadcastSys <- mapB
			} else {
				mapD := map[string]string{"DownloadStatus": "Success", "Msg": "Map Updated"}
				mapB, _ := json.Marshal(mapD)
				h.broadcastSys <- mapB
			}
		}()
	} else if strings.HasPrefix(sl, "bufferalgorithm") {
		go spBufferAlgorithms()
	} else if strings.HasPrefix(sl, "log") {
		go logAction(sl)
	} else if strings.HasPrefix(sl, "baudrate") {
		go spBaudRates()
	} else if strings.HasPrefix(sl, "broadcast") {
		go broadcast(s)
	} else if strings.HasPrefix(sl, "restart") {
		log.Println("Received restart from the daemon. Why? Boh")
		restart("")
	} else if strings.HasPrefix(sl, "exit") {
		exit()
	} else if strings.HasPrefix(sl, "memstats") {
		memoryStats()
	} else if strings.HasPrefix(sl, "gc") {
		garbageCollection()
	} else if strings.HasPrefix(sl, "hostname") {
		getHostname()
	} else if strings.HasPrefix(sl, "version") {
		getVersion()
	} else {
		go spErr("Could not understand command.")
	}

	//log.Print("Done with checkCmd")
}

func logAction(sl string) {
	if strings.HasPrefix(sl, "log on") {
		*logDump = "on"
		multi_writer := io.MultiWriter(&logger_ws, os.Stderr)
		log.SetOutput(multi_writer)
	} else if strings.HasPrefix(sl, "log off") {
		*logDump = "off"
		log.SetOutput(os.Stderr)
	} else if strings.HasPrefix(sl, "log show") {
		// TODO: send all the saved log to websocket
		//h.broadcastSys <- []byte("{\"BufFlowDebug\" : \"" + *logDump + "\"}")
	}
}

func memoryStats() {
	var memStats runtime.MemStats
	runtime.ReadMemStats(&memStats)
	json, _ := json.Marshal(memStats)
	log.Printf("memStats:%v\n", string(json))
	h.broadcastSys <- json
}

func getHostname() {
	h.broadcastSys <- []byte("{\"Hostname\" : \"" + *hostname + "\"}")
}

func getVersion() {
	h.broadcastSys <- []byte("{\"Version\" : \"" + version + "\"}")
}

func garbageCollection() {
	log.Printf("Starting garbageCollection()\n")
	h.broadcastSys <- []byte("{\"gc\":\"starting\"}")
	memoryStats()
	debug.SetGCPercent(100)
	debug.FreeOSMemory()
	debug.SetGCPercent(-1)
	log.Printf("Done with garbageCollection()\n")
	h.broadcastSys <- []byte("{\"gc\":\"done\"}")
	memoryStats()
}

func exit() {
	log.Println("Starting new spjs process")
	h.broadcastSys <- []byte("{\"Exiting\" : true}")
	log.Fatal("Exited current spjs cuz asked to")

}

func restart(path string) {
	log.Println("called restart", path)
	// relaunch ourself and exit
	// the relaunch works because we pass a cmdline in
	// that has serial-port-json-server only initialize 5 seconds later
	// which gives us time to exit and unbind from serial ports and TCP/IP
	// sockets like :8989
	log.Println("Starting new spjs process")
	h.broadcastSys <- []byte("{\"Restarting\" : true}")

	// figure out current path of executable so we know how to restart
	// this process
	/*
		dir, err2 := filepath.Abs(filepath.Dir(os.Args[0]))
		if err2 != nil {
			//log.Fatal(err2)
			fmt.Printf("Error getting executable file path. err: %v\n", err2)
		}
		fmt.Printf("The path to this exe is: %v\n", dir)

		// alternate approach
		_, filename, _, _ := runtime.Caller(1)
		f, _ := os.Open(path.Join(path.Dir(filename), "serial-port-json-server"))
		fmt.Println(f)
	*/

	// using osext
	exePath, err3 := osext.Executable()
	if err3 != nil {
		log.Printf("Error getting exe path using osext lib. err: %v\n", err3)
	}

	if path == "" {
		log.Printf("exePath using osext: %v\n", exePath)
	} else {
		exePath = path
	}

	exePath = strings.Trim(exePath, "\n")
	// figure out garbageCollection flag
	//isGcFlag := "false"

	var cmd *exec.Cmd

	/*if *isGC {
		//isGcFlag = "true"
		cmd = exec.Command(exePath, "-ls", "-addr", *addr, "-regex", *regExpFilter, "-gc")
	} else {
		cmd = exec.Command(exePath, "-ls", "-addr", *addr, "-regex", *regExpFilter)

	}*/

	hiberString := ""
	if *hibernate == true {
		hiberString = "-hibernate"
	}

	cmd = exec.Command(exePath, "-ls", "-regex", *regExpFilter, "-gc", *gcType, hiberString)

	fmt.Println(cmd)

	//cmd := exec.Command("./serial-port-json-server", "ls")
	err := cmd.Start()
	if err != nil {
		log.Printf("Got err restarting spjs: %v\n", err)
		h.broadcastSys <- []byte("{\"Error\" : \"" + fmt.Sprintf("%v", err) + "\"}")
	} else {
		h.broadcastSys <- []byte("{\"Restarted\" : true}")
	}
	log.Fatal("Exited current spjs for restart")
	//log.Printf("Waiting for command to finish...")
	//err = cmd.Wait()
	//log.Printf("Command finished with error: %v", err)
}

type CmdBroadcast struct {
	Cmd string
	Msg string
}

func broadcast(arg string) {
	// we will get a string of broadcast asdf asdf asdf
	log.Println("Inside broadcast arg: " + arg)
	arg = strings.TrimPrefix(arg, " ")
	//log.Println("arg after trim: " + arg)
	args := strings.SplitN(arg, " ", 2)
	if len(args) != 2 {
		errstr := "Could not parse broadcast command: " + arg
		log.Println(errstr)
		spErr(errstr)
		return
	}
	broadcastcmd := strings.Trim(args[1], " ")
	log.Println("The broadcast cmd is:" + broadcastcmd + "---")

	bcmd := CmdBroadcast{
		Cmd: "Broadcast",
		Msg: broadcastcmd,
	}
	json, _ := json.Marshal(bcmd)
	log.Printf("bcmd:%v\n", string(json))
	h.broadcastSys <- json
}
<|endoftext|>


<commit_before>package sdp

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/pions/webrtc/pkg/ice"
)

// ICECandidateUnmarshal takes a candidate strings and returns a ice.Candidate or nil if it fails to parse
func ICECandidateUnmarshal(raw string) ice.Candidate {
	split := strings.Fields(raw)
	if len(split) < 8 {
		fmt.Printf("Attribute not long enough to be ICE candidate (%d) %s \n", len(split), raw)
		return nil
	}

	getValue := func(key string) string {
		rtrnNext := false
		for _, i := range split {
			if rtrnNext {
				return i
			} else if i == key {
				rtrnNext = true
			}
		}
		return ""
	}

	port, err := strconv.Atoi(split[5])
	if err != nil {
		return nil
	}

	// TODO verify valid address
	address := split[4]

	switch getValue("typ") {
	case "host":
		return &ice.CandidateHost{
			CandidateBase: ice.CandidateBase{
				Protocol: ice.ProtoTypeUDP,
				Address:  address,
				Port:     port,
			},
		}
	case "srflx":
		return &ice.CandidateSrflx{
			CandidateBase: ice.CandidateBase{
				Protocol: ice.ProtoTypeUDP,
				Address:  address,
				Port:     port,
			},
		}
	default:
		return nil
	}
}

func iceSrflxCandidateString(c *ice.CandidateSrflx, component int) string {
	return fmt.Sprintf("udpcandidate %d udp %d %s %d typ srflx raddr %s rport %d generation 0",
		component, c.CandidateBase.Priority(ice.SrflxCandidatePreference, uint16(component)), c.CandidateBase.Address, c.CandidateBase.Port, c.RemoteAddress, c.RemotePort)
}

func iceHostCandidateString(c *ice.CandidateHost, component int) string {
	return fmt.Sprintf("udpcandidate %d udp %d %s %d typ host generation 0",
		component, c.CandidateBase.Priority(ice.HostCandidatePreference, uint16(component)), c.CandidateBase.Address, c.CandidateBase.Port)
}

// ICECandidateMarshal takes a candidate and returns a string representation
func ICECandidateMarshal(c ice.Candidate) []string {
	out := make([]string, 0)

	switch c := c.(type) {
	case *ice.CandidateSrflx:
		out = append(out, iceSrflxCandidateString(c, 1))
		out = append(out, iceSrflxCandidateString(c, 2))
	case *ice.CandidateHost:
		out = append(out, iceHostCandidateString(c, 1))
		out = append(out, iceHostCandidateString(c, 2))
	}

	return out
}
<commit_msg>ICE: Transport refactor<commit_after>package sdp

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/pions/webrtc/pkg/ice"
)

// ICECandidateUnmarshal takes a candidate strings and returns a ice.Candidate or nil if it fails to parse
func ICECandidateUnmarshal(raw string) ice.Candidate {
	split := strings.Fields(raw)
	if len(split) < 8 {
		fmt.Printf("Attribute not long enough to be ICE candidate (%d) %s \n", len(split), raw)
		return nil
	}

	getValue := func(key string) string {
		rtrnNext := false
		for _, i := range split {
			if rtrnNext {
				return i
			} else if i == key {
				rtrnNext = true
			}
		}
		return ""
	}

	port, err := strconv.Atoi(split[5])
	if err != nil {
		return nil
	}

	// TODO verify valid address
	address := split[4]

	switch getValue("typ") {
	case "host":
		return &ice.CandidateHost{
			CandidateBase: ice.CandidateBase{
				Protocol: ice.ProtoTypeUDP,
				Address:  address,
				Port:     port,
			},
		}
	case "srflx":
		return &ice.CandidateSrflx{
			CandidateBase: ice.CandidateBase{
				Protocol: ice.ProtoTypeUDP,
				Address:  address,
				Port:     port,
			},
		}
	default:
		return nil
	}
}

func iceSrflxCandidateString(c *ice.CandidateSrflx, component int) string {
	return fmt.Sprintf("udpcandidate %d udp %d %s %d typ srflx raddr %s rport %d generation 0",
		component, c.CandidateBase.Priority(ice.SrflxCandidatePreference, uint16(component)), c.CandidateBase.Address, c.CandidateBase.Port, c.RelatedAddress, c.RelatedPort)
}

func iceHostCandidateString(c *ice.CandidateHost, component int) string {
	return fmt.Sprintf("udpcandidate %d udp %d %s %d typ host generation 0",
		component, c.CandidateBase.Priority(ice.HostCandidatePreference, uint16(component)), c.CandidateBase.Address, c.CandidateBase.Port)
}

// ICECandidateMarshal takes a candidate and returns a string representation
func ICECandidateMarshal(c ice.Candidate) []string {
	out := make([]string, 0)

	switch c := c.(type) {
	case *ice.CandidateSrflx:
		out = append(out, iceSrflxCandidateString(c, 1))
		out = append(out, iceSrflxCandidateString(c, 2))
	case *ice.CandidateHost:
		out = append(out, iceHostCandidateString(c, 1))
		out = append(out, iceHostCandidateString(c, 2))
	}

	return out
}
<|endoftext|>


<commit_before>package news_getter

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

var (
	getTimeout = time.Duration(5 * time.Second)
)

type unMarshalledContent map[string]interface{}

// func httpGet(url_string string) (*http.Response, error) {
// 	response, err := http.Get(url_string)
// 	if err != nil {
// 		fmt.Println(err)
// 		return nil, err
// 	}
// 	return response, nil
// }

func httpGet(urlString string) (*http.Response, error) {

	client := &http.Client{
		Timeout: getTimeout,
	}

	req, err := http.NewRequest("GET", urlString, nil)
	if err != nil {
		fmt.Println(err)
		return nil, err
	}

	resp, err := client.Do(req)
	if err != nil || resp.StatusCode != 200 {
		fmt.Println("status code: ", resp)
		fmt.Println("err: ", err)
		fmt.Println("-----------------------------------")
		return nil, err
	}
	return resp, nil
}

func responseReader(response *http.Response) ([]byte, error) {
	contents, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, err
	}
	return contents, nil
}

func unmarshalResponseContent(content []byte, dataContainer interface{}) (interface{}, error) {
	if err := json.Unmarshal(content, &dataContainer); err != nil {
		fmt.Println(err)
		return nil, err
	}
	return dataContainer, nil
}
<commit_msg>added TODO msg in httpget<commit_after>package news_getter

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

var (
	getTimeout = time.Duration(5 * time.Second)
)

type unMarshalledContent map[string]interface{}

// func httpGet(url_string string) (*http.Response, error) {
// 	response, err := http.Get(url_string)
// 	if err != nil {
// 		fmt.Println(err)
// 		return nil, err
// 	}
// 	return response, nil
// }

// TODO add aditional flag if resp err is nil but fail
func httpGet(urlString string) (*http.Response, error) {

	client := &http.Client{
		Timeout: getTimeout,
	}

	req, err := http.NewRequest("GET", urlString, nil)
	if err != nil {
		fmt.Println(err)
		return nil, err
	}

	resp, err := client.Do(req)
	if err != nil || resp.StatusCode != 200 {
		fmt.Println("status code: ", resp)
		fmt.Println("err: ", err)
		fmt.Println("-----------------------------------")
		return nil, err
	}
	return resp, nil
}

func responseReader(response *http.Response) ([]byte, error) {
	contents, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, err
	}
	return contents, nil
}

func unmarshalResponseContent(content []byte, dataContainer interface{}) (interface{}, error) {
	if err := json.Unmarshal(content, &dataContainer); err != nil {
		fmt.Println(err)
		return nil, err
	}
	return dataContainer, nil
}
<|endoftext|>


<commit_before>package activitystreams

import (
	"net/url"
	"strings"
)

type (
	// IRI is a Internationalized Resource Identifiers (IRIs) RFC3987
	IRI string
	IRIs []IRI
)

// String returns the String value of the IRI object
func (i IRI) String() string {
	return string(i)
}

// GetLink
func (i IRI) GetLink() IRI {
	return i
}

// URL
func (i IRI) URL() (*url.URL, error) {
	return url.Parse(i.String())
}

// UnmarshalJSON
func (i *IRI) UnmarshalJSON(s []byte) error {
	*i = IRI(strings.Trim(string(s), "\""))
	return nil
}

// IsObject
func (i IRI) GetID() *ObjectID {
	o := ObjectID(i)
	return &o
}

// GetType
func (i IRI) GetType() ActivityVocabularyType {
	return LinkType
}

// IsLink
func (i IRI) IsLink() bool {
	return true
}

// IsObject
func (i IRI) IsObject() bool {
	return false
}

// FlattenToIRI checks if Item can be flatten to an IRI and returns it if so
func FlattenToIRI(it Item) Item {
	if it!= nil && it.IsObject() && len(it.GetLink()) > 0 {
		return it.GetLink()
	}
	return it
}

// Contains verifies if IRIs array contains the received one
func(i IRIs) Contains(r IRI) bool {
	if len(i) == 0 {
		return true
	}
	for _, iri := range i {
		if strings.ToLower(r.String()) == strings.ToLower(iri.String()) {
			return true
		}
	}
	return false
}
<commit_msg>Added the public namespace as a constant<commit_after>package activitystreams

import (
	"net/url"
	"strings"
)

const PublicNS = IRI("https://www.w3.org/ns/activitystreams#Public")

type (
	// IRI is a Internationalized Resource Identifiers (IRIs) RFC3987
	IRI string
	IRIs []IRI
)

// String returns the String value of the IRI object
func (i IRI) String() string {
	return string(i)
}

// GetLink
func (i IRI) GetLink() IRI {
	return i
}

// URL
func (i IRI) URL() (*url.URL, error) {
	return url.Parse(i.String())
}

// UnmarshalJSON
func (i *IRI) UnmarshalJSON(s []byte) error {
	*i = IRI(strings.Trim(string(s), "\""))
	return nil
}

// IsObject
func (i IRI) GetID() *ObjectID {
	o := ObjectID(i)
	return &o
}

// GetType
func (i IRI) GetType() ActivityVocabularyType {
	return LinkType
}

// IsLink
func (i IRI) IsLink() bool {
	return true
}

// IsObject
func (i IRI) IsObject() bool {
	return false
}

// FlattenToIRI checks if Item can be flatten to an IRI and returns it if so
func FlattenToIRI(it Item) Item {
	if it!= nil && it.IsObject() && len(it.GetLink()) > 0 {
		return it.GetLink()
	}
	return it
}

// Contains verifies if IRIs array contains the received one
func(i IRIs) Contains(r IRI) bool {
	if len(i) == 0 {
		return true
	}
	for _, iri := range i {
		if strings.ToLower(r.String()) == strings.ToLower(iri.String()) {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package servicing

import (
	"time"

	"github.com/go-kit/kit/log"
	"github.com/pkg/errors"
	"k8s.io/client-go/tools/record"

	"github.com/sapcc/kubernikus/pkg/api/models"
	v1 "github.com/sapcc/kubernikus/pkg/apis/kubernikus/v1"
	"github.com/sapcc/kubernikus/pkg/controller/base"
	"github.com/sapcc/kubernikus/pkg/controller/config"
)

const (
	// AnnotationServicingSafeguard must be set to enable servicing
	AnnotationServicingSafeguard = "kubernikus.cloud.sap/servicing"
)

var (
	// Now is a poor-man's facility to change time during testing
	Now = time.Now
)

// Controller periodically checks for nodes requiting updates or upgrades
//
// This controller handles node upgrades when the Kubernetes or CoreOS versions
// are changed. It gracefully drains nodes before performing any action.
//
// For Kubernetes upgrades the strategy is to replace the fleet by terminating
// the nodes. CoreOS updates are handled by a soft reboot.
//
// In order to allow the payload to settle only a single node per cluster is
// processed at a time. Between updates there's a 1h grace period.
//
// In case any node in the cluster is unhealthy the upgrades are skipped. This
// is to safeguard against failed upgrades destroying the universe.
//
// For rollout and testing purposed the node upgrades are disabled by default.
// They can manually be enabled by setting the node annotaion:
//
//    kubernikus.cloud.sap/servicing=true
//
type Controller struct {
	Logger     log.Logger
	Reconciler ReconcilerFactory
}

// NewController is a helper to create a Servicing Controller instance
func NewController(threadiness int, factories config.Factories, clients config.Clients, recorder record.EventRecorder, logger log.Logger) base.Controller {
	logger = log.With(logger, "controller", "servicing")

	var controller base.Reconciler
	controller = &Controller{
		Logger:     logger,
		Reconciler: NewKlusterReconcilerFactory(logger, recorder, factories, clients),
	}

	RegisterServicingNodesCollector(logger, factories)

	return base.NewController(threadiness, factories, controller, logger, nil, "servicing")
}

// Reconcile checks a kluster for node updates
func (d *Controller) Reconcile(k *v1.Kluster) (requeue bool, err error) {
	//Skip klusters not in state running
	if k.Status.Phase != models.KlusterPhaseRunning {
		return false, nil
	}
	reconciler, err := d.Reconciler.Make(k)
	if err != nil {
		d.Logger.Log("msg", "skippig upgrades. Internal server error.", "err", err)
		return true, errors.Wrap(err, "Couldn't make Servicing Reconciler.")
	}

	return false, reconciler.Do()
}
<commit_msg>disable servicing controller for no cloud clusters<commit_after>package servicing

import (
	"time"

	"github.com/go-kit/kit/log"
	"github.com/pkg/errors"
	"k8s.io/client-go/tools/record"

	"github.com/sapcc/kubernikus/pkg/api/models"
	v1 "github.com/sapcc/kubernikus/pkg/apis/kubernikus/v1"
	"github.com/sapcc/kubernikus/pkg/controller/base"
	"github.com/sapcc/kubernikus/pkg/controller/config"
)

const (
	// AnnotationServicingSafeguard must be set to enable servicing
	AnnotationServicingSafeguard = "kubernikus.cloud.sap/servicing"
)

var (
	// Now is a poor-man's facility to change time during testing
	Now = time.Now
)

// Controller periodically checks for nodes requiting updates or upgrades
//
// This controller handles node upgrades when the Kubernetes or CoreOS versions
// are changed. It gracefully drains nodes before performing any action.
//
// For Kubernetes upgrades the strategy is to replace the fleet by terminating
// the nodes. CoreOS updates are handled by a soft reboot.
//
// In order to allow the payload to settle only a single node per cluster is
// processed at a time. Between updates there's a 1h grace period.
//
// In case any node in the cluster is unhealthy the upgrades are skipped. This
// is to safeguard against failed upgrades destroying the universe.
//
// For rollout and testing purposed the node upgrades are disabled by default.
// They can manually be enabled by setting the node annotaion:
//
//    kubernikus.cloud.sap/servicing=true
//
type Controller struct {
	Logger     log.Logger
	Reconciler ReconcilerFactory
}

// NewController is a helper to create a Servicing Controller instance
func NewController(threadiness int, factories config.Factories, clients config.Clients, recorder record.EventRecorder, logger log.Logger) base.Controller {
	logger = log.With(logger, "controller", "servicing")

	var controller base.Reconciler
	controller = &Controller{
		Logger:     logger,
		Reconciler: NewKlusterReconcilerFactory(logger, recorder, factories, clients),
	}

	RegisterServicingNodesCollector(logger, factories)

	return base.NewController(threadiness, factories, controller, logger, nil, "servicing")
}

// Reconcile checks a kluster for node updates
func (d *Controller) Reconcile(k *v1.Kluster) (requeue bool, err error) {
	//Skip klusters not in state running
	if k.Status.Phase != models.KlusterPhaseRunning {
		return false, nil
	}
	//no servicing for no cloud clusters
	if k.Spec.NoCloud {
		return false, nil
	}
	reconciler, err := d.Reconciler.Make(k)
	if err != nil {
		d.Logger.Log("msg", "skippig upgrades. Internal server error.", "kluster", kluster.Name, "err", err)
		return true, errors.Wrap(err, "Couldn't make Servicing Reconciler.")
	}

	return false, reconciler.Do()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

type hexkitMap map[string]json.RawMessage
type layersList []map[string]json.RawMessage
type tilesList []map[string]interface{}

var fileList = make(map[string][]string, 4096)

// Search fon all png files under the current path
func pathMap(path string, info os.FileInfo, err error) error {
	if err != nil {
		fmt.Println(err)
	}
	name := info.Name()
	lenPath := len(path)
	if lenPath > 16 && path[lenPath-4:] == ".png" {
		fileList[name] = append(fileList[name], path)
	}
	return nil
}

func main() {
	if len(os.Args) != 3 {
		fmt.Println("Usage:", os.Args[0], "HexKitPath MapPath")
		return
	}
	var hexMap hexkitMap
	var layers layersList
	pathSep := regexp.MustCompile(`[/:]`)
	err := filepath.Walk(os.Args[1], pathMap)
	if err != nil {
		log.Fatal(err)
	}
	mapFile := os.Args[2]
	// Read the file
	mapBlob, err := ioutil.ReadFile(mapFile)
	if err != nil {
		log.Fatal("error:", err)
	}
	// Decode it in hexMap
	err = json.Unmarshal(mapBlob, &hexMap)
	if err != nil {
		log.Fatal("error:", mapFile, ":", err)
	}
	// Get the layers list
	layersBlob, ok := hexMap["layers"]
	if !ok {
		log.Fatal("error: no layer in", mapFile)
	}
	err = json.Unmarshal(layersBlob, &layers)
	if err != nil {
		log.Fatal("error:", mapFile, ":", err)
	}
	layersModified := false
	for _, v := range layers {
		var tiles tilesList
		tilesBlob, ok := v["tiles"]
		if !ok {
			log.Println("error: no tiles in", mapFile)
			continue
		}
		err = json.Unmarshal(tilesBlob, &tiles)
		if err != nil {
			log.Println("error:", mapFile, ":", err)
			continue
		}
		tilesModified := false
		for _, t := range tiles {
			// Ignore undefined tiles
			if t == nil {
				continue
			}
			sourceBlob, ok := t["source"]
			if !ok {
				log.Println("error: tile with no source in", mapFile)
				continue
			}
			source, ok := sourceBlob.(string)
			if !ok {
				log.Println("error: incorrect source found in", mapFile)
				continue
			}
			if source[:6] == "Blank:" {
				continue
			}
			fileName := filepath.Base(source)
			pathList, ok := fileList[fileName]
			if !ok {
				log.Println("error: tile", source, "not found in", mapFile)
				continue
			}
			firstSplit := strings.SplitN(source, ":", 2)
			if len(firstSplit) >= 2 {
				targetCollection := firstSplit[0]
				targetPath := firstSplit[1]
				var bestMatch int
				var selected string
			pathSearch:
				for _, p := range pathList {
					splitPath := pathSep.Split(p, -1)
					for k, segment := range splitPath {
						if segment == targetCollection {
							foundPath := "/" + strings.Join(splitPath[k+1:], "/")
							if targetPath == foundPath {
								selected = targetCollection + ":" + foundPath
								break pathSearch
							}
							if len(foundPath) > bestMatch {
								bestMatch = len(foundPath)
								selected = targetCollection + ":" + foundPath
							}
						}
					}
					if selected != "" {
						tilesModified = true
						t["source"] = selected
					}
				}
			}
		}
		if tilesModified {
			tilesBlob, err := json.Marshal(tiles)
			if err != nil {
				log.Println("error:", err)
			}
			v["tiles"] = tilesBlob
			layersModified = true
		}
	}
	if layersModified {
		layersBlob, err := json.Marshal(layers)
		if err != nil {
			log.Println("error:", err)
		}
		hexMap["layers"] = layersBlob
	}
	b, err := json.Marshal(hexMap)
	if err != nil {
		log.Println("error:", err)
	}
	_, err = os.Stdout.Write(b)
	if err != nil {
		log.Println("error:", err)
	}

}
<commit_msg>Use backslash as a path-separator on Windows<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

type hexkitMap map[string]json.RawMessage
type layersList []map[string]json.RawMessage
type tilesList []map[string]interface{}

var fileList = make(map[string][]string, 4096)

// Search fon all png files under the current path
func pathMap(path string, info os.FileInfo, err error) error {
	if err != nil {
		fmt.Println(err)
	}
	name := info.Name()
	lenPath := len(path)
	if lenPath > 16 && path[lenPath-4:] == ".png" {
		fileList[name] = append(fileList[name], path)
	}
	return nil
}

func main() {
	if len(os.Args) != 3 {
		fmt.Println("Usage:", os.Args[0], "HexKitPath MapPath")
		return
	}
	pathSeparator := "/"
	if os.PathSeparator != '/' {
		pathSeparator = "\\\\"
	}
	var hexMap hexkitMap
	var layers layersList
	pathBreak := regexp.MustCompile(`([/:]|\\\\)`)
	err := filepath.Walk(os.Args[1], pathMap)
	if err != nil {
		log.Fatal(err)
	}
	mapFile := os.Args[2]
	// Read the file
	mapBlob, err := ioutil.ReadFile(mapFile)
	if err != nil {
		log.Fatal("error:", err)
	}
	// Decode it in hexMap
	err = json.Unmarshal(mapBlob, &hexMap)
	if err != nil {
		log.Fatal("error:", mapFile, ":", err)
	}
	// Get the layers list
	layersBlob, ok := hexMap["layers"]
	if !ok {
		log.Fatal("error: no layer in", mapFile)
	}
	err = json.Unmarshal(layersBlob, &layers)
	if err != nil {
		log.Fatal("error:", mapFile, ":", err)
	}
	layersModified := false
	for _, v := range layers {
		var tiles tilesList
		tilesBlob, ok := v["tiles"]
		if !ok {
			log.Println("error: no tiles in", mapFile)
			continue
		}
		err = json.Unmarshal(tilesBlob, &tiles)
		if err != nil {
			log.Println("error:", mapFile, ":", err)
			continue
		}
		tilesModified := false
		for _, t := range tiles {
			// Ignore undefined tiles
			if t == nil {
				continue
			}
			sourceBlob, ok := t["source"]
			if !ok {
				log.Println("error: tile with no source in", mapFile)
				continue
			}
			source, ok := sourceBlob.(string)
			if !ok {
				log.Println("error: incorrect source found in", mapFile)
				continue
			}
			if source[:6] == "Blank:" {
				continue
			}
			fileName := filepath.Base(source)
			pathList, ok := fileList[fileName]
			if !ok {
				log.Println("error: tile", source, "not found in", mapFile)
				continue
			}
			firstSplit := strings.SplitN(source, ":", 2)
			if len(firstSplit) >= 2 {
				targetCollection := firstSplit[0]
				targetPath := firstSplit[1]
				var bestMatch int
				var selected string
			pathSearch:
				for _, p := range pathList {
					splitPath := pathBreak.Split(p, -1)
					for k, segment := range splitPath {
						if segment == targetCollection {
							foundPath := pathSeparator + strings.Join(splitPath[k+1:], pathSeparator)
							if targetPath == foundPath {
								selected = targetCollection + ":" + foundPath
								break pathSearch
							}
							if len(foundPath) > bestMatch {
								bestMatch = len(foundPath)
								selected = targetCollection + ":" + foundPath
							}
						}
					}
					if selected != "" {
						tilesModified = true
						t["source"] = selected
					}
				}
			}
		}
		if tilesModified {
			tilesBlob, err := json.Marshal(tiles)
			if err != nil {
				log.Println("error:", err)
			}
			v["tiles"] = tilesBlob
			layersModified = true
		}
	}
	if layersModified {
		layersBlob, err := json.Marshal(layers)
		if err != nil {
			log.Println("error:", err)
		}
		hexMap["layers"] = layersBlob
	}
	b, err := json.Marshal(hexMap)
	if err != nil {
		log.Println("error:", err)
	}
	_, err = os.Stdout.Write(b)
	if err != nil {
		log.Println("error:", err)
	}

}
<|endoftext|>