<commit_before>// Automatically downloads and configures Steam grid images for all games in a
// given Steam installation.
package main

import (
	"bufio"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"time"
)

// Prints an error and quits.
func errorAndExit(err error) {
	fmt.Println(err.Error())
	bufio.NewReader(os.Stdin).ReadBytes('\n')
	os.Exit(0)
}

func main() {
	http.DefaultTransport.(*http.Transport).ResponseHeaderTimeout = time.Second * 10
	startApplication()
}

func startApplication() {
	fmt.Println("Loading overlays...")
	overlays, err := LoadOverlays(filepath.Join(filepath.Dir(os.Args[0]), "overlays by category"))
	if err != nil {
		errorAndExit(err)
	}
	if len(overlays) == 0 {
		fmt.Println("No category overlays found. You can put overlay images in the folder 'overlays by category', where the filename is the game category.\n\nYou can find many user-created overlays at https://www.reddit.com/r/steamgrid/wiki/overlays .\n\nContinuing without overlays...\n")
	} else {
		fmt.Printf("Loaded %v overlays. \n\nYou can find many user-created overlays at https://www.reddit.com/r/steamgrid/wiki/overlays .\n\n", len(overlays))
	}

	fmt.Println("Looking for Steam directory...")
	installationDir, err := GetSteamInstallation()
	if err != nil {
		errorAndExit(err)
	}

	fmt.Println("Loading users...")
	users, err := GetUsers(installationDir)
	if err != nil {
		errorAndExit(err)
	}
	if len(users) == 0 {
		errorAndExit(errors.New("No users found at Steam/userdata. Have you used Steam before in this computer?"))
	}

	nOverlaysApplied := 0
	nDownloaded := 0
	var notFounds []*Game
	var searchedGames []*Game
	var failedGames []*Game
	var errorMessages []string

	for _, user := range users {
		fmt.Println("Loading games for " + user.Name)
		gridDir := filepath.Join(user.Dir, "config", "grid")

		err = os.MkdirAll(filepath.Join(gridDir, "originals"), 0777)
		if err != nil {
			errorAndExit(err)
		}

		games := GetGames(user)

		fmt.Println("Loading existing images and backups...")

		i := 0
		for _, game := range games {
			i++

			overridePath := filepath.Join(filepath.Dir(os.Args[0]), "games")
			LoadExisting(overridePath, gridDir, game)
			// This cleans up unused backups and images for the same game but with different extensions.
			err = RemoveExisting(gridDir, game.ID)
			if err != nil {
				fmt.Println(err.Error())
			}

			var name string
			if game.Name == "" {
				game.Name = GetGameName(game.ID)
			}

			if game.Name != "" {
				name = game.Name
			} else {
				name = "unknown game with id " + game.ID
			}
			fmt.Printf("Processing %v (%v/%v)", name, i, len(games))

			///////////////////////
			// Download if missing.
			///////////////////////
			if game.ImageSource == "" {
				fromSearch, err := DownloadImage(gridDir, game)
				if err != nil {
					fmt.Println(err.Error())
				}

				if game.ImageSource == "" {
					notFounds = append(notFounds, game)
					fmt.Printf(" not found\n")
					// Game has no image, skip it.
					continue
				} else if err == nil {
					nDownloaded++
				}

				if fromSearch {
					searchedGames = append(searchedGames, game)
				}
			}
			fmt.Printf(" found from %v\n", game.ImageSource)

			///////////////////////
			// Apply overlay.
			///////////////////////
			err := ApplyOverlay(game, overlays)
			if err != nil {
				print(err.Error(), "\n")
				failedGames = append(failedGames, game)
				errorMessages = append(errorMessages, err.Error())
			}
			if game.OverlayImageBytes != nil {
				nOverlaysApplied++
			} else {
				game.OverlayImageBytes = game.CleanImageBytes
			}

			///////////////////////
			// Save result.
			///////////////////////
			err = BackupGame(gridDir, game)
			if err != nil {
				errorAndExit(err)
			}
			imagePath := filepath.Join(gridDir, game.ID+game.ImageExt)
			err = ioutil.WriteFile(imagePath, game.OverlayImageBytes, 0666)
			if err != nil {
				fmt.Printf("Failed to write image for %v because: %v\n", game.Name, err.Error())
			}
		}
	}

	fmt.Printf("\n\n%v images downloaded and %v overlays applied.\n\n", nDownloaded, nOverlaysApplied)
	if len(searchedGames) >= 1 {
		fmt.Printf("%v images were found with a Google search and may not be accurate:\n", len(searchedGames))
		for _, game := range searchedGames {
			fmt.Printf("* %v (steam id %v)\n", game.Name, game.ID)
		}

		fmt.Printf("\n\n")
	}

	if len(notFounds) >= 1 {
		fmt.Printf("%v images could not be found anywhere:\n", len(notFounds))
		for _, game := range notFounds {
			fmt.Printf("- %v (id %v)\n", game.Name, game.ID)
		}

		fmt.Printf("\n\n")
	}

	if len(failedGames) >= 1 {
		fmt.Printf("%v images were found but had errors and could not be overlaid:\n", len(failedGames))
		for i, game := range failedGames {
			fmt.Printf("- %v (id %v) (%v)\n", game.Name, game.ID, errorMessages[i])
		}

		fmt.Printf("\n\n")
	}

	fmt.Println("Open Steam in grid view to see the results!\n\nPress enter to close.")

	bufio.NewReader(os.Stdin).ReadBytes('\n')
}
<commit_msg>Added Help details.<commit_after>// Automatically downloads and configures Steam grid images for all games in a
// given Steam installation.
package main

import (
	"bufio"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"time"
)

// Prints an error and quits.
func errorAndExit(err error) {
	fmt.Println(err.Error())
	bufio.NewReader(os.Stdin).ReadBytes('\n')
	os.Exit(0)
}

func main() {
	http.DefaultTransport.(*http.Transport).ResponseHeaderTimeout = time.Second * 10
	startApplication()
}

func startApplication() {
	fmt.Println("Loading overlays...")
	overlays, err := LoadOverlays(filepath.Join(filepath.Dir(os.Args[0]), "overlays by category"))
	if err != nil {
		errorAndExit(err)
	}
	if len(overlays) == 0 {
		fmt.Println("No category overlays found. You can put overlay images in the folder 'overlays by category', where the filename is the game category.\n\nYou can find many user-created overlays at https://www.reddit.com/r/steamgrid/wiki/overlays .\n\nContinuing without overlays...\n")
	} else {
		fmt.Printf("Loaded %v overlays. \n\nYou can find many user-created overlays at https://www.reddit.com/r/steamgrid/wiki/overlays .\n\n", len(overlays))
	}

	fmt.Println("Looking for Steam directory...If SteamGrid doesn´t find the directory automatically, launch it with an argument linking to the Steam directory.")
	installationDir, err := GetSteamInstallation()
	if err != nil {
		errorAndExit(err)
	}

	fmt.Println("Loading users...")
	users, err := GetUsers(installationDir)
	if err != nil {
		errorAndExit(err)
	}
	if len(users) == 0 {
		errorAndExit(errors.New("No users found at Steam/userdata. Have you used Steam before in this computer?"))
	}

	nOverlaysApplied := 0
	nDownloaded := 0
	var notFounds []*Game
	var searchedGames []*Game
	var failedGames []*Game
	var errorMessages []string

	for _, user := range users {
		fmt.Println("Loading games for " + user.Name)
		gridDir := filepath.Join(user.Dir, "config", "grid")

		err = os.MkdirAll(filepath.Join(gridDir, "originals"), 0777)
		if err != nil {
			errorAndExit(err)
		}

		games := GetGames(user)

		fmt.Println("Loading existing images and backups...")

		i := 0
		for _, game := range games {
			i++

			overridePath := filepath.Join(filepath.Dir(os.Args[0]), "games")
			LoadExisting(overridePath, gridDir, game)
			// This cleans up unused backups and images for the same game but with different extensions.
			err = RemoveExisting(gridDir, game.ID)
			if err != nil {
				fmt.Println(err.Error())
			}

			var name string
			if game.Name == "" {
				game.Name = GetGameName(game.ID)
			}

			if game.Name != "" {
				name = game.Name
			} else {
				name = "unknown game with id " + game.ID
			}
			fmt.Printf("Processing %v (%v/%v)", name, i, len(games))

			///////////////////////
			// Download if missing.
			///////////////////////
			if game.ImageSource == "" {
				fromSearch, err := DownloadImage(gridDir, game)
				if err != nil {
					fmt.Println(err.Error())
				}

				if game.ImageSource == "" {
					notFounds = append(notFounds, game)
					fmt.Printf(" not found\n")
					// Game has no image, skip it.
					continue
				} else if err == nil {
					nDownloaded++
				}

				if fromSearch {
					searchedGames = append(searchedGames, game)
				}
			}
			fmt.Printf(" found from %v\n", game.ImageSource)

			///////////////////////
			// Apply overlay.
			///////////////////////
			err := ApplyOverlay(game, overlays)
			if err != nil {
				print(err.Error(), "\n")
				failedGames = append(failedGames, game)
				errorMessages = append(errorMessages, err.Error())
			}
			if game.OverlayImageBytes != nil {
				nOverlaysApplied++
			} else {
				game.OverlayImageBytes = game.CleanImageBytes
			}

			///////////////////////
			// Save result.
			///////////////////////
			err = BackupGame(gridDir, game)
			if err != nil {
				errorAndExit(err)
			}
			imagePath := filepath.Join(gridDir, game.ID+game.ImageExt)
			err = ioutil.WriteFile(imagePath, game.OverlayImageBytes, 0666)
			if err != nil {
				fmt.Printf("Failed to write image for %v because: %v\n", game.Name, err.Error())
			}
		}
	}

	fmt.Printf("\n\n%v images downloaded and %v overlays applied.\n\n", nDownloaded, nOverlaysApplied)
	if len(searchedGames) >= 1 {
		fmt.Printf("%v images were found with a Google search and may not be accurate:\n", len(searchedGames))
		for _, game := range searchedGames {
			fmt.Printf("* %v (steam id %v)\n", game.Name, game.ID)
		}

		fmt.Printf("\n\n")
	}

	if len(notFounds) >= 1 {
		fmt.Printf("%v images could not be found anywhere:\n", len(notFounds))
		for _, game := range notFounds {
			fmt.Printf("- %v (id %v)\n", game.Name, game.ID)
		}

		fmt.Printf("\n\n")
	}

	if len(failedGames) >= 1 {
		fmt.Printf("%v images were found but had errors and could not be overlaid:\n", len(failedGames))
		for i, game := range failedGames {
			fmt.Printf("- %v (id %v) (%v)\n", game.Name, game.ID, errorMessages[i])
		}

		fmt.Printf("\n\n")
	}

	fmt.Println("Open Steam in grid view to see the results!\n\nPress enter to close.")

	bufio.NewReader(os.Stdin).ReadBytes('\n')
}
<|endoftext|>


<commit_before>// Copyright 2013 Artur Grabowski. All rights reserved.
// Use of this source code is governed by a ISC-style
// license that can be found in the LICENSE file.
package stopwatch

import (
	"time"
)

type Stopwatch struct {
	acc time.Duration
	t time.Time
}

func New() Stopwatch {
	return Stopwatch{}
}

func (s *Stopwatch) Start() {
	s.t = time.Now()
}

func (s *Stopwatch) Stop() {
	s.acc = time.Since(s.t)
}

func (s *Stopwatch) Handover(s2 *Stopwatch) {
	s2.t = time.Now()
	s.acc = s.t.Sub(s2.t)
}

func (s *Stopwatch) Snapshot() Stopwatch {
	ret := *s
	ret.Stop()
	return ret
}

func (s *Stopwatch) Reset() {
	*s = Stopwatch{}
}

func (s Stopwatch) Nanoseconds() int64 {
	return s.acc.Nanoseconds()
}

func (s Stopwatch) Seconds() float64 {
	return s.acc.Seconds()
}

func (s Stopwatch) String() string {
	return s.acc.String()
}
<commit_msg>Document.<commit_after>// Copyright 2013 Artur Grabowski. All rights reserved.
// Use of this source code is governed by a ISC-style
// license that can be found in the LICENSE file.
package stopwatch

import (
	"time"
)

// A Stopwatch is used for keeping track of elapsed wall-clock time.
// Stopwatches don't keep track if they are running or not,
// it's left to the user to deal with this. Unmatched Start/Stop
// calls will lead to the stopwatch having an undefined value.
//
// Stopwatches are currently limited by the data type of time.Duration
// and will not measure longer durations than 290 years.
type Stopwatch struct {
	acc time.Duration
	t time.Time
}

// Returns a new Stopwatch.
func New() Stopwatch {
	return Stopwatch{}
}

// Starts counting elapsed wall-clock time
func (s *Stopwatch) Start() {
	s.t = time.Now()
}

// Stops counting elapsed wall-clock time
func (s *Stopwatch) Stop() {
	s.acc = time.Since(s.t)
}

// Equivalent to s.Stop(); s2.Start() with no time elapsed between,
// just using one time stamp.
func (s *Stopwatch) Handover(s2 *Stopwatch) {
	s2.t = time.Now()
	s.acc = s.t.Sub(s2.t)
}

// Takes a snapshot of a currently running stopwatch. If the stopwatch
// wasn't running the result is undefined.
func (s *Stopwatch) Snapshot() Stopwatch {
	ret := *s
	ret.Stop()
	return ret
}

// Reset the accumulated time in the stopwatch and
func (s *Stopwatch) Reset() {
	*s = Stopwatch{}
}

// Returns the accumulated sanoseconds of the stopwatch. If the stopwatch
// is currently running that will not be accounted for.
func (s Stopwatch) Nanoseconds() int64 {
	return s.acc.Nanoseconds()
}

