<commit_before>package main

import (
	"bufio"
	"errors"
	"net"
	"os"
	"strings"
	"io/ioutil"
	"path"

	"gopkg.in/op/go-logging.v1"
	"gopkg.in/yaml.v2"

)

var log = logging.MustGetLogger("wormhole")
var format = logging.MustStringFormatter(
	"%{color}%{time:15:04:05.000} %{shortfunc} %{level:.5s} %{id:03x}%{color:reset} >> %{message}",
)

type Error interface {
	Error() string
}

type WormholeConfig struct {
	port int
	translations map[string]string
	editors map[string]string
}

func main() {

	// Setup logging
	logbackend := logging.NewLogBackend(os.Stdout, "", 0)
	logbackendformatter := logging.NewBackendFormatter(logbackend, format)
	logging.SetBackend(logbackend, logbackendformatter)

	// Read config
	log.Info("Parsing wormhole configuration ...")
	var config WormholeConfig
	source, err := ioutil.ReadFile(path.Join(os.Getenv("HOME"), ".wormhole.yml"))
	if err != nil {
		log.Fatal(err)
	}

	err = yaml.Unmarshal(source, &config)
	if err != nil {
		log.Fatal(err)
	}
	log.Debugf("Configuration: %s", config)

	// Start main
	log.Info("Wormhole server starting ...")

	l, err := net.Listen("tcp", ":2000")
	if err != nil {
		log.Fatal(err)
	}

	defer l.Close()
	for {
		// Wait for connection
		conn, err := l.Accept()
		if err != nil {
			log.Fatal(err)
		}

		log.Debug("Received connection from %s", conn.RemoteAddr().String())

		// Handle connection
		go handleConnection(conn)
	}
}

func handleConnection(c net.Conn) {
	defer c.Close()

	line, err := bufio.NewReader(c).ReadString('\n')
	if err != nil {
		log.Fatal(err)
	}

	writer := bufio.NewWriter(c)

	log.Debug("[%s] %s", c.RemoteAddr().String(), line)
	resp, err := handleLine(c, line)

	if err != nil {
		writer.WriteString("Err ")
		writer.WriteString(err.Error())
	} else {
		writer.WriteString("Ok ")
		writer.WriteString(resp)
	}

	writer.Flush()
}

func handleLine(c net.Conn, line string) (resp string, err Error) {
	parts := strings.Split(strings.TrimSpace(line), " ")

	log.Debug("Extracted parts %s", parts)
	if len(parts) < 2 {
		log.Debug("Too little parts, quit.")
		return "", errors.New("Too few words, expected at least 2.")
	}

	switch parts[0] {
	case "EDIT":
		return handleCommandEdit(parts[1:])

	case "SHELL":
		return handleCommandShell(parts[1:])

	case "EXPLORE":
		return handleCommandExplore(parts[1:])

	case "START":
		return handleCommandStart(parts[1:])
	}

	return "", errors.New("Unknown command, expected one of [EDIT, SHELL, EXPLORE, START]")
}

func handleCommandEdit(parts []string) (resp string, err Error) {
	log.Info("EDIT", parts)
	return "OK", nil
}

func handleCommandStart(parts []string) (resp string, err Error) {
	log.Info("START", parts)
	return "OK", nil
}

func handleCommandExplore(parts []string) (resp string, err Error) {
	log.Info("EXPLORE", parts)
	return "OK", nil
}

func handleCommandShell(parts []string) (resp string, err Error) {
	log.Info("SHELL", parts)
	return "OK", nil
}
<commit_msg>Implement reading from ~/.wormhole.yml<commit_after>package main

import (
	"bufio"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"path"
	"strconv"
	"strings"

	"gopkg.in/op/go-logging.v1"
	"gopkg.in/yaml.v2"
)

var log = logging.MustGetLogger("wormhole")
var format = logging.MustStringFormatter(
	"%{color}%{time:15:04:05.000} %{shortfunc} %{level:.5s} %{id:03x}%{color:reset} >> %{message}",
)

type Error interface {
	Error() string
}

type WormholeConfig struct {
	Port    int               `yaml:"port,omitempty"`
	Mapping map[string]string `yaml:"mapping"`
	Editors map[string]string `yaml:"editors"`
}

func (this *WormholeConfig) String() string {
	str := "Config {\n"
	str += "  Port: " + fmt.Sprint(this.GetPort()) + "\n"

	str += "  Path mappings: {\n"
	for key, value := range this.Mapping {
		str += "    " + key + " -> " + value + "\n"
	}
	str += "  }\n"

	str += "  Editors: {\n"
	for name, path := range this.Editors {
		str += "    " + name + " -> " + path + "\n"
	}
	str += "  }\n"

	str += "}"

	return str
}

func (this *WormholeConfig) GetPort() int {
	if 0 == this.Port {
		return 5115
	}

	return this.Port
}

func main() {

	// Setup logging
	logbackend := logging.NewLogBackend(os.Stdout, "", 0)
	logbackendformatter := logging.NewBackendFormatter(logbackend, format)
	logging.SetBackend(logbackend, logbackendformatter)

	// Read config
	log.Info("Parsing wormhole configuration ...")
	var config WormholeConfig
	source, err := ioutil.ReadFile(path.Join(os.Getenv("HOME"), ".wormhole.yml"))
	log.Debug("%s", source)
	if err != nil {
		log.Fatal(err)
	}

	err = yaml.Unmarshal(source, &config)
	if err != nil {
		log.Fatal(err)
	}
	log.Debug("Configuration: %v", config.String())

	// Start main
	log.Info("Wormhole server starting ...")

	l, err := net.Listen("tcp4", ":"+strconv.Itoa(config.GetPort()))
	if err != nil {
		log.Fatal(err)
	}

	log.Info("Listening at " + l.Addr().String())

	defer l.Close()
	for {
		// Wait for connection
		conn, err := l.Accept()
		if err != nil {
			log.Fatal(err)
		}

		log.Debug("Received connection from %s", conn.RemoteAddr().String())

		// Handle connection
		go handleConnection(conn)
	}
}

func handleConnection(c net.Conn) {
	defer c.Close()

	line, err := bufio.NewReader(c).ReadString('\n')
	if err != nil {
		log.Fatal(err)
	}

	writer := bufio.NewWriter(c)

	log.Debug("[%s] %s", c.RemoteAddr().String(), line)
	resp, err := handleLine(c, line)

	if err != nil {
		writer.WriteString("Err ")
		writer.WriteString(err.Error())
	} else {
		writer.WriteString("Ok ")
		writer.WriteString(resp)
	}

	writer.Flush()
}

func handleLine(c net.Conn, line string) (resp string, err Error) {
	parts := strings.Split(strings.TrimSpace(line), " ")

	log.Debug("Extracted parts %s", parts)
	if len(parts) < 2 {
		log.Debug("Too little parts, quit.")
		return "", errors.New("Too few words, expected at least 2.")
	}

	switch parts[0] {
	case "EDIT":
		return handleCommandEdit(parts[1:])

	case "SHELL":
		return handleCommandShell(parts[1:])

	case "EXPLORE":
		return handleCommandExplore(parts[1:])

	case "START":
		return handleCommandStart(parts[1:])
	}

	return "", errors.New("Unknown command, expected one of [EDIT, SHELL, EXPLORE, START]")
}

func handleCommandEdit(parts []string) (resp string, err Error) {
	log.Info("EDIT", parts)
	return "OK", nil
}

func handleCommandStart(parts []string) (resp string, err Error) {
	log.Info("START", parts)
	return "OK", nil
}

func handleCommandExplore(parts []string) (resp string, err Error) {
	log.Info("EXPLORE", parts)
	return "OK", nil
}

func handleCommandShell(parts []string) (resp string, err Error) {
	log.Info("SHELL", parts)
	return "OK", nil
}
<|endoftext|>


<commit_before>// Copyright 2015-2016, Cyrill @ Schumacher.fm and the CoreStore contributors
//
// 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 ratelimit_test

import (
	"github.com/corestoreio/csfw/net"
	"github.com/corestoreio/csfw/net/ratelimit"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestVaryBy_Key(t *testing.T) {
	tests := []struct {
		varyBy func() ratelimit.VaryByer
		req    func() *http.Request
		want   string
	}{
		{
			func() ratelimit.VaryByer { return (*ratelimit.VaryBy)(nil) },
			func() *http.Request {
				return httptest.NewRequest("GET", "https://corestore.io/_1", nil)
			},
			"",
		},
		{
			func() ratelimit.VaryByer {
				return &ratelimit.VaryBy{
					RemoteAddr: true,
				}
			},
			func() *http.Request {
				r := httptest.NewRequest("GET", "https://corestore.io/_2", nil)
				r.Header.Set(net.XClusterClientIP, "123.123.22.11")
				return r
			},
			"123.123.22.11\n",
		},
		{
			func() ratelimit.VaryByer {
				return &ratelimit.VaryBy{
					RemoteAddr: true,
					Method:     true,
				}
			},
			func() *http.Request {
				r := httptest.NewRequest("PUT", "https://corestore.io/_3", nil)
				r.Header.Set(net.XClusterClientIP, "123.123.22.11")
				return r
			},
			"123.123.22.11\nput\n",
		},
		{
			func() ratelimit.VaryByer {
				return &ratelimit.VaryBy{
					RemoteAddr: true,
					Method:     true,
					Path:       true,
				}
			},
			func() *http.Request {
				r := httptest.NewRequest("PUT", "https://corestore.IO/_4Xy", nil)
				r.Header.Set(net.XClusterClientIP, "123.123.22.11")
				return r
			},
			"123.123.22.11\nput\n/_4Xy\n",
		},
		{
			func() ratelimit.VaryByer {
				return &ratelimit.VaryBy{
					RemoteAddr: true,
					Method:     true,
					Path:       true,
					Headers:    []string{"X-Key"},
				}
			},
			func() *http.Request {
				r := httptest.NewRequest("PUT", "https://corestore.IO/_5_Xy", nil)
				r.RemoteAddr = "123.123.22.11"
				r.Header.Set("X-Key", "y-Value")
				return r
			},
			"123.123.22.11\nput\ny-value\n/_5_Xy\n",
		},
		{
			func() ratelimit.VaryByer {
				return &ratelimit.VaryBy{
					RemoteAddr: true,
					Method:     true,
					Path:       true,
					Headers:    []string{"X-Key"},
					Params:     []string{"aa"},
				}
			},
			func() *http.Request {
				r := httptest.NewRequest("PUT", "https://corestore.IO/_6_Xy?aa=bb", nil)
				r.RemoteAddr = "123.123.22.11"
				r.Header.Set("X-Key", "y-valÜe")
				return r
			},
			"123.123.22.11\nput\ny-valÜe\n/_6_Xy\nbb\n",
		},
		{
			func() ratelimit.VaryByer {
				return &ratelimit.VaryBy{
					RemoteAddr: true,
					Method:     true,
					Path:       true,
					Headers:    []string{"X-Key"},
					Params:     []string{"aa"},
					Cookies:    []string{"keksKey"},
				}
			},
			func() *http.Request {
				r := httptest.NewRequest("PUT", "https://corestore.IO/_7_Xy?aa=bb", nil)
				r.RemoteAddr = "123.123.22.11"
				r.Header.Set("X-Key", "y-Value")
				r.AddCookie(&http.Cookie{Name: "keksKey", Value: "keksVal"})
				return r
			},
			"123.123.22.11\nput\ny-value\n/_7_Xy\nbb\nkeksVal\n",
		},
		{
			func() ratelimit.VaryByer {
				return &ratelimit.VaryBy{
					RemoteAddr:  true,
					Method:      true,
					Path:        true,
					Headers:     []string{"X-Key"},
					Params:      []string{"aa"},
					SafeUnicode: true,
				}
			},
			func() *http.Request {
				r := httptest.NewRequest("PUT", "https://corestore.IO/_8_Xy?aa=bb", nil)
				r.RemoteAddr = "123.123.22.11"
				r.Header.Set("X-Key", "y-valÜe")
				return r
			},
			"123.123.22.11\nput\ny-valüe\n/_8_Xy\nbb\n",
		},
	}
	for _, test := range tests {
		vb := test.varyBy()
		r := test.req()
		if have, want := vb.Key(r), test.want; have != want {
			t.Errorf("Case: %q => Have: %q Want: %q", r.URL.String(), have, want)
		}
	}
}

// todo: optimize allocs
// BenchmarkVaryBy_Key/non-unicode-4         	  500000	      3694 ns/op	     288 B/op	      21 allocs/op
// BenchmarkVaryBy_Key/full-unicode-4        	  500000	      3942 ns/op	     288 B/op	      21 allocs/op
func BenchmarkVaryBy_Key(b *testing.B) {

	vb := &ratelimit.VaryBy{
		RemoteAddr:  true,
		Method:      true,
		Path:        true,
		Headers:     []string{"X-Key"},
		Params:      []string{"aa"},
		SafeUnicode: false,
	}
	r := httptest.NewRequest("PUT", "https://corestore.IO/_8_Xy?aa=bb", nil)
	r.RemoteAddr = "123.123.22.11"
	r.Header.Set("X-Key", "y-valÜe")
	const wantNon = "123.123.22.11\nput\ny-valÜe\n/_8_Xy\nbb\n"
	const wantFull = "123.123.22.11\nput\ny-valüe\n/_8_Xy\nbb\n"

	b.Run("non-unicode", func(b *testing.B) {
		b.ReportAllocs()
		//b.ResetTimer()
		for i := 0; i < b.N; i++ {
			if have, want := vb.Key(r), wantNon; have != want {
				b.Errorf("Case Non: Have: %q Want: %q", have, want)
			}
		}
	})

	b.Run("full-unicode", func(b *testing.B) {
		b.ReportAllocs()
		//b.ResetTimer()
		vb.SafeUnicode = true
		for i := 0; i < b.N; i++ {
			if have, want := vb.Key(r), wantFull; have != want {
				b.Errorf("Case Full: Have: %q Want: %q", have, want)
			}
		}
	})
}
<commit_msg>net/ratelimit: gofmt<commit_after>// Copyright 2015-2016, Cyrill @ Schumacher.fm and the CoreStore contributors
//
// 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 ratelimit_test

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/corestoreio/csfw/net"
	"github.com/corestoreio/csfw/net/ratelimit"
)

