<commit_before>package main

import (
	"encoding/base64"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"time"

	"github.com/raintreeinc/livepkg"

	"github.com/raintreeinc/knowledgebase/auth"
	"github.com/raintreeinc/knowledgebase/kb"
	"github.com/raintreeinc/knowledgebase/kb/pgdb"

	"github.com/raintreeinc/knowledgebase/module/admin"
	"github.com/raintreeinc/knowledgebase/module/dispatch"
	"github.com/raintreeinc/knowledgebase/module/dita"
	"github.com/raintreeinc/knowledgebase/module/group"
	"github.com/raintreeinc/knowledgebase/module/page"
	"github.com/raintreeinc/knowledgebase/module/search"
	"github.com/raintreeinc/knowledgebase/module/tag"
	"github.com/raintreeinc/knowledgebase/module/user"

	_ "github.com/lib/pq"
)

// TODO: add
//  https://github.com/unrolled/secure
//  https://github.com/justinas/nosurf

var (
	addr     = flag.String("listen", ":80", "http server `address`")
	database = flag.String("database", "user=root dbname=knowledgebase sslmode=disable", "database `params`")
	domain   = flag.String("domain", "", "`domain`")

	redirecthttps = flag.Bool("redirecthttps", false, "redirect http to https")

	development = flag.Bool("development", true, "development mode")
	ditamap     = flag.String("dita", "", "ditamap file for showing live dita")

	rules = flag.String("rules", "rules.json", "different rules for server")

	clientdir = flag.String("client", "client", "client `directory`")
)

func main() {
	flag.Parse()

	host, port := os.Getenv("HOST"), os.Getenv("PORT")
	if host != "" || port != "" {
		*addr = host + ":" + port
	}

	if os.Getenv("CLIENTDIR") != "" {
		*clientdir = os.Getenv("CLIENTDIR")
	}
	if rds := RDS(); rds != "" {
		*database = rds
	}
	if os.Getenv("DATABASE") != "" {
		*database = os.Getenv("DATABASE")
	}
	if os.Getenv("DOMAIN") != "" {
		*domain = os.Getenv("DOMAIN")
	}
	if os.Getenv("DITAMAP") != "" {
		*ditamap = os.Getenv("DITAMAP")
	}
	if os.Getenv("RULES") != "" {
		*rules = os.Getenv("RULES")
	}

	if os.Getenv("DEVELOPMENT") != "" {
		v, err := strconv.ParseBool(os.Getenv("DEVELOPMENT"))
		if err == nil {
			*development = v
		}
	}

	if os.Getenv("REDIRECTHTTPS") != "" {
		v, err := strconv.ParseBool(os.Getenv("REDIRECTHTTPS"))
		if err == nil {
			*redirecthttps = v
		}
	}

	log.Printf("Development %v\n", *development)
	log.Printf("Starting with database %s\n", *database)
	log.Printf("Starting %s on %s\n", *domain, *addr)

	// Serve static files
	http.Handle("/assets/", http.StripPrefix("/assets/",
		http.FileServer(http.Dir(filepath.Join(*clientdir, "assets")))))

	// Serve client
	client := livepkg.NewServer(http.Dir(*clientdir), *development, "/kb/app.js")
	http.Handle("/kb/", client)

	// Load database
	db, err := pgdb.New(*database)
	if err != nil {
		log.Fatal(err)
	}

	log.Println("Initializing DB")
	if err := db.Initialize(); err != nil {
		log.Fatal(err)
	}
	log.Println("DB Initialization complete.")

	// protect server with authentication
	url := "http://" + *domain
	auth.Register(os.Getenv("APPKEY"), url, "/system/auth", auth.ClientsFromEnv())

	sec := auth.New()
	sec.Alternate["guest"] = auth.NewDB(db)
	if caskey := os.Getenv("CASKEY"); caskey != "" {
		data, err := base64.StdEncoding.DecodeString(caskey)
		if err != nil {
			log.Fatal(err)
		}
		sec.Alternate["community"] = auth.NewCAS("community", data)
	}

	// create server
	server := kb.NewServer(kb.ServerInfo{
		Domain:     *domain,
		ShortTitle: "KB",
		Title:      "Knowledge Base",
		Company:    "Raintree Systems Inc.",

		TrackingID: os.Getenv("TRACKING_ID"),
		Version:    time.Now().Format("20060102150405"),
	}, sec, db)

	server.TemplatesDir = filepath.Join(*clientdir, "templates")

	ruleset := MustLoadRules(*rules)
	server.Rules = ruleset

	// add systems
	server.AddModule(admin.New(server))
	server.AddModule(group.New(server))
	server.AddModule(page.New(server))
	server.AddModule(search.New(server))
	server.AddModule(tag.New(server))
	server.AddModule(user.New(server))
	server.AddModule(dispatch.New(kb.Group{
		ID:          "help",
		Name:        "Help",
		Public:      false,
		Description: "Raintree Official Help",
	}, server))

	if *ditamap != "" {
		server.AddModule(dita.New("DITA", *ditamap, server))
	}

	http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, filepath.Join(*clientdir, "assets", "ico", "favicon.ico"))
	})

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		ishttps := r.Header.Get("X-Forwarded-Proto") == "https" || r.URL.Scheme == "https"
		if *redirecthttps && !ishttps {
			r.URL.Scheme = "https"
			r.URL.Host = *domain
			http.Redirect(w, r, r.URL.String(), http.StatusMovedPermanently)
			return
		}
		server.ServeHTTP(w, r)
	})
	log.Fatal(http.ListenAndServe(*addr, nil))
}

type RuleSet struct {
	Admins         []kb.Slug
	ByEmail        map[string][]kb.Slug `json:"byEmail"`
	ByAuthProvider map[string][]kb.Slug `json:"byAuthProvider"`
}

func (rs *RuleSet) Login(user kb.User, db kb.Database) error {
	context := db.Context("admin")
	_, err := context.Users().ByID(user.ID)
	created := err == nil

	createUserIfNeeded := func() {
		if !created {
			err := context.Users().Create(user)
			if err != nil {
				log.Println(err)
				return
			}
			created = true
		}
	}

	for rule, groups := range rs.ByEmail {
		matched, err := regexp.MatchString(rule, user.Email)
		if err != nil {
			log.Println(err)
		}
		if matched && err == nil {
			createUserIfNeeded()
			for _, group := range groups {
				context.Access().AddUser(group, user.ID)
			}
		}
	}

	for prov, groups := range rs.ByAuthProvider {
		if prov == user.AuthProvider {
			createUserIfNeeded()
			for _, group := range groups {
				context.Access().AddUser(group, user.ID)
			}
		}
	}

	for _, admin := range rs.Admins {
		if user.ID == admin {
			context.Access().SetAdmin(user.ID, true)
		}
	}

	return context.Access().VerifyUser(user)
}

func MustLoadRules(filename string) *RuleSet {
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatal(err)
	}

	rs := &RuleSet{}
	if err := json.Unmarshal(data, rs); err != nil {
		log.Fatal(err)
	}

	return rs
}

func RDS() string {
	user := os.Getenv("RDS_USERNAME")
	pass := os.Getenv("RDS_PASSWORD")

	dbname := os.Getenv("RDS_DB_NAME")
	host := os.Getenv("RDS_HOSTNAME")
	port := os.Getenv("RDS_PORT")

	if user == "" || pass == "" || dbname == "" || host == "" || port == "" {
		return ""
	}

	return fmt.Sprintf("user='%s' password='%s' dbname='%s' host='%s' port='%s'", user, pass, dbname, host, port)
}
<commit_msg>Add failed verification to log. Task 126436<commit_after>package main

import (
	"encoding/base64"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"time"

	"github.com/raintreeinc/livepkg"

	"github.com/raintreeinc/knowledgebase/auth"
	"github.com/raintreeinc/knowledgebase/kb"
	"github.com/raintreeinc/knowledgebase/kb/pgdb"

	"github.com/raintreeinc/knowledgebase/module/admin"
	"github.com/raintreeinc/knowledgebase/module/dispatch"
	"github.com/raintreeinc/knowledgebase/module/dita"
	"github.com/raintreeinc/knowledgebase/module/group"
	"github.com/raintreeinc/knowledgebase/module/page"
	"github.com/raintreeinc/knowledgebase/module/search"
	"github.com/raintreeinc/knowledgebase/module/tag"
	"github.com/raintreeinc/knowledgebase/module/user"

	_ "github.com/lib/pq"
)

// TODO: add
//  https://github.com/unrolled/secure
//  https://github.com/justinas/nosurf

var (
	addr     = flag.String("listen", ":80", "http server `address`")
	database = flag.String("database", "user=root dbname=knowledgebase sslmode=disable", "database `params`")
	domain   = flag.String("domain", "", "`domain`")

	redirecthttps = flag.Bool("redirecthttps", false, "redirect http to https")

	development = flag.Bool("development", true, "development mode")
	ditamap     = flag.String("dita", "", "ditamap file for showing live dita")

	rules = flag.String("rules", "rules.json", "different rules for server")

	clientdir = flag.String("client", "client", "client `directory`")
)

func main() {
	flag.Parse()

	host, port := os.Getenv("HOST"), os.Getenv("PORT")
	if host != "" || port != "" {
		*addr = host + ":" + port
	}

	if os.Getenv("CLIENTDIR") != "" {
		*clientdir = os.Getenv("CLIENTDIR")
	}
	if rds := RDS(); rds != "" {
		*database = rds
	}
	if os.Getenv("DATABASE") != "" {
		*database = os.Getenv("DATABASE")
	}
	if os.Getenv("DOMAIN") != "" {
		*domain = os.Getenv("DOMAIN")
	}
	if os.Getenv("DITAMAP") != "" {
		*ditamap = os.Getenv("DITAMAP")
	}
	if os.Getenv("RULES") != "" {
		*rules = os.Getenv("RULES")
	}

	if os.Getenv("DEVELOPMENT") != "" {
		v, err := strconv.ParseBool(os.Getenv("DEVELOPMENT"))
		if err == nil {
			*development = v
		}
	}

	if os.Getenv("REDIRECTHTTPS") != "" {
		v, err := strconv.ParseBool(os.Getenv("REDIRECTHTTPS"))
		if err == nil {
			*redirecthttps = v
		}
	}

	log.Printf("Development %v\n", *development)
	log.Printf("Starting with database %s\n", *database)
	log.Printf("Starting %s on %s\n", *domain, *addr)

	// Serve static files
	http.Handle("/assets/", http.StripPrefix("/assets/",
		http.FileServer(http.Dir(filepath.Join(*clientdir, "assets")))))

	// Serve client
	client := livepkg.NewServer(http.Dir(*clientdir), *development, "/kb/app.js")
	http.Handle("/kb/", client)

	// Load database
	db, err := pgdb.New(*database)
	if err != nil {
		log.Fatal(err)
	}

	log.Println("Initializing DB")
	if err := db.Initialize(); err != nil {
		log.Fatal(err)
	}
	log.Println("DB Initialization complete.")

	// protect server with authentication
	url := "http://" + *domain
	auth.Register(os.Getenv("APPKEY"), url, "/system/auth", auth.ClientsFromEnv())

	sec := auth.New()
	sec.Alternate["guest"] = auth.NewDB(db)
	if caskey := os.Getenv("CASKEY"); caskey != "" {
		data, err := base64.StdEncoding.DecodeString(caskey)
		if err != nil {
			log.Fatal(err)
		}
		sec.Alternate["community"] = auth.NewCAS("community", data)
	}

	// create server
	server := kb.NewServer(kb.ServerInfo{
		Domain:     *domain,
		ShortTitle: "KB",
		Title:      "Knowledge Base",
		Company:    "Raintree Systems Inc.",

		TrackingID: os.Getenv("TRACKING_ID"),
		Version:    time.Now().Format("20060102150405"),
	}, sec, db)

	server.TemplatesDir = filepath.Join(*clientdir, "templates")

	ruleset := MustLoadRules(*rules)
	server.Rules = ruleset

	// add systems
	server.AddModule(admin.New(server))
	server.AddModule(group.New(server))
	server.AddModule(page.New(server))
	server.AddModule(search.New(server))
	server.AddModule(tag.New(server))
	server.AddModule(user.New(server))
	server.AddModule(dispatch.New(kb.Group{
		ID:          "help",
		Name:        "Help",
		Public:      false,
		Description: "Raintree Official Help",
	}, server))

	if *ditamap != "" {
		server.AddModule(dita.New("DITA", *ditamap, server))
	}

	http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, filepath.Join(*clientdir, "assets", "ico", "favicon.ico"))
	})

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		ishttps := r.Header.Get("X-Forwarded-Proto") == "https" || r.URL.Scheme == "https"
		if *redirecthttps && !ishttps {
			r.URL.Scheme = "https"
			r.URL.Host = *domain
			http.Redirect(w, r, r.URL.String(), http.StatusMovedPermanently)
			return
		}
		server.ServeHTTP(w, r)
	})
	log.Fatal(http.ListenAndServe(*addr, nil))
}

type RuleSet struct {
	Admins         []kb.Slug
	ByEmail        map[string][]kb.Slug `json:"byEmail"`
	ByAuthProvider map[string][]kb.Slug `json:"byAuthProvider"`
}