// Returns the accumulated seconds of the stopwatch. If the stopwatch is
// currently running that will not be accounted for.
func (s Stopwatch) Seconds() float64 {
	return s.acc.Seconds()
}

func (s Stopwatch) String() string {
	return s.acc.String()
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"hash"
	"io"
	"log"
	"os"
	"regexp"
	"strings"
	"sync"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/cavaliercoder/grab"
	ui "github.com/gizak/termui"
	"github.com/mholt/archiver"
	"github.com/olekukonko/tablewriter"
)

const (
	viewGoVersions = "goversions"
	viewGoFiles    = "gofiles"
)

var mutex = &sync.Mutex{}

var viewInFocus = viewGoFiles
var selectedGoVersion = 0
var selectedGoFile = 0

var goVersions []string
var goFiles []string
var doc *goquery.Document
var downloadFileLinks = make(map[string]string)
var downloadFileSHA = make(map[string]string)

var uiVersionsList = ui.NewList()
var uiFilesList = ui.NewList()

//var uiInfo = ui.NewPar("Info")
var uiInfo = ui.NewList()
var uiDownloadProgress = ui.NewGauge()
var uiDownloadSpeed = ui.NewSparklines()

func getGolangData(url string) {
	var err error
	doc, err = goquery.NewDocument(url)
	if err != nil {
		log.Fatal(err)
	}

	r, err := regexp.Compile("([a-zA-Z0-9.]+)")
	if err != nil {
		log.Fatal(err)
	}

	goVersions = nil
	doc.Find("div .expanded > h2").Each(func(i int, s *goquery.Selection) {
		goVersions = append(goVersions, r.FindString(s.Text()))
	})
}

func updateGoVersions() {
	var strs []string

	checkLimits()

	for index, s := range goVersions {
		if index == selectedGoVersion {
			strs = append(strs, fmt.Sprintf("[%s](fg-white,bg-green)", s))
		} else {
			strs = append(strs, fmt.Sprintf("%s", s))
		}
	}
	uiVersionsList.Items = strs
}

func addLoggingText(text string) {
	uiInfo.Items = append(uiInfo.Items, text)
	height := uiInfo.GetHeight()
	startPosition := len(uiInfo.Items) - height + 2
	if startPosition < 0 {
		startPosition = 0
	}
	uiInfo.Items = uiInfo.Items[startPosition:]

}

func downloadFile(url string) error {

	addLoggingText(fmt.Sprintf("Downloading %s...\n", url))
	respch, err := grab.GetAsync(".", url)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error downloading %s: %v\n", url, err)
		os.Exit(1)
	}

	addLoggingText(fmt.Sprintf("Initializing download...\n"))

	uiDownloadProgress.Percent = 0

	var resp *grab.Response

	go func() {
		t := time.NewTicker(100 * time.Millisecond)
		var sinceLastTime uint64
		var spdata []int
		for {
			select {
			case r := <-respch:
				if r != nil {
					resp = r
					addLoggingText(fmt.Sprintf("Downloading...\n"))
				}
			case <-t.C:
				if resp == nil {
					continue
				}
				if resp.Error != nil {
					fmt.Fprintf(os.Stderr, "Error downloading %s: %v\n", url, resp.Error)
					//return resp.Error
					return
				}
				if resp.IsComplete() {
					addLoggingText(fmt.Sprintf("Successfully downloaded to ./%s\n", resp.Filename))

					uiDownloadProgress.Percent = 100

					addLoggingText("Verifying...\n")
					sha := downloadFileSHA[getGoFile()]

					var hasher hash.Hash
					if len(sha) == 64 {
						hasher = sha256.New()
					} else if len(sha) == 40 {
						hasher = sha1.New()
					} else {
						addLoggingText(fmt.Sprintf("Unknown hash length of %d.\n", len(sha)))
						return
					}

					f, err := os.Open(resp.Filename)
					if err != nil {
						addLoggingText(fmt.Sprintf(err.Error()))
						return
					}
					defer f.Close()

					if _, err := io.Copy(hasher, f); err != nil {
						addLoggingText(fmt.Sprintf(err.Error()))
						return
					}
					fileSHA := hex.EncodeToString(hasher.Sum(nil))

					if sha != fileSHA {
						addLoggingText("Download file doesn't match SHA.\n")
						addLoggingText(fmt.Sprintf("File SHA: %s\nExpected SHA:\n%s\n", fileSHA, sha))
						return
					}

					addLoggingText(fmt.Sprintf("File SHA matches: %s\n", fileSHA))

					addLoggingText(fmt.Sprintf("Extracting...\n"))
					if strings.Contains(resp.Filename, ".zip") {
						archiver.Zip.Open(resp.Filename, ".")
					} else if strings.Contains(resp.Filename, ".tar.gz") {
						archiver.TarGz.Open(resp.Filename, ".")
					}
					os.Rename("go", getGoVersion())
					addLoggingText(fmt.Sprintf("Done extracting.\n"))
					t.Stop()
					return
				}

				uiDownloadProgress.Percent = int(100 * resp.Progress())

				thisTime := resp.BytesTransferred() - sinceLastTime
				sinceLastTime = resp.BytesTransferred()
				spdata = append(spdata, int(thisTime))
				uiDownloadSpeed.Lines[0].Data = spdata
			}
		}
	}()
	return nil
}

func updateFilesView(s string) error {
	var err error

	var b bytes.Buffer
	table := tablewriter.NewWriter(&b)

	var headers []string
	var data [][]string
	goFiles = nil
	doc.Find("div[id=\"" + strings.TrimSpace(s) + "\"] > .expanded > table > thead > tr > th").Each(func(i int, s *goquery.Selection) {
		headers = append(headers, s.Text())
	})

	doc.Find("div[id=\"" + strings.TrimSpace(s) + "\"] > .expanded > table > tbody > tr").Each(func(i int, tr *goquery.Selection) {
		var row []string
		var a *goquery.Selection
		tr.Find("td").Each(func(i int, td *goquery.Selection) {

			if a == nil {
				a = td.Find("a")
			}
			if link, exists := a.Attr("href"); exists {
				downloadFileLinks[a.Text()] = link
			}

			tt := td.Find("tt")
			if tt != nil && a != nil {
				downloadFileSHA[a.Text()] = tt.Text()
			}
			row = append(row, td.Text())
		})
		if len(row) > 0 {
			goFiles = append(goFiles, row[0])
		}
		data = append(data, row)
	})
	table.SetHeader(headers)
	//table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
	table.SetBorder(false)
	//table.SetCenterSeparator("|")
	table.AppendBulk(data)
	table.Render()

	checkLimits()

	strs := strings.Split(b.String(), "\n")

	for index, s := range strs {
		if index == selectedGoFile+2 { // +2 To skip headers.
			strs[index] = "[" + strings.TrimRight(s, "\n") + "](fg-white,bg-blue)\n"
			break
		}
	}

	uiFilesList.Items = strs

	return err
}

func getGoVersion() string {
	return goVersions[selectedGoVersion]
}

func getGoFile() string {
	return goFiles[selectedGoFile]
}

func checkLimits() {
	if selectedGoVersion < 0 {
		selectedGoVersion = 0
	} else if selectedGoVersion >= len(goVersions) {
		selectedGoVersion = len(goVersions) - 1
	}

	if selectedGoFile < 0 {
		selectedGoFile = 0
	} else if selectedGoFile >= len(goFiles) {
		selectedGoFile = len(goFiles) - 1
	}
}

func main() {

	url := "https://golang.org/dl/"
	log.Printf("Getting data from %s...\n", url)
	getGolangData(url)

	if err := ui.Init(); err != nil {
		panic(err)
	}
	defer ui.Close()

	spark := ui.NewSparkline()
	spark.Height = 8
	spark.LineColor = ui.ColorCyan
	spark.TitleColor = ui.ColorWhite

	uiDownloadSpeed.Add(spark)
	uiDownloadSpeed.Height = 11
	uiDownloadSpeed.BorderLabel = "Download Speed"

	uiFilesList.Height = len(goVersions) + 2
	uiFilesList.BorderLabel = "Go Files"
	uiFilesList.Width = 20
	uiFilesList.Border = true

	uiInfo.BorderLabel = "Info Panel"
	uiInfo.Items = []string{"Ready."}
	//uiInfo.Text = "Ready.\n"
	uiInfo.Height = 14

	updateFilesView(getGoVersion())

	uiDownloadProgress.LabelAlign = ui.AlignCenter
	uiDownloadProgress.Height = 3
	uiDownloadProgress.Border = true
	uiDownloadProgress.BorderLabel = "Download Progress"
	uiDownloadProgress.BarColor = ui.ColorRed

	updateGoVersions()
	uiVersionsList.BorderLabel = "Go Versions"
	uiVersionsList.Height = len(goVersions) + 2
	uiVersionsList.Width = 10

	// build layout
	ui.Body.AddRows(
		ui.NewRow(
			ui.NewCol(2, 0, uiVersionsList),
			ui.NewCol(10, 0, uiFilesList)),
		ui.NewRow(
			ui.NewCol(6, 0, uiDownloadProgress, uiDownloadSpeed),
			ui.NewCol(6, 0, uiInfo)))

	// calculate layout
	ui.Body.Align()

	ui.Merge("timer", ui.NewTimerCh(10*time.Millisecond))
	ui.Render(ui.Body)

	ui.Handle("/sys/kbd/q", func(ui.Event) {
		ui.StopLoop()
	})
	ui.Handle("/sys/kbd/Q", func(ui.Event) {
		ui.StopLoop()
	})
	ui.Handle("/sys/kbd/C-c", func(ui.Event) {
		ui.StopLoop()
	})
	ui.Handle("/sys/kbd/<up>", func(ui.Event) {
		mutex.Lock()
		defer mutex.Unlock()
		if viewInFocus == viewGoFiles {
			selectedGoFile--
			updateFilesView(getGoVersion())
		} else if viewInFocus == viewGoVersions {
			selectedGoVersion--
			updateGoVersions()
			updateFilesView(getGoVersion())
		}
	})
	ui.Handle("/sys/kbd/<enter>", func(ui.Event) {
		downloadFile(downloadFileLinks[getGoFile()])
	})
	ui.Handle("/sys/kbd/<down>", func(ui.Event) {
		mutex.Lock()
		defer mutex.Unlock()
		if viewInFocus == viewGoFiles {
			selectedGoFile++
			checkLimits()
			updateFilesView(getGoVersion())
		} else if viewInFocus == viewGoVersions {
			selectedGoVersion++
			checkLimits()
			updateGoVersions()
			updateFilesView(getGoVersion())
		}
	})
	ui.Handle("/sys/kbd/<tab>", func(ui.Event) {
		if viewInFocus == viewGoFiles {
			viewInFocus = viewGoVersions
			uiFilesList.BorderLabelBg = ui.ColorDefault
			//uiFilesList.BorderLabelFg = ui.ColorGreen
			uiVersionsList.BorderLabelBg = ui.ColorWhite
		} else if viewInFocus == viewGoVersions {
			viewInFocus = viewGoFiles
			uiFilesList.BorderLabelBg = ui.ColorWhite
			//uiFilesList.BorderLabelFg = ui.ColorBlack
			//uiVersionsList.BorderLabelFg = ui.ColorGreen
			uiVersionsList.BorderLabelBg = ui.ColorDefault
		}
	})
	ui.Handle("/timer/", func(e ui.Event) {
		ui.Render(ui.Body)
	})

	ui.Handle("/sys/wnd/resize", func(e ui.Event) {
		ui.Body.Width = ui.TermWidth()
		ui.Body.Align()
		ui.Clear()
		ui.Render(ui.Body)
	})

	uiFilesList.BorderLabelBg = ui.ColorWhite
	ui.Loop()
}
<commit_msg>Minor refactoring.<commit_after>package main

import (
	"bytes"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"hash"
	"io"
	"log"
	"os"
	"regexp"
	"strings"
	"sync"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/cavaliercoder/grab"
	ui "github.com/gizak/termui"
	"github.com/mholt/archiver"
	"github.com/olekukonko/tablewriter"
)

const (
	viewGoVersions = "goversions"
	viewGoFiles    = "gofiles"
)

var mutex = &sync.Mutex{}

var viewInFocus = viewGoFiles
var selectedGoVersion = 0
var selectedGoFile = 0

var goVersions []string
var goFiles []string
var doc *goquery.Document
var downloadFileLinks = make(map[string]string)
var downloadFileSHA = make(map[string]string)

var uiVersionsList = ui.NewList()
var uiFilesList = ui.NewList()

//var uiInfo = ui.NewPar("Info")
var uiInfo = ui.NewList()
var uiDownloadProgress = ui.NewGauge()
var uiDownloadSpeed = ui.NewSparklines()

func getGolangData(url string) {
	var err error
	doc, err = goquery.NewDocument(url)
	if err != nil {
		log.Fatal(err)
	}

	r, err := regexp.Compile("([a-zA-Z0-9.]+)")
	if err != nil {
		log.Fatal(err)
	}

	goVersions = nil
	doc.Find("div .expanded > h2").Each(func(i int, s *goquery.Selection) {
		goVersions = append(goVersions, r.FindString(s.Text()))
	})
}

func updateGoVersions() {
	var strs []string

	checkLimits()

	for index, s := range goVersions {
		if index == selectedGoVersion {
			strs = append(strs, fmt.Sprintf("[%s](fg-white,bg-green)", s))
		} else {
			strs = append(strs, fmt.Sprintf("%s", s))
		}
	}

	uiVersionsList.Items = strs
}

func addTextToInfoPanel(text string) {
	uiInfo.Items = append(uiInfo.Items, text)
	height := uiInfo.GetHeight()
	startPosition := len(uiInfo.Items) - height + 2
	if startPosition < 0 {
		startPosition = 0
	}

	uiInfo.Items = uiInfo.Items[startPosition:]
}