func TestVaryBy_Key(t *testing.T) {
	tests := []struct {
		varyBy func() ratelimit.VaryByer
		req    func() *http.Request
		want   string
	}{
		{
			func() ratelimit.VaryByer { return (*ratelimit.VaryBy)(nil) },
			func() *http.Request {
				return httptest.NewRequest("GET", "https://corestore.io/_1", nil)
			},
			"",
		},
		{
			func() ratelimit.VaryByer {
				return &ratelimit.VaryBy{
					RemoteAddr: true,
				}
			},
			func() *http.Request {
				r := httptest.NewRequest("GET", "https://corestore.io/_2", nil)
				r.Header.Set(net.XClusterClientIP, "123.123.22.11")
				return r
			},
			"123.123.22.11\n",
		},
		{
			func() ratelimit.VaryByer {
				return &ratelimit.VaryBy{
					RemoteAddr: true,
					Method:     true,
				}
			},
			func() *http.Request {
				r := httptest.NewRequest("PUT", "https://corestore.io/_3", nil)
				r.Header.Set(net.XClusterClientIP, "123.123.22.11")
				return r
			},
			"123.123.22.11\nput\n",
		},
		{
			func() ratelimit.VaryByer {
				return &ratelimit.VaryBy{
					RemoteAddr: true,
					Method:     true,
					Path:       true,
				}
			},
			func() *http.Request {
				r := httptest.NewRequest("PUT", "https://corestore.IO/_4Xy", nil)
				r.Header.Set(net.XClusterClientIP, "123.123.22.11")
				return r
			},
			"123.123.22.11\nput\n/_4Xy\n",
		},
		{
			func() ratelimit.VaryByer {
				return &ratelimit.VaryBy{
					RemoteAddr: true,
					Method:     true,
					Path:       true,
					Headers:    []string{"X-Key"},
				}
			},
			func() *http.Request {
				r := httptest.NewRequest("PUT", "https://corestore.IO/_5_Xy", nil)
				r.RemoteAddr = "123.123.22.11"
				r.Header.Set("X-Key", "y-Value")
				return r
			},
			"123.123.22.11\nput\ny-value\n/_5_Xy\n",
		},
		{
			func() ratelimit.VaryByer {
				return &ratelimit.VaryBy{
					RemoteAddr: true,
					Method:     true,
					Path:       true,
					Headers:    []string{"X-Key"},
					Params:     []string{"aa"},
				}
			},
			func() *http.Request {
				r := httptest.NewRequest("PUT", "https://corestore.IO/_6_Xy?aa=bb", nil)
				r.RemoteAddr = "123.123.22.11"
				r.Header.Set("X-Key", "y-valÜe")
				return r
			},
			"123.123.22.11\nput\ny-valÜe\n/_6_Xy\nbb\n",
		},
		{
			func() ratelimit.VaryByer {
				return &ratelimit.VaryBy{
					RemoteAddr: true,
					Method:     true,
					Path:       true,
					Headers:    []string{"X-Key"},
					Params:     []string{"aa"},
					Cookies:    []string{"keksKey"},
				}
			},
			func() *http.Request {
				r := httptest.NewRequest("PUT", "https://corestore.IO/_7_Xy?aa=bb", nil)
				r.RemoteAddr = "123.123.22.11"
				r.Header.Set("X-Key", "y-Value")
				r.AddCookie(&http.Cookie{Name: "keksKey", Value: "keksVal"})
				return r
			},
			"123.123.22.11\nput\ny-value\n/_7_Xy\nbb\nkeksVal\n",
		},
		{
			func() ratelimit.VaryByer {
				return &ratelimit.VaryBy{
					RemoteAddr:  true,
					Method:      true,
					Path:        true,
					Headers:     []string{"X-Key"},
					Params:      []string{"aa"},
					SafeUnicode: true,
				}
			},
			func() *http.Request {
				r := httptest.NewRequest("PUT", "https://corestore.IO/_8_Xy?aa=bb", nil)
				r.RemoteAddr = "123.123.22.11"
				r.Header.Set("X-Key", "y-valÜe")
				return r
			},
			"123.123.22.11\nput\ny-valüe\n/_8_Xy\nbb\n",
		},
	}
	for _, test := range tests {
		vb := test.varyBy()
		r := test.req()
		if have, want := vb.Key(r), test.want; have != want {
			t.Errorf("Case: %q => Have: %q Want: %q", r.URL.String(), have, want)
		}
	}
}

// todo: optimize allocs
// BenchmarkVaryBy_Key/non-unicode-4         	  500000	      3694 ns/op	     288 B/op	      21 allocs/op
// BenchmarkVaryBy_Key/full-unicode-4        	  500000	      3942 ns/op	     288 B/op	      21 allocs/op
func BenchmarkVaryBy_Key(b *testing.B) {

	vb := &ratelimit.VaryBy{
		RemoteAddr:  true,
		Method:      true,
		Path:        true,
		Headers:     []string{"X-Key"},
		Params:      []string{"aa"},
		SafeUnicode: false,
	}
	r := httptest.NewRequest("PUT", "https://corestore.IO/_8_Xy?aa=bb", nil)
	r.RemoteAddr = "123.123.22.11"
	r.Header.Set("X-Key", "y-valÜe")
	const wantNon = "123.123.22.11\nput\ny-valÜe\n/_8_Xy\nbb\n"
	const wantFull = "123.123.22.11\nput\ny-valüe\n/_8_Xy\nbb\n"

	b.Run("non-unicode", func(b *testing.B) {
		b.ReportAllocs()
		//b.ResetTimer()
		for i := 0; i < b.N; i++ {
			if have, want := vb.Key(r), wantNon; have != want {
				b.Errorf("Case Non: Have: %q Want: %q", have, want)
			}
		}
	})

	b.Run("full-unicode", func(b *testing.B) {
		b.ReportAllocs()
		//b.ResetTimer()
		vb.SafeUnicode = true
		for i := 0; i < b.N; i++ {
			if have, want := vb.Key(r), wantFull; have != want {
				b.Errorf("Case Full: Have: %q Want: %q", have, want)
			}
		}
	})
}
<|endoftext|>


<commit_before>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 oglematchers

Foo(Ǝ, Ǝ)
Foo(Ɂ, Ɂ)
Foo(A, A)
Foo(𝐀, 𝐀)
Foo(Ə, Ə)
Foo(Г, Г)
Foo(Ꙩ, Ꙩ)

import (
	"strings"
)
<commit_msg>Added a stub Any function, for #2.<commit_after>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 oglematchers

// Any returns a matcher that matches any value.
func Any() Matcher {
	return nil
}
<|endoftext|>


<commit_before>package main

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

const apiEndpoint = "http://dbios.herokuapp.com/"

type Program struct {
    Title    string `json:"title"`
    Id       int    `json:"id"`
    ImageUrl string `json:"image_url"`
}

type ProgramCollection []Program

type Workout struct {
    ImageUrl           string `json:"image_url"`
    WorkoutDescription string `json:"workout_description"`
    Title              string `json:"title"`
    ProgramIDs         []int  `json:"program_ids"`
    TrainerName        string `json:"trainer_name"`
}

type WorkoutCollection []Workout

func getJawn(thingType string) []byte {
    apiURL := apiEndpoint + thingType
    res, err := http.Get(apiURL)
    if err != nil {
        panic(err)
    }
    defer res.Body.Close()
    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err)
    }

    return body
}

func parsePrograms() ProgramCollection {
    response := getJawn("programs")
    var result ProgramCollection
    if err := json.Unmarshal(response, &result); err != nil {
        panic(err)
    }

    return result
}

func parseWorkouts() WorkoutCollection {
    response := getJawn("workouts")
    var result WorkoutCollection
    if err := json.Unmarshal(response, &result); err != nil {
        panic(err)
    }

    return result
}

func listPrograms() {
    programs := parsePrograms()
    for i := range programs {
        fmt.Println(programs[i].Title, programs[i].Id, programs[i].ImageUrl)
    }
}

func main() {
    listPrograms()
}
<commit_msg>add listWorkouts()<commit_after>package main

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

const apiEndpoint = "http://dbios.herokuapp.com/"