func (rs *RuleSet) Login(user kb.User, db kb.Database) error {
	context := db.Context("admin")
	_, err := context.Users().ByID(user.ID)
	created := err == nil

	createUserIfNeeded := func() {
		if !created {
			err := context.Users().Create(user)
			if err != nil {
				log.Println(err)
				return
			}
			created = true
		}
	}

	for rule, groups := range rs.ByEmail {
		matched, err := regexp.MatchString(rule, user.Email)
		if err != nil {
			log.Println(err)
		}
		if matched && err == nil {
			createUserIfNeeded()
			for _, group := range groups {
				context.Access().AddUser(group, user.ID)
			}
		}
	}

	for prov, groups := range rs.ByAuthProvider {
		if prov == user.AuthProvider {
			createUserIfNeeded()
			for _, group := range groups {
				context.Access().AddUser(group, user.ID)
			}
		}
	}

	for _, admin := range rs.Admins {
		if user.ID == admin {
			context.Access().SetAdmin(user.ID, true)
		}
	}

	err = context.Access().VerifyUser(user)
	if err != nil {
		log.Printf("Failed to login: %v\n", user)
	}
	return err
}

func MustLoadRules(filename string) *RuleSet {
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatal(err)
	}

	rs := &RuleSet{}
	if err := json.Unmarshal(data, rs); err != nil {
		log.Fatal(err)
	}

	return rs
}

func RDS() string {
	user := os.Getenv("RDS_USERNAME")
	pass := os.Getenv("RDS_PASSWORD")

	dbname := os.Getenv("RDS_DB_NAME")
	host := os.Getenv("RDS_HOSTNAME")
	port := os.Getenv("RDS_PORT")

	if user == "" || pass == "" || dbname == "" || host == "" || port == "" {
		return ""
	}

	return fmt.Sprintf("user='%s' password='%s' dbname='%s' host='%s' port='%s'", user, pass, dbname, host, port)
}
<|endoftext|>


<commit_before>// Author: Yoshiyuki Koyanagi <moutend@gmail.com>
// License: mIT

// Package main implements mediumctl.
package main

import (
	"crypto/rand"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/user"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	medium "github.com/moutend/go-medium"
	"github.com/skratchdot/open-golang/open"
)

type token struct {
	ApplicationID     string
	ApplicationSecret string
	AccessToken       string
	ExpiresAt         int
	RefreshToken      string
}

var (
	version       = "v0.1.6"
	revision      = "dev"
	tokenFilePath string
)

const tokenFileName = ".mediumctl"

func showPostedArticleInfo(p *medium.PostedArticle) {
	fmt.Printf("Your article was successfully posted.\n\n")
	fmt.Printf("title: %s\n", p.Title)
	fmt.Printf("publishStatus: %s\n", p.PublishStatus)
	if len(p.Tags) > 0 {
		fmt.Printf("tags: %s\n", strings.Join(p.Tags, " "))
	}
	fmt.Printf("URL: %s\n", p.URL)
	if p.CanonicalURL != "" {
		fmt.Printf("canonicalURL: %s\n", p.CanonicalURL)
	}
	return
}

func parseArticle(filename string) (article medium.Article, publicationNumber int, err error) {
	b, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}
	if len(b) == 0 {
		err = fmt.Errorf("%s is empty", filename)
		return
	}

	var (
		content         string
		contentFormat   string
		canonicalURL    string
		license         string
		notifyFollowers bool
		publishedAt     string
		publishStatus   string
		tags            []string
		title           string
	)
	contentFormat = "markdown"
	if strings.HasSuffix(filename, "html") || strings.HasSuffix(filename, "htm") {
		contentFormat = "html"
	}
	lines := strings.Split(string(b), "\n")

	for i, line := range lines[1:] {
		if strings.HasPrefix(line, "---") {
			content = strings.Join(lines[i+2:], "\n")
			break
		}
		if strings.HasPrefix(line, "canonicalURL: ") {
			canonicalURL = line[len("canonicalURL: "):]
		}
		if strings.HasPrefix(line, "license: ") {
			license = line[len("license: "):]
		}
		if strings.HasPrefix(line, "number: ") {
			publicationNumber, err = strconv.Atoi(line[len("number: "):])
			if err != nil {
				return
			}
		}
		if strings.HasPrefix(line, "notifyFollowers: true") {
			notifyFollowers = true
		}
		if strings.HasPrefix(line, "publishedAt: ") {
			publishedAt = line[len("publishedAt: "):]
		}
		if strings.HasPrefix(line, "publishStatus: ") {
			publishStatus = line[len("publishStatus: "):]
		}
		if strings.HasPrefix(line, "tags: ") {
			tags = strings.Split(line[len("tags: "):], " ")
		}
		if strings.HasPrefix(line, "title: ") {
			title = line[len("title: "):]
		}
	}
	if content == "" {
		content = strings.Join(lines, "\n")
	}
	article = medium.Article{
		Title:           title,
		ContentFormat:   contentFormat,
		Content:         content,
		CanonicalURL:    canonicalURL,
		Tags:            tags,
		PublishStatus:   publishStatus,
		PublishedAt:     publishedAt,
		License:         license,
		NotifyFollowers: notifyFollowers,
	}
	return
}
func getCode(clientID, redirectURI string) (code string, err error) {
	l, err := net.Listen("tcp", "192.168.1.107:4000")
	if err != nil {
		return
	}
	defer l.Close()

	type value struct {
		code  string
		error error
	}
	quit := make(chan value)
	go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		w.Write([]byte(`<script>window.open("about:blank","_self").close()</script>`))
		w.(http.Flusher).Flush()
		c := req.FormValue("code")
		e := req.FormValue("error")
		v := value{
			code:  c,
			error: nil,
		}
		if e != "" {
			v.error = fmt.Errorf(e)
		}
		quit <- v
	}))
	stateBytes := make([]byte, 88)
	_, err = rand.Read(stateBytes)
	if err != nil {
		return
	}
	state := fmt.Sprintf("%x", stateBytes)
	scope := "basicProfile,listPublications,publishPost"
	redirectURI = url.QueryEscape(redirectURI)
	q := fmt.Sprintf("client_id=%s&scope=%s&state=%s&response_type=code&redirect_uri=%s", clientID, scope, state, redirectURI)
	p := "https://medium.com/m/oauth/authorize?" + q
	if err = open.Start(p); err != nil {
		return
	}
	select {
	case v := <-quit:
		if v.error != nil {
			return "", v.error
		}
		return v.code, nil
	case <-time.After(60 * time.Second):
		return "", fmt.Errorf("timeout")
	}
}

func saveToken(clientID, clientSecret string, t *medium.Token) (err error) {
	b, err := json.Marshal(token{
		ApplicationID:     clientID,
		ApplicationSecret: clientSecret,
		AccessToken:       t.AccessToken,
		ExpiresAt:         t.ExpiresAt,
		RefreshToken:      t.RefreshToken,
	})
	if err != nil {
		return
	}
	err = ioutil.WriteFile(tokenFilePath, b, 0644)
	return
}

func loadToken() (*token, error) {
	b, err := ioutil.ReadFile(tokenFilePath)
	if err != nil {
		return nil, fmt.Errorf("API token is not set. Please run 'auth' at first")
	}
	var t token
	err = json.Unmarshal(b, &t)
	return &t, err
}

func main() {
	err := run(os.Args)

	if err != nil {
		log.New(os.Stderr, "error: ", 0).Fatal(err)
		os.Exit(1)
	}

	os.Exit(0)
}
func run(args []string) (err error) {
	if len(args) < 2 {
		return helpCommand(args)
	}
	u, err := user.Current()
	if err != nil {
		return
	}
	tokenFilePath = filepath.Join(u.HomeDir, tokenFileName)
	switch args[1] {
	case "oauth":
		err = authCommand(args)
	case "o":
		err = authCommand(args)
	case "i":
		err = infoCommand(args)
	case "info":
		err = infoCommand(args)
	case "p":
		err = postCommand(args, false)
	case "publication":
		err = postCommand(args, false)
	case "u":
		err = postCommand(args, true)
	case "user":
		err = postCommand(args, true)
	case "v":
		err = versionCommand(args)
	case "version":
		err = versionCommand(args)
	case "h":
		err = helpCommand(args)
	case "help":
		err = helpCommand(args)
	default:
		fmt.Fprintf(os.Stderr, "%s: '%s' is not a %s subcommand.\n", args[0], args[1], args[0])
		err = helpCommand(args)
	}
	return
}

func authCommand(args []string) (err error) {
	var (
		clientIDFlag     string
		clientSecretFlag string
		debugFlag        bool
		redirectURIFlag  string
	)

	f := flag.NewFlagSet(fmt.Sprintf("%s %s", args[0], args[1]), flag.ExitOnError)
	f.StringVar(&redirectURIFlag, "u", "", "Redirect URI for OAuth application.")
	f.StringVar(&clientIDFlag, "i", "", "Client ID of OAuth application.")
	f.StringVar(&clientSecretFlag, "s", "", "Client secret of OAuth application.")
	f.BoolVar(&debugFlag, "debug", false, "Enable debug output.")
	f.Parse(args[2:])
	if redirectURIFlag == "" {
		return fmt.Errorf("please specify redirect URI")
	}
	if clientIDFlag == "" {
		return fmt.Errorf("please specify client ID")
	}
	if clientSecretFlag == "" {
		return fmt.Errorf("please specify client secret")
	}

	code, err := getCode(clientIDFlag, redirectURIFlag)
	if err != nil {
		return
	}
	c := medium.NewClient(clientIDFlag, clientSecretFlag, "")
	if debugFlag {
		c.SetLogger(log.New(os.Stdout, "debug: ", 0))
	}
	token, err := c.Token(code, redirectURIFlag)
	if err != nil {
		return
	}
	if err = saveToken(clientIDFlag, clientSecretFlag, token); err != nil {
		return
	}
	fmt.Printf("Your API token was successfully saved in '%s'.\n", tokenFilePath)
	fmt.Println("Note: This file should be treated as the password and please do NOT expose it.")
	return
}

func infoCommand(args []string) (err error) {
	var (
		debugFlag bool
	)

	f := flag.NewFlagSet(fmt.Sprintf("%s %s", args[0], args[1]), flag.ExitOnError)
	f.BoolVar(&debugFlag, "debug", false, "Enable debug output.")
	f.Parse(args[2:])

	t, err := loadToken()
	if err != nil {
		return
	}
	c := medium.NewClient(t.ApplicationID, t.ApplicationSecret, t.AccessToken)
	if debugFlag {
		c.SetLogger(log.New(os.Stdout, "debug: ", 0))
	}
	u, err := c.User()
	if err != nil {
		return
	}
	fmt.Printf("You are logged in as:\n\n")
	fmt.Printf("Name: %s\n", u.Name)
	fmt.Printf("Username: %s\n", u.Username)
	fmt.Printf("URL: %s", u.URL)
	fmt.Printf("\n")

	ps, err := u.Publications()
	if err != nil {
		return
	}
	if len(ps) == 0 {
		fmt.Println("You have no publications yet.")
		return
	}
	fmt.Printf("\nYou have publication(s) below:\n\n")
	for i, p := range ps {
		fmt.Printf("Number: %d\n", i)
		fmt.Printf("Name: %s\n", p.Name)
		fmt.Printf("Description: %s\n", p.Description)
		fmt.Printf("URL: %s\n\n", p.URL)
	}
	return
}

func postCommand(args []string, userFlag bool) (err error) {
	var (
		debugFlag bool
	)

	f := flag.NewFlagSet(fmt.Sprintf("%s %s", args[0], args[1]), flag.ExitOnError)
	f.BoolVar(&debugFlag, "debug", false, "Enable debug output.")
	f.Parse(args[2:])

	article, publicationNumber, err := parseArticle(f.Args()[0])
	if err != nil {
		return
	}
	t, err := loadToken()
	if err != nil {
		return
	}
	c := medium.NewClient(t.ApplicationID, t.ApplicationSecret, t.AccessToken)
	if debugFlag {
		c.SetLogger(log.New(os.Stdout, "debug: ", 0))
	}
	u, err := c.User()
	if err != nil {
		return
	}
	if userFlag {
		p, err := u.Post(article)
		if err != nil {
			return err
		}
		showPostedArticleInfo(p)
		return nil
	}
	ps, err := u.Publications()
	if err != nil {
		return
	}
	if len(ps) == 0 {
		return fmt.Errorf("you have no publications yet")
	}
	if publicationNumber < 0 || publicationNumber > len(ps)-1 {
		err = fmt.Errorf("publication number '%d' is invalid", publicationNumber)
		return
	}
	p, err := ps[publicationNumber].Post(article)
	if err != nil {
		return
	}
	showPostedArticleInfo(p)
	return
}

func versionCommand(args []string) (err error) {
	fmt.Printf("%s-%s\n", version, revision)
	return
}

func helpCommand(args []string) (err error) {
	fmt.Println(`usage: mediumctl <command> [options]

Commands:
  oauth, o
    Setting up API token for Medium with OAuth.
  info, i
    Show the information about current user and its publications.
  user, u
    Post HTML or Markdown file to current user profile.
  publication, p
    Post HTML or Markdown file to current user's publication.
  version, v
  Show version and revision information.
  help, h
    Show this message.

For more information, please see https://github.com/moutend/mediumctl.`)
	return
}
<commit_msg>Change version<commit_after>// Author: Yoshiyuki Koyanagi <moutend@gmail.com>
// License: mIT