func downloadFile(url string) error {

	addTextToInfoPanel(fmt.Sprintf("Downloading %s...\n", url))
	respch, err := grab.GetAsync(".", url)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error downloading %s: %v\n", url, err)
		os.Exit(1)
	}

	addTextToInfoPanel(fmt.Sprintf("Initializing download...\n"))

	uiDownloadProgress.Percent = 0

	go func() {
		var resp *grab.Response
		t := time.NewTicker(100 * time.Millisecond)
		var sinceLastTime uint64
		var spdata []int
		for {
			select {
			case r := <-respch:
				if r != nil {
					resp = r
					addTextToInfoPanel(fmt.Sprintf("Downloading...\n"))
				}
			case <-t.C:

				if resp == nil {
					continue
				}

				if resp.Error != nil {
					fmt.Fprintf(os.Stderr, "Error downloading %s: %v\n", url, resp.Error)
					//return resp.Error
					return
				}

				if resp.IsComplete() {
					addTextToInfoPanel(fmt.Sprintf("Successfully downloaded to ./%s\n", resp.Filename))

					uiDownloadProgress.Percent = 100

					addTextToInfoPanel("Verifying...\n")
					sha := downloadFileSHA[getGoFile()]

					var hasher hash.Hash
					if len(sha) == 64 {
						hasher = sha256.New()
					} else if len(sha) == 40 {
						hasher = sha1.New()
					} else {
						addTextToInfoPanel(fmt.Sprintf("Unknown hash length of %d.\n", len(sha)))
						return
					}

					f, err := os.Open(resp.Filename)
					if err != nil {
						addTextToInfoPanel(fmt.Sprintf(err.Error()))
						return
					}
					defer f.Close()

					if _, err := io.Copy(hasher, f); err != nil {
						addTextToInfoPanel(fmt.Sprintf(err.Error()))
						return
					}

					fileSHA := hex.EncodeToString(hasher.Sum(nil))
					if sha != fileSHA {
						addTextToInfoPanel("Download file doesn't match SHA.\n")
						addTextToInfoPanel(fmt.Sprintf("File SHA: %s\nExpected SHA:\n%s\n", fileSHA, sha))
						return
					}

					addTextToInfoPanel(fmt.Sprintf("File SHA matches: %s\n", fileSHA))

					addTextToInfoPanel(fmt.Sprintf("Extracting...\n"))

					if strings.Contains(resp.Filename, ".zip") {
						archiver.Zip.Open(resp.Filename, ".")
					} else if strings.Contains(resp.Filename, ".tar.gz") {
						archiver.TarGz.Open(resp.Filename, ".")
					}

					os.Rename("go", getGoVersion())

					addTextToInfoPanel(fmt.Sprintf("Done extracting.\n"))

					t.Stop()

					return
				}

				uiDownloadProgress.Percent = int(100 * resp.Progress())

				thisTime := resp.BytesTransferred() - sinceLastTime
				sinceLastTime = resp.BytesTransferred()
				spdata = append(spdata, int(thisTime))
				uiDownloadSpeed.Lines[0].Data = spdata
			}
		}
	}()

	return nil
}

func updateFilesView(s string) error {
	var err error
	var b bytes.Buffer
	var headers []string
	var data [][]string

	goFiles = nil

	table := tablewriter.NewWriter(&b)
	doc.Find("div[id=\"" + strings.TrimSpace(s) + "\"] > .expanded > table > thead > tr > th").Each(func(i int, s *goquery.Selection) {
		headers = append(headers, s.Text())
	})

	doc.Find("div[id=\"" + strings.TrimSpace(s) + "\"] > .expanded > table > tbody > tr").Each(func(i int, tr *goquery.Selection) {
		var row []string
		var a *goquery.Selection
		tr.Find("td").Each(func(i int, td *goquery.Selection) {

			if a == nil {
				a = td.Find("a")
			}
			if link, exists := a.Attr("href"); exists {
				downloadFileLinks[a.Text()] = link
			}

			tt := td.Find("tt")
			if tt != nil && a != nil {
				downloadFileSHA[a.Text()] = tt.Text()
			}
			row = append(row, td.Text())
		})
		if len(row) > 0 {
			goFiles = append(goFiles, row[0])
		}
		data = append(data, row)
	})

	table.SetHeader(headers)
	//table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
	table.SetBorder(false)
	//table.SetCenterSeparator("|")
	table.AppendBulk(data)
	table.Render()

	checkLimits()

	strs := strings.Split(b.String(), "\n")
	for index, s := range strs {
		if index == selectedGoFile+2 { // +2 To skip headers.
			strs[index] = "[" + strings.TrimRight(s, "\n") + "](fg-white,bg-blue)\n"
			break
		}
	}

	uiFilesList.Items = strs

	return err
}

func getGoVersion() string {
	return goVersions[selectedGoVersion]
}

func getGoFile() string {
	return goFiles[selectedGoFile]
}

func checkLimits() {
	if selectedGoVersion < 0 {
		selectedGoVersion = 0
	} else if selectedGoVersion >= len(goVersions) {
		selectedGoVersion = len(goVersions) - 1
	}

	if selectedGoFile < 0 {
		selectedGoFile = 0
	} else if selectedGoFile >= len(goFiles) {
		selectedGoFile = len(goFiles) - 1
	}
}

func updateViewInFocus() {
	if viewInFocus == viewGoFiles {
		uiFilesList.BorderLabelBg = ui.ColorWhite
		//uiFilesList.BorderLabelFg = ui.ColorBlack
		//uiVersionsList.BorderLabelFg = ui.ColorGreen
		uiVersionsList.BorderLabelBg = ui.ColorDefault
	} else if viewInFocus == viewGoVersions {
		uiFilesList.BorderLabelBg = ui.ColorDefault
		//uiFilesList.BorderLabelFg = ui.ColorGreen
		uiVersionsList.BorderLabelBg = ui.ColorWhite
	}
}

func main() {

	url := "https://golang.org/dl/"
	log.Printf("Getting data from %s...\n", url)
	getGolangData(url)

	if err := ui.Init(); err != nil {
		panic(err)
	}
	defer ui.Close()

	spark := ui.NewSparkline()
	spark.Height = 8
	spark.LineColor = ui.ColorCyan
	spark.TitleColor = ui.ColorWhite

	uiDownloadSpeed.Add(spark)
	uiDownloadSpeed.Height = 11
	uiDownloadSpeed.BorderLabel = "Download Speed"

	uiFilesList.Height = len(goVersions) + 2
	uiFilesList.BorderLabel = "Go Files"
	uiFilesList.Width = 20
	uiFilesList.Border = true

	uiInfo.BorderLabel = "Info Panel"
	uiInfo.Items = []string{"Ready."}
	//uiInfo.Text = "Ready.\n"
	uiInfo.Height = 14

	updateFilesView(getGoVersion())

	uiDownloadProgress.LabelAlign = ui.AlignCenter
	uiDownloadProgress.Height = 3
	uiDownloadProgress.Border = true
	uiDownloadProgress.BorderLabel = "Download Progress"
	uiDownloadProgress.BarColor = ui.ColorRed

	updateGoVersions()
	uiVersionsList.BorderLabel = "Go Versions"
	uiVersionsList.Height = len(goVersions) + 2
	uiVersionsList.Width = 10

	// build layout
	ui.Body.AddRows(
		ui.NewRow(
			ui.NewCol(2, 0, uiVersionsList),
			ui.NewCol(10, 0, uiFilesList)),
		ui.NewRow(
			ui.NewCol(6, 0, uiDownloadProgress, uiDownloadSpeed),
			ui.NewCol(6, 0, uiInfo)))

	// calculate layout
	ui.Body.Align()

	ui.Merge("timer", ui.NewTimerCh(10*time.Millisecond))
	ui.Render(ui.Body)

	ui.Handle("/sys/kbd/q", func(ui.Event) {
		ui.StopLoop()
	})
	ui.Handle("/sys/kbd/Q", func(ui.Event) {
		ui.StopLoop()
	})
	ui.Handle("/sys/kbd/C-c", func(ui.Event) {
		ui.StopLoop()
	})
	ui.Handle("/sys/kbd/<up>", func(ui.Event) {
		mutex.Lock()
		defer mutex.Unlock()
		if viewInFocus == viewGoFiles {
			selectedGoFile--
			updateFilesView(getGoVersion())
		} else if viewInFocus == viewGoVersions {
			selectedGoVersion--
			updateGoVersions()
			updateFilesView(getGoVersion())
		}
	})
	ui.Handle("/sys/kbd/<enter>", func(ui.Event) {
		downloadFile(downloadFileLinks[getGoFile()])
	})
	ui.Handle("/sys/kbd/<down>", func(ui.Event) {
		mutex.Lock()
		defer mutex.Unlock()
		if viewInFocus == viewGoFiles {
			selectedGoFile++
			updateFilesView(getGoVersion())
		} else if viewInFocus == viewGoVersions {
			selectedGoVersion++
			updateGoVersions()
			updateFilesView(getGoVersion())
		}
	})
	ui.Handle("/sys/kbd/<tab>", func(ui.Event) {
		if viewInFocus == viewGoFiles {
			viewInFocus = viewGoVersions
		} else if viewInFocus == viewGoVersions {
			viewInFocus = viewGoFiles
		}
		updateViewInFocus()
	})
	ui.Handle("/timer/", func(e ui.Event) {
		ui.Render(ui.Body)
	})
	ui.Handle("/sys/wnd/resize", func(e ui.Event) {
		ui.Body.Width = ui.TermWidth()
		ui.Body.Align()
		ui.Clear()
		ui.Render(ui.Body)
	})

	updateViewInFocus()

	ui.Loop()
}
<|endoftext|>


<commit_before>package sms

const (
	URI         = "https://sms-rassilka.com/api/simple"
	defaultFrom = "inform"

	// Successful delivery statuses.
	StatusQueued    = "0"
	StatusSent      = "1"
	StatusDelivered = "3"

	// Unsuccessful delivery statuses.
	StatusUndeliveredUnavailable = "4"
	StatusUndeliveredSpam        = "15"
	StatusUndeliveredInvPhone    = "16"

	// TODO: Other delivery statuses.
)

// Sender is an object for sending SMS.
type Sender struct {
	Login    string
	Password string
	DevMode  bool
}

// DeliveryStatus represents a delivery status. If you need an exact status, compare with constants above.
type DeliveryStatus string

// IsInProcess tells if a message is still being processed.
func (d DeliveryStatus) IsInProcess() bool {
	return d == StatusQueued || d == StatusSent
}

// IsDelivered tells if a message has in fact been delivered.
func (d DeliveryStatus) IsDelivered() bool {
	return d == StatusDelivered
}

// IsUndelivered tells if a message has been processed and undelivered by any reason.
func (d DeliveryStatus) IsUndelivered() bool {
	return d == StatusUndeliveredUnavailable || d == StatusUndeliveredSpam || d == StatusUndeliveredInvPhone
}
<commit_msg>IsInProcess -> IsInProgress<commit_after>package sms

const (
	URI         = "https://sms-rassilka.com/api/simple"
	defaultFrom = "inform"

	// Successful delivery statuses.
	StatusQueued    = "0"
	StatusSent      = "1"
	StatusDelivered = "3"

	// Unsuccessful delivery statuses.
	StatusUndeliveredUnavailable = "4"
	StatusUndeliveredSpam        = "15"
	StatusUndeliveredInvPhone    = "16"

	// TODO: Other delivery statuses.
)

// Sender is an object for sending SMS.
type Sender struct {
	Login    string
	Password string
	DevMode  bool
}

// DeliveryStatus represents a delivery status. If you need an exact status, compare with constants above.
type DeliveryStatus string

// IsInProgress tells if a message is still being processed.
func (d DeliveryStatus) IsInProgress() bool {
	return d == StatusQueued || d == StatusSent
}

// IsDelivered tells if a message has in fact been delivered.
func (d DeliveryStatus) IsDelivered() bool {
	return d == StatusDelivered
}

// IsUndelivered tells if a message has been processed and undelivered by any reason.
func (d DeliveryStatus) IsUndelivered() bool {
	return d == StatusUndeliveredUnavailable || d == StatusUndeliveredSpam || d == StatusUndeliveredInvPhone
}
<|endoftext|>


<commit_before>package goesi

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"sync"

	"context"

	"golang.org/x/oauth2"
)

// SSOAuthenticator provides interfacing to the EVE SSO. NewSSOAuthenticator is used to create
// this structure.

// [TODO] lose this mutex and allow scopes to change without conflict.
type SSOAuthenticator struct {
	httpClient *http.Client
	// Hide this...
	oauthConfig *oauth2.Config
	scopeLock   sync.Mutex
}

// NewSSOAuthenticator create a new EVE SSO Authenticator.
// Requires your application clientID, clientSecret, and redirectURL.
// RedirectURL must match exactly to what you registered with CCP.
func NewSSOAuthenticator(client *http.Client, clientID string, clientSecret string, redirectURL string, scopes []string) *SSOAuthenticator {

	if client == nil {
		return nil
	}

	c := &SSOAuthenticator{}

	c.httpClient = client

	c.oauthConfig = &oauth2.Config{
		ClientID:     clientID,
		ClientSecret: clientSecret,
		Endpoint: oauth2.Endpoint{
			AuthURL:  "https://login.eveonline.com/oauth/authorize",
			TokenURL: "https://login.eveonline.com/oauth/token",
		},
		Scopes:      scopes,
		RedirectURL: redirectURL,
	}

	return c
}

// ChangeAuthURL changes the oauth2 configuration url for authentication
func (c *SSOAuthenticator) ChangeAuthURL(url string) {
	c.oauthConfig.Endpoint.AuthURL = url
}