type Program struct {
    Title    string `json:"title"`
    Id       int    `json:"id"`
    ImageUrl string `json:"image_url"`
}

type ProgramCollection []Program

type Workout struct {
    ImageUrl           string `json:"image_url"`
    WorkoutDescription string `json:"workout_description"`
    Title              string `json:"title"`
    ProgramIDs         []int  `json:"program_ids"`
    TrainerName        string `json:"trainer_name"`
}

type WorkoutCollection []Workout

func getJawn(thingType string) []byte {
    apiURL := apiEndpoint + thingType
    res, err := http.Get(apiURL)
    if err != nil {
        panic(err)
    }
    defer res.Body.Close()
    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err)
    }

    return body
}

func parsePrograms() ProgramCollection {
    response := getJawn("programs")
    var result ProgramCollection
    if err := json.Unmarshal(response, &result); err != nil {
        panic(err)
    }

    return result
}

func parseWorkouts() WorkoutCollection {
    response := getJawn("workouts")
    var result WorkoutCollection
    if err := json.Unmarshal(response, &result); err != nil {
        panic(err)
    }

    return result
}

func listPrograms() {
    programs := parsePrograms()
    for i := range programs {
        fmt.Println(programs[i].Title, programs[i].Id, programs[i].ImageUrl)
    }
}

func listWorkouts() {
    workouts := parseWorkouts()
    for i := range workouts {
        fmt.Println(workouts[i].ImageUrl, workouts[i].WorkoutDescription, workouts[i].Title, workouts[i].ProgramIDs, workouts[i].TrainerName)
    }
}

func main() {
    listPrograms()
}
<|endoftext|>


<commit_before>// Package fbapi provides wrappers to access the Facebook API.
package fbapi

import (
	"crypto/tls"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/daaku/go.fburl"
	"github.com/daaku/go.httpcontrol"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const redactedStub = "$1=-- XX -- REDACTED -- XX --"

var (
	insecureSSL = flag.Bool(
		"fbapi.insecure", false, "Skip SSL certificate validation.")
	redact = flag.Bool(
		"fbapi.redact",
		true,
		"When true known sensitive information will be stripped from errors.")
	timeout = flag.Duration(
		"fbapi.timeout",
		5*time.Second,
		"Timeout for http requests.")
	maxTries = flag.Uint(
		"fbapi.max-tries",
		3,
		"Number of retries for known safe to retry calls.")
	cleanURLRegExp  = regexp.MustCompile("(access_token|client_secret)=([^&]*)")
	httpClientCache *http.Client
)

// An Error from the API.
type Error struct {
	Message string `json:"message"`
	Type    string `json:"type"`
	Code    int    `json:"code"`
	Body    []byte
}

// Wrapper for "error"
type errorResponse struct {
	Error Error `json:"error"`
}

// Represents a thing that wants to modify the url.Values.
type Values interface {
	Set(url.Values)
}

// Represents an "access_token" for the Facebook API.
type Token string

const (
	PublicToken = Token("")
)

// Generic Page options for list type queries.
type Page struct {
	Limit  int
	Offset int
}

// Set the corresponding values for the Page.
func (page Page) Set(values url.Values) {
	if page.Limit != 0 {
		values.Set("limit", strconv.Itoa(page.Limit))
	}
	if page.Offset != 0 {
		values.Set("offset", strconv.Itoa(page.Offset))
	}
}

// A slice of field names.
type Fields []string

// For selecting fields.
func (fields Fields) Set(values url.Values) {
	if len(fields) > 0 {
		values.Set("fields", strings.Join(fields, ","))
	}
}

// Set the token if necessary.
func (token Token) Set(values url.Values) {
	if token != PublicToken {
		values.Set("access_token", string(token))
	}
}

// String representation as defined by the error interface.
func (e *Error) Error() string {
	return fmt.Sprintf("API call failed with error body:\n%s", string(e.Body))
}

// Disable SSL cert, useful when debugging or hitting internal self-signed certs
func httpClient() *http.Client {
	if httpClientCache == nil {
		httpClientCache = &http.Client{
			Transport: &httpcontrol.Control{
				Transport: &http.Transport{
					Proxy:           http.ProxyFromEnvironment,
					TLSClientConfig: &tls.Config{InsecureSkipVerify: *insecureSSL},
				},
				Timeout:  *timeout,
				MaxTries: *maxTries,
			},
		}
	}
	return httpClientCache
}

// remove known sensitive tokens from data
func cleanURL(url string) string {
	if *redact {
		return cleanURLRegExp.ReplaceAllString(url, redactedStub)
	}
	return url
}

// Make a GET Graph API request and get the raw body byte slice.
func GetRaw(path string, values url.Values) ([]byte, error) {
	const phpRFC3339 = `Y-m-d\TH:i:s\Z`
	values.Set("date_format", phpRFC3339)
	u := &fburl.URL{
		Scheme:    "https",
		SubDomain: fburl.DGraph,
		Path:      path,
		Values:    values,
	}
	resp, err := httpClient().Get(u.String())
	if err != nil {
		return nil, fmt.Errorf(
			"Request for URL %s failed with error %s.", cleanURL(u.String()), err)
	}
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf(
			"Request for URL %s failed because body could not be read "+
				"with error %s.",
			cleanURL(u.String()), err)
	}
	if resp.StatusCode > 399 || resp.StatusCode < 200 {
		apiError := &errorResponse{Error{Body: b}}
		err = json.Unmarshal(b, apiError)
		if err != nil {
			return nil, fmt.Errorf(
				"Parsing error response failed with %s:\n%s", err, string(b))
		}
		return nil, &apiError.Error
	}
	return b, nil
}

// Make a GET Graph API request.
func Get(result interface{}, path string, values ...Values) error {
	final := url.Values{}
	for _, v := range values {
		v.Set(final)
	}
	b, err := GetRaw(path, final)
	if err != nil {
		return err
	}
	err = json.Unmarshal(b, result)
	if err != nil {
		return fmt.Errorf(
			"Request for path %s with response %s failed with "+
				"json.Unmarshal error %s.",
			cleanURL(path), string(b), err)
	}
	return nil
}
<commit_msg>new httpcontrol.Transport API<commit_after>// Package fbapi provides wrappers to access the Facebook API.
package fbapi

import (
	"crypto/tls"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/daaku/go.fburl"
	"github.com/daaku/go.httpcontrol"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const redactedStub = "$1=-- XX -- REDACTED -- XX --"

var (
	insecureSSL = flag.Bool(
		"fbapi.insecure", false, "Skip SSL certificate validation.")
	redact = flag.Bool(
		"fbapi.redact",
		true,
		"When true known sensitive information will be stripped from errors.")
	timeout = flag.Duration(
		"fbapi.timeout",
		5*time.Second,
		"Timeout for http requests.")
	maxTries = flag.Uint(
		"fbapi.max-tries",
		3,
		"Number of retries for known safe to retry calls.")
	cleanURLRegExp  = regexp.MustCompile("(access_token|client_secret)=([^&]*)")
	httpClientCache *http.Client
)

// An Error from the API.
type Error struct {
	Message string `json:"message"`
	Type    string `json:"type"`
	Code    int    `json:"code"`
	Body    []byte
}

// Wrapper for "error"
type errorResponse struct {
	Error Error `json:"error"`
}

// Represents a thing that wants to modify the url.Values.
type Values interface {
	Set(url.Values)
}

// Represents an "access_token" for the Facebook API.
type Token string

const (
	PublicToken = Token("")
)

// Generic Page options for list type queries.
type Page struct {
	Limit  int
	Offset int
}

// Set the corresponding values for the Page.
func (page Page) Set(values url.Values) {
	if page.Limit != 0 {
		values.Set("limit", strconv.Itoa(page.Limit))
	}
	if page.Offset != 0 {
		values.Set("offset", strconv.Itoa(page.Offset))
	}
}

// A slice of field names.
type Fields []string

// For selecting fields.
func (fields Fields) Set(values url.Values) {
	if len(fields) > 0 {
		values.Set("fields", strings.Join(fields, ","))
	}
}

// Set the token if necessary.
func (token Token) Set(values url.Values) {
	if token != PublicToken {
		values.Set("access_token", string(token))
	}
}

// String representation as defined by the error interface.
func (e *Error) Error() string {
	return fmt.Sprintf("API call failed with error body:\n%s", string(e.Body))
}

// Disable SSL cert, useful when debugging or hitting internal self-signed certs
func httpClient() *http.Client {
	if httpClientCache == nil {
		httpClientCache = &http.Client{
			Transport: &httpcontrol.Transport{
				Proxy:           http.ProxyFromEnvironment,
				TLSClientConfig: &tls.Config{InsecureSkipVerify: *insecureSSL},
				RequestTimeout:  *timeout,
				MaxTries:        *maxTries,
			},
		}
	}
	return httpClientCache
}

// remove known sensitive tokens from data
func cleanURL(url string) string {
	if *redact {
		return cleanURLRegExp.ReplaceAllString(url, redactedStub)
	}
	return url
}

// Make a GET Graph API request and get the raw body byte slice.
func GetRaw(path string, values url.Values) ([]byte, error) {
	const phpRFC3339 = `Y-m-d\TH:i:s\Z`
	values.Set("date_format", phpRFC3339)
	u := &fburl.URL{
		Scheme:    "https",
		SubDomain: fburl.DGraph,
		Path:      path,
		Values:    values,
	}
	resp, err := httpClient().Get(u.String())
	if err != nil {
		return nil, fmt.Errorf(
			"Request for URL %s failed with error %s.", cleanURL(u.String()), err)
	}
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf(
			"Request for URL %s failed because body could not be read "+
				"with error %s.",
			cleanURL(u.String()), err)
	}
	if resp.StatusCode > 399 || resp.StatusCode < 200 {
		apiError := &errorResponse{Error{Body: b}}
		err = json.Unmarshal(b, apiError)
		if err != nil {
			return nil, fmt.Errorf(
				"Parsing error response failed with %s:\n%s", err, string(b))
		}
		return nil, &apiError.Error
	}
	return b, nil
}

// Make a GET Graph API request.
func Get(result interface{}, path string, values ...Values) error {
	final := url.Values{}
	for _, v := range values {
		v.Set(final)
	}
	b, err := GetRaw(path, final)
	if err != nil {
		return err
	}
	err = json.Unmarshal(b, result)
	if err != nil {
		return fmt.Errorf(
			"Request for path %s with response %s failed with "+
				"json.Unmarshal error %s.",
			cleanURL(path), string(b), err)
	}
	return nil
}
<|endoftext|>


<commit_before>package gochatwork

import (
	"encoding/json"
)

const BaseUrl = `https://api.chatwork.com/v1`

type Me struct {
	AccountId        int    `json:"account_id"`
	RoomId           int    `json:"room_id"`
	Name             string `json:"name"`
	ChatworkId       string `json:"chatwork_id"`
	OrganizationId   int    `json:"organization_id"`
	OrganizationName string `json:"organization_name"`
	Department       string `json:"department"`
	Title            string `json:"title"`
	Url              string `json:"url"`
	Introduction     string `json:"introduction"`
	Mail             string `json:"mail"`
	TelOrganization  string `json:"tel_organization"`
	TelExtension     string `json:"tel_extension"`
	TelMobile        string `json:"tel_mobile"`
	Skype            string `json:"skype"`
	Facebook         string `json:"facebook"`
	Twitter          string `json:"twitter"`
	AvatarImageUrl   string `json:"avatar_image_url"`
}