// Package main implements mediumctl.
package main

import (
	"crypto/rand"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/user"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	medium "github.com/moutend/go-medium"
	"github.com/skratchdot/open-golang/open"
)

type token struct {
	ApplicationID     string
	ApplicationSecret string
	AccessToken       string
	ExpiresAt         int
	RefreshToken      string
}

var (
	version       = "v0.2.0"
	revision      = "dev"
	tokenFilePath string
)

const tokenFileName = ".mediumctl"

func showPostedArticleInfo(p *medium.PostedArticle) {
	fmt.Printf("Your article was successfully posted.\n\n")
	fmt.Printf("title: %s\n", p.Title)
	fmt.Printf("publishStatus: %s\n", p.PublishStatus)
	if len(p.Tags) > 0 {
		fmt.Printf("tags: %s\n", strings.Join(p.Tags, " "))
	}
	fmt.Printf("URL: %s\n", p.URL)
	if p.CanonicalURL != "" {
		fmt.Printf("canonicalURL: %s\n", p.CanonicalURL)
	}
	return
}

func parseArticle(filename string) (article medium.Article, publicationNumber int, err error) {
	b, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}
	if len(b) == 0 {
		err = fmt.Errorf("%s is empty", filename)
		return
	}

	var (
		content         string
		contentFormat   string
		canonicalURL    string
		license         string
		notifyFollowers bool
		publishedAt     string
		publishStatus   string
		tags            []string
		title           string
	)
	contentFormat = "markdown"
	if strings.HasSuffix(filename, "html") || strings.HasSuffix(filename, "htm") {
		contentFormat = "html"
	}
	lines := strings.Split(string(b), "\n")

	for i, line := range lines[1:] {
		if strings.HasPrefix(line, "---") {
			content = strings.Join(lines[i+2:], "\n")
			break
		}
		if strings.HasPrefix(line, "canonicalURL: ") {
			canonicalURL = line[len("canonicalURL: "):]
		}
		if strings.HasPrefix(line, "license: ") {
			license = line[len("license: "):]
		}
		if strings.HasPrefix(line, "number: ") {
			publicationNumber, err = strconv.Atoi(line[len("number: "):])
			if err != nil {
				return
			}
		}
		if strings.HasPrefix(line, "notifyFollowers: true") {
			notifyFollowers = true
		}
		if strings.HasPrefix(line, "publishedAt: ") {
			publishedAt = line[len("publishedAt: "):]
		}
		if strings.HasPrefix(line, "publishStatus: ") {
			publishStatus = line[len("publishStatus: "):]
		}
		if strings.HasPrefix(line, "tags: ") {
			tags = strings.Split(line[len("tags: "):], " ")
		}
		if strings.HasPrefix(line, "title: ") {
			title = line[len("title: "):]
		}
	}
	if content == "" {
		content = strings.Join(lines, "\n")
	}
	article = medium.Article{
		Title:           title,
		ContentFormat:   contentFormat,
		Content:         content,
		CanonicalURL:    canonicalURL,
		Tags:            tags,
		PublishStatus:   publishStatus,
		PublishedAt:     publishedAt,
		License:         license,
		NotifyFollowers: notifyFollowers,
	}
	return
}
func getCode(clientID, redirectURI string) (code string, err error) {
	l, err := net.Listen("tcp", "192.168.1.107:4000")
	if err != nil {
		return
	}
	defer l.Close()

	type value struct {
		code  string
		error error
	}
	quit := make(chan value)
	go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		w.Write([]byte(`<script>window.open("about:blank","_self").close()</script>`))
		w.(http.Flusher).Flush()
		c := req.FormValue("code")
		e := req.FormValue("error")
		v := value{
			code:  c,
			error: nil,
		}
		if e != "" {
			v.error = fmt.Errorf(e)
		}
		quit <- v
	}))
	stateBytes := make([]byte, 88)
	_, err = rand.Read(stateBytes)
	if err != nil {
		return
	}
	state := fmt.Sprintf("%x", stateBytes)
	scope := "basicProfile,listPublications,publishPost"
	redirectURI = url.QueryEscape(redirectURI)
	q := fmt.Sprintf("client_id=%s&scope=%s&state=%s&response_type=code&redirect_uri=%s", clientID, scope, state, redirectURI)
	p := "https://medium.com/m/oauth/authorize?" + q
	if err = open.Start(p); err != nil {
		return
	}
	select {
	case v := <-quit:
		if v.error != nil {
			return "", v.error
		}
		return v.code, nil
	case <-time.After(60 * time.Second):
		return "", fmt.Errorf("timeout")
	}
}

func saveToken(clientID, clientSecret string, t *medium.Token) (err error) {
	b, err := json.Marshal(token{
		ApplicationID:     clientID,
		ApplicationSecret: clientSecret,
		AccessToken:       t.AccessToken,
		ExpiresAt:         t.ExpiresAt,
		RefreshToken:      t.RefreshToken,
	})
	if err != nil {
		return
	}
	err = ioutil.WriteFile(tokenFilePath, b, 0644)
	return
}

func loadToken() (*token, error) {
	b, err := ioutil.ReadFile(tokenFilePath)
	if err != nil {
		return nil, fmt.Errorf("API token is not set. Please run 'auth' at first")
	}
	var t token
	err = json.Unmarshal(b, &t)
	return &t, err
}

func main() {
	err := run(os.Args)

	if err != nil {
		log.New(os.Stderr, "error: ", 0).Fatal(err)
		os.Exit(1)
	}

	os.Exit(0)
}
func run(args []string) (err error) {
	if len(args) < 2 {
		return helpCommand(args)
	}
	u, err := user.Current()
	if err != nil {
		return
	}
	tokenFilePath = filepath.Join(u.HomeDir, tokenFileName)
	switch args[1] {
	case "oauth":
		err = authCommand(args)
	case "o":
		err = authCommand(args)
	case "i":
		err = infoCommand(args)
	case "info":
		err = infoCommand(args)
	case "p":
		err = postCommand(args, false)
	case "publication":
		err = postCommand(args, false)
	case "u":
		err = postCommand(args, true)
	case "user":
		err = postCommand(args, true)
	case "v":
		err = versionCommand(args)
	case "version":
		err = versionCommand(args)
	case "h":
		err = helpCommand(args)
	case "help":
		err = helpCommand(args)
	default:
		fmt.Fprintf(os.Stderr, "%s: '%s' is not a %s subcommand.\n", args[0], args[1], args[0])
		err = helpCommand(args)
	}
	return
}

func authCommand(args []string) (err error) {
	var (
		clientIDFlag     string
		clientSecretFlag string
		debugFlag        bool
		redirectURIFlag  string
	)

	f := flag.NewFlagSet(fmt.Sprintf("%s %s", args[0], args[1]), flag.ExitOnError)
	f.StringVar(&redirectURIFlag, "u", "", "Redirect URI for OAuth application.")
	f.StringVar(&clientIDFlag, "i", "", "Client ID of OAuth application.")
	f.StringVar(&clientSecretFlag, "s", "", "Client secret of OAuth application.")
	f.BoolVar(&debugFlag, "debug", false, "Enable debug output.")
	f.Parse(args[2:])
	if redirectURIFlag == "" {
		return fmt.Errorf("please specify redirect URI")
	}
	if clientIDFlag == "" {
		return fmt.Errorf("please specify client ID")
	}
	if clientSecretFlag == "" {
		return fmt.Errorf("please specify client secret")
	}

	code, err := getCode(clientIDFlag, redirectURIFlag)
	if err != nil {
		return
	}
	c := medium.NewClient(clientIDFlag, clientSecretFlag, "")
	if debugFlag {
		c.SetLogger(log.New(os.Stdout, "debug: ", 0))
	}
	token, err := c.Token(code, redirectURIFlag)
	if err != nil {
		return
	}
	if err = saveToken(clientIDFlag, clientSecretFlag, token); err != nil {
		return
	}
	fmt.Printf("Your API token was successfully saved in '%s'.\n", tokenFilePath)
	fmt.Println("Note: This file should be treated as the password and please do NOT expose it.")
	return
}

func infoCommand(args []string) (err error) {
	var (
		debugFlag bool
	)

	f := flag.NewFlagSet(fmt.Sprintf("%s %s", args[0], args[1]), flag.ExitOnError)
	f.BoolVar(&debugFlag, "debug", false, "Enable debug output.")
	f.Parse(args[2:])

	t, err := loadToken()
	if err != nil {
		return
	}
	c := medium.NewClient(t.ApplicationID, t.ApplicationSecret, t.AccessToken)
	if debugFlag {
		c.SetLogger(log.New(os.Stdout, "debug: ", 0))
	}
	u, err := c.User()
	if err != nil {
		return
	}
	fmt.Printf("You are logged in as:\n\n")
	fmt.Printf("Name: %s\n", u.Name)
	fmt.Printf("Username: %s\n", u.Username)
	fmt.Printf("URL: %s", u.URL)
	fmt.Printf("\n")

	ps, err := u.Publications()
	if err != nil {
		return
	}
	if len(ps) == 0 {
		fmt.Println("You have no publications yet.")
		return
	}
	fmt.Printf("\nYou have publication(s) below:\n\n")
	for i, p := range ps {
		fmt.Printf("Number: %d\n", i)
		fmt.Printf("Name: %s\n", p.Name)
		fmt.Printf("Description: %s\n", p.Description)
		fmt.Printf("URL: %s\n\n", p.URL)
	}
	return
}

func postCommand(args []string, userFlag bool) (err error) {
	var (
		debugFlag bool
	)

	f := flag.NewFlagSet(fmt.Sprintf("%s %s", args[0], args[1]), flag.ExitOnError)
	f.BoolVar(&debugFlag, "debug", false, "Enable debug output.")
	f.Parse(args[2:])

	article, publicationNumber, err := parseArticle(f.Args()[0])
	if err != nil {
		return
	}
	t, err := loadToken()
	if err != nil {
		return
	}
	c := medium.NewClient(t.ApplicationID, t.ApplicationSecret, t.AccessToken)
	if debugFlag {
		c.SetLogger(log.New(os.Stdout, "debug: ", 0))
	}
	u, err := c.User()
	if err != nil {
		return
	}
	if userFlag {
		p, err := u.Post(article)
		if err != nil {
			return err
		}
		showPostedArticleInfo(p)
		return nil
	}
	ps, err := u.Publications()
	if err != nil {
		return
	}
	if len(ps) == 0 {
		return fmt.Errorf("you have no publications yet")
	}
	if publicationNumber < 0 || publicationNumber > len(ps)-1 {
		err = fmt.Errorf("publication number '%d' is invalid", publicationNumber)
		return
	}
	p, err := ps[publicationNumber].Post(article)
	if err != nil {
		return
	}
	showPostedArticleInfo(p)
	return
}

func versionCommand(args []string) (err error) {
	fmt.Printf("%s-%s\n", version, revision)
	return
}

func helpCommand(args []string) (err error) {
	fmt.Println(`usage: mediumctl <command> [options]

Commands:
  oauth, o
    Setting up API token for Medium with OAuth.
  info, i
    Show the information about current user and its publications.
  user, u
    Post HTML or Markdown file to current user profile.
  publication, p
    Post HTML or Markdown file to current user's publication.
  version, v
  Show version and revision information.
  help, h
    Show this message.

For more information, please see https://github.com/moutend/mediumctl.`)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/nlopes/slack"

	"k8s.io/kubernetes/pkg/api"
	client "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/labels"
	"k8s.io/kubernetes/pkg/watch"
)

// Sends a message to the Slack channel about the Event.
func sendMessage(e *api.Event, color string) error {
	api := slack.New(os.Getenv("SLACK_TOKEN"))
	params := slack.PostMessageParameters{}
	metadata := e.GetObjectMeta()
	attachment := slack.Attachment{
		// The fallback message shows in clients such as IRC or OS X notifications.
		Fallback: e.Message,
		Fields: []slack.AttachmentField{
			slack.AttachmentField{
				Title: "Message",
				Value: e.Message,
			},
			slack.AttachmentField{
				Title: "Object",
				Value: e.InvolvedObject.Kind,
				Short: true,
			},
			slack.AttachmentField{
				Title: "Name",
				Value: metadata.GetName(),
				Short: true,
			},
			slack.AttachmentField{
				Title: "Reason",
				Value: e.Reason,
				Short: true,
			},
			slack.AttachmentField{
				Title: "Component",
				Value: e.Source.Component,
				Short: true,
			},
		},
	}

	// Use a color if provided, otherwise try to guess.
	if color != "" {
		attachment.Color = color
	} else if strings.HasPrefix(e.Reason, "Success") {
		attachment.Color = "good"
	} else if strings.HasPrefix(e.Reason, "Fail") {
		attachment.Color = "danger"
	}
	params.Attachments = []slack.Attachment{attachment}

	channelID, timestamp, err := api.PostMessage(os.Getenv("SLACK_CHANNEL"), "", params)
	if err != nil {
		fmt.Printf("%s\n", err)
		return err
	}

	log.Printf("Message successfully sent to channel %s at %s", channelID, timestamp)
	return nil
}