// ChangeTokenURL changes the oauth2 configuration url for token
func (c *SSOAuthenticator) ChangeTokenURL(url string) {
	c.oauthConfig.Endpoint.TokenURL = url
}

// AuthorizeURL returns a url for an end user to authenticate with EVE SSO
// and return success to the redirectURL.
// It is important to create a significatly unique state for this request
// and verify the state matches when returned to the redirectURL.
func (c *SSOAuthenticator) AuthorizeURL(state string, onlineAccess bool, scopes []string) string {
	var url string

	// Generate the URL
	if onlineAccess == true {
		url = c.oauthConfig.AuthCodeURL(state, oauth2.AccessTypeOnline, oauth2.SetAuthURLParam("scope", strings.Join(scopes, " ")))
	} else {
		url = c.oauthConfig.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.SetAuthURLParam("scope", strings.Join(scopes, " ")))
	}

	return url
}

// TokenRevoke revokes a refresh token
func (c *SSOAuthenticator) TokenRevoke(refreshToken string) error {
	v := url.Values{
		"token_type_hint": {"refresh_token"},
		"token":           {refreshToken},
	}
	req, err := http.NewRequest("POST", "https://login.eveonline.com/oauth/revoke", strings.NewReader(v.Encode()))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	req.Header.Set("Authorization",
		"Basic "+base64.URLEncoding.EncodeToString(
			[]byte(c.oauthConfig.ClientID+":"+c.oauthConfig.ClientSecret),
		))

	r, err := c.httpClient.Do(req)
	if err != nil {
		return err
	}
	defer r.Body.Close()
	body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20))
	if err != nil {
		return fmt.Errorf("oauth2: cannot revoke token: %v", err)
	}
	if code := r.StatusCode; code < 200 || code > 299 {
		return &oauth2.RetrieveError{
			Response: r,
			Body:     body,
		}
	}
	return nil
}

// TokenExchange exchanges the code returned to the redirectURL with
// the CREST server to an access token. A caching client must be passed.
// This client MUST cache per CCP guidelines or face banning.
func (c *SSOAuthenticator) TokenExchange(code string) (*oauth2.Token, error) {
	tok, err := c.oauthConfig.Exchange(createContext(c.httpClient), code)
	if err != nil {
		return nil, err
	}
	return tok, nil
}

// TokenSource creates a refreshable token that can be passed to ESI functions
func (c *SSOAuthenticator) TokenSource(token *oauth2.Token) (oauth2.TokenSource, error) {
	return c.oauthConfig.TokenSource(createContext(c.httpClient), token), nil
}

type VerifyResponse struct {
	CharacterID        int32
	CharacterName      string
	ExpiresOn          string
	Scopes             string
	TokenType          string
	CharacterOwnerHash string
}

// Verify the client and collect user information.
func (c *SSOAuthenticator) Verify(auth oauth2.TokenSource) (*VerifyResponse, error) {
	v := &VerifyResponse{}
	_, err := c.doJSON("GET", "https://login.eveonline.com/oauth/verify", nil, v, "application/json;", auth)

	if err != nil {
		return nil, err
	}
	return v, nil
}

// Creates a new http.Request for a public resource.
func (c *SSOAuthenticator) newRequest(method, urlStr string, body interface{}, mediaType string) (*http.Request, error) {
	rel, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	buf := new(bytes.Buffer)
	if body != nil {
		err = json.NewEncoder(buf).Encode(body)
		if err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, rel.String(), buf)
	if err != nil {
		return nil, err
	}

	return req, nil
}

// Calls a resource from the public CREST
func (c *SSOAuthenticator) doJSON(method, urlStr string, body interface{}, v interface{}, mediaType string, auth oauth2.TokenSource) (*http.Response, error) {

	req, err := c.newRequest(method, urlStr, body, mediaType)
	if err != nil {
		return nil, err
	}

	if auth != nil {
		// We were able to grab an oauth2 token from the context
		var latestToken *oauth2.Token
		if latestToken, err = auth.Token(); err != nil {
			return nil, err
		}
		latestToken.SetAuthHeader(req)
	}

	res, err := c.executeRequest(req)
	if err != nil {
		return nil, err
	}

	defer res.Body.Close()
	buf, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	if res.StatusCode != http.StatusOK {
		return nil, errors.New(string(buf))
	}
	if err := json.Unmarshal([]byte(buf), v); err != nil {
		return nil, err
	}

	return res, nil
}

// Executes a request generated with newRequest
func (c *SSOAuthenticator) executeRequest(req *http.Request) (*http.Response, error) {
	res, err := c.httpClient.Do(req)

	if err != nil {
		return nil, err
	}
	if res.StatusCode == http.StatusOK ||
		res.StatusCode == http.StatusCreated {
		return res, nil
	}
	return res, errors.New(res.Status)
}

// Add custom clients to the context.
func createContext(httpClient *http.Client) context.Context {
	parent := oauth2.NoContext
	ctx := context.WithValue(parent, oauth2.HTTPClient, httpClient)
	return ctx
}

// TokenToJSON helper function to convert a token to a storable format.
func TokenToJSON(token *oauth2.Token) (string, error) {
	if d, err := json.Marshal(token); err != nil {
		return "", err
	} else {
		return string(d), nil
	}
}

// TokenFromJSON helper function to convert stored JSON to a token.
func TokenFromJSON(jsonStr string) (*oauth2.Token, error) {
	var token oauth2.Token
	if err := json.Unmarshal([]byte(jsonStr), &token); err != nil {
		return nil, err
	}
	return &token, nil
}
<commit_msg>[feat] support v2 sso endpoints<commit_after>package goesi

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"sync"

	"context"

	"golang.org/x/oauth2"
)

// SSOAuthenticator provides interfacing to the EVE SSO. NewSSOAuthenticator is used to create
// this structure.

// [TODO] lose this mutex and allow scopes to change without conflict.
type SSOAuthenticator struct {
	httpClient *http.Client
	// Hide this...
	oauthConfig *oauth2.Config
	scopeLock   sync.Mutex
}

// NewSSOAuthenticator create a new EVE SSO Authenticator.
// Requires your application clientID, clientSecret, and redirectURL.
// RedirectURL must match exactly to what you registered with CCP.
func NewSSOAuthenticator(client *http.Client, clientID string, clientSecret string, redirectURL string, scopes []string) *SSOAuthenticator {
	return newSSOAuthenticator(
		client,
		clientID,
		clientSecret,
		redirectURL,
		scopes,
		oauth2.Endpoint{
			AuthURL:  "https://login.eveonline.com/oauth/authorize",
			TokenURL: "https://login.eveonline.com/oauth/token",
		},
	)
}

// NewSSOAuthenticatorV2 create a new EVE SSO Authenticator with the v2 urls.
// Requires your application clientID, clientSecret, and redirectURL.
// RedirectURL must match exactly to what you registered with CCP.
func NewSSOAuthenticatorV2(client *http.Client, clientID string, clientSecret string, redirectURL string, scopes []string) *SSOAuthenticator {
	return newSSOAuthenticator(
		client,
		clientID,
		clientSecret,
		redirectURL,
		scopes,
		oauth2.Endpoint{
			AuthURL:  "https://login.eveonline.com/v2/oauth/authorize",
			TokenURL: "https://login.eveonline.com/v2/oauth/token",
		},
	)
}

func newSSOAuthenticator(client *http.Client, clientID string, clientSecret string, redirectURL string, scopes []string, endpoint oauth2.Endpoint) *SSOAuthenticator {
	if client == nil {
		return nil
	}

	c := &SSOAuthenticator{}
	c.httpClient = client
	c.oauthConfig = &oauth2.Config{
		ClientID:     clientID,
		ClientSecret: clientSecret,
		Endpoint:     endpoint,
		Scopes:       scopes,
		RedirectURL:  redirectURL,
	}

	return c
}

// ChangeAuthURL changes the oauth2 configuration url for authentication
func (c *SSOAuthenticator) ChangeAuthURL(url string) {
	c.oauthConfig.Endpoint.AuthURL = url
}

// ChangeTokenURL changes the oauth2 configuration url for token
func (c *SSOAuthenticator) ChangeTokenURL(url string) {
	c.oauthConfig.Endpoint.TokenURL = url
}

// AuthorizeURL returns a url for an end user to authenticate with EVE SSO
// and return success to the redirectURL.
// It is important to create a significatly unique state for this request
// and verify the state matches when returned to the redirectURL.
func (c *SSOAuthenticator) AuthorizeURL(state string, onlineAccess bool, scopes []string) string {
	var url string

	// Generate the URL
	if onlineAccess == true {
		url = c.oauthConfig.AuthCodeURL(state, oauth2.AccessTypeOnline, oauth2.SetAuthURLParam("scope", strings.Join(scopes, " ")))
	} else {
		url = c.oauthConfig.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.SetAuthURLParam("scope", strings.Join(scopes, " ")))
	}

	return url
}

// TokenRevoke revokes a refresh token
func (c *SSOAuthenticator) TokenRevoke(refreshToken string) error {
	v := url.Values{
		"token_type_hint": {"refresh_token"},
		"token":           {refreshToken},
	}
	req, err := http.NewRequest("POST", "https://login.eveonline.com/oauth/revoke", strings.NewReader(v.Encode()))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	req.Header.Set("Authorization",
		"Basic "+base64.URLEncoding.EncodeToString(
			[]byte(c.oauthConfig.ClientID+":"+c.oauthConfig.ClientSecret),
		))

	r, err := c.httpClient.Do(req)
	if err != nil {
		return err
	}
	defer r.Body.Close()
	body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20))
	if err != nil {
		return fmt.Errorf("oauth2: cannot revoke token: %v", err)
	}
	if code := r.StatusCode; code < 200 || code > 299 {
		return &oauth2.RetrieveError{
			Response: r,
			Body:     body,
		}
	}
	return nil
}

// TokenExchange exchanges the code returned to the redirectURL with
// the CREST server to an access token. A caching client must be passed.
// This client MUST cache per CCP guidelines or face banning.
func (c *SSOAuthenticator) TokenExchange(code string) (*oauth2.Token, error) {
	tok, err := c.oauthConfig.Exchange(createContext(c.httpClient), code)
	if err != nil {
		return nil, err
	}
	return tok, nil
}

// TokenSource creates a refreshable token that can be passed to ESI functions
func (c *SSOAuthenticator) TokenSource(token *oauth2.Token) (oauth2.TokenSource, error) {
	return c.oauthConfig.TokenSource(createContext(c.httpClient), token), nil
}

type VerifyResponse struct {
	CharacterID        int32
	CharacterName      string
	ExpiresOn          string
	Scopes             string
	TokenType          string
	CharacterOwnerHash string
}

// Verify the client and collect user information.
func (c *SSOAuthenticator) Verify(auth oauth2.TokenSource) (*VerifyResponse, error) {
	v := &VerifyResponse{}
	_, err := c.doJSON("GET", "https://login.eveonline.com/oauth/verify", nil, v, "application/json;", auth)

	if err != nil {
		return nil, err
	}
	return v, nil
}

// Creates a new http.Request for a public resource.
func (c *SSOAuthenticator) newRequest(method, urlStr string, body interface{}, mediaType string) (*http.Request, error) {
	rel, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	buf := new(bytes.Buffer)
	if body != nil {
		err = json.NewEncoder(buf).Encode(body)
		if err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, rel.String(), buf)
	if err != nil {
		return nil, err
	}

	return req, nil
}

// Calls a resource from the public CREST
func (c *SSOAuthenticator) doJSON(method, urlStr string, body interface{}, v interface{}, mediaType string, auth oauth2.TokenSource) (*http.Response, error) {

	req, err := c.newRequest(method, urlStr, body, mediaType)
	if err != nil {
		return nil, err
	}

	if auth != nil {
		// We were able to grab an oauth2 token from the context
		var latestToken *oauth2.Token
		if latestToken, err = auth.Token(); err != nil {
			return nil, err
		}
		latestToken.SetAuthHeader(req)
	}

	res, err := c.executeRequest(req)
	if err != nil {
		return nil, err
	}

	defer res.Body.Close()
	buf, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	if res.StatusCode != http.StatusOK {
		return nil, errors.New(string(buf))
	}
	if err := json.Unmarshal([]byte(buf), v); err != nil {
		return nil, err
	}

	return res, nil
}

// Executes a request generated with newRequest
func (c *SSOAuthenticator) executeRequest(req *http.Request) (*http.Response, error) {
	res, err := c.httpClient.Do(req)

	if err != nil {
		return nil, err
	}
	if res.StatusCode == http.StatusOK ||
		res.StatusCode == http.StatusCreated {
		return res, nil
	}
	return res, errors.New(res.Status)
}

// Add custom clients to the context.
func createContext(httpClient *http.Client) context.Context {
	parent := oauth2.NoContext
	ctx := context.WithValue(parent, oauth2.HTTPClient, httpClient)
	return ctx
}

// TokenToJSON helper function to convert a token to a storable format.
func TokenToJSON(token *oauth2.Token) (string, error) {
	if d, err := json.Marshal(token); err != nil {
		return "", err
	} else {
		return string(d), nil
	}
}

// TokenFromJSON helper function to convert stored JSON to a token.
func TokenFromJSON(jsonStr string) (*oauth2.Token, error) {
	var token oauth2.Token
	if err := json.Unmarshal([]byte(jsonStr), &token); err != nil {
		return nil, err
	}
	return &token, nil
}
<|endoftext|>


<commit_before>package thegotribe

import (
	"encoding/json"
	"errors"
	"io"
	"log"
	"net"
	"os"
	"reflect"
	"strings"
	"time"
)

var logger = log.New(os.Stdout, "[thegotribe] ", log.LstdFlags)