func (c *Client) Me() Me {
	ret := c.Get("/me", map[string]string{})
	var me Me
	json.Unmarshal(ret, &me)
	return me
}

type Status struct {
	UnreadRoomNum  int `json:"unread_room_num"`
	MentionRoomNum int `json:"mention_room_num"`
	MytaskRoomNum  int `json:"mytask_room_num"`
	UnreadNum      int `json:"unread_num"`
	MentionNum     int `json:"mention_num"`
	MyTaskNum      int `json:"mytask_num"`
}

func (c *Client) MyStatus() Status {
	ret := c.Get("/my/status", map[string]string{})
	var status Status
	json.Unmarshal(ret, &status)
	return status
}

type MyTask struct {
	Task
	Room struct {
		Roomid   int    `json:"room_id"`
		Name     string `json:"name"`
		IconPath string `json:"icon_path"`
	}
}

// params keys
//  - assigned_by_account_id
//  - status: [open, done]
func (c *Client) MyTasks(params map[string]string) []MyTask {
	ret := c.Get("/my/tasks", params)
	var tasks []MyTask
	json.Unmarshal(ret, &tasks)
	return tasks
}

type Contact struct {
	AccountId        int    `json:"account_id"`
	RoomId           int    `json:"room_id"`
	Name             string `json:"name"`
	ChatworkId       string `json:"chatwork_id"`
	OrganizationId   int    `json:"organization_id"`
	OrganizationName string `json:"organization_name"`
	Department       string `json:"department"`
	AvatarImageUrl   string `json:"avatar_image_url"`
}

func (c *Client) Contacts() []Contact {
	ret := c.Get("/contacts", map[string]string{})
	var contacts []Contact
	json.Unmarshal(ret, &contacts)
	return contacts
}

type Room struct {
	RoomId         int    `json:"room_id"`
	Name           string `json:"name"`
	Type           string `json:"type"`
	Role           string `json:"role"`
	Sticky         bool   `json:"sticky"`
	UnreadNum      int    `json:"unread_num"`
	MentionNum     int    `json:"mention_num"`
	MytaskNum      int    `json:"mytask_num"`
	MessageNum     int    `json:"message_num"`
	FileNum        int    `json:"file_num"`
	TaskNum        int    `json:"task_num"`
	IconPath       string `json:"icon_path"`
	LastUpdateTime int64  `json:"last_update_time"`
}

func (c *Client) Rooms() []Room {
	ret := c.Get("/rooms", map[string]string{})
	var rooms []Room
	json.Unmarshal(ret, &rooms)
	return rooms
}

func (c *Client) Room(roomId string) Room {
	ret := c.Get("/rooms/"+roomId, map[string]string{})
	var room Room
	json.Unmarshal(ret, &room)
	return room
}

// params keys
//   * name
//   * members_admin_ids
//   - description
//   - icon_preset
//   - members_member_ids
//   - members_readonly_ids
func (c *Client) CreateRoom(params map[string]string) []byte {
	return c.Post("/rooms", params)
}

// params keys
//   - description
//   - icon_preset
//   - name
func (c *Client) UpdateRoom(roomId string, params map[string]string) []byte {
	return c.Put("/rooms/"+roomId, params)
}

// params key
//   * action_type: [leave, delete]
func (c *Client) DeleteRoom(roomId string, params map[string]string) []byte {
	return c.Delete("/rooms/"+roomId, params)
}

type Member struct {
	AccountId         int    `json:"account_id"`
	Role              string `json:"role"`
	Name              string `json:"name"`
	ChatworkId        string `json:"chatwork_id"`
	Organization_Id   int    `json:"organization_id"`
	Organization_Name string `json:"organization_name"`
	Department        string `json:"department"`
	AvatarImageUrl    string `json:"avatar_image_url"`
}

func (c *Client) RoomMembers(roomId string) []Member {
	ret := c.Get("/rooms/"+roomId+"/members", map[string]string{})
	var members []Member
	json.Unmarshal(ret, &members)
	return members
}

// params keys
//   * members_admin_ids
//   - members_member_ids
//   - members_readonly_ids
func (c *Client) UpdateRoomMembers(roomId string, params map[string]string) []byte {
	return c.Put("/rooms/"+roomId+"/members", params)
}

type Account struct {
	AccountId      int    `json:"account_id"`
	Name           string `json:"name"`
	AvatarImageUrl string `json:"avatar_image_url"`
}

type Message struct {
	MessageId  int     `json:"message_id"`
	Account    Account `json:"account"`
	Body       string  `json:"body"`
	SendTime   int64   `json:"send_time"`
	UpdateTime int64   `json:"update_time"`
}

// XXX: Not yet implement
func (c *Client) RoomMessages(roomId string) []byte {
	return c.Get("/rooms/"+roomId+"/messages", map[string]string{})
}

func (c *Client) PostRoomMessage(roomId string, body string) []byte {
	return c.Post("/rooms/"+roomId+"/messages", map[string]string{"body": body})
}

func (c *Client) RoomMessage(roomId, messageId string) Message {
	ret := c.Get("/rooms/"+roomId+"/messages/"+messageId, map[string]string{})
	var message Message
	json.Unmarshal(ret, &message)
	return message
}

type Task struct {
	TaskId            int     `json:"task_id"`
	Account           Account `json:"account"`
	AssignedByAccount Account `json:"assigned_by_account"`
	MessageId         int     `json:"message_id"`
	Body              string  `json:"body"`
	LimitTime         int64   `json:"limit_time"`
	Status            string  `json:"status"`
}

func (c *Client) RoomTasks(roomId string) []Task {
	ret := c.Get("/rooms/"+roomId+"/tasks", map[string]string{})
	var tasks []Task
	json.Unmarshal(ret, &tasks)
	return tasks
}

// params keys
//   * body
//   * to_ids
//   - limit
func (c *Client) PostRoomTask(roomId string, params map[string]string) []byte {
	return c.Post("/rooms/"+roomId+"/tasks", params)
}

func (c *Client) RoomTask(roomId, taskId string) Task {
	ret := c.Get("/rooms/"+roomId+"/tasks/"+taskId, map[string]string{})
	var task Task
	json.Unmarshal(ret, &task)
	return task
}

type File struct {
	FileId     int     `json:"file_id"`
	Account    Account `json:"account"`
	MessageId  int     `json:"message_id"`
	Filename   string  `json:"filename"`
	Filesize   int     `json:"filesize"`
	UploadTime int64   `json:"upload_time"`
}

// params key
//   - account_id
func (c *Client) RoomFiles(roomId string, params map[string]string) []File {
	ret := c.Get("/rooms/"+roomId+"/files", params)
	var files []File
	json.Unmarshal(ret, &files)
	return files
}

func (c *Client) RoomFile(roomId, fileId string) File {
	ret := c.Get("/rooms/"+roomId+"/files/"+fileId, map[string]string{})
	var file File
	json.Unmarshal(ret, &file)
	return file
}
<commit_msg>support room message api<commit_after>package gochatwork

import (
	"encoding/json"
)

const BaseUrl = `https://api.chatwork.com/v1`

type Me struct {
	AccountId        int    `json:"account_id"`
	RoomId           int    `json:"room_id"`
	Name             string `json:"name"`
	ChatworkId       string `json:"chatwork_id"`
	OrganizationId   int    `json:"organization_id"`
	OrganizationName string `json:"organization_name"`
	Department       string `json:"department"`
	Title            string `json:"title"`
	Url              string `json:"url"`
	Introduction     string `json:"introduction"`
	Mail             string `json:"mail"`
	TelOrganization  string `json:"tel_organization"`
	TelExtension     string `json:"tel_extension"`
	TelMobile        string `json:"tel_mobile"`
	Skype            string `json:"skype"`
	Facebook         string `json:"facebook"`
	Twitter          string `json:"twitter"`
	AvatarImageUrl   string `json:"avatar_image_url"`
}

func (c *Client) Me() Me {
	ret := c.Get("/me", map[string]string{})
	var me Me
	json.Unmarshal(ret, &me)
	return me
}

type Status struct {
	UnreadRoomNum  int `json:"unread_room_num"`
	MentionRoomNum int `json:"mention_room_num"`
	MytaskRoomNum  int `json:"mytask_room_num"`
	UnreadNum      int `json:"unread_num"`
	MentionNum     int `json:"mention_num"`
	MyTaskNum      int `json:"mytask_num"`
}

func (c *Client) MyStatus() Status {
	ret := c.Get("/my/status", map[string]string{})
	var status Status
	json.Unmarshal(ret, &status)
	return status
}

type MyTask struct {
	Task
	Room struct {
		Roomid   int    `json:"room_id"`
		Name     string `json:"name"`
		IconPath string `json:"icon_path"`
	}
}

// params keys
//  - assigned_by_account_id
//  - status: [open, done]
func (c *Client) MyTasks(params map[string]string) []MyTask {
	ret := c.Get("/my/tasks", params)
	var tasks []MyTask
	json.Unmarshal(ret, &tasks)
	return tasks
}

type Contact struct {
	AccountId        int    `json:"account_id"`
	RoomId           int    `json:"room_id"`
	Name             string `json:"name"`
	ChatworkId       string `json:"chatwork_id"`
	OrganizationId   int    `json:"organization_id"`
	OrganizationName string `json:"organization_name"`
	Department       string `json:"department"`
	AvatarImageUrl   string `json:"avatar_image_url"`
}

func (c *Client) Contacts() []Contact {
	ret := c.Get("/contacts", map[string]string{})
	var contacts []Contact
	json.Unmarshal(ret, &contacts)
	return contacts
}

type Room struct {
	RoomId         int    `json:"room_id"`
	Name           string `json:"name"`
	Type           string `json:"type"`
	Role           string `json:"role"`
	Sticky         bool   `json:"sticky"`
	UnreadNum      int    `json:"unread_num"`
	MentionNum     int    `json:"mention_num"`
	MytaskNum      int    `json:"mytask_num"`
	MessageNum     int    `json:"message_num"`
	FileNum        int    `json:"file_num"`
	TaskNum        int    `json:"task_num"`
	IconPath       string `json:"icon_path"`
	LastUpdateTime int64  `json:"last_update_time"`
}

func (c *Client) Rooms() []Room {
	ret := c.Get("/rooms", map[string]string{})
	var rooms []Room
	json.Unmarshal(ret, &rooms)
	return rooms
}

func (c *Client) Room(roomId string) Room {
	ret := c.Get("/rooms/"+roomId, map[string]string{})
	var room Room
	json.Unmarshal(ret, &room)
	return room
}

// params keys
//   * name
//   * members_admin_ids
//   - description
//   - icon_preset
//   - members_member_ids
//   - members_readonly_ids
func (c *Client) CreateRoom(params map[string]string) []byte {
	return c.Post("/rooms", params)
}

// params keys
//   - description
//   - icon_preset
//   - name
func (c *Client) UpdateRoom(roomId string, params map[string]string) []byte {
	return c.Put("/rooms/"+roomId, params)
}