func main() {

	kubeClient, err := client.NewInCluster()
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
	}

	// Setup a watcher for events.
	eventClient := kubeClient.Events(api.NamespaceAll)
	options := api.ListOptions{LabelSelector: labels.Everything()}
	w, err := eventClient.Watch(options)
	if err != nil {
		log.Fatalf("Failed to set up watch: %v", err)
	}
	for {
		select {
		case watchEvent, _ := <-w.ResultChan():

			e, _ := watchEvent.Object.(*api.Event)
			// Log all events for now.
			log.Printf("Reason: %s\nMessage: %s\nCount: %s\nFirstTimestamp: %s\nLastTimestamp: %s\n\n", e.Reason, e.Message, strconv.Itoa(int(e.Count)), e.FirstTimestamp, e.LastTimestamp)

			send := false
			color := ""
			if watchEvent.Type == watch.Added {
				send = true
				color = "good"
			} else if watchEvent.Type == watch.Deleted {
				send = true
				color = "warning"
			} else if e.Reason == "SuccessfulCreate" {
				send = true
				color = "good"
			} else if e.Reason == "NodeReady" {
				send = true
				color = "good"
			} else if e.Reason == "NodeNotReady" {
				send = true
				color = "warning"
			} else if e.Reason == "NodeOutOfDisk" {
				send = true
				color = "danger"
			}

			// For now, dont alert multiple times, except if it's a backoff
			if e.Count > 1 {
				send = false
			}
			if e.Reason == "BackOff" && e.Count == 3 {
				send = true
				color = "danger"
			}

			if send {
				err = sendMessage(e, color)
				if err != nil {
					log.Fatalf("sendMessage: %v", err)
				}
			}
		}
	}
}
<commit_msg>quiet down.<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/nlopes/slack"

	"k8s.io/kubernetes/pkg/api"
	client "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/labels"
	"k8s.io/kubernetes/pkg/watch"
)

// Sends a message to the Slack channel about the Event.
func sendMessage(e *api.Event, color string) error {
	api := slack.New(os.Getenv("SLACK_TOKEN"))
	params := slack.PostMessageParameters{}
	metadata := e.GetObjectMeta()
	attachment := slack.Attachment{
		// The fallback message shows in clients such as IRC or OS X notifications.
		Fallback: e.Message,
		Fields: []slack.AttachmentField{
			slack.AttachmentField{
				Title: "Message",
				Value: e.Message,
			},
			slack.AttachmentField{
				Title: "Object",
				Value: e.InvolvedObject.Kind,
				Short: true,
			},
			slack.AttachmentField{
				Title: "Name",
				Value: metadata.GetName(),
				Short: true,
			},
			slack.AttachmentField{
				Title: "Reason",
				Value: e.Reason,
				Short: true,
			},
			slack.AttachmentField{
				Title: "Component",
				Value: e.Source.Component,
				Short: true,
			},
		},
	}

	// Use a color if provided, otherwise try to guess.
	if color != "" {
		attachment.Color = color
	} else if strings.HasPrefix(e.Reason, "Success") {
		attachment.Color = "good"
	} else if strings.HasPrefix(e.Reason, "Fail") {
		attachment.Color = "danger"
	}
	params.Attachments = []slack.Attachment{attachment}

	channelID, timestamp, err := api.PostMessage(os.Getenv("SLACK_CHANNEL"), "", params)
	if err != nil {
		fmt.Printf("%s\n", err)
		return err
	}

	log.Printf("Message successfully sent to channel %s at %s", channelID, timestamp)
	return nil
}

func main() {

	kubeClient, err := client.NewInCluster()
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
	}

	// Setup a watcher for events.
	eventClient := kubeClient.Events(api.NamespaceAll)
	options := api.ListOptions{LabelSelector: labels.Everything()}
	w, err := eventClient.Watch(options)
	if err != nil {
		log.Fatalf("Failed to set up watch: %v", err)
	}
	for {
		select {
		case watchEvent, _ := <-w.ResultChan():

			e, _ := watchEvent.Object.(*api.Event)

			// Log all events for now.
			log.Printf("Reason: %s\nMessage: %s\nCount: %s\nFirstTimestamp: %s\nLastTimestamp: %s\n\n", e.Reason, e.Message, strconv.Itoa(int(e.Count)), e.FirstTimestamp, e.LastTimestamp)

			send := false
			color := ""
			if watchEvent.Type == watch.Added {
				send = true
				color = "good"
			} else if watchEvent.Type == watch.Deleted {
				send = true
				color = "warning"
			} else if e.Reason == "SuccessfulCreate" {
				send = true
				color = "good"
			} else if e.Reason == "NodeReady" {
				send = true
				color = "good"
			} else if e.Reason == "NodeNotReady" {
				send = true
				color = "warning"
			} else if e.Reason == "NodeOutOfDisk" {
				send = true
				color = "danger"
			}

			// kubelet is loud.
			if e.Source.Component == "kubelet" {
				send = false
			}

			// For now, dont alert multiple times, except if it's a backoff
			if e.Count > 1 {
				send = false
			}
			if e.Reason == "BackOff" && e.Count == 3 {
				send = true
				color = "danger"
			}

			if send {
				sendMessage(e, color)
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"archive/tar"
	"bufio"
	"compress/gzip"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/docker/docker/image"
	flag "github.com/docker/docker/pkg/mflag"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strings"
)

var (
	verbose, help bool
	target        string
)

type BlobSum struct {
	Sum string `json:"blobSum"`
}

type Compat struct {
	Data string `json:"v1Compatibility"`
}

type Layer struct {
	Id, Parent string
	BlobSum    string
	Data       string
}

type LayerMap map[string]*Layer

type Manifest struct {
	Version      int       `json:"schemaVersion"`
	Name         string    `json:"name"`
	Tag          string    `json:"tag"`
	Architecture string    `json:"architecture"`
	Layers       []BlobSum `json:"fsLayers"`
	History      []Compat  `json:"history"`
}

func init() {
	flag.Bool([]string{"-h", "--help"}, false, "Display help")
	flag.BoolVar(&verbose, []string{"-v", "--verbose"}, false, "Switch to verbose output")
	flag.Parse()
}

func blobSumLayer(r *tar.Reader) (string, error) {
	sha := sha256.New()
	gw := gzip.NewWriter(sha)
	if _, err := io.Copy(gw, r); err != nil {
		return "", err
	}
	gw.Close()
	return hex.EncodeToString(sha.Sum(nil)), nil
}

func getLayerPrefix(s string) string {
	_, b := path.Split(path.Dir(s))
	return path.Clean(b)
}

func getLayerInfo(b []byte) (string, string, error) {
	var raw map[string]interface{}
	if err := json.Unmarshal(b, &raw); err != nil {
		return "", "", err
	}
	if raw["parent"] == nil {
		return "", raw["id"].(string), nil
	}
	return raw["parent"].(string), raw["id"].(string), nil
}

func getLayersFromMap(lm LayerMap) []*Layer {
	out := make([]*Layer, 0, len(lm))
	for _, v := range lm {
		out = append(out, v)
	}
	return out
}

func findChild(id string, layers []*Layer) *Layer {
	for _, l := range layers {
		if l.Parent == id {
			return l
		}
	}
	return nil
}

func getLayersInOrder(layers []*Layer) []*Layer {
	root := findChild("", layers)

	if root == nil {
		panic(errors.New("Unable to find root layer"))
	}

	out := make([]*Layer, 0, len(layers))
	out = append(out, root)
	for {
		root = findChild(root.Id, layers)
		if root == nil {
			break
		}
		out = append(out, root)
	}

	for i, j := 0, len(out)-1; i < j; i, j = i+1, j-1 {
		out[i], out[j] = out[j], out[i]
	}

	return out
}

func getRepoInfo(ri map[string]interface{}) (string, string) {
	var (
		repo string
		tag  string
	)

	for k, v := range ri {
		repo = k
		for vv, _ := range v.(map[string]interface{}) {
			tag = vv
		}
	}

	return repo, tag
}

func outputManifestFor(target string) {
	f, err := os.Open(target)
	if err != nil {
		return
	}

	defer func() {
		if err := f.Close(); err != nil {
			panic(err)
		}
	}()

	var (
		repo, tag string
	)
	layers := LayerMap{}
	t := tar.NewReader(bufio.NewReader(f))
	for {
		hdr, err := t.Next()
		if err == io.EOF {
			break
		}

		if strings.HasSuffix(hdr.Name, "layer.tar") {
			fmt.Printf("Layer size: %d\n", hdr.Size)
			id := getLayerPrefix(hdr.Name)
			sum, _ := blobSumLayer(t)
			if _, ok := layers[id]; !ok {
				layers[id] = &Layer{Id: id}
			} else {
				layers[id].BlobSum = sum
			}
		}

		if strings.HasSuffix(hdr.Name, "json") {
			data, _ := ioutil.ReadAll(t)
			parent, id, _ := getLayerInfo(data)
			if _, ok := layers[id]; !ok {
				layers[id] = &Layer{Id: id, Parent: parent}
			} else {
				layers[id].Parent = parent
			}

			var img image.Image
			json.Unmarshal(data, &img)
			b, _ := json.Marshal(img)
			layers[id].Data = string(b) + "\n"
		}

		if hdr.Name == "repositories" {
			r, _ := ioutil.ReadAll(t)
			var raw map[string]interface{}
			if err := json.Unmarshal(r, &raw); err != nil {
				return
			}

			repo, tag = getRepoInfo(raw)
			if !strings.Contains(repo, "/") {
				repo = "library/" + repo
			}
		}
	}

	m := Manifest{Name: repo, Tag: tag, Architecture: "amd64", Version: 1}
	ll := getLayersFromMap(layers)
	for _, l := range getLayersInOrder(ll) {
		m.Layers = append(m.Layers, BlobSum{Sum: "sha256:" + l.BlobSum})
		m.History = append(m.History, Compat{Data: l.Data})
	}
	x, _ := json.MarshalIndent(m, "", "   ")
	fmt.Println(string(x))
}

func main() {
	if help {
		flag.PrintDefaults()
	} else {
		target := flag.Arg(0)
		if target != "" {
			//fmt.Printf("outputting manifest for: %q\n", target)
			outputManifestFor(target)
		}
	}
}
<commit_msg>do not print layer size<commit_after>package main

import (
	"archive/tar"
	"bufio"
	"compress/gzip"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/docker/docker/image"
	flag "github.com/docker/docker/pkg/mflag"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strings"
)

var (
	verbose, help bool
	target        string
)

type BlobSum struct {
	Sum string `json:"blobSum"`
}

type Compat struct {
	Data string `json:"v1Compatibility"`
}

type Layer struct {
	Id, Parent string
	BlobSum    string
	Data       string
}

type LayerMap map[string]*Layer

type Manifest struct {
	Version      int       `json:"schemaVersion"`
	Name         string    `json:"name"`
	Tag          string    `json:"tag"`
	Architecture string    `json:"architecture"`
	Layers       []BlobSum `json:"fsLayers"`
	History      []Compat  `json:"history"`
}

func init() {
	flag.Bool([]string{"-h", "--help"}, false, "Display help")
	flag.BoolVar(&verbose, []string{"-v", "--verbose"}, false, "Switch to verbose output")
	flag.Parse()
}

func blobSumLayer(r *tar.Reader) (string, error) {
	sha := sha256.New()
	gw := gzip.NewWriter(sha)
	if _, err := io.Copy(gw, r); err != nil {
		return "", err
	}
	gw.Close()
	return hex.EncodeToString(sha.Sum(nil)), nil
}

func getLayerPrefix(s string) string {
	_, b := path.Split(path.Dir(s))
	return path.Clean(b)
}

func getLayerInfo(b []byte) (string, string, error) {
	var raw map[string]interface{}
	if err := json.Unmarshal(b, &raw); err != nil {
		return "", "", err
	}
	if raw["parent"] == nil {
		return "", raw["id"].(string), nil
	}
	return raw["parent"].(string), raw["id"].(string), nil
}

func getLayersFromMap(lm LayerMap) []*Layer {
	out := make([]*Layer, 0, len(lm))
	for _, v := range lm {
		out = append(out, v)
	}
	return out
}

func findChild(id string, layers []*Layer) *Layer {
	for _, l := range layers {
		if l.Parent == id {
			return l
		}
	}
	return nil
}

func getLayersInOrder(layers []*Layer) []*Layer {
	root := findChild("", layers)

	if root == nil {
		panic(errors.New("Unable to find root layer"))
	}

	out := make([]*Layer, 0, len(layers))
	out = append(out, root)
	for {
		root = findChild(root.Id, layers)
		if root == nil {
			break
		}
		out = append(out, root)
	}

	for i, j := 0, len(out)-1; i < j; i, j = i+1, j-1 {
		out[i], out[j] = out[j], out[i]
	}

	return out
}

func getRepoInfo(ri map[string]interface{}) (string, string) {
	var (
		repo string
		tag  string
	)

	for k, v := range ri {
		repo = k
		for vv, _ := range v.(map[string]interface{}) {
			tag = vv
		}
	}

	return repo, tag
}

func outputManifestFor(target string) {
	f, err := os.Open(target)
	if err != nil {
		return
	}

	defer func() {
		if err := f.Close(); err != nil {
			panic(err)
		}
	}()

	var (
		repo, tag string
	)
	layers := LayerMap{}
	t := tar.NewReader(bufio.NewReader(f))
	for {
		hdr, err := t.Next()
		if err == io.EOF {
			break
		}

		if strings.HasSuffix(hdr.Name, "layer.tar") {
			id := getLayerPrefix(hdr.Name)
			sum, _ := blobSumLayer(t)
			if _, ok := layers[id]; !ok {
				layers[id] = &Layer{Id: id}
			} else {
				layers[id].BlobSum = sum
			}
		}

		if strings.HasSuffix(hdr.Name, "json") {
			data, _ := ioutil.ReadAll(t)
			parent, id, _ := getLayerInfo(data)
			if _, ok := layers[id]; !ok {
				layers[id] = &Layer{Id: id, Parent: parent}
			} else {
				layers[id].Parent = parent
			}

			var img image.Image
			json.Unmarshal(data, &img)
			b, _ := json.Marshal(img)
			layers[id].Data = string(b) + "\n"
		}

		if hdr.Name == "repositories" {
			r, _ := ioutil.ReadAll(t)
			var raw map[string]interface{}
			if err := json.Unmarshal(r, &raw); err != nil {
				return
			}

			repo, tag = getRepoInfo(raw)
			if !strings.Contains(repo, "/") {
				repo = "library/" + repo
			}
		}
	}

	m := Manifest{Name: repo, Tag: tag, Architecture: "amd64", Version: 1}
	ll := getLayersFromMap(layers)
	for _, l := range getLayersInOrder(ll) {
		m.Layers = append(m.Layers, BlobSum{Sum: "sha256:" + l.BlobSum})
		m.History = append(m.History, Compat{Data: l.Data})
	}
	x, _ := json.MarshalIndent(m, "", "   ")
	fmt.Println(string(x))
}

func main() {
	if help {
		flag.PrintDefaults()
	} else {
		target := flag.Arg(0)
		if target != "" {
			//fmt.Printf("outputting manifest for: %q\n", target)
			outputManifestFor(target)
		}
	}
}
<|endoftext|>


<commit_before>// 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 main

import (
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/line/line-bot-sdk-go/linebot"
)

var bot *linebot.Client

func main() {
	var err error
	bot, err = linebot.New(os.Getenv("ChannelSecret"), os.Getenv("ChannelAccessToken"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	events, err := bot.ParseRequest(r)

	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}

	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {
			switch message := event.Message.(type) {
			case *linebot.TextMessage:
			   if message.Text == "MyID" {
				  if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(  "Line_ID:已取得"+message.UserID )).Do(); err != nil {
					log.Print(err)
				   }
			    }
			}
		}
	}
}
<commit_msg>no message<commit_after>// 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 main

import (
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/line/line-bot-sdk-go/linebot"
)

var bot *linebot.Client

func main() {
	var err error
	bot, err = linebot.New(os.Getenv("ChannelSecret"), os.Getenv("ChannelAccessToken"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	events, err := bot.ParseRequest(r)

	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}

	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {
			switch message := event.Message.(type) {
			case *linebot.TextMessage:
			   if message.Text == "MyID" {
				  if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(  "Line_ID:已取得"+message.HandleFunc )).Do(); err != nil {
					log.Print(err)
				   }
			    }
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"io/ioutil"
	"encoding/json"
	"strings"
	"github.com/line/line-bot-sdk-go/linebot"
	"github.com/go-redis/redis"
	"strconv"
	// "time"
)

type device struct {
	// Gps_num float32 `json:"gps_num"`
	// App string `json:"app"`
	// Gps_alt float32 `json:"gps_alt"`
	// Fmt_opt int `json:"fmt_opt"`
	// Device string `json:"device"`
	// S_d2 float32 `json:"s_d2"`
	S_d0 float32 `json:"s_d0"`
	// S_d1 float32 `json:"s_d1"`
	S_h0 float32 `json:"s_h0"`
	SiteName string `json:"SiteName"`
	// Gps_fix float32 `json:"gps_fix"`
	// Ver_app string `json:"ver_app"`
	Gps_lat float32 `json:"gps_lat"`
	S_t0 float32 `json:"s_t0"`
	Timestamp string `json:"timestamp"`
	Gps_lon float32 `json:"gps_lon"`
	// Date string `json:"date"`
	// Tick float32 `json:"tick"`
	Device_id string `json:"device_id"`
	// S_1 float32 `json:"s_1"`
	// S_0 float32 `json:"s_0"`
	// S_3 float32 `json:"s_3"`
	// S_2 float32 `json:"s_2"`
	// Ver_format string `json:"ver_format"`
	// Time string `json:"time"`
}

type airbox struct {
	Source string `json:"source"`
	Feeds []device `json:"feeds"`
	Version string `json:"version"`
	Num_of_records int `json:"num_of_records"`
}

type subscribeid struct {
	Device_id []string `json:"device_id"`
	Sitename []string `json:"sitename"`
}

var bot *linebot.Client
var airbox_json airbox
var lass_json airbox
var maps_json airbox
var all_device []device
var history_json subscribeid
var	client=redis.NewClient(&redis.Options{
		Addr:"hipposerver.ddns.net:6379",
		Password:"",
		DB:0,
	})

func main() {
	url := "https://data.lass-net.org/data/last-all-airbox.json"
	req, _ := http.NewRequest("GET", url, nil)
	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)
	errs := json.Unmarshal(body, &airbox_json)
	if errs != nil {
		fmt.Println(errs)
	}

	url = "https://data.lass-net.org/data/last-all-lass.json"
	req, _ = http.NewRequest("GET", url, nil)
	res, _ = http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ = ioutil.ReadAll(res.Body)
	errs = json.Unmarshal(body, &lass_json)
	if errs != nil {
		fmt.Println(errs)
	}

	url = "https://data.lass-net.org/data/last-all-maps.json"
	req, _ = http.NewRequest("GET", url, nil)
	res, _ = http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ = ioutil.ReadAll(res.Body)
	errs = json.Unmarshal(body, &maps_json)
	if errs != nil {
		fmt.Println(errs)
	}

	all_device=append(maps_json.Feeds,lass_json.Feeds...)
	all_device=append(all_device,airbox_json.Feeds...)

	url = "https://data.lass-net.org/data/airbox_list.json"
	req, _ = http.NewRequest("GET", url, nil)
	res, _ = http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ = ioutil.ReadAll(res.Body)
	errs = json.Unmarshal(body, &history_json)
	if errs != nil {
		fmt.Println(errs)
	}
	// pushmessage()
	// fmt.Println(airbox_json)
	var err error
	bot, err = linebot.New(os.Getenv("ChannelSecret"), os.Getenv("ChannelAccessToken"))
	// _,_=bot.PushMessage("U3617adbdd46283d7e859f36302f4f471", linebot.NewTextMessage("hi!")).Do()
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)

}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	events, err := bot.ParseRequest(r)

	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}

	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {
			switch message := event.Message.(type) {
			case *linebot.TextMessage:
				var txtmessage string
				inText := strings.ToLower(message.Text)
				if strings.Contains(inText,"訂閱"){
					userID:=event.Source.UserID
					// pong, _ := client.Ping().Result()
					// txtmessage=pong
					for i:=0; i<len(history_json.Device_id); i++ {
						if strings.Contains(inText,strings.ToLower(history_json.Device_id[i]))||strings.Contains(inText,strings.ToLower(history_json[i].Sitename)) {
							val, err:=client.Get(history_json.Device_id[i]).Result()
							if err!=nil{
								client.Set(history_json.Device_id[i],userID,0)
								txtmessage="訂閱成功!"
								break
							}
							if strings.Contains(inText,"取消"){
								stringSlice:=strings.Split(val,",")
								if stringInSlice(userID,stringSlice){
									if len(stringSlice)==1{
										client.Del(history_json.Device_id[i])
										txtmessage="取消訂閱成功!"
										break
									}else{
										var s []string
										s = removeStringInSlice(stringSlice, userID)
										client.Set(history_json.Device_id[i],s,0)
										txtmessage="取消訂閱成功!"
										break
									}
								}else{
									txtmessage="你並沒有訂閱此ID。"
									break
								}
							}
							stringSlice:=strings.Split(val,",")
							if stringInSlice(userID,stringSlice){
								txtmessage="您已訂閱過此ID!"
								break
							} else{
								val=val+","+userID
								client.Set(history_json.Device_id[i],val,0)
								txtmessage="訂閱成功!"
								break
							}
						}
					}
				} else{
					for i:=0; i<len(all_device); i++ {
						if strings.Contains(inText,strings.ToLower(all_device[i].Device_id))||strings.Contains(inText,strings.ToLower(history_json[i].Sitename)) {
							txtmessage="Device_id: "+all_device[i].Device_id+"\n"
							txtmessage=txtmessage+"Site Name: "+all_device[i].SiteName+"\n"
							txtmessage=txtmessage+"Location: ("+strconv.FormatFloat(float64(all_device[i].Gps_lon),'f',3,64)+","+strconv.FormatFloat(float64(all_device[i].Gps_lat),'f',3,64)+")"+"\n"
							txtmessage=txtmessage+"Timestamp: "+all_device[i].Timestamp+"\n"
							txtmessage=txtmessage+"PM2.5: "+strconv.FormatFloat(float64(all_device[i].S_d0),'f',0,64)+"\n"
							txtmessage=txtmessage+"Humidity: "+strconv.FormatFloat(float64(all_device[i].S_h0),'f',0,64)+"\n"
							txtmessage=txtmessage+"Temperature: "+strconv.FormatFloat(float64(all_device[i].S_t0),'f',0,64)
							break
						}
					}
				}
				if len(txtmessage)==0{
					txtmessage="Sorry! No this device ID, please check again."
				}
				if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(txtmessage)).Do(); err != nil {
					log.Print(err)
				}
			}
		}
	}
}