type EyeTracker struct {
	conn       io.ReadWriteCloser
	enc        *json.Encoder
	dec        *json.Decoder
	incoming   chan Response
	heartbeats chan Response
	OnGaze     GazeFunc
}

func Create() (tracker *EyeTracker, err error) {
	conn, err := net.Dial("tcp", "localhost:6555")
	if err != nil {
		return
	}
	return New(conn), nil
}

func New(conn io.ReadWriteCloser) (tracker *EyeTracker) {
	tracker = &EyeTracker{
		conn:       conn,
		enc:        json.NewEncoder(conn),
		dec:        json.NewDecoder(conn),
		incoming:   make(chan Response, 10),
		heartbeats: make(chan Response),
		OnGaze:     NullFunc,
	}
	go tracker.readPackets()

	res, err := tracker.Get("heartbeatinterval")
	heartbeat := 250 * time.Millisecond
	if err == nil {
		requested := time.Duration(res.(float64)) * time.Millisecond
		if requested < heartbeat {
			heartbeat = requested / 2
		}
	}
	go tracker.heartbeat(heartbeat)

	tracker.Set("version", ProtocolVersion)
	tracker.Set("push", true)

	return
}

func (et *EyeTracker) Close() error {
	logger.Println("Closing tracker")
	return et.conn.Close()
}

func (et *EyeTracker) readPackets() {
	var res Response

	for {
		err := et.dec.Decode(&res)
		logger.Println("Raw:", res)
		if err != nil {
			logger.Println(err)
			close(et.incoming)
			close(et.heartbeats)
			return
		}

		if res.Category == CategoryHeartbeat {
			et.heartbeats <- res
		}

		if et.OnGaze == nil {
			logger.Println("OnGaze == nil")
		}

		if frame := res.Values.Frame; frame != nil && et.OnGaze != nil {
			logger.Println(frame)
			et.OnGaze(*frame)
			res.Values.Frame = nil // Handeled
		}
		if res.Values.StatusMessage != nil ||
			res.Values.Push != nil ||
			res.Values.HeartbeatInterval != nil ||
			res.Values.Version != nil ||
			res.Values.TrackerState != nil ||
			res.Values.Framerate != nil ||
			res.Values.ScreenIndex != nil ||
			res.Values.ScreenPsyW != nil ||
			res.Values.ScreenResW != nil ||
			res.Values.ScreenResH != nil ||
			res.Values.ScreenPsyH != nil {
			et.incoming <- res
		}
	}
}

func (et *EyeTracker) heartbeat(interval time.Duration) {
	ticker := time.NewTicker(interval)
	for _ = range ticker.C {
		err := et.enc.Encode(Request{
			Category: CategoryHeartbeat,
		})
		if err != nil {
			ticker.Stop()
		}
		<-et.heartbeats
	}
}

func (et *EyeTracker) Set(attribute string, value interface{}) error {
	et.SetAll(map[string]interface{}{
		attribute: value,
	})
	return nil
}

func (et *EyeTracker) SetAll(attributes map[string]interface{}) error {
	et.enc.Encode(Request{
		Category: CategoryTracker,
		Request:  "set",
		Values:   attributes,
	})
	res := <-et.incoming
	if res.StatusCode != OK {
		return res.StatusCode
	}
	return nil
}

func (et *EyeTracker) Get(attribute string) (interface{}, error) {
	res, err := et.GetAll(attribute)

	if err != nil {
		return nil, err
	} else {
		if val := reflect.ValueOf(res).Elem().FieldByNameFunc(func(name string) bool {
			return strings.ToLower(name) == attribute
		}); !val.IsNil() {
			return val.Elem().Interface(), nil
		}
		return nil, errors.New(*res.StatusMessage)
	}
}

func (et *EyeTracker) GetAll(attributes ...string) (*Values, error) {
	et.enc.Encode(Request{
		Category: CategoryTracker,
		Request:  "get",
		Values:   attributes,
	})

	result, ok := <-et.incoming
	if !ok {
		return nil, errors.New("End of Connection")
	}
	if result.StatusCode != OK {
		return &result.Values, result.StatusCode
	}

	return &result.Values, nil
}

type GazeFunc func(Frame)

func NullFunc(f Frame) {

}
<commit_msg>Appears to work now. Frame stream is examplified and tested in examples/tet-tracegaze.<commit_after>package thegotribe

import (
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"net"
	"reflect"
	"time"
)

var logger = log.New(ioutil.Discard, "[thegotribe] ", log.LstdFlags)

type EyeTracker struct {
	conn io.ReadWriteCloser
	enc  *json.Encoder
	dec  *json.Decoder

	Frames     chan Frame
	heartbeats chan Response
	sets       chan Response
	interests  map[string][]chan<- interface{}
}

func Create() (tracker *EyeTracker, err error) {
	conn, err := net.Dial("tcp", "localhost:6555")
	if err != nil {
		return
	}
	return New(conn), nil
}

func New(conn io.ReadWriteCloser) (tracker *EyeTracker) {
	tracker = &EyeTracker{
		conn: conn,
		enc:  json.NewEncoder(conn),
		dec:  json.NewDecoder(conn),

		Frames:     make(chan Frame, 1),
		heartbeats: make(chan Response),
		sets:       make(chan Response),
		interests:  make(map[string][]chan<- interface{}),
	}
	go tracker.readPackets()

	res, err := tracker.Get("heartbeatinterval")
	heartbeat := 250 * time.Millisecond
	if err == nil {
		requested := time.Duration(res.(float64)) * time.Millisecond
		if requested < heartbeat {
			heartbeat = requested / 2
		}
	}
	go tracker.heartbeat(heartbeat)

	tracker.Set("version", ProtocolVersion)
	tracker.Set("push", true)

	return
}

func (et *EyeTracker) Close() error {
	logger.Println("Closing tracker")
	return et.conn.Close()
}

func (et *EyeTracker) readPackets() {
	var res Response

	for {
		err := et.dec.Decode(&res)
		logger.Println("Raw:", res)
		if err != nil {
			logger.Println(err)
			close(et.heartbeats)
			close(et.Frames)
			return
		}

		if res.StatusCode != OK { // Deals with bad status codes
			continue
		}

		if res.Category == CategoryHeartbeat {
			et.heartbeats <- res
			continue
		}

		if res.Category == CategoryCalibration {
			// Not yet supported.
			continue
		}

		// Only res.Category == CategoryTracker possible at this point
		if res.Category != CategoryTracker {
			panic("Unknown category " + res.Category)
		}

		if res.Request == RequestSet {
			et.sets <- res
			continue
		}

		// Only res.Request == RequestGet possible at this point
		if res.Request != RequestGet {
			panic("Unknown request method " + res.Request)
		}

		if frame := res.Values.Frame; frame != nil {
			select {
			case et.Frames <- *frame:
			default: //Throw it away. Client is busy.
			}
			res.Values.Frame = nil // Handeled
		}

		// Deal with every other value of tracker
		val, typ := reflect.ValueOf(res.Values), reflect.TypeOf(res.Values)
		for i := 0; i < val.NumField(); i++ {
			if field := val.Field(i); !field.IsNil() {
				name := typ.Field(i).Tag.Get("json") // Only if value is present
				if list, ok := et.interests[name]; ok && len(list) > 0 {
					for _, ch := range list { // Only if value is present and there are interested parties
						ch <- field.Elem().Interface() // Notify
						close(ch)                      // Close
					}
					et.interests[name] = list[0:0] //Clear interest list
				}
			}
		}
	}
}

func (et *EyeTracker) heartbeat(interval time.Duration) {
	ticker := time.NewTicker(interval)
	for _ = range ticker.C {
		err := et.enc.Encode(Request{
			Category: CategoryHeartbeat,
		})
		if err != nil {
			ticker.Stop()
		}
		<-et.heartbeats
	}
}

func (et *EyeTracker) Set(attribute string, value interface{}) error {
	return et.SetAll(map[string]interface{}{
		attribute: value,
	})

}

func (et *EyeTracker) SetAll(attributes map[string]interface{}) error {
	et.enc.Encode(Request{
		Category: CategoryTracker,
		Request:  RequestSet,
		Values:   attributes,
	})
	res := <-et.sets
	if res.StatusCode != OK {
		return res.StatusCode
	}
	return nil
}

func (et *EyeTracker) Get(attribute string) (interface{}, error) {
	resch := make(chan interface{}, 1)
	et.interests[attribute] = append(et.interests[attribute], resch)

	err := et.enc.Encode(Request{
		Category: CategoryTracker,
		Request:  RequestGet,
		Values:   []string{attribute},
	})

	if err != nil {
		return nil, err
	}

	select {
	case res := <-resch:
		return res, nil
	case <-time.After(3 * time.Second):
		return nil, errors.New("Request timeout")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"reflect"
	"regexp"
	"strings"
	"text/template"
)

func inputToObject(inputStr string, debug *bool) (result interface{}, err error) {
	jsonStr := ""
	lastChar := ""

	if *debug {
		fmt.Fprintf(os.Stderr, "input is: %v\n", inputStr)
	}

	for position, rune := range inputStr {
		currentChar := string(rune)

		isOpeningBrace, _ := regexp.MatchString("[{\\[]", currentChar)
		isColonOrComma, _ := regexp.MatchString("[:,]", currentChar)
		isNotSpecial, _ := regexp.MatchString("[^{\\[:,]", currentChar)
		lastWasSpecial, _ := regexp.MatchString("[{\\[:,]", lastChar)
		isClosingBrace, _ := regexp.MatchString("[}\\]]", currentChar)
		lastWasClosingBrace, _ := regexp.MatchString("[^}\\]]", lastChar)

		if position > 0 && isOpeningBrace && !lastWasSpecial {
			jsonStr += "\""
		}

		if isNotSpecial && lastWasSpecial {
			jsonStr += "\""
		}

		if isColonOrComma && lastWasClosingBrace {
			jsonStr += "\""
		}

		if isClosingBrace && lastWasClosingBrace {
			jsonStr += "\""
		}

		jsonStr += currentChar
		lastChar = currentChar
	}

	if *debug {
		fmt.Fprintf(os.Stderr, "json is: %v\n", jsonStr)
	}

	err = json.Unmarshal([]byte(jsonStr), &result)
	if err != nil || reflect.TypeOf(result).Kind() == reflect.Float64 {
		result = inputStr
		if *debug {
			fmt.Fprintf(os.Stderr, "result is: %v (error: %v)\n", result, err)
		}
	} else if *debug {
		fmt.Fprintf(os.Stderr, "result is: %v\n", result)
	}

	return result, err
}

func main() {

	// set and parse cmd line flags
	debug := flag.Bool("d", false, "enable debug mode")
	templateFile := flag.String("t", "", "template file")
	version := flag.Bool("v", false, "show version")

	flag.Parse()

	if *version {
		fmt.Fprintf(os.Stdout, "version %s\n", "0.4")
		os.Exit(0)
	}

	if len(*templateFile) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	if _, err := os.Stat(*templateFile); os.IsNotExist(err) {
		fmt.Fprintf(os.Stderr, "%s not found\n", *templateFile)
		os.Exit(2)
	}

	// generate environment map
	environment := make(map[string]interface{})
	for _, envVar := range os.Environ() {

		envKeyValuePair := strings.Split(envVar, "=")
		envKey, envValue := envKeyValuePair[0], envKeyValuePair[1]

		data, err := inputToObject(envValue, debug)
		if err != nil {
			environment[envKey] = envValue
		} else {
			environment[envKey] = data
		}
	}

	if *debug {
		fmt.Fprintf(os.Stderr, "environment map is: %v\n", environment)
	}

	// render template
	tpl := template.Must(template.ParseGlob(*templateFile))
	err := tpl.Execute(os.Stdout, environment)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error rendering template %v: %v", *templateFile, err)
		os.Exit(2)
	}

}
<commit_msg>bump version<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"reflect"
	"regexp"
	"strings"
	"text/template"
)

func inputToObject(inputStr string, debug *bool) (result interface{}, err error) {
	jsonStr := ""
	lastChar := ""

	if *debug {
		fmt.Fprintf(os.Stderr, "input is: %v\n", inputStr)
	}

	for position, rune := range inputStr {
		currentChar := string(rune)

		isOpeningBrace, _ := regexp.MatchString("[{\\[]", currentChar)
		isColonOrComma, _ := regexp.MatchString("[:,]", currentChar)
		isNotSpecial, _ := regexp.MatchString("[^{\\[:,]", currentChar)
		lastWasSpecial, _ := regexp.MatchString("[{\\[:,]", lastChar)
		isClosingBrace, _ := regexp.MatchString("[}\\]]", currentChar)
		lastWasClosingBrace, _ := regexp.MatchString("[^}\\]]", lastChar)

		if position > 0 && isOpeningBrace && !lastWasSpecial {
			jsonStr += "\""
		}

		if isNotSpecial && lastWasSpecial {
			jsonStr += "\""
		}

		if isColonOrComma && lastWasClosingBrace {
			jsonStr += "\""
		}

		if isClosingBrace && lastWasClosingBrace {
			jsonStr += "\""
		}

		jsonStr += currentChar
		lastChar = currentChar
	}

	if *debug {
		fmt.Fprintf(os.Stderr, "json is: %v\n", jsonStr)
	}

	err = json.Unmarshal([]byte(jsonStr), &result)
	if err != nil || reflect.TypeOf(result).Kind() == reflect.Float64 {
		result = inputStr
		if *debug {
			fmt.Fprintf(os.Stderr, "result is: %v (error: %v)\n", result, err)
		}
	} else if *debug {
		fmt.Fprintf(os.Stderr, "result is: %v\n", result)
	}

	return result, err
}