// params key
//   * action_type: [leave, delete]
func (c *Client) DeleteRoom(roomId string, params map[string]string) []byte {
	return c.Delete("/rooms/"+roomId, params)
}

type Member struct {
	AccountId         int    `json:"account_id"`
	Role              string `json:"role"`
	Name              string `json:"name"`
	ChatworkId        string `json:"chatwork_id"`
	Organization_Id   int    `json:"organization_id"`
	Organization_Name string `json:"organization_name"`
	Department        string `json:"department"`
	AvatarImageUrl    string `json:"avatar_image_url"`
}

func (c *Client) RoomMembers(roomId string) []Member {
	ret := c.Get("/rooms/"+roomId+"/members", map[string]string{})
	var members []Member
	json.Unmarshal(ret, &members)
	return members
}

// params keys
//   * members_admin_ids
//   - members_member_ids
//   - members_readonly_ids
func (c *Client) UpdateRoomMembers(roomId string, params map[string]string) []byte {
	return c.Put("/rooms/"+roomId+"/members", params)
}

type Account struct {
	AccountId      int    `json:"account_id"`
	Name           string `json:"name"`
	AvatarImageUrl string `json:"avatar_image_url"`
}

type Message struct {
	MessageId  int     `json:"message_id"`
	Account    Account `json:"account"`
	Body       string  `json:"body"`
	SendTime   int64   `json:"send_time"`
	UpdateTime int64   `json:"update_time"`
}

func (c *Client) RoomMessages(roomId string) []Message {
	ret := c.Get("/rooms/"+roomId+"/messages", map[string]string{})
	var messages []Message
	json.Unmarshal(ret, &messages)
	return messages
}

func (c *Client) PostRoomMessage(roomId string, body string) []byte {
	return c.Post("/rooms/"+roomId+"/messages", map[string]string{"body": body})
}

func (c *Client) RoomMessage(roomId, messageId string) Message {
	ret := c.Get("/rooms/"+roomId+"/messages/"+messageId, map[string]string{})
	var message Message
	json.Unmarshal(ret, &message)
	return message
}

type Task struct {
	TaskId            int     `json:"task_id"`
	Account           Account `json:"account"`
	AssignedByAccount Account `json:"assigned_by_account"`
	MessageId         int     `json:"message_id"`
	Body              string  `json:"body"`
	LimitTime         int64   `json:"limit_time"`
	Status            string  `json:"status"`
}

func (c *Client) RoomTasks(roomId string) []Task {
	ret := c.Get("/rooms/"+roomId+"/tasks", map[string]string{})
	var tasks []Task
	json.Unmarshal(ret, &tasks)
	return tasks
}

// params keys
//   * body
//   * to_ids
//   - limit
func (c *Client) PostRoomTask(roomId string, params map[string]string) []byte {
	return c.Post("/rooms/"+roomId+"/tasks", params)
}

func (c *Client) RoomTask(roomId, taskId string) Task {
	ret := c.Get("/rooms/"+roomId+"/tasks/"+taskId, map[string]string{})
	var task Task
	json.Unmarshal(ret, &task)
	return task
}

type File struct {
	FileId     int     `json:"file_id"`
	Account    Account `json:"account"`
	MessageId  int     `json:"message_id"`
	Filename   string  `json:"filename"`
	Filesize   int     `json:"filesize"`
	UploadTime int64   `json:"upload_time"`
}

// params key
//   - account_id
func (c *Client) RoomFiles(roomId string, params map[string]string) []File {
	ret := c.Get("/rooms/"+roomId+"/files", params)
	var files []File
	json.Unmarshal(ret, &files)
	return files
}

func (c *Client) RoomFile(roomId, fileId string) File {
	ret := c.Get("/rooms/"+roomId+"/files/"+fileId, map[string]string{})
	var file File
	json.Unmarshal(ret, &file)
	return file
}
<|endoftext|>


<commit_before>package inbucket

import (
	"bytes"
	"fmt"
	"io"
	"mime"
	"mime/multipart"
	"net/mail"
)

const MIME_BUF_BYTES = 1024

type MIMEMessage struct {
	text string
	html string
}

func ParseMIMEMessage(mailMsg *mail.Message) (*MIMEMessage, error) {
	mimeMsg := new(MIMEMessage)

	// Parse top-level multipart
	ctype := mailMsg.Header.Get("Content-Type")
	mediatype, params, err := mime.ParseMediaType(ctype)
	if err != nil {
		return nil, err
	}
	switch mediatype {
	case "multipart/alternative":
		// Good
	default:
		return nil, fmt.Errorf("Unknown mediatype: %v", mediatype)
	}
	boundary := params["boundary"]
	if boundary == "" {
		return nil, fmt.Errorf("Unable to locate boundary param in Content-Type header")
	}

	// Buffer used by Part.Read to hand us chunks of data
	readBytes := make([]byte, MIME_BUF_BYTES)

	// Loop over MIME parts
	mr := multipart.NewReader(mailMsg.Body, boundary)
	for {
		part, err := mr.NextPart()
		if err != nil {
			if err == io.EOF {
				// This is a clean end-of-message signal
				break
			}
			return nil, err
		}
		mediatype, params, err = mime.ParseMediaType(part.Header.Get("Content-Type"))
		if err != nil {
			return nil, err
		}
		if mediatype == "text/plain" && mimeMsg.text == "" {
			// First text section, we'll have that, but first we have to deal with
			// the odd way Part lets us read data.
			var buf bytes.Buffer
			for {
				n, err := part.Read(readBytes)
				if err != nil {
					if err == io.EOF {
						// Clean end of part signal
						break
					}
					return nil, err
				}
				// Extra data in readBytes is not cleared, so we must respect
				// the value returned in 'n'
				buf.Write(readBytes[:n])
			}

			mimeMsg.text = buf.String()
			fmt.Printf("text: '%v'\n", mimeMsg.text)
		}
	}

	return mimeMsg, nil
}
<commit_msg>Parse MIME parts into a node tree<commit_after>package inbucket

import (
	"bytes"
	"fmt"
	"io"
	"mime"
	"mime/multipart"
	"net/mail"
	"os"
)

const MIME_BUF_BYTES = 1024

type MIMEMessage struct {
	text string
	html string
}

type MIMENode struct {
	Parent      *MIMENode
	FirstChild  *MIMENode
	NextSibling *MIMENode
	Type        string
	Content     *bytes.Buffer
}

func NewMIMENode(parent *MIMENode, contentType string) *MIMENode {
	return &MIMENode{Parent: parent, Type: contentType}
}

func (n *MIMENode) String() string {
	children := ""
	siblings := ""
	if n.FirstChild != nil {
		children = n.FirstChild.String()
	}
	if n.NextSibling != nil {
		siblings = n.NextSibling.String()
	}
	return fmt.Sprintf("[%v %v] %v", n.Type, children, siblings)
}

func ParseMIMEMessage(mailMsg *mail.Message) (*MIMEMessage, error) {
	mimeMsg := new(MIMEMessage)

	// Parse top-level multipart
	ctype := mailMsg.Header.Get("Content-Type")
	mediatype, params, err := mime.ParseMediaType(ctype)
	if err != nil {
		return nil, err
	}
	switch mediatype {
	case "multipart/alternative":
		// Good
	default:
		return nil, fmt.Errorf("Unknown mediatype: %v", mediatype)
	}
	boundary := params["boundary"]
	if boundary == "" {
		return nil, fmt.Errorf("Unable to locate boundary param in Content-Type header")
	}

	// Root Node of our tree
	root := NewMIMENode(nil, mediatype)

	err = parseNodes(root, mailMsg.Body, boundary)
	fmt.Println(root.String())
	return mimeMsg, err
}