func stringInSlice(a string, list []string) bool {
    for _, b := range list {
        if b == a {
            return true
        }
    }
    return false
}

func removeStringInSlice(s []string, r string) []string {
    for i, v := range s {
        if v == r {
            return append(s[:i], s[i+1:]...)
        }
    }
    return s
}

<commit_msg>resolve errors<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"io/ioutil"
	"encoding/json"
	"strings"
	"github.com/line/line-bot-sdk-go/linebot"
	"github.com/go-redis/redis"
	"strconv"
	// "time"
)

type device struct {
	// Gps_num float32 `json:"gps_num"`
	// App string `json:"app"`
	// Gps_alt float32 `json:"gps_alt"`
	// Fmt_opt int `json:"fmt_opt"`
	// Device string `json:"device"`
	// S_d2 float32 `json:"s_d2"`
	S_d0 float32 `json:"s_d0"`
	// S_d1 float32 `json:"s_d1"`
	S_h0 float32 `json:"s_h0"`
	SiteName string `json:"SiteName"`
	// Gps_fix float32 `json:"gps_fix"`
	// Ver_app string `json:"ver_app"`
	Gps_lat float32 `json:"gps_lat"`
	S_t0 float32 `json:"s_t0"`
	Timestamp string `json:"timestamp"`
	Gps_lon float32 `json:"gps_lon"`
	// Date string `json:"date"`
	// Tick float32 `json:"tick"`
	Device_id string `json:"device_id"`
	// S_1 float32 `json:"s_1"`
	// S_0 float32 `json:"s_0"`
	// S_3 float32 `json:"s_3"`
	// S_2 float32 `json:"s_2"`
	// Ver_format string `json:"ver_format"`
	// Time string `json:"time"`
}

type airbox struct {
	Source string `json:"source"`
	Feeds []device `json:"feeds"`
	Version string `json:"version"`
	Num_of_records int `json:"num_of_records"`
}

type subscribeid struct {
	Device_id []string `json:"device_id"`
	Sitename []string `json:"sitename"`
}

var bot *linebot.Client
var airbox_json airbox
var lass_json airbox
var maps_json airbox
var all_device []device
var history_json subscribeid
var	client=redis.NewClient(&redis.Options{
		Addr:"hipposerver.ddns.net:6379",
		Password:"",
		DB:0,
	})