func main() {

	// set and parse cmd line flags
	debug := flag.Bool("d", false, "enable debug mode")
	templateFile := flag.String("t", "", "template file")
	version := flag.Bool("v", false, "show version")

	flag.Parse()

	if *version {
		fmt.Fprintf(os.Stdout, "version %s\n", "0.3.1")
		os.Exit(0)
	}

	if len(*templateFile) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	if _, err := os.Stat(*templateFile); os.IsNotExist(err) {
		fmt.Fprintf(os.Stderr, "%s not found\n", *templateFile)
		os.Exit(2)
	}

	// generate environment map
	environment := make(map[string]interface{})
	for _, envVar := range os.Environ() {

		envKeyValuePair := strings.Split(envVar, "=")
		envKey, envValue := envKeyValuePair[0], envKeyValuePair[1]

		data, err := inputToObject(envValue, debug)
		if err != nil {
			environment[envKey] = envValue
		} else {
			environment[envKey] = data
		}
	}

	if *debug {
		fmt.Fprintf(os.Stderr, "environment map is: %v\n", environment)
	}

	// render template
	tpl := template.Must(template.ParseGlob(*templateFile))
	err := tpl.Execute(os.Stdout, environment)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error rendering template %v: %v", *templateFile, err)
		os.Exit(2)
	}

}
<|endoftext|>


<commit_before>package url

import (
	"github.com/golangplus/bytes"

	. "github.com/gohtml/elements"
	. "github.com/gohtml/utils"
)

// Makes a URL.
// port is ignored if set to zero.
// fragment is optional. If specified as an empty string, a trailing '#' will be appended.
func U(scheme, host string, port int, path string, q QUERY, fragment ...string) URL {
	var b bytesp.ByteSlice
	if len(host) > 0 {
		if len(scheme) > 0 {
			b.WriteString(scheme)
			b.WriteByte(':')
		}

		b.WriteString(`//`)
		b.WriteString(EscapeHost(host))

		if port > 0 {
			b.WriteByte(':')
			b.WriteItoa(int64(port), 10)
		}

		if len(path) == 0 || path[0] != '/' {
			b.WriteByte('/')
		}
	}

	b.WriteString(path)

	if len(q) > 0 {
		b.WriteByte('?')
		b.WriteString(string(q))
	}

	if fragment != nil {
		b.WriteByte('#')
		b.WriteString(fragment[0])
	}

	return URL(b)
}

// Generates a URL QUERY.
// nameValue's should be paired otherwise the last one is ignored.
func Q(nameValue ...string) QUERY {
	if len(nameValue) < 2 {
		return ""
	}

	var b bytesp.ByteSlice

	for i := 1; i < len(nameValue); i += 2 {
		if i > 1 {
			b.WriteByte('&')
		}
		b.WriteString(EscapeQuery(nameValue[i-1]))
		b.WriteByte('=')
		b.WriteString(EscapeQuery(nameValue[i]))
	}

	return QUERY(b)
}
<commit_msg>dot import to default import for utils pacakge<commit_after>package url

import (
	"github.com/golangplus/bytes"

	. "github.com/gohtml/elements"
	"github.com/gohtml/utils"
)

// Makes a URL.
// port is ignored if set to zero.
// fragment is optional. If specified as an empty string, a trailing '#' will be appended.
func U(scheme, host string, port int, path string, q QUERY, fragment ...string) URL {
	var b bytesp.ByteSlice
	if len(host) > 0 {
		if len(scheme) > 0 {
			b.WriteString(scheme)
			b.WriteByte(':')
		}

		b.WriteString(`//`)
		b.WriteString(utils.EscapeHost(host))

		if port > 0 {
			b.WriteByte(':')
			b.WriteItoa(int64(port), 10)
		}

		if len(path) == 0 || path[0] != '/' {
			b.WriteByte('/')
		}
	}

	b.WriteString(path)

	if len(q) > 0 {
		b.WriteByte('?')
		b.WriteString(string(q))
	}

	if fragment != nil {
		b.WriteByte('#')
		b.WriteString(fragment[0])
	}

	return URL(b)
}

// Generates a URL QUERY.
// nameValue's should be paired otherwise the last one is ignored.
func Q(nameValue ...string) QUERY {
	if len(nameValue) < 2 {
		return ""
	}

	var b bytesp.ByteSlice

	for i := 1; i < len(nameValue); i += 2 {
		if i > 1 {
			b.WriteByte('&')
		}
		b.WriteString(utils.EscapeQuery(nameValue[i-1]))
		b.WriteByte('=')
		b.WriteString(utils.EscapeQuery(nameValue[i]))
	}

	return QUERY(b)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/rach/pomod/Godeps/_workspace/src/github.com/elazarl/go-bindata-assetfs"
	"github.com/rach/pomod/Godeps/_workspace/src/github.com/jmoiron/sqlx"
	_ "github.com/rach/pomod/Godeps/_workspace/src/github.com/lib/pq"
	"io"
	"log"
	"net/http"
)

func metricsHandler(a *appContext, w http.ResponseWriter, r *http.Request) (int, error) {
	// Our handlers now have access to the members of our context struct.
	// e.g. we can call methods on our DB type via err := a.db.GetPosts()
	v, _ := json.Marshal(a.metrics)
	fmt.Fprintf(w, string(v))
	return 200, nil
}

func staticHandler(rw http.ResponseWriter, req *http.Request) {
	var path string = req.URL.Path
	//fmt.Println(path)
	if path == "" {
		path = "index.html"
	}
	if bs, err := Asset(path); err != nil {
		rw.WriteHeader(http.StatusNotFound)
	} else {
		fmt.Fprintf(rw, http.DetectContentType(bs[:]))
		rw.Header().Set("Content-Type", http.DetectContentType(bs[:]))
		var reader = bytes.NewBuffer(bs)
		io.Copy(rw, reader)
	}
}

type appContext struct {
	db      *sqlx.DB
	metrics *MetricList
}

type appHandler struct {
	*appContext
	H func(*appContext, http.ResponseWriter, *http.Request) (int, error)
}

func initWebServer(context *appContext) {
	http.Handle("/api/stats", appHandler{context, metricsHandler})
	http.Handle("/",
		http.FileServer(
			&assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, Prefix: ""}))
	http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)
}

func (ah appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Updated to pass ah.appContext as a parameter to our handler type.
	status, err := ah.H(ah.appContext, w, r)
	if err != nil {
		log.Printf("HTTP %d: %q", status, err)
		switch status {
		case http.StatusNotFound:
			http.NotFound(w, r)
			// And if we wanted a friendlier error page, we can
			// now leverage our context instance - e.g.
			// err := ah.renderTemplate(w, "http_404.tmpl", nil)
		case http.StatusInternalServerError:
			http.Error(w, http.StatusText(status), status)
		default:
			http.Error(w, http.StatusText(status), status)
		}
	}
}
<commit_msg>Removing Old handmade static handler<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/rach/pomod/Godeps/_workspace/src/github.com/elazarl/go-bindata-assetfs"
	"github.com/rach/pomod/Godeps/_workspace/src/github.com/jmoiron/sqlx"
	_ "github.com/rach/pomod/Godeps/_workspace/src/github.com/lib/pq"
	"io"
	"log"
	"net/http"
)

func metricsHandler(a *appContext, w http.ResponseWriter, r *http.Request) (int, error) {
	// Our handlers now have access to the members of our context struct.
	// e.g. we can call methods on our DB type via err := a.db.GetPosts()
	v, _ := json.Marshal(a.metrics)
	fmt.Fprintf(w, string(v))
	return 200, nil
}

type appContext struct {
	db      *sqlx.DB
	metrics *MetricList
}

type appHandler struct {
	*appContext
	H func(*appContext, http.ResponseWriter, *http.Request) (int, error)
}

func initWebServer(context *appContext) {
	http.Handle("/api/stats", appHandler{context, metricsHandler})
	http.Handle("/",
		http.FileServer(
			&assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, Prefix: ""}))
	http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)
}

func (ah appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Updated to pass ah.appContext as a parameter to our handler type.
	status, err := ah.H(ah.appContext, w, r)
	if err != nil {
		log.Printf("HTTP %d: %q", status, err)
		switch status {
		case http.StatusNotFound:
			http.NotFound(w, r)
			// And if we wanted a friendlier error page, we can
			// now leverage our context instance - e.g.
			// err := ah.renderTemplate(w, "http_404.tmpl", nil)
		case http.StatusInternalServerError:
			http.Error(w, http.StatusText(status), status)
		default:
			http.Error(w, http.StatusText(status), status)
		}
	}
}
<|endoftext|>


<commit_before>package main

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

var host = flag.String("host", "127.0.0.1", "Host")
var port = flag.String("port", "8080", "Port")

func IndexHandler(w http.ResponseWriter, r *http.Request) {
	isJsonRequest := false

	if acceptHeaders, ok := r.Header["Accept"]; ok {
		for _, acceptHeader := range acceptHeaders {
			if strings.Contains(acceptHeader, "json") {
				isJsonRequest = true
				break
			}
		}
	}

	if isJsonRequest {
		w.Write([]byte(resourceListingJson))
	} else {
		http.Redirect(w, r, "/swagger-ui/", http.StatusFound)
	}
}

func ApiDescriptionHandler(w http.ResponseWriter, r *http.Request) {
	apiKey := strings.Trim(r.RequestURI, "/")

	if json, ok := apiDescriptionsJson[apiKey]; ok {
		w.Write([]byte(json))
	} else {
		w.WriteHeader(http.StatusNotFound)
	}
}

func main() {
	flag.Parse()

	// To serve a directory on disk (/tmp) under an alternate URL
	// path (/tmpfiles/), use StripPrefix to modify the request
	// URL's path before the FileServer sees it:
	http.HandleFunc("/", IndexHandler)
	http.Handle("/swagger-ui/", http.StripPrefix("/swagger-ui/", http.FileServer(http.Dir("./swagger-ui"))))

	for apiKey, _ := range apiDescriptionsJson {
		http.HandleFunc("/"+apiKey+"/", ApiDescriptionHandler)
	}

	listenTo := *host + ":" + *port
	log.Printf("Star listen to %s", listenTo)

	http.ListenAndServe(listenTo, http.DefaultServeMux)
	//http.ListenAndServe(":8080", http.StripPrefix("/swagger-ui/", http.FileServer(http.Dir("./swagger-ui")) )
}
<commit_msg>Add "staticPath" options to web client<commit_after>package main

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

var host = flag.String("host", "127.0.0.1", "Host")
var port = flag.String("port", "8080", "Port")
var staticContent = flag.String("staticPath", "./swagger-ui", "Path to folder with Swagger UI")

func IndexHandler(w http.ResponseWriter, r *http.Request) {
	isJsonRequest := false

	if acceptHeaders, ok := r.Header["Accept"]; ok {
		for _, acceptHeader := range acceptHeaders {
			if strings.Contains(acceptHeader, "json") {
				isJsonRequest = true
				break
			}
		}
	}

	if isJsonRequest {
		w.Write([]byte(resourceListingJson))
	} else {
		http.Redirect(w, r, "/swagger-ui/", http.StatusFound)
	}
}

func ApiDescriptionHandler(w http.ResponseWriter, r *http.Request) {
	apiKey := strings.Trim(r.RequestURI, "/")

	if json, ok := apiDescriptionsJson[apiKey]; ok {
		w.Write([]byte(json))
	} else {
		w.WriteHeader(http.StatusNotFound)
	}
}

func main() {
	flag.Parse()

	// To serve a directory on disk (/tmp) under an alternate URL
	// path (/tmpfiles/), use StripPrefix to modify the request
	// URL's path before the FileServer sees it:
	http.HandleFunc("/", IndexHandler)
	http.Handle("/swagger-ui/", http.StripPrefix("/swagger-ui/", http.FileServer(http.Dir(*staticContent))))

	for apiKey, _ := range apiDescriptionsJson {
		http.HandleFunc("/"+apiKey+"/", ApiDescriptionHandler)
	}

	listenTo := *host + ":" + *port
	log.Printf("Star listen to %s", listenTo)

	http.ListenAndServe(listenTo, http.DefaultServeMux)
	//http.ListenAndServe(":8080", http.StripPrefix("/swagger-ui/", http.FileServer(http.Dir("./swagger-ui")) )
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"os"
	"time"
)

func main() {
	Start(os.Getenv("PORT"))
}

func Start(port string) {
	http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
		switch req.Method {
		case "GET":
			handleGet(res, req)
			//		case "POST":
			//			handlePost(res, req)
		default:
			http.Error(res, "Only GET and POST supported", http.StatusMethodNotAllowed)
		}
	})

	if port == "" {
		port = "5000"
	}
	log.Println("listening on port:", port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}

type fileInfoResponse struct {
	Name    string    `json:"name"`
	Size    int64     `json:"size"`
	Type    string    `json:"type"`
	Perm    int       `json:"permission"`
	ModTime time.Time `json:"updated_at"`
}

func toFileInfoResponse(fi os.FileInfo) fileInfoResponse {
	return fileInfoResponse{
		Name:    fi.Name(),
		Size:    fi.Size(),
		Type:    string(fi.Mode().String()[0]),
		Perm:    int(fi.Mode().Perm()),
		ModTime: fi.ModTime(),
	}
}

func handleGet(res http.ResponseWriter, req *http.Request) {
	path, err := os.Open(req.URL.Path)
	if err != nil {
		http.Error(res, "Error reading path: "+err.Error(), http.StatusBadRequest)
		return
	}

	pathInfo, err := path.Stat()
	if err != nil {
		http.Error(res, "Error reading path info: "+err.Error(), http.StatusInternalServerError)
		return
	}

	if pathInfo.Mode().IsDir() {
		fileInfos, err := path.Readdir(0)
		if err != nil {
			http.Error(res, "Error reading dir: "+err.Error(), http.StatusInternalServerError)
			return
		}

		fileResponses := []fileInfoResponse{}
		for _, fi := range fileInfos {
			fileResponses = append(fileResponses, toFileInfoResponse(fi))
		}

		res.Header().Set("Content-Type", "application/json") // TODO allow others
		fileResponsesJson, err := json.Marshal(fileResponses)
		if err != nil {
			http.Error(res, "Error converting JSON: "+err.Error(), http.StatusInternalServerError)
			return
		}
		res.Write(fileResponsesJson)
	} else if pathInfo.Mode().IsRegular() {
		io.Copy(res, path)
	} else {
		http.Error(res, "Invalid file type: "+string(pathInfo.Mode().String()[0]), http.StatusBadRequest)
	}
}