func parseNodes(parent *MIMENode, reader io.Reader, boundary string) error {
	var prevSibling *MIMENode

	// Loop over MIME parts
	mr := multipart.NewReader(reader, boundary)
	for {
		part, err := mr.NextPart()
		if err != nil {
			if err == io.EOF {
				// This is a clean end-of-message signal
				break
			}
			return err
		}
		mediatype, params, err := mime.ParseMediaType(part.Header.Get("Content-Type"))
		if err != nil {
			return err
		}

		// Insert ourselves into tree
		node := NewMIMENode(parent, mediatype)
		if prevSibling != nil {
			prevSibling.NextSibling = node
		} else {
			parent.FirstChild = node
		}
		prevSibling = node

		boundary := params["boundary"]
		if boundary != "" {
			// Content is another multipart
			err = parseNodes(node, part, boundary)
			if err != nil {
				return err
			}
		} else {
			// Content is data, allocate a buffer
			node.Content = new(bytes.Buffer)
			_, err = io.Copy(node.Content, part)
			if err != nil {
				return err
			}
			fmt.Printf("\n----\n")
			io.Copy(os.Stdout, node.Content)
			fmt.Printf("\n----\n")
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package admin

import (
	"context"
	"time"

	"google.golang.org/api/identitytoolkit/v3"
)

// Providers
const (
	Google   string = "google.com"
	Facebook string = "facebook.com"
	Github   string = "github.com"
	Twitter  string = "twitter.com"
)

// UserRecord is the firebase authentication user
type UserRecord struct {
	UserID        string
	Email         string
	EmailVerified bool
	DisplayName   string
	PhotoURL      string
	Disabled      bool
	Metadata      UserMetadata
	ProviderData  []*UserInfo
}

// UserMetadata is the metadata for user
type UserMetadata struct {
	CreatedAt      time.Time
	LastSignedInAt time.Time
}

// UserInfo is the user provider information
type UserInfo struct {
	UserID      string
	Email       string
	DisplayName string
	PhotoURL    string
	ProviderID  string
}

func parseDate(t int64) time.Time {
	if t == 0 {
		return time.Time{}
	}
	return time.Unix(t/1000, 0)
}

func toUserRecord(user *identitytoolkit.UserInfo) *UserRecord {
	return &UserRecord{
		UserID:        user.LocalId,
		Email:         user.Email,
		EmailVerified: user.EmailVerified,
		DisplayName:   user.DisplayName,
		PhotoURL:      user.PhotoUrl,
		Disabled:      user.Disabled,
		Metadata: UserMetadata{
			CreatedAt:      parseDate(user.CreatedAt),
			LastSignedInAt: parseDate(user.LastLoginAt),
		},
		ProviderData: toUserInfos(user.ProviderUserInfo),
	}
}

func toUserRecords(users []*identitytoolkit.UserInfo) []*UserRecord {
	result := make([]*UserRecord, len(users))
	for i, user := range users {
		result[i] = toUserRecord(user)
	}
	return result
}

func toUserInfo(info *identitytoolkit.UserInfoProviderUserInfo) *UserInfo {
	return &UserInfo{
		UserID:      info.RawId,
		Email:       info.Email,
		DisplayName: info.DisplayName,
		PhotoURL:    info.PhotoUrl,
		ProviderID:  info.ProviderId,
	}
}

func toUserInfos(infos []*identitytoolkit.UserInfoProviderUserInfo) []*UserInfo {
	result := make([]*UserInfo, len(infos))
	for i, info := range infos {
		result[i] = toUserInfo(info)
	}
	return result
}

// User use for create new user
// use Password when create user (plain text)
// use RawPassword when update user (hashed password)
type User struct {
	UserID        string
	Email         string
	EmailVerified bool
	Password      string
	DisplayName   string
	PhotoURL      string
	Disabled      bool
}

// UpdateAccount use for update existing account
type UpdateAccount struct {
	// UserID is the existing user id to update
	UserID        string `json:"localId,omitempty"`
	Email         string `json:"email,omitempty"`
	EmailVerified bool   `json:"emailVerified,omitempty"`
	Password      string `json:"password,omitempty"`
	DisplayName   string `json:"displayName,omitempty"`
	PhotoURL      string `json:"photoUrl,omitempty"`
	Disabled      bool   `json:"disableUser,omitempty"`
}

var scopes = []string{
	"https://www.googleapis.com/auth/userinfo.email",
	"https://www.googleapis.com/auth/firebase.database",
	"https://www.googleapis.com/auth/identitytoolkit",
}

const (
	baseURL = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/"
	timeout = time.Second * 10000
)

func getContext() (context.Context, context.CancelFunc) {
	return context.WithTimeout(context.Background(), timeout)
}
<commit_msg>add FCM Message type + update doc<commit_after>package admin

import (
	"context"
	"time"

	"google.golang.org/api/identitytoolkit/v3"
)

// Providers
const (
	Google   string = "google.com"
	Facebook string = "facebook.com"
	Github   string = "github.com"
	Twitter  string = "twitter.com"
)

type (
	// UserRecord is the firebase authentication user
	// See https://firebase.google.com/docs/reference/functions/functions.auth.UserRecord
	UserRecord struct {
		// The user's uid, unique to the Firebase project
		UserID string
		// The user's primary email, if set.
		Email string
		// Whether or not the user's primary email is verified.
		EmailVerified bool
		// The user's display name.
		DisplayName string
		// The user's photo URL.
		PhotoURL string
		// Whether or not the user is disabled: true for disabled; false for enabled.
		Disabled bool
		//Additional metadata about the user.
		Metadata UserMetadata
		// An array of providers (for example, Google, Facebook) linked to the user.
		ProviderData []*UserInfo
	}

	// UserMetadata is the metadata for user
	// See https://firebase.google.com/docs/reference/functions/functions.auth.UserMetadata
	UserMetadata struct {
		// The date the user was created.
		CreatedAt time.Time
		// The date the user last signed in.
		LastSignedInAt time.Time
	}

	// UserInfo is the user provider information
	// See https://firebase.google.com/docs/reference/functions/functions.auth.UserInfo
	UserInfo struct {
		// The user identifier for the linked provider.
		UserID string
		// The email for the linked provider.
		Email string
		// The display name for the linked provider.
		DisplayName string
		// The photo URL for the linked provider.
		PhotoURL string
		// The linked provider ID (for example, "google.com" for the Google provider).
		ProviderID string
	}

	// Message is the FCM message
	// See https://firebase.google.com/docs/cloud-messaging/http-server-ref#notification-payload-support
	Message struct {

		// To this parameter specifies the recipient of a message.
		//
		// The value can be a device's registration token, a device group's notification key, or a single topic
		// (prefixed with /topics/). To send to multiple topics, use the condition parameter.
		To string `json:"to,omitempty"`

		// This parameter specifies the recipient of a multicast message, a message sent to more than
		// one registration token.
		//
		// The value should be an array of registration tokens to which to send the multicast message.
		// The array must contain at least 1 and at most 1000 registration tokens. To send a message to a
		// single device, use the to parameter.
		//
		// Multicast messages are only allowed using the HTTP JSON format.
		RegistrationIDs []string `json:"registration_ids,omitempty"`

		// This parameter specifies a logical expression of conditions that determine the message target.
		//
		// Supported condition: Topic, formatted as "'yourTopic' in topics". This value is case-insensitive.
		//
		// Supported operators: &&, ||. Maximum two operators per topic message supported.
		Condition string `json:"condition,omitempty"`

		// This parameter identifies a group of messages (e.g., with collapse_key: "Updates
		// Available") that can be collapsed, so that only the last message gets sent when delivery can
		// be resumed. This is intended to avoid sending too many of the same messages when the
		// device comes back online or becomes active.
		//
		// Note that there is no guarantee of the order in which messages get sent.
		//
		// Note: A maximum of 4 different collapse keys is allowed at any given time. This means a FCM
		// connection server can simultaneously store 4 different send-to-sync messages per client app. If
		// you exceed this number, there is no guarantee which 4 collapse keys the FCM connection server
		// will keep.
		CollapseKey string `json:"collapse_key,omitempty"`

		// Sets the priority of the message. Valid values are "normal" and "high." On iOS, these correspond
		// to APNs priorities 5 and 10.
		//
		// By default, notification messages are sent with high priority, and data messages are sent with
		// normal priority. Normal priority optimizes the client app's battery consumption and should be
		// used unless immediate delivery is required. For messages with normal priority, the app may
		// receive the message with unspecified delay.
		//
		// When a message is sent with high priority, it is sent immediately, and the app can wake a
		// sleeping device and open a network connection to your server.
		//
		// For more information, see Setting the priority of a message.
		// See https://firebase.google.com/docs/cloud-messaging/concept-options#setting-the-priority-of-a-message
		Priority string `json:"priority,omitempty"`

		// On iOS, use this field to represent content-available in the APNs payload. When a
		// notification or message is sent and this is set to true, an inactive client app is awoken. On
		// Android, data messages wake the app by default. On Chrome, currently not supported.
		ContentAvailable bool `json:"content_available,omitempty"`

		// Currently for iOS 10+ devices only. On iOS, use this field to represent mutable-content in the
		// APNS payload. When a notification is sent and this is set to true, the content of the notification
		// can be modified before it is displayed, using a Notification Service app extension. This
		// parameter will be ignored for Android and web.
		// See https://developer.apple.com/documentation/usernotifications/unnotificationserviceextension
		MutableContent bool `json:"mutable_content,omitempty"`

		// This parameter specifies how long (in seconds) the message should be kept in FCM storage if
		// the device is offline. The maximum time to live supported is 4 weeks, and the default value is 4
		// weeks. For more information, see Setting the lifespan of a message.
		// See https://firebase.google.com/docs/cloud-messaging/concept-options#ttl
		TimeToLive int `json:"time_to_live,omitempty"`

		// This parameter specifies the package name of the application where the registration tokens
		// must match in order to receive the message.
		RestrictedPackageName string `json:"restricted_package_name,omitempty"`

		// This parameter, when set to true, allows developers to test a request without actually sending
		// a message.
		//
		// The default value is false.
		DryRun bool `json:"dry_run,omitempty"`

		// Data parameter specifies the custom key-value pairs of the message's payload.
		//
		// For example, with data:{"score":"3x1"}:
		//
		// On iOS, if the message is sent via APNS, it represents the custom data fields.
		// If it is sent via FCM connection server, it would be represented as key value dictionary
		// in AppDelegate application:didReceiveRemoteNotification:.
		//
		// On Android, this would result in an intent extra named score with the string value 3x1.
		//
		// The key should not be a reserved word ("from" or any word starting with "google" or "gcm").
		// Do not use any of the words defined in this table (such as collapse_key).
		//
		// Values in string types are recommended. You have to convert values in objects
		// or other non-string data types (e.g., integers or booleans) to string.
		//
		Data interface{} `json:"data,omitempty"`

		// This parameter specifies the predefined, user-visible key-value pairs of the notification payload.
		// See Notification payload support for detail. For more information about notification message
		// and data message options, see Message types.
		Notification Notification `json:"notification,omitempty"`
	}

	// Notification notification message payload
	Notification struct {

		// The notification's title.
		//
		// This field is not visible on iOS phones and tablets.
		Title string `json:"title,omitempty"`

		// The notification's body text.
		Body string `json:"body,omitempty"`

		// The notification's channel id (new in Android O).
		// See https://developer.android.com/preview/features/notification-channels.html
		//
		// The app must create a channel with this ID before any notification with this key is received.
		//
		// If you don't send this key in the request, or if the channel id provided has not yet been
		// created by your app, FCM uses the channel id specified in your app manifest.
		AndroidChannelID string `json:"android_channel_id,omitempty"`

		// The notification's icon.
		//
		// Sets the notification icon to myicon for drawable resource myicon. If you don't send this
		// key in the request, FCM displays the launcher icon specified in your app manifest.
		Icon string `json:"icon,omitempty"`

		// The sound to play when the device receives the notification.
		//
		// Sound files can be in the main bundle of the client app or in the Library/Sounds folder of the
		// app's data container. See the iOS Developer Library for more information.
		// See https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/SupportingNotificationsinYourApp.html#//apple_ref/doc/uid/TP40008194-CH4-SW10
		Sound string `json:"sound,omitempty"`

		// The value of the badge on the home screen app icon.
		//
		// If not specified, the badge is not changed.
		//
		// If set to 0, the badge is removed.
		Badge string `json:"badge,omitempty"`

		// Identifier used to replace existing notifications in the notification drawer.
		//
		// If not specified, each request creates a new notification.
		//
		// If specified and a notification with the same tag is already being shown, the new
		// notification replaces the existing one in the notification drawer.
		Tag string `json:"tag,omitempty"`

		// The notification's icon color, expressed in #rrggbb format.
		Color string `json:"color,omitempty"`

		// The action associated with a user click on the notification.
		//
		// If specified, an activity with a matching intent filter is launched when a user clicks on the
		// notification.
		ClickAction string `json:"click_action,omitempty"`

		// The key to the body string in the app's string resources to use to localize the body text to
		// the user's current localization.
		//
		// See String Resources for more information.
		// https://developer.android.com/guide/topics/resources/string-resource.html
		BodyLocKey string `json:"body_loc_key,omitempty"`

		// Variable string values to be used in place of the format specifiers in body_loc_key to use
		// to localize the body text to the user's current localization.
		//
		// See Formatting and Styling for more information.
		// https://developer.android.com/guide/topics/resources/string-resource.html#FormattingAndStyling
		BodyLocArgs string `json:"body_loc_args,omitempty"`

		// The key to the title string in the app's string resources to use to localize the title text to
		// the user's current localization.
		//
		// See String Resources for more information.
		// https://developer.android.com/guide/topics/resources/string-resource.html
		TitleLocKey string `json:"title_loc_key,omitempty"`

		// Variable string values to be used in place of the format specifiers in title_loc_key to use
		// to localize the title text to the user's current localization.
		//
		// See Formatting and Styling for more information.
		// https://developer.android.com/guide/topics/resources/string-resource.html#FormattingAndStyling
		TitleLocArgs string `json:"title_loc_args,omitempty"`
	}
)

func parseDate(t int64) time.Time {
	if t == 0 {
		return time.Time{}
	}
	return time.Unix(t/1000, 0)
}

func toUserRecord(user *identitytoolkit.UserInfo) *UserRecord {
	return &UserRecord{
		UserID:        user.LocalId,
		Email:         user.Email,
		EmailVerified: user.EmailVerified,
		DisplayName:   user.DisplayName,
		PhotoURL:      user.PhotoUrl,
		Disabled:      user.Disabled,
		Metadata: UserMetadata{
			CreatedAt:      parseDate(user.CreatedAt),
			LastSignedInAt: parseDate(user.LastLoginAt),
		},
		ProviderData: toUserInfos(user.ProviderUserInfo),
	}
}

func toUserRecords(users []*identitytoolkit.UserInfo) []*UserRecord {
	result := make([]*UserRecord, len(users))
	for i, user := range users {
		result[i] = toUserRecord(user)
	}
	return result
}

func toUserInfo(info *identitytoolkit.UserInfoProviderUserInfo) *UserInfo {
	return &UserInfo{
		UserID:      info.RawId,
		Email:       info.Email,
		DisplayName: info.DisplayName,
		PhotoURL:    info.PhotoUrl,
		ProviderID:  info.ProviderId,
	}
}

func toUserInfos(infos []*identitytoolkit.UserInfoProviderUserInfo) []*UserInfo {
	result := make([]*UserInfo, len(infos))
	for i, info := range infos {
		result[i] = toUserInfo(info)
	}
	return result
}

// User use for create new user
// use Password when create user (plain text)
// use RawPassword when update user (hashed password)
type User struct {
	UserID        string
	Email         string
	EmailVerified bool
	Password      string
	DisplayName   string
	PhotoURL      string
	Disabled      bool
}

// UpdateAccount use for update existing account
type UpdateAccount struct {
	// UserID is the existing user id to update
	UserID        string `json:"localId,omitempty"`
	Email         string `json:"email,omitempty"`
	EmailVerified bool   `json:"emailVerified,omitempty"`
	Password      string `json:"password,omitempty"`
	DisplayName   string `json:"displayName,omitempty"`
	PhotoURL      string `json:"photoUrl,omitempty"`
	Disabled      bool   `json:"disableUser,omitempty"`
}

var scopes = []string{
	"https://www.googleapis.com/auth/userinfo.email",
	"https://www.googleapis.com/auth/firebase.database",
	"https://www.googleapis.com/auth/identitytoolkit",
}

const (
	baseURL = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/"
	timeout = time.Second * 10000
)

func getContext() (context.Context, context.CancelFunc) {
	return context.WithTimeout(context.Background(), timeout)
}
<|endoftext|>


<commit_before>// Extract the information on running processes from gopsutil
package gops

import (
	"fmt"
	"runtime"

	// 3p
	log "github.com/cihub/seelog"

	// project
	"github.com/shirou/gopsutil/mem"
	"github.com/shirou/gopsutil/process"
)

type ProcessInfo struct {
	PID      int32
	PPID     int32
	Name     string
	RSS      uint64
	PctMem   float64
	VMS      uint64
	Username string
}

// Return a slice of all the processes that are running
func GetProcesses() ([]*ProcessInfo, error) {
	processInfos := make([]*ProcessInfo, 0, 10)

	virtMemStat, err := mem.VirtualMemory()
	if err != nil {
		err = fmt.Errorf("Error fetching system memory stats: %s", err)
		return nil, err
	}
	totalMem := float64(virtMemStat.Total)

	pids, err := process.Pids()
	if err != nil {
		err = fmt.Errorf("Error fetching PIDs: %s", err)
		return nil, err
	}

	for _, pid := range pids {
		p, err := process.NewProcess(pid)
		if err != nil {
			// an error can occur here only if the process has disappeared,
			log.Debugf("Process with pid %d disappeared while scanning: %s", pid, err)
			continue
		}

		processInfo, err := newProcessInfo(p, pid, totalMem)
		if err != nil {
			log.Infof("Error fetching info for pid %d: %s", pid, err)
			continue
		}

		processInfos = append(processInfos, processInfo)
	}

	// platform-specific post-processing on the collected info
	postProcess(processInfos)

	return processInfos, nil
}

// Make a new ProcessInfo from a Process from gopsutil
func newProcessInfo(p *process.Process, pid int32, totalMem float64) (*ProcessInfo, error) {
	memInfo, err := p.MemoryInfo()
	if err != nil {
		return nil, err
	}

	ppid, err := p.Ppid()
	if err != nil {
		return nil, err
	}

	name, err := p.Name()
	if err != nil {
		return nil, err
	}

	pctMem := 100. * float64(memInfo.RSS) / totalMem

	var username string
	if runtime.GOOS != "android" {
		username, err = p.Username()
		if err != nil {
			return nil, err
		}
	}

	return &ProcessInfo{pid, ppid, name, memInfo.RSS, pctMem, memInfo.VMS, username}, nil
}
<commit_msg>Lower log level<commit_after>// Extract the information on running processes from gopsutil
package gops

import (
	"fmt"
	"runtime"

	// 3p
	log "github.com/cihub/seelog"

	// project
	"github.com/shirou/gopsutil/mem"
	"github.com/shirou/gopsutil/process"
)

type ProcessInfo struct {
	PID      int32
	PPID     int32
	Name     string
	RSS      uint64
	PctMem   float64
	VMS      uint64
	Username string
}

// Return a slice of all the processes that are running
func GetProcesses() ([]*ProcessInfo, error) {
	processInfos := make([]*ProcessInfo, 0, 10)

	virtMemStat, err := mem.VirtualMemory()
	if err != nil {
		err = fmt.Errorf("Error fetching system memory stats: %s", err)
		return nil, err
	}
	totalMem := float64(virtMemStat.Total)

	pids, err := process.Pids()
	if err != nil {
		err = fmt.Errorf("Error fetching PIDs: %s", err)
		return nil, err
	}

	for _, pid := range pids {
		p, err := process.NewProcess(pid)
		if err != nil {
			// an error can occur here only if the process has disappeared,
			log.Debugf("Process with pid %d disappeared while scanning: %s", pid, err)
			continue
		}

		processInfo, err := newProcessInfo(p, pid, totalMem)
		if err != nil {
			log.Debugf("Error fetching info for pid %d: %s", pid, err)
			continue
		}

		processInfos = append(processInfos, processInfo)
	}

	// platform-specific post-processing on the collected info
	postProcess(processInfos)

	return processInfos, nil
}

// Make a new ProcessInfo from a Process from gopsutil
func newProcessInfo(p *process.Process, pid int32, totalMem float64) (*ProcessInfo, error) {
	memInfo, err := p.MemoryInfo()
	if err != nil {
		return nil, err
	}

	ppid, err := p.Ppid()
	if err != nil {
		return nil, err
	}

	name, err := p.Name()
	if err != nil {
		return nil, err
	}

	pctMem := 100. * float64(memInfo.RSS) / totalMem

	var username string
	if runtime.GOOS != "android" {
		username, err = p.Username()
		if err != nil {
			return nil, err
		}
	}

	return &ProcessInfo{pid, ppid, name, memInfo.RSS, pctMem, memInfo.VMS, username}, nil
}
<|endoftext|>


<commit_before>package sirius

import (
	"fmt"
	"github.com/kayex/sirius/slack"
	api "github.com/nlopes/slack"
	"strings"
)

type Connection interface {
	Listen()
	Auth() chan slack.UserID
	Messages() chan Message
	Update(*Message) error
}

type RTMConnection struct {
	token    string
	rtm      *api.RTM
	client   *api.Client
	auth     chan slack.UserID
	messages chan Message
}

func NewRTMConnection(token string) *RTMConnection {
	client := api.New(token)

	rtm := client.NewRTM()
	auth := make(chan slack.UserID, 1)
	msg := make(chan Message)

	return &RTMConnection{
		rtm:      rtm,
		auth:     auth,
		messages: msg,
		client:   client,
		token:    token,
	}
}

func (conn *RTMConnection) Listen() {
	go conn.rtm.ManageConnection()

	for {
		select {
		case ev := <-conn.rtm.IncomingEvents:
			conn.handleIncomingEvent(ev)
		}
	}
}

func (conn *RTMConnection) Auth() chan slack.UserID {
	return conn.auth
}

func (conn *RTMConnection) Messages() chan Message {
	return conn.messages
}

func (conn *RTMConnection) SendMessage(msg *Message) {
	omsg := conn.rtm.NewOutgoingMessage(msg.Text, msg.Channel)
	conn.rtm.SendMessage(omsg)
}

func (conn *RTMConnection) Update(msg *Message) error {
	_, _, _, err := conn.rtm.UpdateMessage(msg.Channel, msg.Timestamp, msg.Text)
	return err
}

func (conn *RTMConnection) authenticate(e *api.ConnectedEvent) {
	info := e.Info
	id := slack.UserID{info.User.ID, info.Team.ID}
	conn.auth <- id
}

func (conn *RTMConnection) handleIncomingEvent(ev api.RTMEvent) {
	switch msg := ev.Data.(type) {
	case *api.ConnectedEvent:
		conn.authenticate(msg)
	case *api.InvalidAuthEvent:
		panic(msg)
	case *api.MessageEvent:
		conn.handleIncomingMessage(msg)

	case *api.RTMError:
		fmt.Printf("Error: %s\n", msg.Error())
		panic(msg)
	}
}

func (conn *RTMConnection) handleIncomingMessage(ev *api.MessageEvent) {
	// Drop messages with incomplete data
	if ev.User == "" || ev.Team == "" {
		return
	}

	text := removeEscapeCharacters(ev.Text)
	msg := NewMessage(slack.UserID{ev.User, ev.Team}, text, ev.Channel, ev.Timestamp)

	conn.messages <- msg
}

var escapeCharacters map[string]string = map[string]string{
	"<":  "<",
	">":  ">",
	"&": "&",
}

func removeEscapeCharacters(msg string) string {
	for html, unicode := range escapeCharacters {
		msg = strings.Replace(msg, html, unicode, -1)
	}

	return msg
}
<commit_msg>Properly disconnect from RTM when terminating client<commit_after>package sirius

import (
	"fmt"
	"github.com/kayex/sirius/slack"
	api "github.com/nlopes/slack"
	"golang.org/x/net/context"
	"strings"
)

type Connection interface {
	Auth() chan slack.UserID
	Messages() chan Message
	Listen(context.Context)
	Update(*Message) error
}

type RTMConnection struct {
	token    string
	rtm      *api.RTM
	client   *api.Client
	auth     chan slack.UserID
	messages chan Message
}

func NewRTMConnection(token string) *RTMConnection {
	client := api.New(token)

	rtm := client.NewRTM()
	auth := make(chan slack.UserID, 1)
	msg := make(chan Message)

	return &RTMConnection{
		rtm:      rtm,
		auth:     auth,
		messages: msg,
		client:   client,
		token:    token,
	}
}

func (conn *RTMConnection) Listen(ctx context.Context) {
	go conn.rtm.ManageConnection()

	for {
		select {
		case <-ctx.Done():
			conn.rtm.Disconnect()
			return
		case ev := <-conn.rtm.IncomingEvents:
			conn.handleIncomingEvent(ev)
		}
	}
}

func (conn *RTMConnection) Auth() chan slack.UserID {
	return conn.auth
}

func (conn *RTMConnection) Messages() chan Message {
	return conn.messages
}

func (conn *RTMConnection) SendMessage(msg *Message) {
	omsg := conn.rtm.NewOutgoingMessage(msg.Text, msg.Channel)
	conn.rtm.SendMessage(omsg)
}

func (conn *RTMConnection) Update(msg *Message) error {
	_, _, _, err := conn.rtm.UpdateMessage(msg.Channel, msg.Timestamp, msg.Text)
	return err
}

func (conn *RTMConnection) authenticate(e *api.ConnectedEvent) {
	info := e.Info
	id := slack.UserID{info.User.ID, info.Team.ID}
	conn.auth <- id
}

func (conn *RTMConnection) handleIncomingEvent(ev api.RTMEvent) {
	switch msg := ev.Data.(type) {
	case *api.ConnectedEvent:
		conn.authenticate(msg)
	case *api.InvalidAuthEvent:
		panic(msg)
	case *api.MessageEvent:
		conn.handleIncomingMessage(msg)

	case *api.RTMError:
		fmt.Printf("Error: %s\n", msg.Error())
		panic(msg)
	}
}

func (conn *RTMConnection) handleIncomingMessage(ev *api.MessageEvent) {
	// Drop messages with incomplete data
	if ev.User == "" || ev.Team == "" {
		return
	}

	text := removeEscapeCharacters(ev.Text)
	msg := NewMessage(slack.UserID{ev.User, ev.Team}, text, ev.Channel, ev.Timestamp)

	conn.messages <- msg
}

var escapeCharacters map[string]string = map[string]string{
	"<":  "<",
	">":  ">",
	"&": "&",
}

func removeEscapeCharacters(msg string) string {
	for html, unicode := range escapeCharacters {
		msg = strings.Replace(msg, html, unicode, -1)
	}

	return msg
}
<|endoftext|>


<commit_before>package svc

import (
	"fmt"
	"os"
	"os/exec"
	"time"
)

// Start starts a scoring service.
func Start(warfile string, port int) (int, error) {

	argv := []string{"10000"} // FIXME use jetty-runner args

	cmd := exec.Command("/bin/sleep", argv...) // FIXME use jetty-runner

	if err := cmd.Start(); err != nil {
		return 0, fmt.Errorf("Failed starting scoring service for %s at port %d: %v", warfile, port, err)
	}

	return cmd.Process.Pid, nil
}

// Stop stops a scoring service.
func Stop(pid int) error {
	p, err := os.FindProcess(pid)
	if err != nil {
		return fmt.Errorf("Failed locating scoring service with pid %d: %v", pid, err)
	}

	const sigintInterval = time.Second
	const sigintTimeout = time.Second * 10

	// retry SIGINTs;  SIGKILL on timeout
	ticker := time.NewTicker(sigintInterval)
	timeout := time.NewTimer(sigintTimeout)
	for {
		select {
		case <-timeout.C:
			ticker.Stop()
			if err := p.Signal(os.Kill); err != nil {
				return fmt.Errorf("Failed terminating scoring service at port %d: %v", pid, err)

			}
		case <-ticker.C:
			err := p.Signal(os.Interrupt)
			if err == nil || (err != nil && isProcessFinished(err)) {
				ticker.Stop()
				return nil
			}
		}
	}
}

func isProcessFinished(err error) bool {
	return err.Error() == "os: process already finished"
}
<commit_msg>STEAM-138 Verify pid command string prior to sigterm<commit_after>package svc

import (
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"
)

// Start starts a scoring service.
func Start(warfile string, port int) (int, error) {

	argv := []string{"10000"} // FIXME use jetty-runner args

	cmd := exec.Command("/bin/sleep", argv...) // FIXME use jetty-runner

	if err := cmd.Start(); err != nil {
		return 0, fmt.Errorf("Failed starting scoring service for %s at port %d: %v", warfile, port, err)
	}

	return cmd.Process.Pid, nil
}

// Stop stops a scoring service.
func Stop(pid int) error {
	p, err := os.FindProcess(pid)
	if err != nil {
		return fmt.Errorf("Failed locating scoring service with pid %d: %v", pid, err)
	}

	// Verify if this pid belongs to a scoring service
	pscmd, err := getProcessCommand(pid)
	if err != nil {
		return fmt.Errorf("Failed inspecting pid %d: %v", pid, err)
	}
	if !strings.Contains(pscmd, "/bin/sleep") { // FIXME check for jetty-runner
		return fmt.Errorf("Process %d is not a scoring service")
	}

	const sigintInterval = time.Second
	const sigintTimeout = time.Second * 10

	// Retry SIGINTs;  SIGKILL on timeout
	ticker := time.NewTicker(sigintInterval)
	timeout := time.NewTimer(sigintTimeout)
	for {
		select {
		case <-timeout.C:
			ticker.Stop()
			if err := p.Signal(os.Kill); err != nil {
				return fmt.Errorf("Failed terminating scoring service at port %d: %v", pid, err)

			}
		case <-ticker.C:
			err := p.Signal(os.Interrupt)
			if err == nil || (err != nil && isProcessFinished(err)) {
				ticker.Stop()
				return nil
			}
		}
	}
}

func getProcessCommand(pid int) (string, error) {
	lines, err := exec.Command("/bin/ps", "-o", "command", "-p", strconv.Itoa(pid)).Output()
	if err != nil {
		return "", fmt.Errorf("Failed inspecting process with pid %d: %v", pid, err)
	}
	return string(lines), nil
}

func isProcessFinished(err error) bool {
	return err.Error() == "os: process already finished"
}
<|endoftext|>


<commit_before>package instana

import (
	"time"

	ot "github.com/opentracing/opentracing-go"
)

const (
	// MaxLogsPerSpan The maximum number of logs allowed on a span.
	MaxLogsPerSpan = 2
)

type tracerS struct {
	options        TracerOptions
	textPropagator *textMapPropagator
}

func (r *tracerS) Inject(sc ot.SpanContext, format interface{}, carrier interface{}) error {
	switch format {
	case ot.TextMap, ot.HTTPHeaders:
		return r.textPropagator.inject(sc, carrier)
	}

	return ot.ErrUnsupportedFormat
}

func (r *tracerS) Extract(format interface{}, carrier interface{}) (ot.SpanContext, error) {
	switch format {
	case ot.TextMap, ot.HTTPHeaders:
		return r.textPropagator.extract(carrier)
	}

	return nil, ot.ErrUnsupportedFormat
}

func (r *tracerS) StartSpan(operationName string, opts ...ot.StartSpanOption) ot.Span {
	sso := ot.StartSpanOptions{}
	for _, o := range opts {
		o.Apply(&sso)
	}

	return r.StartSpanWithOptions(operationName, sso)
}

func (r *tracerS) StartSpanWithOptions(operationName string, opts ot.StartSpanOptions) ot.Span {
	startTime := opts.StartTime
	if startTime.IsZero() {
		startTime = time.Now()
	}

	tags := opts.Tags
	span := &spanS{
		tracer:    r,
		Operation: operationName,
		Start:     startTime,
		Duration:  -1,
		Tags:      tags,
	}
Loop:
	for _, ref := range opts.References {
		switch ref.Type {
		case ot.ChildOfRef, ot.FollowsFromRef:
			refCtx := ref.ReferencedContext.(SpanContext)
			span.context.TraceID = refCtx.TraceID
			span.context.SpanID = randomID()
			span.context.Sampled = refCtx.Sampled
			span.context.ParentID = refCtx.SpanID
			if l := len(refCtx.Baggage); l > 0 {
				span.context.Baggage = make(map[string]string, l)
				for k, v := range refCtx.Baggage {
					span.context.Baggage[k] = v
				}
			}

			break Loop
		}
	}

	if span.context.TraceID == 0 {
		span.context.SpanID = randomID()
		span.context.TraceID = span.context.SpanID
		span.context.Sampled = r.options.ShouldSample(span.context.TraceID)
	}

	return span
}

func shouldSample(traceID int64) bool {
	return false
}

// NewTracer Get a new Tracer with the default options applied.
func NewTracer() ot.Tracer {
	return NewTracerWithOptions(&Options{})
}

// NewTracerWithOptions Get a new Tracer with the specified options.
func NewTracerWithOptions(options *Options) ot.Tracer {
	InitSensor(options)

	return NewTracerWithEverything(options, NewRecorder())
}

// NewTracerWithEverything Get a new Tracer with the works.
func NewTracerWithEverything(options *Options, recorder SpanRecorder) ot.Tracer {
	InitSensor(options)
	ret := &tracerS{options: TracerOptions{
		Recorder:       recorder,
		ShouldSample:   shouldSample,
		MaxLogsPerSpan: MaxLogsPerSpan}}
	ret.textPropagator = &textMapPropagator{ret}

	return ret
}
<commit_msg>Use SpanContext constructor functions to initialize context for a new span<commit_after>package instana

import (
	"time"

	ot "github.com/opentracing/opentracing-go"
)

const (
	// MaxLogsPerSpan The maximum number of logs allowed on a span.
	MaxLogsPerSpan = 2
)

type tracerS struct {
	options        TracerOptions
	textPropagator *textMapPropagator
}

func (r *tracerS) Inject(sc ot.SpanContext, format interface{}, carrier interface{}) error {
	switch format {
	case ot.TextMap, ot.HTTPHeaders:
		return r.textPropagator.inject(sc, carrier)
	}

	return ot.ErrUnsupportedFormat
}

func (r *tracerS) Extract(format interface{}, carrier interface{}) (ot.SpanContext, error) {
	switch format {
	case ot.TextMap, ot.HTTPHeaders:
		return r.textPropagator.extract(carrier)
	}

	return nil, ot.ErrUnsupportedFormat
}

func (r *tracerS) StartSpan(operationName string, opts ...ot.StartSpanOption) ot.Span {
	sso := ot.StartSpanOptions{}
	for _, o := range opts {
		o.Apply(&sso)
	}

	return r.StartSpanWithOptions(operationName, sso)
}

func (r *tracerS) StartSpanWithOptions(operationName string, opts ot.StartSpanOptions) ot.Span {
	startTime := opts.StartTime
	if startTime.IsZero() {
		startTime = time.Now()
	}

	span := &spanS{
		tracer:    r,
		Operation: operationName,
		Start:     startTime,
		Duration:  -1,
		Tags:      opts.Tags,
	}

	for _, ref := range opts.References {
		switch ref.Type {
		case ot.ChildOfRef, ot.FollowsFromRef:
			parentCtx := ref.ReferencedContext.(SpanContext)
			span.context = NewSpanContext(parentCtx)

			return span
		}
	}

	span.context = NewRootSpanContext()
	span.context.Sampled = r.options.ShouldSample(span.context.TraceID)

	return span
}

func shouldSample(traceID int64) bool {
	return false
}

// NewTracer Get a new Tracer with the default options applied.
func NewTracer() ot.Tracer {
	return NewTracerWithOptions(&Options{})
}

// NewTracerWithOptions Get a new Tracer with the specified options.
func NewTracerWithOptions(options *Options) ot.Tracer {
	InitSensor(options)

	return NewTracerWithEverything(options, NewRecorder())
}

// NewTracerWithEverything Get a new Tracer with the works.
func NewTracerWithEverything(options *Options, recorder SpanRecorder) ot.Tracer {
	InitSensor(options)
	ret := &tracerS{options: TracerOptions{
		Recorder:       recorder,
		ShouldSample:   shouldSample,
		MaxLogsPerSpan: MaxLogsPerSpan}}
	ret.textPropagator = &textMapPropagator{ret}

	return ret
}
<|endoftext|>