func main() {
	url := "https://data.lass-net.org/data/last-all-airbox.json"
	req, _ := http.NewRequest("GET", url, nil)
	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)
	errs := json.Unmarshal(body, &airbox_json)
	if errs != nil {
		fmt.Println(errs)
	}

	url = "https://data.lass-net.org/data/last-all-lass.json"
	req, _ = http.NewRequest("GET", url, nil)
	res, _ = http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ = ioutil.ReadAll(res.Body)
	errs = json.Unmarshal(body, &lass_json)
	if errs != nil {
		fmt.Println(errs)
	}

	url = "https://data.lass-net.org/data/last-all-maps.json"
	req, _ = http.NewRequest("GET", url, nil)
	res, _ = http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ = ioutil.ReadAll(res.Body)
	errs = json.Unmarshal(body, &maps_json)
	if errs != nil {
		fmt.Println(errs)
	}

	all_device=append(maps_json.Feeds,lass_json.Feeds...)
	all_device=append(all_device,airbox_json.Feeds...)

	url = "https://data.lass-net.org/data/airbox_list.json"
	req, _ = http.NewRequest("GET", url, nil)
	res, _ = http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ = ioutil.ReadAll(res.Body)
	errs = json.Unmarshal(body, &history_json)
	if errs != nil {
		fmt.Println(errs)
	}
	// pushmessage()
	// fmt.Println(airbox_json)
	var err error
	bot, err = linebot.New(os.Getenv("ChannelSecret"), os.Getenv("ChannelAccessToken"))
	// _,_=bot.PushMessage("U3617adbdd46283d7e859f36302f4f471", linebot.NewTextMessage("hi!")).Do()
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)

}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	events, err := bot.ParseRequest(r)

	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}

	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {
			switch message := event.Message.(type) {
			case *linebot.TextMessage:
				var txtmessage string
				inText := strings.ToLower(message.Text)
				if strings.Contains(inText,"訂閱"){
					userID:=event.Source.UserID
					// pong, _ := client.Ping().Result()
					// txtmessage=pong
					for i:=0; i<len(history_json.Device_id); i++ {
						if strings.Contains(inText,strings.ToLower(history_json.Device_id[i]))||strings.Contains(inText,strings.ToLower(history_json.Sitename[i])) {
							val, err:=client.Get(history_json.Device_id[i]).Result()
							if err!=nil{
								client.Set(history_json.Device_id[i],userID,0)
								txtmessage="訂閱成功!"
								break
							}
							if strings.Contains(inText,"取消"){
								stringSlice:=strings.Split(val,",")
								if stringInSlice(userID,stringSlice){
									if len(stringSlice)==1{
										client.Del(history_json.Device_id[i])
										txtmessage="取消訂閱成功!"
										break
									}else{
										var s []string
										s = removeStringInSlice(stringSlice, userID)
										client.Set(history_json.Device_id[i],s,0)
										txtmessage="取消訂閱成功!"
										break
									}
								}else{
									txtmessage="你並沒有訂閱此ID。"
									break
								}
							}
							stringSlice:=strings.Split(val,",")
							if stringInSlice(userID,stringSlice){
								txtmessage="您已訂閱過此ID!"
								break
							} else{
								val=val+","+userID
								client.Set(history_json.Device_id[i],val,0)
								txtmessage="訂閱成功!"
								break
							}
						}
					}
				} else{
					for i:=0; i<len(all_device); i++ {
						if strings.Contains(inText,strings.ToLower(all_device[i].Device_id))||strings.Contains(inText,strings.ToLower(all_device[i].SiteName)) {
							txtmessage="Device_id: "+all_device[i].Device_id+"\n"
							txtmessage=txtmessage+"Site Name: "+all_device[i].SiteName+"\n"
							txtmessage=txtmessage+"Location: ("+strconv.FormatFloat(float64(all_device[i].Gps_lon),'f',3,64)+","+strconv.FormatFloat(float64(all_device[i].Gps_lat),'f',3,64)+")"+"\n"
							txtmessage=txtmessage+"Timestamp: "+all_device[i].Timestamp+"\n"
							txtmessage=txtmessage+"PM2.5: "+strconv.FormatFloat(float64(all_device[i].S_d0),'f',0,64)+"\n"
							txtmessage=txtmessage+"Humidity: "+strconv.FormatFloat(float64(all_device[i].S_h0),'f',0,64)+"\n"
							txtmessage=txtmessage+"Temperature: "+strconv.FormatFloat(float64(all_device[i].S_t0),'f',0,64)
							break
						}
					}
				}
				if len(txtmessage)==0{
					txtmessage="Sorry! No this device ID, please check again."
				}
				if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(txtmessage)).Do(); err != nil {
					log.Print(err)
				}
			}
		}
	}
}

func stringInSlice(a string, list []string) bool {
    for _, b := range list {
        if b == a {
            return true
        }
    }
    return false
}

func removeStringInSlice(s []string, r string) []string {
    for i, v := range s {
        if v == r {
            return append(s[:i], s[i+1:]...)
        }
    }
    return s
}

<|endoftext|>


<commit_before>// Copyright 2015 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

// apidoc 是一个 RESTful api 文档生成工具。
package main

import (
	"flag"
	"runtime"
	"strings"
	"time"

	"github.com/caixw/apidoc/input"
	"github.com/caixw/apidoc/logs"
	"github.com/caixw/apidoc/output"
)

const (
	// 版本号
	//
	// 版本号按照 http://semver.org/lang/zh-CN/ 中的规则，分成以下四个部分：
	// 主版本号.次版本号.修订号.修订日期
	version = "2.1.55.160530"

	// 配置文件名称。
	configFilename = ".apidoc.json"
)

const usage = `apidoc 是一个 RESTful api 文档生成工具。

参数:
 -h       显示帮助信息；
 -v       显示版本信息；
 -l       显示所有支持的语言类型；
 -g       在当前目录下创建一个默认的配置文件。

有关 apidoc 的详细信息，可访问官网：http://apidoc.site`

func main() {
	if flags() {
		return
	}

	start := time.Now() // 记录处理开始时间

	cfg, err := loadConfig()
	if err != nil {
		panic(err)
	}

	docs, err := input.Parse(cfg.Input)
	if err != nil {
		panic(err)
	}

	cfg.Output.AppVersion = version
	cfg.Output.Elapsed = time.Now().UnixNano() - start.UnixNano()
	if err = output.Render(docs, cfg.Output); err != nil {
		panic(err)
	}
}

// 处理命令行参数，若被处理，返回 true，否则返回 false。
func flags() bool {
	flag.Usage = func() { logs.Println(usage) }
	h := flag.Bool("h", false, "显示帮助信息")
	v := flag.Bool("v", false, "显示版本信息")
	l := flag.Bool("l", false, "显示所有支持的语言")
	g := flag.Bool("g", false, "在当前目录下创建一个默认的配置文件")
	flag.Parse()

	switch {
	case *h:
		flag.Usage()
		return true
	case *v:
		logs.Info("apidoc ", version, "build with", runtime.Version())
		return true
	case *l:
		langs := "[" + strings.Join(input.Langs(), ", ") + "]"
		logs.Info("目前支持以下语言：", langs)
		return true
	case *g:
		if err := genConfigFile(); err != nil {
			panic(err)
		}
		return true
	}
	return false
}
<commit_msg>修正版本号<commit_after>// Copyright 2015 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

// apidoc 是一个 RESTful api 文档生成工具。
package main

import (
	"flag"
	"runtime"
	"strings"
	"time"

	"github.com/caixw/apidoc/input"
	"github.com/caixw/apidoc/logs"
	"github.com/caixw/apidoc/output"
)

const (
	// 版本号
	//
	// 版本号按照 http://semver.org/lang/zh-CN/ 中的规则，分成以下四个部分：
	// 主版本号.次版本号.修订号.修订日期
	version = "2.2.56.160601"

	// 配置文件名称。
	configFilename = ".apidoc.json"
)

const usage = `apidoc 是一个 RESTful api 文档生成工具。

参数:
 -h       显示帮助信息；
 -v       显示版本信息；
 -l       显示所有支持的语言类型；
 -g       在当前目录下创建一个默认的配置文件。

有关 apidoc 的详细信息，可访问官网：http://apidoc.site`

func main() {
	if flags() {
		return
	}

	start := time.Now() // 记录处理开始时间

	cfg, err := loadConfig()
	if err != nil {
		panic(err)
	}

	docs, err := input.Parse(cfg.Input)
	if err != nil {
		panic(err)
	}

	cfg.Output.AppVersion = version
	cfg.Output.Elapsed = time.Now().UnixNano() - start.UnixNano()
	if err = output.Render(docs, cfg.Output); err != nil {
		panic(err)
	}
}

// 处理命令行参数，若被处理，返回 true，否则返回 false。
func flags() bool {
	flag.Usage = func() { logs.Println(usage) }
	h := flag.Bool("h", false, "显示帮助信息")
	v := flag.Bool("v", false, "显示版本信息")
	l := flag.Bool("l", false, "显示所有支持的语言")
	g := flag.Bool("g", false, "在当前目录下创建一个默认的配置文件")
	flag.Parse()

	switch {
	case *h:
		flag.Usage()
		return true
	case *v:
		logs.Info("apidoc ", version, "build with", runtime.Version())
		return true
	case *l:
		langs := "[" + strings.Join(input.Langs(), ", ") + "]"
		logs.Info("目前支持以下语言：", langs)
		return true
	case *g:
		if err := genConfigFile(); err != nil {
			panic(err)
		}
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/armed/nver/cmd"
	"github.com/codegangsta/cli"
	"log"
	"os"
	"runtime"
)

func main() {
	if runtime.GOOS != "darwin" && runtime.GOOS != "linux" {
		log.Fatalf("Sorry, nver currently supports only Mac OS X and Linux")
	}

	app := cli.NewApp()
	app.Name = "nver"
	app.Version = "0.0.1"
	app.Usage = "Manage your Node.js versions"
	app.Commands = cmd.Commands
	app.Run(os.Args)
}
<commit_msg>bump version 0.0.2<commit_after>package main

import (
	"github.com/armed/nver/cmd"
	"github.com/codegangsta/cli"
	"log"
	"os"
	"runtime"
)

func main() {
	if runtime.GOOS != "darwin" && runtime.GOOS != "linux" {
		log.Fatalf("Sorry, nver currently supports only Mac OS X and Linux")
	}

	app := cli.NewApp()
	app.Name = "nver"
	app.Version = "0.0.2"
	app.Usage = "Manage your Node.js versions"
	app.Commands = cmd.Commands
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"time"
	"flag"
	"fmt"
	"net/http"
	"log"
)

var (
	PORT = flag.Int("port", 80, "Server port")
	DELAY = flag.Int("delay", 150, "delay in millisecond")
)

func main() {

	flag.Parse()

	http.HandleFunc("/", handler)

	err := http.ListenAndServe(fmt.Sprintf(":%d", *PORT), nil)

	fmt.Printf("ListenAndServe: %v\n", err)
}

func handler(w http.ResponseWriter, r *http.Request) {

	log.Printf("start")

	time.Sleep(time.Duration(*DELAY) * time.Millisecond)

	log.Printf("end")

	fmt.Fprint(w, "quack")
}<commit_msg>Add logs.<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"time"
)

var (
	PORT  = flag.Int("port", 80, "Server port")
	DELAY = flag.Int("delay", 150, "delay in millisecond")
	LOGS  = flag.Bool("logs", false, "Show logs")
)

func main() {

	flag.Parse()

	http.HandleFunc("/", handler)

	err := http.ListenAndServe(fmt.Sprintf(":%d", *PORT), nil)

	fmt.Printf("ListenAndServe: %v\n", err)
}

func handler(w http.ResponseWriter, r *http.Request) {

	logs("start")

	time.Sleep(time.Duration(*DELAY) * time.Millisecond)

	logs("end")

	fmt.Fprint(w, "quack")
}

func logs(format string, v ...interface{}) {
	if *LOGS {
		log.Printf(format, v...)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/csv"
	"github.com/ActiveState/tail"
	"github.com/prometheus/client_golang/prometheus"
	"log"
	"net/http"
	"strconv"
	"strings"
)

var (
	loadEvents = prometheus.NewCounter(prometheus.CounterOpts{
		Name: "datalogger_rows_loaded",
		Help: "the number of rows loaded into the database",
	})
	batteryVoltage = prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "datalogger_main_battery_voltage",
		Help: "The current main battery voltage",
	})
)

func init() {
	prometheus.MustRegister(loadEvents)
	prometheus.MustRegister(batteryVoltage)
}

type stringSlice []string

func (slice stringSlice) pos(value string) int {
	for p, v := range slice {
		if v == value {
			return p
		}
	}
	return -1
}

func readCSVLine(text string) []string {
	reader := csv.NewReader(strings.NewReader(text))
	fields, err := reader.Read()
	if err != nil {
		log.Fatal(err)
	}
	return fields
}

func loadData(fileName string) {

	t, err := tail.TailFile(fileName, tail.Config{
		Follow: true,
		ReOpen: true,
	})
	if err != nil {
		log.Fatal(err)
	}

	battery := 1

	// Read title and variables and units
	skip := 0
	for line := range t.Lines {
		if strings.Contains(line.Text, "TOA5") {
			skip = 4
		}
		if skip == 3 {
			// decode headers here
			fields := readCSVLine(line.Text)
			variates := stringSlice(fields)
			battery = variates.pos("GageMinV")
		}
		if skip > 0 {
			// skip the rest
			skip = skip - 1
			continue
		}
		// Read data
		fields := readCSVLine(line.Text)
		voltage, err := strconv.ParseFloat(fields[battery], 64)
		if err != nil {
			log.Fatal(err)
		}
		log.Println(voltage)
		batteryVoltage.Set(voltage)
	}
}

func main() {

	go loadData("raingauge_Table1.dat")

	http.Handle("/metrics", prometheus.Handler())
	http.ListenAndServe(":9094", nil)

}
<commit_msg>added event counter<commit_after>package main

import (
	"encoding/csv"
	"github.com/ActiveState/tail"
	"github.com/prometheus/client_golang/prometheus"
	"log"
	"net/http"
	"strconv"
	"strings"
)

var (
	loadEvents = prometheus.NewCounter(prometheus.CounterOpts{
		Name: "datalogger_rows_loaded",
		Help: "the number of rows loaded into the database",
	})
	batteryVoltage = prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "datalogger_main_battery_voltage",
		Help: "The current main battery voltage",
	})
)

func init() {
	prometheus.MustRegister(loadEvents)
	prometheus.MustRegister(batteryVoltage)
}

type stringSlice []string