//func handlePost(res http.ResponseWriter, req *http.Request) {
//	scheme := "http"
//	if req.TLS != nil || req.Header.Get("X-Forwarded-Proto") == "https" {
//		scheme = "https"
//	}
//
//	data, err := ioutil.ReadAll(req.Body)
//	if err != nil {
//		log.Println("post.error.body:", err)
//		http.Error(res, "Error reading request body: "+err.Error(), http.StatusBadRequest)
//		return
//	}
//
//	if err := handleStatusParam(res, req); err != nil {
//		return
//	}
//
//	res.Header().Set("Content-Type", "text/uri-list; charset=utf-8")
//	contentType := req.Header.Get("Content-Type")
//	uri := shaas.CreateUri(scheme, req.Host, req.URL.Path, contentType, data)
//	fmt.Fprintln(res, uri)
//}
<commit_msg>json only<commit_after>package main

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"os"
	"time"
)

func main() {
	Start(os.Getenv("PORT"))
}

func Start(port string) {
	http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
		switch req.Method {
		case "GET":
			handleGet(res, req)
			//		case "POST":
			//			handlePost(res, req)
		default:
			http.Error(res, "Only GET and POST supported", http.StatusMethodNotAllowed)
		}
	})

	if port == "" {
		port = "5000"
	}
	log.Println("listening on port:", port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}

type fileInfoResponse struct {
	Name    string    `json:"name"`
	Size    int64     `json:"size"`
	Type    string    `json:"type"`
	Perm    int       `json:"permission"`
	ModTime time.Time `json:"updated_at"`
}

func toFileInfoResponse(fi os.FileInfo) fileInfoResponse {
	return fileInfoResponse{
		Name:    fi.Name(),
		Size:    fi.Size(),
		Type:    string(fi.Mode().String()[0]),
		Perm:    int(fi.Mode().Perm()),
		ModTime: fi.ModTime(),
	}
}

func handleGet(res http.ResponseWriter, req *http.Request) {
	path, err := os.Open(req.URL.Path)
	if err != nil {
		http.Error(res, "Error reading path: "+err.Error(), http.StatusBadRequest)
		return
	}

	pathInfo, err := path.Stat()
	if err != nil {
		http.Error(res, "Error reading path info: "+err.Error(), http.StatusInternalServerError)
		return
	}

	if pathInfo.Mode().IsDir() {
		fileInfos, err := path.Readdir(0)
		if err != nil {
			http.Error(res, "Error reading dir: "+err.Error(), http.StatusInternalServerError)
			return
		}

		fileResponses := []fileInfoResponse{}
		for _, fi := range fileInfos {
			fileResponses = append(fileResponses, toFileInfoResponse(fi))
		}

		res.Header().Set("Content-Type", "application/json")
		fileResponsesJson, err := json.Marshal(fileResponses)
		if err != nil {
			http.Error(res, "Error converting JSON: "+err.Error(), http.StatusInternalServerError)
			return
		}
		res.Write(fileResponsesJson)
	} else if pathInfo.Mode().IsRegular() {
		io.Copy(res, path)
	} else {
		http.Error(res, "Invalid file type: "+string(pathInfo.Mode().String()[0]), http.StatusBadRequest)
	}
}

//func handlePost(res http.ResponseWriter, req *http.Request) {
//	scheme := "http"
//	if req.TLS != nil || req.Header.Get("X-Forwarded-Proto") == "https" {
//		scheme = "https"
//	}
//
//	data, err := ioutil.ReadAll(req.Body)
//	if err != nil {
//		log.Println("post.error.body:", err)
//		http.Error(res, "Error reading request body: "+err.Error(), http.StatusBadRequest)
//		return
//	}
//
//	if err := handleStatusParam(res, req); err != nil {
//		return
//	}
//
//	res.Header().Set("Content-Type", "text/uri-list; charset=utf-8")
//	contentType := req.Header.Get("Content-Type")
//	uri := shaas.CreateUri(scheme, req.Host, req.URL.Path, contentType, data)
//	fmt.Fprintln(res, uri)
//}
<|endoftext|>


<commit_before>// +build windows

/*
Package wmi provides a WQL interface for WMI on Windows.

Example code to print names of running processes:

	type Win32_Process struct {
		Name string
	}

	func main() {
		var dst []Win32_Process
		q := wmi.CreateQuery(&dst, "")
		err := wmi.Query(q, &dst)
		if err != nil {
			log.Fatal(err)
		}
		for i, v := range dst {
			println(i, v.Name)
		}
	}

*/
package wmi

import (
	"bytes"
	"errors"
	"fmt"
	"log"
	"os"
	"reflect"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/mattn/go-ole"
	"github.com/mattn/go-ole/oleutil"
)

var l = log.New(os.Stdout, "", log.LstdFlags)

var (
	ErrInvalidEntityType = errors.New("wmi: invalid entity type")
	lock                 sync.Mutex
)

// QueryNamespace invokes Query with the given namespace on the local machine.
func QueryNamespace(query string, dst interface{}, namespace string) error {
	return Query(query, dst, nil, namespace)
}

// Query runs the WQL query and appends the values to dst.
//
// dst must have type *[]S or *[]*S, for some struct type S. Fields selected in
// the query must have the same name in dst. Supported types are all signed and
// unsigned integers, time.Time, string, bool, or a pointer to one of those.
// Array types are not supported.
//
// By default, the local machine and default namespace are used. These can be
// changed using connectServerArgs. See
// http://msdn.microsoft.com/en-us/library/aa393720.aspx for details.
func Query(query string, dst interface{}, connectServerArgs ...interface{}) error {
	dv := reflect.ValueOf(dst)
	if dv.Kind() != reflect.Ptr || dv.IsNil() {
		return ErrInvalidEntityType
	}
	dv = dv.Elem()
	mat, elemType := checkMultiArg(dv)
	if mat == multiArgTypeInvalid {
		return ErrInvalidEntityType
	}

	lock.Lock()
	defer lock.Unlock()
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED)
	if err != nil {
		oleerr := err.(*ole.OleError)
		// S_FALSE           = 0x00000001 // CoInitializeEx was already called on this thread
		if oleerr.Code() != ole.S_OK && oleerr.Code() != 0x00000001 {
			return err
		}
	} else {
		// Only invoke CoUninitialize if the thread was not initizlied before.
		// This will allow other go packages based on go-ole play along
		// with this library.
		defer ole.CoUninitialize()
	}

	unknown, err := oleutil.CreateObject("WbemScripting.SWbemLocator")
	if err != nil {
		return err
	}
	defer unknown.Release()

	wmi, err := unknown.QueryInterface(ole.IID_IDispatch)
	if err != nil {
		return err
	}
	defer wmi.Release()

	// service is a SWbemServices
	serviceRaw, err := oleutil.CallMethod(wmi, "ConnectServer", connectServerArgs...)
	if err != nil {
		return err
	}
	service := serviceRaw.ToIDispatch()
	defer serviceRaw.Clear()

	// result is a SWBemObjectSet
	resultRaw, err := oleutil.CallMethod(service, "ExecQuery", query)
	if err != nil {
		return err
	}
	result := resultRaw.ToIDispatch()
	defer resultRaw.Clear()

	count, err := oleInt64(result, "Count")
	if err != nil {
		return err
	}

	// Initialize a slice with Count capacity
	dv.Set(reflect.MakeSlice(dv.Type(), 0, int(count)))

	var errFieldMismatch error
	for i := int64(0); i < count; i++ {
		err := func() error {
			// item is a SWbemObject, but really a Win32_Process
			itemRaw, err := oleutil.CallMethod(result, "ItemIndex", i)
			if err != nil {
				return err
			}
			item := itemRaw.ToIDispatch()
			defer itemRaw.Clear()

			ev := reflect.New(elemType)
			if err = loadEntity(ev.Interface(), item); err != nil {
				if _, ok := err.(*ErrFieldMismatch); ok {
					// We continue loading entities even in the face of field mismatch errors.
					// If we encounter any other error, that other error is returned. Otherwise,
					// an ErrFieldMismatch is returned.
					errFieldMismatch = err
				} else {
					return err
				}
			}
			if mat != multiArgTypeStructPtr {
				ev = ev.Elem()
			}
			dv.Set(reflect.Append(dv, ev))
			return nil
		}()
		if err != nil {
			return err
		}
	}
	return errFieldMismatch
}

// ErrFieldMismatch is returned when a field is to be loaded into a different
// type than the one it was stored from, or when a field is missing or
// unexported in the destination struct.
// StructType is the type of the struct pointed to by the destination argument.
type ErrFieldMismatch struct {
	StructType reflect.Type
	FieldName  string
	Reason     string
}

func (e *ErrFieldMismatch) Error() string {
	return fmt.Sprintf("wmi: cannot load field %q into a %q: %s",
		e.FieldName, e.StructType, e.Reason)
}

var timeType = reflect.TypeOf(time.Time{})

// loadEntity loads a SWbemObject into a struct pointer.
func loadEntity(dst interface{}, src *ole.IDispatch) (errFieldMismatch error) {
	v := reflect.ValueOf(dst).Elem()
	for i := 0; i < v.NumField(); i++ {
		f := v.Field(i)
		of := f
		isPtr := f.Kind() == reflect.Ptr
		if isPtr {
			ptr := reflect.New(f.Type().Elem())
			f.Set(ptr)
			f = f.Elem()
		}
		n := v.Type().Field(i).Name
		if !f.CanSet() {
			return &ErrFieldMismatch{
				StructType: of.Type(),
				FieldName:  n,
				Reason:     "CanSet() is false",
			}
		}
		prop, err := oleutil.GetProperty(src, n)
		if err != nil {
			errFieldMismatch = &ErrFieldMismatch{
				StructType: of.Type(),
				FieldName:  n,
				Reason:     "no such struct field",
			}
			continue
		}
		defer prop.Clear()

		switch val := prop.Value().(type) {
		case int, int64:
			var v int64
			switch val := val.(type) {
			case int:
				v = int64(val)
			case int64:
				v = val
			default:
				panic("unexpected type")
			}
			switch f.Kind() {
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				f.SetInt(v)
			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
				f.SetUint(uint64(v))
			default:
				return &ErrFieldMismatch{
					StructType: of.Type(),
					FieldName:  n,
					Reason:     "not an integer class",
				}
			}
		case string:
			iv, err := strconv.ParseInt(val, 10, 64)
			switch f.Kind() {
			case reflect.String:
				f.SetString(val)
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				if err != nil {
					return err
				}
				f.SetInt(iv)
			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
				if err != nil {
					return err
				}
				f.SetUint(uint64(iv))
			case reflect.Struct:
				switch f.Type() {
				case timeType:
					if len(val) == 25 {
						mins, err := strconv.Atoi(val[22:])
						if err != nil {
							return err
						}
						val = val[:22] + fmt.Sprintf("%02d%02d", mins/60, mins%60)
					}
					t, err := time.Parse("20060102150405.000000-0700", val)
					if err != nil {
						return err
					}
					f.Set(reflect.ValueOf(t))
				}
			}
		case bool:
			switch f.Kind() {
			case reflect.Bool:
				f.SetBool(val)
			default:
				return &ErrFieldMismatch{
					StructType: of.Type(),
					FieldName:  n,
					Reason:     "not a bool",
				}
			}
		default:
			typeof := reflect.TypeOf(val)
			if isPtr && typeof == nil {
				of.Set(reflect.Zero(of.Type()))
				break
			}
			return &ErrFieldMismatch{
				StructType: of.Type(),
				FieldName:  n,
				Reason:     fmt.Sprintf("unsupported type (%T)", val),
			}
		}
	}
	return errFieldMismatch
}

type multiArgType int

const (
	multiArgTypeInvalid multiArgType = iota
	multiArgTypeStruct
	multiArgTypeStructPtr
)

// checkMultiArg checks that v has type []S, []*S for some struct type S.
//
// It returns what category the slice's elements are, and the reflect.Type
// that represents S.
func checkMultiArg(v reflect.Value) (m multiArgType, elemType reflect.Type) {
	if v.Kind() != reflect.Slice {
		return multiArgTypeInvalid, nil
	}
	elemType = v.Type().Elem()
	switch elemType.Kind() {
	case reflect.Struct:
		return multiArgTypeStruct, elemType
	case reflect.Ptr:
		elemType = elemType.Elem()
		if elemType.Kind() == reflect.Struct {
			return multiArgTypeStructPtr, elemType
		}
	}
	return multiArgTypeInvalid, nil
}

func oleInt64(item *ole.IDispatch, prop string) (int64, error) {
	v, err := oleutil.GetProperty(item, prop)
	if err != nil {
		return 0, err
	}
	defer v.Clear()

	i := int64(v.Val)
	return i, nil
}

// CreateQuery returns a WQL query string that queries all columns of src. where
// is an optional string that is appended to the query, to be used with WHERE
// clauses. In such a case, the "WHERE" string should appear at the beginning.
func CreateQuery(src interface{}, where string) string {
	var b bytes.Buffer
	b.WriteString("SELECT ")
	s := reflect.Indirect(reflect.ValueOf(src))
	t := s.Type()
	if s.Kind() == reflect.Slice {
		t = t.Elem()
	}
	if t.Kind() != reflect.Struct {
		return ""
	}
	var fields []string
	for i := 0; i < t.NumField(); i++ {
		fields = append(fields, t.Field(i).Name)
	}
	b.WriteString(strings.Join(fields, ", "))
	b.WriteString(" FROM ")
	b.WriteString(t.Name())
	b.WriteString(" " + where)
	return b.String()
}
<commit_msg>Add behaviour control for nil field value handling<commit_after>// +build windows