func (slice stringSlice) pos(value string) int {
	for p, v := range slice {
		if v == value {
			return p
		}
	}
	return -1
}

func readCSVLine(text string) []string {
	reader := csv.NewReader(strings.NewReader(text))
	fields, err := reader.Read()
	if err != nil {
		log.Fatal(err)
	}
	return fields
}

func loadData(fileName string) {

	t, err := tail.TailFile(fileName, tail.Config{
		Follow: true,
		ReOpen: true,
	})
	if err != nil {
		log.Fatal(err)
	}

	battery := 1

	// Read title and variables and units
	skip := 0
	for line := range t.Lines {
		if strings.Contains(line.Text, "TOA5") {
			skip = 4
		}
		if skip == 3 {
			// decode headers here
			fields := readCSVLine(line.Text)
			variates := stringSlice(fields)
			battery = variates.pos("GageMinV")
		}
		if skip > 0 {
			// skip the rest
			skip = skip - 1
			continue
		}
		// Read data
		fields := readCSVLine(line.Text)
		voltage, err := strconv.ParseFloat(fields[battery], 64)
		if err != nil {
			log.Fatal(err)
		}
		log.Println(voltage)
		batteryVoltage.Set(voltage)
		loadEvents.Inc()
	}
}

func main() {

	go loadData("raingauge_Table1.dat")

	http.Handle("/metrics", prometheus.Handler())
	http.ListenAndServe(":9094", nil)

}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"gopkg.in/alecthomas/kingpin.v2"

	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/pkg/api/unversioned"
	"k8s.io/client-go/pkg/api/v1"
	"k8s.io/client-go/pkg/apis/extensions/v1beta1"
	"k8s.io/client-go/pkg/labels"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"

	"github.com/linki/chaoskube/chaoskube"
)

const (
	appName = "chaoskube"
	image   = "quay.io/linki/chaoskube"
	version = "v0.3.1"
)

var (
	labelString string
	kubeconfig  string
	interval    time.Duration
	inCluster   bool
	deploy      bool
	dryRun      bool
	debug       bool
)

func init() {
	kingpin.Flag("labels", "A set of labels that restricts the Pods available for termination").Default(labels.Everything().String()).StringVar(&labelString)
	kingpin.Flag("kubeconfig", "Path to a kubeconfig file").Default(clientcmd.RecommendedHomeFile).StringVar(&kubeconfig)
	kingpin.Flag("interval", "Interval between Pod terminations").Short('i').Default("10m").DurationVar(&interval)
	kingpin.Flag("in-cluster", "If true, finds the Kubernetes cluster from the environment").Short('c').BoolVar(&inCluster)
	kingpin.Flag("deploy", "If true, deploys chaoskube in the current cluster with the provided configuration").Short('d').BoolVar(&deploy)
	kingpin.Flag("dry-run", "If true, don't actually do anything.").Default("true").BoolVar(&dryRun)
	kingpin.Flag("debug", "Enable debug logging.").BoolVar(&debug)
}

func main() {
	kingpin.Version(version)
	kingpin.Parse()

	if debug {
		log.SetLevel(log.DebugLevel)
	}

	if dryRun {
		log.Infof("Dry run enabled. I won't kill anything. Use --no-dry-run when you're ready.")
	}

	client, err := newClient()
	if err != nil {
		log.Fatal(err)
	}

	if deploy {
		log.Debugf("Deploying %s:%s", image, version)

		manifest := generateManifest()

		deployment := client.Extensions().Deployments(manifest.Namespace)

		_, err := deployment.Get(manifest.Name)
		if err != nil {
			_, err = deployment.Create(manifest)
		} else {
			_, err = deployment.Update(manifest)
		}
		if err != nil {
			log.Fatal(err)
		}

		log.Infof("Deployed %s:%s", image, version)
		os.Exit(0)
	}

	selector, err := labels.Parse(labelString)
	if err != nil {
		log.Fatal(err)
	}

	log.Infof("Filtering pods by label selector: %s", selector.String())

	chaoskube := chaoskube.New(client, selector, dryRun, time.Now().UTC().UnixNano())

	for {
		if err := terminateVictim(chaoskube); err != nil {
			log.Fatal(err)
		}

		log.Debugf("Sleeping for %s...", interval)
		time.Sleep(interval)
	}
}

func terminateVictim(ck *chaoskube.Chaoskube) error {
	victim, err := ck.Victim()
	if err == chaoskube.ErrPodNotFound {
		log.Warnf("No victim could be found. If that's surprising double-check your label selector.")
		return nil
	}
	if err != nil {
		return err
	}

	log.Infof("Killing pod %s/%s", victim.Namespace, victim.Name)

	if err := ck.DeletePod(victim); err != nil {
		return err
	}

	return nil
}

func newClient() (*kubernetes.Clientset, error) {
	var (
		config *rest.Config
		err    error
	)

	if inCluster {
		config, err = rest.InClusterConfig()
		log.Infof("Using in-cluster config.")
	} else {
		config, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
		log.Infof("Using current context from kubeconfig at %s.", kubeconfig)
	}
	if err != nil {
		return nil, err
	}
	log.Debugf("Targeting cluster at %s", config.Host)

	client, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, err
	}

	return client, nil
}

func generateManifest() *v1beta1.Deployment {
	// modifies flags for deployment
	args := append(os.Args[1:], "--in-cluster")
	args = stripFlags(args, "--kubeconfig")
	args = stripFlags(args, "--deploy")

	return &v1beta1.Deployment{
		TypeMeta: unversioned.TypeMeta{
			APIVersion: "extensions/v1beta1",
			Kind:       "Deployment",
		},
		ObjectMeta: v1.ObjectMeta{
			Name:      appName,
			Namespace: v1.NamespaceDefault,
			Labels: map[string]string{
				"app":      appName,
				"heritage": appName,
			},
		},
		Spec: v1beta1.DeploymentSpec{
			Template: v1.PodTemplateSpec{
				ObjectMeta: v1.ObjectMeta{
					Labels: map[string]string{
						"app": appName,
					},
				},
				Spec: v1.PodSpec{
					Containers: []v1.Container{
						v1.Container{
							Name:  appName,
							Image: image + ":" + version,
							Args:  args,
						},
					},
				},
			},
		},
	}
}

func stripFlags(elements []string, candidate string) []string {
	for i := range elements {
		if strings.Contains(elements[i], candidate) {
			elements = append(elements[:i], elements[i+1:]...)
			break
		}
	}

	return elements
}
<commit_msg>fix: cleanup wrong log levels<commit_after>package main

import (
	"os"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"gopkg.in/alecthomas/kingpin.v2"

	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/pkg/api/unversioned"
	"k8s.io/client-go/pkg/api/v1"
	"k8s.io/client-go/pkg/apis/extensions/v1beta1"
	"k8s.io/client-go/pkg/labels"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"

	"github.com/linki/chaoskube/chaoskube"
)

const (
	appName = "chaoskube"
	image   = "quay.io/linki/chaoskube"
	version = "v0.3.1"
)

var (
	labelString string
	kubeconfig  string
	interval    time.Duration
	inCluster   bool
	deploy      bool
	dryRun      bool
	debug       bool
)

func init() {
	kingpin.Flag("labels", "A set of labels that restricts the Pods available for termination").Default(labels.Everything().String()).StringVar(&labelString)
	kingpin.Flag("kubeconfig", "Path to a kubeconfig file").Default(clientcmd.RecommendedHomeFile).StringVar(&kubeconfig)
	kingpin.Flag("interval", "Interval between Pod terminations").Short('i').Default("10m").DurationVar(&interval)
	kingpin.Flag("in-cluster", "If true, finds the Kubernetes cluster from the environment").Short('c').BoolVar(&inCluster)
	kingpin.Flag("deploy", "If true, deploys chaoskube in the current cluster with the provided configuration").Short('d').BoolVar(&deploy)
	kingpin.Flag("dry-run", "If true, don't actually do anything.").Default("true").BoolVar(&dryRun)
	kingpin.Flag("debug", "Enable debug logging.").BoolVar(&debug)
}

func main() {
	kingpin.Version(version)
	kingpin.Parse()

	if debug {
		log.SetLevel(log.DebugLevel)
	}

	if dryRun {
		log.Infof("Dry run enabled. I won't kill anything. Use --no-dry-run when you're ready.")
	}

	client, err := newClient()
	if err != nil {
		log.Fatal(err)
	}

	if deploy {
		log.Debugf("Deploying %s:%s", image, version)

		manifest := generateManifest()

		deployment := client.Extensions().Deployments(manifest.Namespace)

		_, err := deployment.Get(manifest.Name)
		if err != nil {
			_, err = deployment.Create(manifest)
		} else {
			_, err = deployment.Update(manifest)
		}
		if err != nil {
			log.Fatal(err)
		}

		log.Infof("Deployed %s:%s", image, version)
		os.Exit(0)
	}

	selector, err := labels.Parse(labelString)
	if err != nil {
		log.Fatal(err)
	}

	log.Infof("Filtering pods by label selector: %s", selector.String())

	chaoskube := chaoskube.New(client, selector, dryRun, time.Now().UTC().UnixNano())

	for {
		if err := terminateVictim(chaoskube); err != nil {
			log.Fatal(err)
		}

		log.Debugf("Sleeping for %s...", interval)
		time.Sleep(interval)
	}
}

func terminateVictim(ck *chaoskube.Chaoskube) error {
	victim, err := ck.Victim()
	if err == chaoskube.ErrPodNotFound {
		log.Warnf("No victim could be found. If that's surprising double-check your label selector.")
		return nil
	}
	if err != nil {
		return err
	}

	log.Infof("Killing pod %s/%s", victim.Namespace, victim.Name)

	if err := ck.DeletePod(victim); err != nil {
		return err
	}

	return nil
}

func newClient() (*kubernetes.Clientset, error) {
	var (
		config *rest.Config
		err    error
	)

	if inCluster {
		config, err = rest.InClusterConfig()
		log.Debug("Using in-cluster config.")
	} else {
		config, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
		log.Debugf("Using current context from kubeconfig at %s.", kubeconfig)
	}
	if err != nil {
		return nil, err
	}
	log.Infof("Targeting cluster at %s", config.Host)

	client, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, err
	}

	return client, nil
}

func generateManifest() *v1beta1.Deployment {
	// modifies flags for deployment
	args := append(os.Args[1:], "--in-cluster")
	args = stripFlags(args, "--kubeconfig")
	args = stripFlags(args, "--deploy")

	return &v1beta1.Deployment{
		TypeMeta: unversioned.TypeMeta{
			APIVersion: "extensions/v1beta1",
			Kind:       "Deployment",
		},
		ObjectMeta: v1.ObjectMeta{
			Name:      appName,
			Namespace: v1.NamespaceDefault,
			Labels: map[string]string{
				"app":      appName,
				"heritage": appName,
			},
		},
		Spec: v1beta1.DeploymentSpec{
			Template: v1.PodTemplateSpec{
				ObjectMeta: v1.ObjectMeta{
					Labels: map[string]string{
						"app": appName,
					},
				},
				Spec: v1.PodSpec{
					Containers: []v1.Container{
						v1.Container{
							Name:  appName,
							Image: image + ":" + version,
							Args:  args,
						},
					},
				},
			},
		},
	}
}

func stripFlags(elements []string, candidate string) []string {
	for i := range elements {
		if strings.Contains(elements[i], candidate) {
			elements = append(elements[:i], elements[i+1:]...)
			break
		}
	}

	return elements
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/codegangsta/cli"
	"github.com/glyn/pango/disc"
	"github.com/glyn/pango/pkg"
)

func main() {
	app := cli.NewApp()
	app.Name = "pango"
	app.Usage = "Package Analysis for Go"
	app.Action = func(c *cli.Context) {
		println("Try pango help")
	}

	app.Commands = []cli.Command{
		{
			Name:    "analyse",
			Aliases: []string{"a"},
			Usage:   "analyse Go package",
			Action:  analyse,
		},
	}

	app.Run(os.Args)
}

func analyse(c *cli.Context) {
	d := disc.New(c.Args().Get(0))

	root := pkg.Pkg(c.Args().Get(1))
	var imports pkg.PGraph
	if root != "" {
		imports = d.Discover(root)
	} else {
		imports = d.DiscoverAll()
	}

	// Analyse self-contained packages.
	imports.Packages().Walk(func(p pkg.Pkg) {
		escape := false
		d.Walk(p, func(q pkg.Pkg, qi pkg.PSet) {
			qi.Walk(func(i pkg.Pkg) {
				if !p.HasSubpackage(i) {
					escape = true
				}
			})
		})
		if !escape {
			fmt.Printf("%s is self-contained\n", d.ShortName(p))
		}
	})

	// Compute scoped fan-out of each package.
	fanOut := make(map[pkg.Pkg]int, 1)
	imports.Walk(func(p pkg.Pkg, i pkg.PSet) {
		fanOut[p] = i.Size()
	})

	// Compute scoped fan-in of each package.
	fanIn := make(map[pkg.Pkg]int, 1)
	imports.Walk(func(_ pkg.Pkg, i pkg.PSet) {
		i.Walk(func(q pkg.Pkg) {
			fanIn[q] = fanIn[q] + 1
		})
	})

	// Compute scoped instability of each package.
	instab := make(map[pkg.Pkg]float32, 1)
	imports.Walk(func(p pkg.Pkg, i pkg.PSet) {
		instab[p] = instability(fanIn[p], fanOut[p])
		fmt.Printf("%s has fan-in %d, fan-out %d, and instability %.2f\n", d.ShortName(p), fanIn[p], fanOut[p], instab[p])
	})

	// Check stable dependencies principle violations.
	imports.Walk(func(p pkg.Pkg, i pkg.PSet) {
		i.Walk(func(q pkg.Pkg) {
			if instab[q] > instab[p] {
				fmt.Printf("%s depends on the less stable %s\n", d.ShortName(p), d.ShortName(q))
			}
		})
	})

	// Detect direct dependency cycles.
	imports.Walk(func(p pkg.Pkg, imp pkg.PSet) {
		imp.Walk(func(i pkg.Pkg) {
			if q, ok := imports.Imports(i); ok {
				if q.Contains(p) {
					fmt.Printf("Direct dependency cycle between %s and %s\n", d.ShortName(p), d.ShortName(i))
				}
			}
		})
	})
}

func instability(fanIn, fanOut int) float32 {
	if fan := fanIn + fanOut; fan > 0 {
		return float32(fanOut) / float32(fan)
	}
	return 0
}
<commit_msg>Improve docs<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/codegangsta/cli"
	"github.com/glyn/pango/disc"
	"github.com/glyn/pango/pkg"
)

func main() {
	app := cli.NewApp()
	app.Name = "pango"
	app.Usage = "Package Analysis for Go"
	app.Action = func(c *cli.Context) {
		println("Try pango help")
	}

	app.Commands = []cli.Command{
		{
			Name:    "analyse",
			Aliases: []string{"a"},
			Usage:   "Analyses a Go package and its dependencies",
			Action:  analyse,
		},
	}

	app.Run(os.Args)
}

func analyse(c *cli.Context) {
	d := disc.New(c.Args().Get(0))

	root := pkg.Pkg(c.Args().Get(1))
	var imports pkg.PGraph
	if root != "" {
		imports = d.Discover(root)
	} else {
		imports = d.DiscoverAll()
	}

	// Analyse self-contained packages.
	imports.Packages().Walk(func(p pkg.Pkg) {
		escape := false
		d.Walk(p, func(q pkg.Pkg, qi pkg.PSet) {
			qi.Walk(func(i pkg.Pkg) {
				if !p.HasSubpackage(i) {
					escape = true
				}
			})
		})
		if !escape {
			fmt.Printf("%s is self-contained\n", d.ShortName(p))
		}
	})

	// Compute scoped fan-out of each package.
	fanOut := make(map[pkg.Pkg]int, 1)
	imports.Walk(func(p pkg.Pkg, i pkg.PSet) {
		fanOut[p] = i.Size()
	})

	// Compute scoped fan-in of each package.
	fanIn := make(map[pkg.Pkg]int, 1)
	imports.Walk(func(_ pkg.Pkg, i pkg.PSet) {
		i.Walk(func(q pkg.Pkg) {
			fanIn[q] = fanIn[q] + 1
		})
	})

	// Compute scoped instability of each package.
	instab := make(map[pkg.Pkg]float32, 1)
	imports.Walk(func(p pkg.Pkg, i pkg.PSet) {
		instab[p] = instability(fanIn[p], fanOut[p])
		fmt.Printf("%s has fan-in %d, fan-out %d, and instability %.2f\n", d.ShortName(p), fanIn[p], fanOut[p], instab[p])
	})

	// Check stable dependencies principle violations.
	imports.Walk(func(p pkg.Pkg, i pkg.PSet) {
		i.Walk(func(q pkg.Pkg) {
			if instab[q] > instab[p] {
				fmt.Printf("%s depends on the less stable %s\n", d.ShortName(p), d.ShortName(q))
			}
		})
	})

	// Detect direct dependency cycles.
	imports.Walk(func(p pkg.Pkg, imp pkg.PSet) {
		imp.Walk(func(i pkg.Pkg) {
			if q, ok := imports.Imports(i); ok {
				if q.Contains(p) {
					fmt.Printf("Direct dependency cycle between %s and %s\n", d.ShortName(p), d.ShortName(i))
				}
			}
		})
	})
}

func instability(fanIn, fanOut int) float32 {
	if fan := fanIn + fanOut; fan > 0 {
		return float32(fanOut) / float32(fan)
	}
	return 0
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ssm"
)

var (
	client *ssm.SSM
	paths  []string
	tags   []string

	trueBool = true
)

func main() {
	// initialize AWS client
	initClient()

	// initialize command line flags
	initFlags()

	// fetch parameters
	params, err := fetchParams(paths)
	if err != nil {
		panic(err)
	}

	// print as env variables
	printParams(params)
}

func initClient() {
	session := session.Must(session.NewSession())
	client = ssm.New(session)
}

func initFlags() {
	pathsFlag := flag.String("paths", "", "comma delimited string of parameter path hierarchies")
	tagsFlag := flag.String("tags", "", "comma delimited string of tags to filter by")
	flag.Parse()

	initPaths(pathsFlag)
	initTags(tagsFlag)
}

func initPaths(pathsFlag *string) {
	if *pathsFlag != "" {
		paths = strings.Split(*pathsFlag, ",")
	}

	// ensure only path hierarchies were given
	for _, path := range paths {
		if !strings.Contains(path, "/") {
			fmt.Printf("Invalid path: '%s' - only path hierarchies are supported (e.g. '/production/webapp/')\n", path)
			os.Exit(1)
		}
	}
}

func initTags(tagsFlag *string) {
	if *tagsFlag != "" {
		tags = strings.Split(*tagsFlag, ",")
	}
}

func fetchParams(paths []string) ([]*ssm.Parameter, error) {
	// create tag filters
	tagFilters := make([]*ssm.ParameterStringFilter, len(tags))
	for i, tag := range tags {
		tagFilter := fmt.Sprintf("tag:%s", tag)
		tagFilters[i] = &ssm.ParameterStringFilter{
			Key: &tagFilter,
		}
	}

	// TEMP: until parameter-filters work for get-parameters-by-path (https://github.com/aws/aws-cli/issues/2850),
	// 1) retrieve parameters by tags via describe-parameters
	// 2) retrieve parameters by path via get-parameters-by-path
	// 3) calculate union of two sets

	// retrieve all parameters with given tags
	paramNames, err := describeParams(tagFilters)
	if err != nil {
		return nil, err
	}

	// retrieve params for given paths
	params, err := getParamsByPath(paths)
	if err != nil {
		return params, err
	}

	// calculate union of two sets
	union := calcUnion(paramNames, params)

	return union, nil
}

func describeParams(filters []*ssm.ParameterStringFilter) ([]string, error) {
	paramNames := make([]string, 0)

	done := false
	var nextToken string
	for !done {
		input := &ssm.DescribeParametersInput{
			ParameterFilters: filters,
		}

		if nextToken != "" {
			input.SetNextToken(nextToken)
		}

		output, err := client.DescribeParameters(input)
		if err != nil {
			return paramNames, err
		}

		for _, param := range output.Parameters {
			paramNames = append(paramNames, *param.Name)
		}

		// there are more parameters if nextToken is given in response
		if output.NextToken != nil {
			nextToken = *output.NextToken
		} else {
			done = true
		}
	}

	return paramNames, nil
}

func getParamsByPath(paths []string) ([]*ssm.Parameter, error) {
	params := make([]*ssm.Parameter, 0)

	// retrieve params for all paths
	for _, path := range paths {

		done := false
		var nextToken string
		for !done {
			input := &ssm.GetParametersByPathInput{
				Path:           &path,
				Recursive:      &trueBool,
				WithDecryption: &trueBool,
			}

			if nextToken != "" {
				input.SetNextToken(nextToken)
			}

			output, err := client.GetParametersByPath(input)
			if err != nil {
				return params, err
			}

			params = append(params, output.Parameters...)

			// there are more parameters for this path if nextToken is given in response
			if output.NextToken != nil {
				nextToken = *output.NextToken
			} else {
				done = true
			}
		}
	}

	return params, nil
}

func calcUnion(paramNames []string, params []*ssm.Parameter) []*ssm.Parameter {
	// build map lookup
	lookup := make(map[string]bool)
	for _, paramName := range paramNames {
		lookup[paramName] = true
	}

	// calculate union
	union := make([]*ssm.Parameter, 0)
	for _, param := range params {
		if lookup[*param.Name] {
			union = append(union, param)
		}
	}

	return union
}

func printParams(params []*ssm.Parameter) {
	for _, param := range params {
		split := strings.Split(*param.Name, "/")
		name := split[len(split)-1]
		fmt.Printf("%s=%s\n", strings.ToUpper(name), *param.Value)
	}
}
<commit_msg>Added link to AWS doc stating non-support for tag filtering<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ssm"
)

var (
	client *ssm.SSM
	paths  []string
	tags   []string

	trueBool = true
)

func main() {
	// initialize AWS client
	initClient()

	// initialize command line flags
	initFlags()

	// fetch parameters
	params, err := fetchParams(paths)
	if err != nil {
		panic(err)
	}

	// print as env variables
	printParams(params)
}

func initClient() {
	session := session.Must(session.NewSession())
	client = ssm.New(session)
}

func initFlags() {
	pathsFlag := flag.String("paths", "", "comma delimited string of parameter path hierarchies")
	tagsFlag := flag.String("tags", "", "comma delimited string of tags to filter by")
	flag.Parse()

	initPaths(pathsFlag)
	initTags(tagsFlag)
}

func initPaths(pathsFlag *string) {
	if *pathsFlag != "" {
		paths = strings.Split(*pathsFlag, ",")
	}

	// ensure only path hierarchies were given
	for _, path := range paths {
		if !strings.Contains(path, "/") {
			fmt.Printf("Invalid path: '%s' - only path hierarchies are supported (e.g. '/production/webapp/')\n", path)
			os.Exit(1)
		}
	}
}

func initTags(tagsFlag *string) {
	if *tagsFlag != "" {
		tags = strings.Split(*tagsFlag, ",")
	}
}

func fetchParams(paths []string) ([]*ssm.Parameter, error) {
	// create tag filters
	tagFilters := make([]*ssm.ParameterStringFilter, len(tags))
	for i, tag := range tags {
		tagFilter := fmt.Sprintf("tag:%s", tag)
		tagFilters[i] = &ssm.ParameterStringFilter{
			Key: &tagFilter,
		}
	}

	// TEMP: until parameter-filters work for get-parameters-by-path
	// - https://docs.aws.amazon.com/cli/latest/reference/ssm/get-parameters-by-path.html ("This API action doesn't support filtering by tags.")
	// - https://github.com/aws/aws-cli/issues/2850)
	//
	// 1) retrieve parameters by tags via describe-parameters
	// 2) retrieve parameters by path via get-parameters-by-path
	// 3) calculate union of two sets

	// retrieve all parameters with given tags
	paramNames, err := describeParams(tagFilters)
	if err != nil {
		return nil, err
	}

	// retrieve params for given paths
	params, err := getParamsByPath(paths)
	if err != nil {
		return params, err
	}

	// calculate union of two sets
	union := calcUnion(paramNames, params)

	return union, nil
}

func describeParams(filters []*ssm.ParameterStringFilter) ([]string, error) {
	paramNames := make([]string, 0)

	done := false
	var nextToken string
	for !done {
		input := &ssm.DescribeParametersInput{
			ParameterFilters: filters,
		}

		if nextToken != "" {
			input.SetNextToken(nextToken)
		}

		output, err := client.DescribeParameters(input)
		if err != nil {
			return paramNames, err
		}

		for _, param := range output.Parameters {
			paramNames = append(paramNames, *param.Name)
		}

		// there are more parameters if nextToken is given in response
		if output.NextToken != nil {
			nextToken = *output.NextToken
		} else {
			done = true
		}
	}

	return paramNames, nil
}

func getParamsByPath(paths []string) ([]*ssm.Parameter, error) {
	params := make([]*ssm.Parameter, 0)

	// retrieve params for all paths
	for _, path := range paths {

		done := false
		var nextToken string
		for !done {
			input := &ssm.GetParametersByPathInput{
				Path:           &path,
				Recursive:      &trueBool,
				WithDecryption: &trueBool,
			}

			if nextToken != "" {
				input.SetNextToken(nextToken)
			}

			output, err := client.GetParametersByPath(input)
			if err != nil {
				return params, err
			}

			params = append(params, output.Parameters...)

			// there are more parameters for this path if nextToken is given in response
			if output.NextToken != nil {
				nextToken = *output.NextToken
			} else {
				done = true
			}
		}
	}

	return params, nil
}

func calcUnion(paramNames []string, params []*ssm.Parameter) []*ssm.Parameter {
	// build map lookup
	lookup := make(map[string]bool)
	for _, paramName := range paramNames {
		lookup[paramName] = true
	}

	// calculate union
	union := make([]*ssm.Parameter, 0)
	for _, param := range params {
		if lookup[*param.Name] {
			union = append(union, param)
		}
	}

	return union
}

func printParams(params []*ssm.Parameter) {
	for _, param := range params {
		split := strings.Split(*param.Name, "/")
		name := split[len(split)-1]
		fmt.Printf("%s=%s\n", strings.ToUpper(name), *param.Value)
	}
}
<|endoftext|>