/*
Package wmi provides a WQL interface for WMI on Windows.

Example code to print names of running processes:

	type Win32_Process struct {
		Name string
	}

	func main() {
		var dst []Win32_Process
		q := wmi.CreateQuery(&dst, "")
		err := wmi.Query(q, &dst)
		if err != nil {
			log.Fatal(err)
		}
		for i, v := range dst {
			println(i, v.Name)
		}
	}

*/
package wmi

import (
	"bytes"
	"errors"
	"fmt"
	"log"
	"os"
	"reflect"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/mattn/go-ole"
	"github.com/mattn/go-ole/oleutil"
)

var l = log.New(os.Stdout, "", log.LstdFlags)

var (
	ErrInvalidEntityType = errors.New("wmi: invalid entity type")
	lock                 sync.Mutex
)

// QueryNamespace invokes Query with the given namespace on the local machine.
func QueryNamespace(query string, dst interface{}, namespace string) error {
	return Query(query, dst, nil, namespace)
}

// Query runs the WQL query and appends the values to dst.
//
// dst must have type *[]S or *[]*S, for some struct type S. Fields selected in
// the query must have the same name in dst. Supported types are all signed and
// unsigned integers, time.Time, string, bool, or a pointer to one of those.
// Array types are not supported.
//
// By default, the local machine and default namespace are used. These can be
// changed using connectServerArgs. See
// http://msdn.microsoft.com/en-us/library/aa393720.aspx for details.
//
// Query is a wrapper around DefaultClient.Query.
func Query(query string, dst interface{}, connectServerArgs ...interface{}) error {
	return DefaultClient.Query(query, dst, connectServerArgs...)
}

// A Client is an WMI query client.
//
// Its zero value (DefaultClient) is a usable client.
type Client struct {
	// NonePtrZero specifies if nil values for fields which aren't pointers
	// should be returned as the field types zero value.
	//
	// Setting this to true allows stucts without pointer fields to be used
	// without the risk failure should a nil value returned from WMI.
	NonePtrZero bool

	// PtrNil specifies if nil values for pointer fields should be returned
	// as nil.
	//
	// Setting this to true will set pointer fields to nil where WMI
	// returned nil, otherwise the types zero value will be returned.
	PtrNil bool
}

// DefaultClient is the default Client and is used by Query, QueryNamespace
var DefaultClient = &Client{}

// Query runs the WQL query and appends the values to dst.
//
// dst must have type *[]S or *[]*S, for some struct type S. Fields selected in
// the query must have the same name in dst. Supported types are all signed and
// unsigned integers, time.Time, string, bool, or a pointer to one of those.
// Array types are not supported.
//
// By default, the local machine and default namespace are used. These can be
// changed using connectServerArgs. See
// http://msdn.microsoft.com/en-us/library/aa393720.aspx for details.
func (c *Client) Query(query string, dst interface{}, connectServerArgs ...interface{}) error {
	dv := reflect.ValueOf(dst)
	if dv.Kind() != reflect.Ptr || dv.IsNil() {
		return ErrInvalidEntityType
	}
	dv = dv.Elem()
	mat, elemType := checkMultiArg(dv)
	if mat == multiArgTypeInvalid {
		return ErrInvalidEntityType
	}

	lock.Lock()
	defer lock.Unlock()
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED)
	if err != nil {
		oleerr := err.(*ole.OleError)
		// S_FALSE           = 0x00000001 // CoInitializeEx was already called on this thread
		if oleerr.Code() != ole.S_OK && oleerr.Code() != 0x00000001 {
			return err
		}
	} else {
		// Only invoke CoUninitialize if the thread was not initizlied before.
		// This will allow other go packages based on go-ole play along
		// with this library.
		defer ole.CoUninitialize()
	}

	unknown, err := oleutil.CreateObject("WbemScripting.SWbemLocator")
	if err != nil {
		return err
	}
	defer unknown.Release()

	wmi, err := unknown.QueryInterface(ole.IID_IDispatch)
	if err != nil {
		return err
	}
	defer wmi.Release()

	// service is a SWbemServices
	serviceRaw, err := oleutil.CallMethod(wmi, "ConnectServer", connectServerArgs...)
	if err != nil {
		return err
	}
	service := serviceRaw.ToIDispatch()
	defer serviceRaw.Clear()

	// result is a SWBemObjectSet
	resultRaw, err := oleutil.CallMethod(service, "ExecQuery", query)
	if err != nil {
		return err
	}
	result := resultRaw.ToIDispatch()
	defer resultRaw.Clear()

	count, err := oleInt64(result, "Count")
	if err != nil {
		return err
	}

	// Initialize a slice with Count capacity
	dv.Set(reflect.MakeSlice(dv.Type(), 0, int(count)))

	var errFieldMismatch error
	for i := int64(0); i < count; i++ {
		err := func() error {
			// item is a SWbemObject, but really a Win32_Process
			itemRaw, err := oleutil.CallMethod(result, "ItemIndex", i)
			if err != nil {
				return err
			}
			item := itemRaw.ToIDispatch()
			defer itemRaw.Clear()

			ev := reflect.New(elemType)
			if err = c.loadEntity(ev.Interface(), item); err != nil {
				if _, ok := err.(*ErrFieldMismatch); ok {
					// We continue loading entities even in the face of field mismatch errors.
					// If we encounter any other error, that other error is returned. Otherwise,
					// an ErrFieldMismatch is returned.
					errFieldMismatch = err
				} else {
					return err
				}
			}
			if mat != multiArgTypeStructPtr {
				ev = ev.Elem()
			}
			dv.Set(reflect.Append(dv, ev))
			return nil
		}()
		if err != nil {
			return err
		}
	}
	return errFieldMismatch
}

// ErrFieldMismatch is returned when a field is to be loaded into a different
// type than the one it was stored from, or when a field is missing or
// unexported in the destination struct.
// StructType is the type of the struct pointed to by the destination argument.
type ErrFieldMismatch struct {
	StructType reflect.Type
	FieldName  string
	Reason     string
}

func (e *ErrFieldMismatch) Error() string {
	return fmt.Sprintf("wmi: cannot load field %q into a %q: %s",
		e.FieldName, e.StructType, e.Reason)
}

var timeType = reflect.TypeOf(time.Time{})

// loadEntity loads a SWbemObject into a struct pointer.
func (c *Client) loadEntity(dst interface{}, src *ole.IDispatch) (errFieldMismatch error) {
	v := reflect.ValueOf(dst).Elem()
	for i := 0; i < v.NumField(); i++ {
		f := v.Field(i)
		of := f
		isPtr := f.Kind() == reflect.Ptr
		if isPtr {
			ptr := reflect.New(f.Type().Elem())
			f.Set(ptr)
			f = f.Elem()
		}
		n := v.Type().Field(i).Name
		if !f.CanSet() {
			return &ErrFieldMismatch{
				StructType: of.Type(),
				FieldName:  n,
				Reason:     "CanSet() is false",
			}
		}
		prop, err := oleutil.GetProperty(src, n)
		if err != nil {
			errFieldMismatch = &ErrFieldMismatch{
				StructType: of.Type(),
				FieldName:  n,
				Reason:     "no such struct field",
			}
			continue
		}
		defer prop.Clear()

		switch val := prop.Value().(type) {
		case int, int64:
			var v int64
			switch val := val.(type) {
			case int:
				v = int64(val)
			case int64:
				v = val
			default:
				panic("unexpected type")
			}
			switch f.Kind() {
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				f.SetInt(v)
			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
				f.SetUint(uint64(v))
			default:
				return &ErrFieldMismatch{
					StructType: of.Type(),
					FieldName:  n,
					Reason:     "not an integer class",
				}
			}
		case string:
			iv, err := strconv.ParseInt(val, 10, 64)
			switch f.Kind() {
			case reflect.String:
				f.SetString(val)
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				if err != nil {
					return err
				}
				f.SetInt(iv)
			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
				if err != nil {
					return err
				}
				f.SetUint(uint64(iv))
			case reflect.Struct:
				switch f.Type() {
				case timeType:
					if len(val) == 25 {
						mins, err := strconv.Atoi(val[22:])
						if err != nil {
							return err
						}
						val = val[:22] + fmt.Sprintf("%02d%02d", mins/60, mins%60)
					}
					t, err := time.Parse("20060102150405.000000-0700", val)
					if err != nil {
						return err
					}
					f.Set(reflect.ValueOf(t))
				}
			}
		case bool:
			switch f.Kind() {
			case reflect.Bool:
				f.SetBool(val)
			default:
				return &ErrFieldMismatch{
					StructType: of.Type(),
					FieldName:  n,
					Reason:     "not a bool",
				}
			}
		default:
			typeof := reflect.TypeOf(val)
			if typeof == nil && (isPtr || c.NonePtrZero) {
				if (isPtr && c.PtrNil) || (!isPtr && c.NonePtrZero) {
					of.Set(reflect.Zero(of.Type()))
				}
				break
			}
			return &ErrFieldMismatch{
				StructType: of.Type(),
				FieldName:  n,
				Reason:     fmt.Sprintf("unsupported type (%T)", val),
			}
		}
	}
	return errFieldMismatch
}

type multiArgType int

const (
	multiArgTypeInvalid multiArgType = iota
	multiArgTypeStruct
	multiArgTypeStructPtr
)

// checkMultiArg checks that v has type []S, []*S for some struct type S.
//
// It returns what category the slice's elements are, and the reflect.Type
// that represents S.
func checkMultiArg(v reflect.Value) (m multiArgType, elemType reflect.Type) {
	if v.Kind() != reflect.Slice {
		return multiArgTypeInvalid, nil
	}
	elemType = v.Type().Elem()
	switch elemType.Kind() {
	case reflect.Struct:
		return multiArgTypeStruct, elemType
	case reflect.Ptr:
		elemType = elemType.Elem()
		if elemType.Kind() == reflect.Struct {
			return multiArgTypeStructPtr, elemType
		}
	}
	return multiArgTypeInvalid, nil
}

func oleInt64(item *ole.IDispatch, prop string) (int64, error) {
	v, err := oleutil.GetProperty(item, prop)
	if err != nil {
		return 0, err
	}
	defer v.Clear()

	i := int64(v.Val)
	return i, nil
}

// CreateQuery returns a WQL query string that queries all columns of src. where
// is an optional string that is appended to the query, to be used with WHERE
// clauses. In such a case, the "WHERE" string should appear at the beginning.
func CreateQuery(src interface{}, where string) string {
	var b bytes.Buffer
	b.WriteString("SELECT ")
	s := reflect.Indirect(reflect.ValueOf(src))
	t := s.Type()
	if s.Kind() == reflect.Slice {
		t = t.Elem()
	}
	if t.Kind() != reflect.Struct {
		return ""
	}
	var fields []string
	for i := 0; i < t.NumField(); i++ {
		fields = append(fields, t.Field(i).Name)
	}
	b.WriteString(strings.Join(fields, ", "))
	b.WriteString(" FROM ")
	b.WriteString(t.Name())
	b.WriteString(" " + where)
	return b.String()
}
<|endoftext|>


<commit_before>package goque

import (
	"encoding/binary"
)

// Item represents an entry in either a stack or queue.
type Item struct {
	ID    uint64
	Key   []byte
	Value []byte
}

// ToString returns the item value as a string.
func (i *Item) ToString() string {
	return string(i.Value)
}

// PriorityItem represents an entry in a priority queue.
type PriorityItem struct {
	ID       uint64
	Priority uint8
	Key      []byte
	Value    []byte
}

// ToString returns the item value as a string.
//func (pi *PriorityItem) ToString() string {}

// NewItem creates a new item for use with a stack or queue.
func NewItem(value []byte) *Item {
	return &Item{Value: value}
}

// NewItemString is a helper function for NewItem that accepts a
// value as a string rather than a byte slice.
func NewItemString(value string) *Item {
	return NewItem([]byte(value))
}

// idToKey converts and returns the given ID to a key.
func idToKey(id uint64) []byte {
	key := make([]byte, 8)
	binary.BigEndian.PutUint64(key, id)
	return key
}

// keyToID converts and returns the given key to an ID.
func keyToID(key []byte) uint64 {
	return binary.BigEndian.Uint64(key)
}
<commit_msg>Changed function position back in item.go<commit_after>package goque

import (
	"encoding/binary"
)

// Item represents an entry in either a stack or queue.
type Item struct {
	ID    uint64
	Key   []byte
	Value []byte
}

// NewItem creates a new item for use with a stack or queue.
func NewItem(value []byte) *Item {
	return &Item{Value: value}
}

// NewItemString is a helper function for NewItem that accepts a
// value as a string rather than a byte slice.
func NewItemString(value string) *Item {
	return NewItem([]byte(value))
}

// ToString returns the item value as a string.
func (i *Item) ToString() string {
	return string(i.Value)
}

// PriorityItem represents an entry in a priority queue.
type PriorityItem struct {
	ID       uint64
	Priority uint8
	Key      []byte
	Value    []byte
}

// ToString returns the item value as a string.
//func (pi *PriorityItem) ToString() string {}

// idToKey converts and returns the given ID to a key.
func idToKey(id uint64) []byte {
	key := make([]byte, 8)
	binary.BigEndian.PutUint64(key, id)
	return key
}

// keyToID converts and returns the given key to an ID.
func keyToID(key []byte) uint64 {
	return binary.BigEndian.Uint64(key)
}
<|endoftext|>