<commit_before>package main

import (
	"errors"
	"log"

	"github.com/BurntSushi/xgbutil"
	"github.com/BurntSushi/xgbutil/ewmh"
	"github.com/BurntSushi/xgbutil/xinerama"
	"github.com/BurntSushi/xgbutil/xwindow"

	"github.com/mpasternacki/termbox-go"

	"../urxvtermbox"
)

var (
	origX0 = 0
	origX1 = 0
	origY0 = 0
	origY1 = 1
	posX   = 0
	posY   = 0
	markX  = -1
	markY  = -1
	prefix = 1
)

func draw() {
	// axes
	for i := 0; i < 12; i++ {
		ch0 := ' '
		if i >= 9 {
			ch0 = '1'
		}
		ch1 := rune('0' + (i+1)%10)
		fgX := termbox.ColorDefault
		fgY := termbox.ColorDefault
		if i == posX {
			fgX = termbox.ColorWhite | termbox.AttrBold
		}
		if i == posY {
			fgY = termbox.ColorWhite | termbox.AttrBold
		}
		termbox.SetCell(0, i+1, ch0, fgY, termbox.ColorDefault)
		termbox.SetCell(1, i+1, ch1, fgY, termbox.ColorDefault)
		termbox.SetCell(26, i+1, ch0, fgY, termbox.ColorDefault)
		termbox.SetCell(27, i+1, ch1, fgY, termbox.ColorDefault)
		termbox.SetCell(2*i+2, 0, ch0, fgX, termbox.ColorDefault)
		termbox.SetCell(2*i+3, 0, ch1, fgX, termbox.ColorDefault)
		termbox.SetCell(2*i+2, 13, ch0, fgX, termbox.ColorDefault)
		termbox.SetCell(2*i+3, 13, ch1, fgX, termbox.ColorDefault)
	}

	// grid
	for i := 0; i < 12; i++ {
		for j := 0; j < 12; j++ {
			// default fg & char
			fg := termbox.ColorBlue
			ch := '░'

			// original win dimensions are green
			if i >= origX0 && i <= origX1 && j >= origY0 && j <= origY1 {
				fg = termbox.ColorGreen
			}

			// cursor is yellow & solid
			if i == posX && j == posY {
				ch = '█'
				fg = termbox.ColorYellow
			} else if markX >= 0 && markY >= 0 {
				// besides cursor, selected block is more solid
				l, r, t, b := posX, markX, posY, markY
				if l > r {
					l, r = r, l
				}
				if t > b {
					t, b = b, t
				}
				if l <= i && i <= r && t <= j && j <= b {
					ch = '▓'
				}
			}

			// bold/regular checkers
			if (i+j)%2 == 1 {
				fg = fg | termbox.AttrBold
			}

			termbox.SetCell(2*i+2, j+1, ch, fg, termbox.ColorDefault)
			termbox.SetCell(2*i+3, j+1, ch, fg, termbox.ColorDefault)
		}
	}

	// prefix
	prfg := termbox.ColorGreen | termbox.AttrBold
	if prefix == 1 {
		prfg = termbox.ColorBlack | termbox.AttrBold
	}
	pr0 := ' '
	if prefix >= 10 {
		pr0 = '1'
	}
	pr1 := rune('0' + prefix%10)
	termbox.SetCell(0, 0, pr0, prfg, termbox.ColorDefault)
	termbox.SetCell(1, 0, pr1, prfg, termbox.ColorDefault)

	termbox.Flush()
}

func mousePos(ev termbox.Event) (x int, y int) {
	x, y = (ev.MouseX-2)/2, ev.MouseY-1
	if x < 0 {
		x = 0
	}
	if x > 11 {
		x = 11
	}
	if y < 0 {
		y = 0
	}
	if y > 11 {
		y = 11
	}
	return
}

func doMove(dx, dy int) {
	posX += dx
	if posX < 0 {
		posX = 0
	}
	if posX > 11 {
		posX = 11
	}
	posY += dy
	if posY < 0 {
		posY = 0
	}
	if posY > 11 {
		posY = 11
	}
}

func uiMain() error {
	if fini, err := urxvtermbox.TermboxUrxvt(28, 14); err != nil {
		return err
	} else {
		defer fini()
	}

	if err := termbox.Init(); err != nil {
		return err
	}
	defer termbox.Close()
	termbox.SetInputMode(termbox.InputEsc | termbox.InputMouse)

	draw()
	mouseHold := false
	for {
		switch ev := termbox.PollEvent(); ev.Type {
		case termbox.EventKey:
			switch ev.Key {
			case termbox.KeyEsc:
				markX = -1
				markY = -1
				return nil
			case termbox.KeyArrowUp:
				doMove(0, -prefix)
				prefix = 1
			case termbox.KeyArrowDown:
				doMove(0, prefix)
				prefix = 1
			case termbox.KeyArrowLeft:
				doMove(-prefix, 0)
				prefix = 1
			case termbox.KeyArrowRight:
				doMove(prefix, 0)
				prefix = 1
			case termbox.KeyEnter:
				if markX >= 0 {
					return nil
				}
				fallthrough
			case termbox.KeySpace:
				markX, markY = posX, posY
				prefix = 1
			case termbox.KeyTab:
				if markX >= 0 {
					markX, posX = posX, markX
					markY, posY = posY, markY
				}
				prefix = 1
			case termbox.KeyBackspace, termbox.KeyBackspace2:
				markX = -1
				markY = -1
				prefix = 1
			default:
				switch ev.Ch {
				case 'q':
					markX = -1
					markY = -1
					return nil
				case 'e':
					markX = -1
					markY = -1
					prefix = 1
				case 'w':
					doMove(0, -prefix)
					prefix = 1
				case 's':
					doMove(0, prefix)
					prefix = 1
				case 'a':
					doMove(-prefix, 0)
					prefix = 1
				case 'd':
					doMove(prefix, 0)
					prefix = 1
				case 'W':
					posY = 0
					prefix = 1
				case 'S':
					posY = 11
					prefix = 1
				case 'A':
					posX = 0
					prefix = 1
				case 'D':
					posX = 11
					prefix = 1
				case '1', '2', '3', '4', '5', '6', '7', '8', '9':
					prefix = int(ev.Ch - '0')
				case '0':
					prefix = 10
				case '-':
					prefix = 11
				case '=':
					prefix = 12
				}
			}
		case termbox.EventMouse:
			switch ev.Key {
			case termbox.MouseLeft:
				posX, posY = mousePos(ev)
				if !mouseHold {
					markX, markY = posX, posY
				}
				mouseHold = true
			case termbox.MouseRight:
				markX, markY = mousePos(ev)
			case termbox.MouseRelease:
				mouseHold = false
			}
		case termbox.EventError:
			return ev.Err
		}
		draw()
	}

	return errors.New("CAN'T HAPPEN")
}

func main() {
	xu, err := xgbutil.NewConn()
	if err != nil {
		log.Fatal(err)
	}

	// get active window's center
	axw, err := ewmh.ActiveWindowGet(xu)
	if err != nil {
		log.Fatal(err)
	}

	aw := xwindow.New(xu, axw)
	geom, err := aw.Geometry()
	if err != nil {
		log.Fatal(err)
	}

	cx := geom.X() + geom.Width()/2
	cy := geom.Y() + geom.Height()/2

	heads, err := xinerama.PhysicalHeads(xu)
	if err != nil {
		log.Fatal(err)
	}

	awHead := heads[0]
	for _, head := range heads {
		if cx >= head.X() &&
			cx <= head.X()+head.Width() &&
			cy >= head.Y() &&
			cy <= head.X()+head.Height() {
			awHead = head
			break
		}
	}

	// fmt.Println(heads)
	// fmt.Println(geom, "→", cx, cy, "→", awHead)

	// Figure out original position on grid
	x0, x1, y0, y1 := geom.X(), geom.X()+geom.Width(), geom.Y(), geom.Y()+geom.Height()
	if awhx0 := awHead.X(); x0 < awhx0 {
		x0 = awhx0
	}
	if awhx1 := awHead.X() + awHead.Width(); x1 > awhx1 {
		x1 = awhx1
	}
	if awhy0 := awHead.Y(); y0 < awhy0 {
		y0 = awhy0
	}
	if awhy1 := awHead.Y() + awHead.Height(); y1 > awhy1 {
		y1 = awhy1
	}

	stepX := awHead.Width() / 12
	stepY := awHead.Height() / 12
	origX0 = (x0 + 1) / stepX
	origX1 = (x1 - 1) / stepX
	origY0 = (y0 + 1) / stepY
	origY1 = (y1 - 1) / stepY

	err = uiMain()
	if err != nil {
		log.Fatal(err)
	}

	if markX < 0 {
		return
	}

	if posX > markX {
		posX, markX = markX, posX
	}

	if posY > markY {
		posY, markY = markY, posY
	}

	markX++
	markY++

	x := posX * stepX
	y := posY * stepY
	w := (markX - posX) * stepX
	h := (markY - posY) * stepY
	// if r := awHead.X() + awHead.Width(); x+w > r {
	// 	w -= r - (x + w)
	// }
	// if b := awHead.Y() + awHead.Height(); y+h > b {
	// 	h -= b - (y + h)
	// }

	// fmt.Println(posX, posY, markX, markY, "*", stepX, stepY, "→", x, y, w, h)

	// TODO: check if ewmh.MoveresizeWindow(xu, aw, x, y, w, h) is supported (not in cwm)
	aw.MoveResize(x+2, y+2, w-4, h-4)
	err = ewmh.ActiveWindowReq(xu, axw)
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>tiler: moar keybindings<commit_after>package main

import (
	"errors"
	"log"

	"github.com/BurntSushi/xgbutil"
	"github.com/BurntSushi/xgbutil/ewmh"
	"github.com/BurntSushi/xgbutil/xinerama"
	"github.com/BurntSushi/xgbutil/xwindow"

	"github.com/mpasternacki/termbox-go"

	"../urxvtermbox"
)

var (
	origX0 = 0
	origX1 = 0
	origY0 = 0
	origY1 = 1
	posX   = 0
	posY   = 0
	markX  = -1
	markY  = -1
	prefix = 1
)

func draw() {
	// axes
	for i := 0; i < 12; i++ {
		ch0 := ' '
		if i >= 9 {
			ch0 = '1'
		}
		ch1 := rune('0' + (i+1)%10)
		fgX := termbox.ColorDefault
		fgY := termbox.ColorDefault
		if i == posX {
			fgX = termbox.ColorWhite | termbox.AttrBold
		}
		if i == posY {
			fgY = termbox.ColorWhite | termbox.AttrBold
		}
		termbox.SetCell(0, i+1, ch0, fgY, termbox.ColorDefault)
		termbox.SetCell(1, i+1, ch1, fgY, termbox.ColorDefault)
		termbox.SetCell(26, i+1, ch0, fgY, termbox.ColorDefault)
		termbox.SetCell(27, i+1, ch1, fgY, termbox.ColorDefault)
		termbox.SetCell(2*i+2, 0, ch0, fgX, termbox.ColorDefault)
		termbox.SetCell(2*i+3, 0, ch1, fgX, termbox.ColorDefault)
		termbox.SetCell(2*i+2, 13, ch0, fgX, termbox.ColorDefault)
		termbox.SetCell(2*i+3, 13, ch1, fgX, termbox.ColorDefault)
	}

	// grid
	for i := 0; i < 12; i++ {
		for j := 0; j < 12; j++ {
			// default fg & char
			fg := termbox.ColorBlue
			ch := '░'

			// original win dimensions are green
			if i >= origX0 && i <= origX1 && j >= origY0 && j <= origY1 {
				fg = termbox.ColorGreen
			}

			// cursor is yellow & solid
			if i == posX && j == posY {
				ch = '█'
				fg = termbox.ColorYellow
			} else if markX >= 0 && markY >= 0 {
				// besides cursor, selected block is more solid
				l, r, t, b := posX, markX, posY, markY
				if l > r {
					l, r = r, l
				}
				if t > b {
					t, b = b, t
				}
				if l <= i && i <= r && t <= j && j <= b {
					ch = '▓'
				}
			}

			// bold/regular checkers
			if (i+j)%2 == 1 {
				fg = fg | termbox.AttrBold
			}

			termbox.SetCell(2*i+2, j+1, ch, fg, termbox.ColorDefault)
			termbox.SetCell(2*i+3, j+1, ch, fg, termbox.ColorDefault)
		}
	}

	// prefix
	prfg := termbox.ColorGreen | termbox.AttrBold
	if prefix == 1 {
		prfg = termbox.ColorBlack | termbox.AttrBold
	}
	pr0 := ' '
	if prefix >= 10 {
		pr0 = '1'
	}
	pr1 := rune('0' + prefix%10)
	termbox.SetCell(0, 0, pr0, prfg, termbox.ColorDefault)
	termbox.SetCell(1, 0, pr1, prfg, termbox.ColorDefault)

	termbox.Flush()
}

func mousePos(ev termbox.Event) (x int, y int) {
	x, y = (ev.MouseX-2)/2, ev.MouseY-1
	if x < 0 {
		x = 0
	}
	if x > 11 {
		x = 11
	}
	if y < 0 {
		y = 0
	}
	if y > 11 {
		y = 11
	}
	return
}

func doMove(dx, dy int) {
	posX += dx
	if posX < 0 {
		posX = 0
	}
	if posX > 11 {
		posX = 11
	}
	posY += dy
	if posY < 0 {
		posY = 0
	}
	if posY > 11 {
		posY = 11
	}
}

func uiMain() error {
	if fini, err := urxvtermbox.TermboxUrxvt(28, 14); err != nil {
		return err
	} else {
		defer fini()
	}

	if err := termbox.Init(); err != nil {
		return err
	}
	defer termbox.Close()
	termbox.SetInputMode(termbox.InputEsc | termbox.InputMouse)

	draw()
	mouseHold := false
	for {
		switch ev := termbox.PollEvent(); ev.Type {
		case termbox.EventKey:
			switch ev.Key {
			case termbox.KeyEsc:
				markX = -1
				markY = -1
				return nil
			case termbox.KeyArrowUp:
				doMove(0, -prefix)
				prefix = 1
			case termbox.KeyArrowDown:
				doMove(0, prefix)
				prefix = 1
			case termbox.KeyArrowLeft:
				doMove(-prefix, 0)
				prefix = 1
			case termbox.KeyArrowRight:
				doMove(prefix, 0)
				prefix = 1
			case termbox.KeyEnter:
				if markX >= 0 {
					return nil
				}
				fallthrough
			case termbox.KeySpace:
				markX, markY = posX, posY
				prefix = 1
			case termbox.KeyTab:
				if markX >= 0 {
					markX, posX = posX, markX
					markY, posY = posY, markY
				}
				prefix = 1
			case termbox.KeyBackspace, termbox.KeyBackspace2:
				markX = -1
				markY = -1
				prefix = 1
			default:
				switch ev.Ch {
				case 'q':
					markX = -1
					markY = -1
					prefix = 1
				case 'e':
					posX = origX1
					posY = origY1
					markX = origX0
					markY = origY0
					prefix = 1
				case 'w':
					doMove(0, -prefix)
					prefix = 1
				case 's':
					doMove(0, prefix)
					prefix = 1
				case 'a':
					doMove(-prefix, 0)
					prefix = 1
				case 'd':
					doMove(prefix, 0)
					prefix = 1
				case 'W':
					posY = 0
					prefix = 1
				case 'S':
					posY = 11
					prefix = 1
				case 'A':
					posX = 0
					prefix = 1
				case 'D':
					posX = 11
					prefix = 1
				case '1', '2', '3', '4', '5', '6', '7', '8', '9':
					prefix = int(ev.Ch - '0')
				case '0':
					prefix = 10
				case '-':
					prefix = 11
				case '=':
					prefix = 12
				case 'h':
					if posX < markX {
						posX = 0
						markX = 11
					} else {
						posX = 11
						markX = 0
					}
					if markY < 0 {
						markY = posY
					}
				case 'v':
					if posY < markY {
						posY = 0
						markY = 11
					} else {
						posY = 11
						markY = 0
					}
					if markX < 0 {
						markX = posX
					}
				}
			}
		case termbox.EventMouse:
			switch ev.Key {
			case termbox.MouseLeft:
				posX, posY = mousePos(ev)
				if !mouseHold {
					markX, markY = posX, posY
				}
				mouseHold = true
			case termbox.MouseRight:
				markX, markY = mousePos(ev)
			case termbox.MouseRelease:
				mouseHold = false
			}
		case termbox.EventError:
			return ev.Err
		}
		draw()
	}

	return errors.New("CAN'T HAPPEN")
}

func main() {
	xu, err := xgbutil.NewConn()
	if err != nil {
		log.Fatal(err)
	}

	// get active window's center
	axw, err := ewmh.ActiveWindowGet(xu)
	if err != nil {
		log.Fatal(err)
	}

	aw := xwindow.New(xu, axw)
	geom, err := aw.Geometry()
	if err != nil {
		log.Fatal(err)
	}

	cx := geom.X() + geom.Width()/2
	cy := geom.Y() + geom.Height()/2

	heads, err := xinerama.PhysicalHeads(xu)
	if err != nil {
		log.Fatal(err)
	}

	awHead := heads[0]
	for _, head := range heads {
		if cx >= head.X() &&
			cx <= head.X()+head.Width() &&
			cy >= head.Y() &&
			cy <= head.X()+head.Height() {
			awHead = head
			break
		}
	}

	// fmt.Println(heads)
	// fmt.Println(geom, "→", cx, cy, "→", awHead)

	// Figure out original position on grid
	x0, x1, y0, y1 := geom.X(), geom.X()+geom.Width(), geom.Y(), geom.Y()+geom.Height()
	if awhx0 := awHead.X(); x0 < awhx0 {
		x0 = awhx0
	}
	if awhx1 := awHead.X() + awHead.Width(); x1 > awhx1 {
		x1 = awhx1
	}
	if awhy0 := awHead.Y(); y0 < awhy0 {
		y0 = awhy0
	}
	if awhy1 := awHead.Y() + awHead.Height(); y1 > awhy1 {
		y1 = awhy1
	}

	stepX := awHead.Width() / 12
	stepY := awHead.Height() / 12
	origX0 = (x0 + 1) / stepX
	origX1 = (x1 - 1) / stepX
	origY0 = (y0 + 1) / stepY
	origY1 = (y1 - 1) / stepY

	err = uiMain()
	if err != nil {
		log.Fatal(err)
	}

	if markX < 0 {
		return
	}

	if posX > markX {
		posX, markX = markX, posX
	}

	if posY > markY {
		posY, markY = markY, posY
	}

	markX++
	markY++

	x := posX * stepX
	y := posY * stepY
	w := (markX - posX) * stepX
	h := (markY - posY) * stepY
	// if r := awHead.X() + awHead.Width(); x+w > r {
	// 	w -= r - (x + w)
	// }
	// if b := awHead.Y() + awHead.Height(); y+h > b {
	// 	h -= b - (y + h)
	// }

	// fmt.Println(posX, posY, markX, markY, "*", stepX, stepY, "→", x, y, w, h)

	// TODO: check if ewmh.MoveresizeWindow(xu, aw, x, y, w, h) is supported (not in cwm)
	aw.MoveResize(x+2, y+2, w-4, h-4)
	err = ewmh.ActiveWindowReq(xu, axw)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


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

package cmd

import (
	"fmt"
	"net/http"
	"os"
	"os/exec"
)

func clientID() string {
	return os.Getenv("TSURU_AUTH_CLIENTID")
}

func localServer() {
	func() {
		http.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) {
			fmt.Fprintf(w, "Test")
		})
		http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
			url := fmt.Sprintf("https://github.com/login/oauth/authorize?client_id=%s&redirect_uri=http://localhost:4242/callback&scope=user:email", clientID())
			http.Redirect(w, r, url, 302)
		})
		http.ListenAndServe(":4242", nil)
	}()
	exec.Command("open", "http://localhost:4242").Start()
}

func oauthLogin(context *Context, client *Client) error {
	localServer()
	return nil
}
<commit_msg>cmd: improved method that opens the browser to support linux.<commit_after>// Copyright 2014 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cmd

import (
	"fmt"
	"net/http"
	"os"
	"os/exec"
	"runtime"
)

func clientID() string {
	return os.Getenv("TSURU_AUTH_CLIENTID")
}

func open(url string) error {
	if runtime.GOOS == "linux" {
		return exec.Command("xdg-open", url).Start()
	}
	return exec.Command("open", url).Start()
}

func localServer() {
	func() {
		http.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) {
			fmt.Fprintf(w, "Test")
		})
		http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
			url := fmt.Sprintf("https://github.com/login/oauth/authorize?client_id=%s&redirect_uri=http://localhost:4242/callback&scope=user:email", clientID())
			http.Redirect(w, r, url, 302)
		})
		http.ListenAndServe(":4242", nil)
	}()
	open("http://localhost:4242")
}

func oauthLogin(context *Context, client *Client) error {
	localServer()
	return nil
}
<|endoftext|>


<commit_before>// Copyright © 2016 Theotime LEVEQUE theotime@protonmail.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"fmt"
	"os"

	"github.com/fatih/color"
	"github.com/spf13/cobra"
	"github.com/thylong/ian/backend/config"
	"github.com/thylong/ian/backend/share"
)

var key = ""

var encryptShareCmdParam bool
var decryptShareCmdParam bool

// var shortLinkShareCmdParam bool

func init() {
	RootCmd.AddCommand(shareCmd)

	shareCmd.PersistentFlags().BoolVarP(&encryptShareCmdParam, "encrypt", "e", false, "Encrypt with private key before uploading")
	shareCmd.PersistentFlags().BoolVarP(&decryptShareCmdParam, "decrypt", "d", false, "Decrypt config file")
	// shareCmd.PersistentFlags().BoolVarP(&shortLinkShareCmdParam, "bitlink", "b", false, "Get a Bit.ly shorten URL")
	shareRetrieveFromLinkCmd.SetUsageTemplate(share.GetshareRetrieveFromLinkCmdUsageTemplate())

	shareCmd.AddCommand(
		shareConfigCmd,
		shareProjectsCmd,
		shareEnvCmd,
		shareRetrieveFromLinkCmd,
		// shareAllCmd,
	)
}

// shareCmd represents the env command
var shareCmd = &cobra.Command{
	Use:   "share",
	Short: "Share ian configuration",
	Long:  `Share a public link to a single (or multiple) ian configuration file.`,
}

var shareConfigCmd = &cobra.Command{
	Use:   "config",
	Short: "Share a public link to ian config.yml file",
	Long:  `Share a public link to ian config.yml file.`,
	Run: func(cmd *cobra.Command, args []string) {
		if encryptShareCmdParam {
			key = config.GetUserInput("Enter a secret key: ")
		}
		link, err := share.Upload(config.ConfigFilesPathes[cmd.Use], "https://transfer.sh/", key)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v It looks like I cannot upload configuration file... :(.", color.RedString("Error:"))
			return
		}
		fmt.Println(link)
	},
}

var shareProjectsCmd = &cobra.Command{
	Use:   "projects",
	Short: "Share a public link to ian projects.yml file",
	Long:  `Share a public link to ian projects.yml file.`,
	Run: func(cmd *cobra.Command, args []string) {
		if encryptShareCmdParam {
			key = config.GetUserPrivateInput("Enter a secret key: ")
		}
		link, err := share.Upload(config.ConfigFilesPathes[cmd.Use], "https://transfer.sh/", key)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v It looks like I cannot upload configuration file... :(.", color.RedString("Error:"))
			return
		}
		fmt.Println(link)
	},
}

var shareEnvCmd = &cobra.Command{
	Use:   "env",
	Short: "Share a public link to ian env.yml file",
	Long:  `Share a public link to ian env.yml file.`,
	Run: func(cmd *cobra.Command, args []string) {
		if encryptShareCmdParam {
			key = config.GetUserPrivateInput("Enter a secret key (32 characters minimum)")
		}
		link, err := share.Upload(config.ConfigFilesPathes[cmd.Use], "https://transfer.sh/", key)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v It looks like I cannot upload configuration file... :(.", color.RedString("Error:"))
			return
		}
		fmt.Println(link)
	},
}

var shareRetrieveFromLinkCmd = &cobra.Command{
	Use:   "retrieve",
	Short: "Retrieve config from config file link",
	Long:  `Retrieve config from config file link.`,
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) < 1 {
			fmt.Fprintf(os.Stderr, "%v Not enough argument.\n\n", color.RedString("Error:"))
			cmd.Usage()
			os.Exit(1)
		}

		key := ""
		if decryptShareCmdParam {
			key = config.GetUserInput("Enter the secret key")
		}
		err := share.Download(args[0], args[1], key)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v %s.", color.RedString("Error:"), err)
			return
		}
	},
}

var shareAllCmd = &cobra.Command{
	Use:   "all",
	Short: "Share a public link to ian a zip containing all files",
	Long:  `Share a public link to ian env.yml file.`,
	Run: func(cmd *cobra.Command, args []string) {
	},
}
<commit_msg>Share: Adjust Usage of encrypt/decrypt parameters.<commit_after>// Copyright © 2016 Theotime LEVEQUE theotime@protonmail.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"fmt"
	"os"

	"github.com/fatih/color"
	"github.com/spf13/cobra"
	"github.com/thylong/ian/backend/config"
	"github.com/thylong/ian/backend/share"
)

var key = ""

var encryptShareCmdParam bool
var decryptShareCmdParam bool

// var shortLinkShareCmdParam bool

func init() {
	RootCmd.AddCommand(shareCmd)

	shareCmd.PersistentFlags().BoolVarP(&encryptShareCmdParam, "encrypt", "e", false, "Encrypt with key before uploading (32 characters minimum)")
	shareCmd.PersistentFlags().BoolVarP(&decryptShareCmdParam, "decrypt", "d", false, "Decrypt config file")
	// shareCmd.PersistentFlags().BoolVarP(&shortLinkShareCmdParam, "bitlink", "b", false, "Get a Bit.ly shorten URL")
	shareRetrieveFromLinkCmd.SetUsageTemplate(share.GetshareRetrieveFromLinkCmdUsageTemplate())

	shareCmd.AddCommand(
		shareConfigCmd,
		shareProjectsCmd,
		shareEnvCmd,
		shareRetrieveFromLinkCmd,
		// shareAllCmd,
	)
}

// shareCmd represents the env command
var shareCmd = &cobra.Command{
	Use:   "share",
	Short: "Share ian configuration",
	Long:  `Share a public link to a single (or multiple) ian configuration file.`,
}

var shareConfigCmd = &cobra.Command{
	Use:   "config",
	Short: "Share a public link to ian config.yml file",
	Long:  `Share a public link to ian config.yml file.`,
	Run: func(cmd *cobra.Command, args []string) {
		if encryptShareCmdParam {
			key = config.GetUserInput("Enter a secret key: ")
		}
		link, err := share.Upload(config.ConfigFilesPathes[cmd.Use], "https://transfer.sh/", key)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v It looks like I cannot upload configuration file... :(.", color.RedString("Error:"))
			return
		}
		fmt.Println(link)
	},
}

var shareProjectsCmd = &cobra.Command{
	Use:   "projects",
	Short: "Share a public link to ian projects.yml file",
	Long:  `Share a public link to ian projects.yml file.`,
	Run: func(cmd *cobra.Command, args []string) {
		if encryptShareCmdParam {
			key = config.GetUserPrivateInput("Enter a secret key: ")
		}
		link, err := share.Upload(config.ConfigFilesPathes[cmd.Use], "https://transfer.sh/", key)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v It looks like I cannot upload configuration file... :(.", color.RedString("Error:"))
			return
		}
		fmt.Println(link)
	},
}

var shareEnvCmd = &cobra.Command{
	Use:   "env",
	Short: "Share a public link to ian env.yml file",
	Long:  `Share a public link to ian env.yml file.`,
	Run: func(cmd *cobra.Command, args []string) {
		if encryptShareCmdParam {
			key = config.GetUserPrivateInput("Enter a secret key (32 characters minimum)")
		}
		link, err := share.Upload(config.ConfigFilesPathes[cmd.Use], "https://transfer.sh/", key)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v It looks like I cannot upload configuration file... :(.", color.RedString("Error:"))
			return
		}
		fmt.Println(link)
	},
}

var shareRetrieveFromLinkCmd = &cobra.Command{
	Use:   "retrieve",
	Short: "Retrieve config from config file link",
	Long:  `Retrieve config from config file link.`,
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) < 1 {
			fmt.Fprintf(os.Stderr, "%v Not enough argument.\n\n", color.RedString("Error:"))
			cmd.Usage()
			os.Exit(1)
		}

		key := ""
		if decryptShareCmdParam {
			key = config.GetUserInput("Enter the secret key")
		}
		err := share.Download(args[0], args[1], key)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v %s.", color.RedString("Error:"), err)
			return
		}
	},
}

var shareAllCmd = &cobra.Command{
	Use:   "all",
	Short: "Share a public link to ian a zip containing all files",
	Long:  `Share a public link to ian env.yml file.`,
	Run: func(cmd *cobra.Command, args []string) {
	},
}
<|endoftext|>


<commit_before>// Copyright 2015 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cmd

import (
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"regexp"
	"strconv"
	"syscall"

	"golang.org/x/crypto/ssh/terminal"
	"github.com/tsuru/tsuru/errors"
)

var httpHeaderRegexp = regexp.MustCompile(`HTTP/.*? (\d+)`)

type ShellToContainerCmd struct {
	GuessingCommand
}

func (c *ShellToContainerCmd) Info() *Info {
	return &Info{
		Name:  "app-shell",
		Usage: "app-shell [unit-id] -a/--app <appname>",
		Desc: `Opens a remote shell inside unit, using the API server as a proxy. You
can access an app unit just giving app name, or specifying the id of the unit.
You can get the ID of the unit using the app-info command.`,
		MinArgs: 0,
	}
}

func (c *ShellToContainerCmd) Run(context *Context, client *Client) error {
	var width, height int
	if stdin, ok := context.Stdin.(*os.File); ok {
		fd := int(stdin.Fd())
		if terminal.IsTerminal(fd) {
			width, height, _ = terminal.GetSize(fd)
			oldState, err := terminal.MakeRaw(fd)
			if err != nil {
				return err
			}
			defer terminal.Restore(fd, oldState)
			sigChan := make(chan os.Signal, 2)
			go func(c <-chan os.Signal) {
				if _, ok := <-c; ok {
					terminal.Restore(fd, oldState)
					os.Exit(1)
				}
			}(sigChan)
			signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGQUIT)
		}
	}
	queryString := make(url.Values)
	queryString.Set("width", strconv.Itoa(width))
	queryString.Set("height", strconv.Itoa(height))
	if len(context.Args) > 0 {
		queryString.Set("unit-id", context.Args[0])
	}
	appName, err := c.Guess()
	if err != nil {
		return err
	}
	serverURL, err := GetURL(fmt.Sprintf("/apps/%s/shell?%s", appName, queryString.Encode()))
	if err != nil {
		return err
	}
	request, err := http.NewRequest("GET", serverURL, nil)
	if err != nil {
		return err
	}
	request.Close = true
	token, err := ReadToken()
	if err == nil {
		request.Header.Set("Authorization", "bearer "+token)
	}
	parsedURL, _ := url.Parse(serverURL)
	host := parsedURL.Host
	if _, _, err := net.SplitHostPort(host); err != nil {
		port := "80"
		if parsedURL.Scheme == "https" {
			port = "443"
		}
		host += ":" + port
	}
	conn, err := net.Dial("tcp", host)
	if err != nil {
		return err
	}
	defer conn.Close()
	request.Write(conn)
	bytesLimit := 12
	var readStr string
	byteBuffer := make([]byte, 1)
	for i := 0; i < bytesLimit && byteBuffer[0] != '\n'; i++ {
		_, err := conn.Read(byteBuffer)
		if err != nil {
			break
		}
		readStr += string(byteBuffer)
	}
	matches := httpHeaderRegexp.FindAllStringSubmatch(readStr, -1)
	if len(matches) > 0 && len(matches[0]) > 1 {
		httpError, _ := strconv.Atoi(matches[0][1])
		var message string
		if (httpError == http.StatusNotFound) {
			message = fmt.Sprintf("App %s not found", appName)
		} else {
			message = http.StatusText(httpError)
		}
		return &errors.HTTP{Code: httpError, Message: message};
	} else {
		context.Stdout.Write([]byte(readStr))
	}
	errs := make(chan error, 2)
	quit := make(chan bool)
	go io.Copy(conn, context.Stdin)
	go func() {
		defer close(quit)
		_, err := io.Copy(context.Stdout, conn)
		if err != nil && err != io.EOF {
			errs <- err
		}
	}()
	<-quit
	close(errs)
	return <-errs
}
<commit_msg>cmd/shell: formatting code<commit_after>// Copyright 2015 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cmd

import (
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"regexp"
	"strconv"
	"syscall"

	"github.com/tsuru/tsuru/errors"
	"golang.org/x/crypto/ssh/terminal"
)

var httpHeaderRegexp = regexp.MustCompile(`HTTP/.*? (\d+)`)

type ShellToContainerCmd struct {
	GuessingCommand
}

func (c *ShellToContainerCmd) Info() *Info {
	return &Info{
		Name:  "app-shell",
		Usage: "app-shell [unit-id] -a/--app <appname>",
		Desc: `Opens a remote shell inside unit, using the API server as a proxy. You
can access an app unit just giving app name, or specifying the id of the unit.
You can get the ID of the unit using the app-info command.`,
		MinArgs: 0,
	}
}

func (c *ShellToContainerCmd) Run(context *Context, client *Client) error {
	var width, height int
	if stdin, ok := context.Stdin.(*os.File); ok {
		fd := int(stdin.Fd())
		if terminal.IsTerminal(fd) {
			width, height, _ = terminal.GetSize(fd)
			oldState, err := terminal.MakeRaw(fd)
			if err != nil {
				return err
			}
			defer terminal.Restore(fd, oldState)
			sigChan := make(chan os.Signal, 2)
			go func(c <-chan os.Signal) {
				if _, ok := <-c; ok {
					terminal.Restore(fd, oldState)
					os.Exit(1)
				}
			}(sigChan)
			signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGQUIT)
		}
	}
	queryString := make(url.Values)
	queryString.Set("width", strconv.Itoa(width))
	queryString.Set("height", strconv.Itoa(height))
	if len(context.Args) > 0 {
		queryString.Set("unit-id", context.Args[0])
	}
	appName, err := c.Guess()
	if err != nil {
		return err
	}
	serverURL, err := GetURL(fmt.Sprintf("/apps/%s/shell?%s", appName, queryString.Encode()))
	if err != nil {
		return err
	}
	request, err := http.NewRequest("GET", serverURL, nil)
	if err != nil {
		return err
	}
	request.Close = true
	token, err := ReadToken()
	if err == nil {
		request.Header.Set("Authorization", "bearer "+token)
	}
	parsedURL, _ := url.Parse(serverURL)
	host := parsedURL.Host
	if _, _, err := net.SplitHostPort(host); err != nil {
		port := "80"
		if parsedURL.Scheme == "https" {
			port = "443"
		}
		host += ":" + port
	}
	conn, err := net.Dial("tcp", host)
	if err != nil {
		return err
	}
	defer conn.Close()
	request.Write(conn)
	bytesLimit := 12
	var readStr string
	byteBuffer := make([]byte, 1)
	for i := 0; i < bytesLimit && byteBuffer[0] != '\n'; i++ {
		_, err := conn.Read(byteBuffer)
		if err != nil {
			break
		}
		readStr += string(byteBuffer)
	}
	matches := httpHeaderRegexp.FindAllStringSubmatch(readStr, -1)
	if len(matches) > 0 && len(matches[0]) > 1 {
		httpError, _ := strconv.Atoi(matches[0][1])
		var message string
		if httpError == http.StatusNotFound {
			message = fmt.Sprintf("App %s not found", appName)
		} else {
			message = http.StatusText(httpError)
		}
		return &errors.HTTP{Code: httpError, Message: message}
	} else {
		context.Stdout.Write([]byte(readStr))
	}
	errs := make(chan error, 2)
	quit := make(chan bool)
	go io.Copy(conn, context.Stdin)
	go func() {
		defer close(quit)
		_, err := io.Copy(context.Stdout, conn)
		if err != nil && err != io.EOF {
			errs <- err
		}
	}()
	<-quit
	close(errs)
	return <-errs
}
<|endoftext|>


<commit_before>package tools

import (
	"math"
	"math/big"
	"sort"
	"strconv"
)

// Sum returns the sum of its argument.
func Sum(a ...int) int {
	var s int
	for _, v := range a {
		s += v
	}
	return s
}

// SqrtInt computes the square root of n and casts to an int.
func SqrtInt(n int) int {
	return int(math.Sqrt(float64(n)))
}

// Divisors returns all the proper divisors of n.
func Divisors(n int) []int {
	d := []int{1}
	for i := 2; i <= SqrtInt(n); i++ {
		if n%i == 0 {
			d = append(d, i)
			if other := n / i; other != i {
				d = append(d, other)
			}
		}
	}
	return d
}

// SumDivisors sums all the proper divisors of n.
func SumDivisors(n int) int {
	return Sum(Divisors(n)...)
}

// Perms return a channel of each permutation of a slice.
func Perms(slice []int) chan []int {
	c := make(chan []int)
	go func() {
		if len(slice) == 1 {
			c <- slice
		} else {
			for i, v := range slice {
				b := append([]int(nil), slice[:i]...)
				b = append(b, slice[i+1:]...)
				for p := range Perms(b) {
					c <- append([]int{v}, p...)
				}
			}
		}
		close(c)
	}()
	return c
}

// Divmod gives the quotient and remainder of integer division.
func Divmod(a, b int) (int, int) {
	return a / b, a % b
}

// PrimeFactors gives the prime factors of an int.
func PrimeFactors(n int) map[int]int {
	factors := make(map[int]int)
	d := 2
	for n > 1 {
		for n%d == 0 {
			n /= d
			factors[d]++
		}
		d++
	}
	return factors
}

// IsPrime determines if a given number is prime.
// https://en.wikipedia.org/wiki/Primality_test
func IsPrime(n int) bool {
	if n <= 1 {
		return false
	}
	if n <= 3 {
		return true
	}
	if n%2 == 0 || n%3 == 0 {
		return false
	}
	b := SqrtInt(n)
	for i := 5; i <= b; i += 6 {
		if n%i == 0 || n%(i+2) == 0 {
			return false
		}
	}
	return true
}

// SievePrime gives all the primes below n via the method of Eratosthenes.
func SievePrime(n int) []int {
	var primes []int
	comp := make([]bool, n+2)
	for i := 2; i <= int(math.Sqrt(float64(n))); i++ {
		for j := i * i; j < n; j += i {
			comp[j] = true
		}
	}
	for i, v := range comp {
		if i > 1 && !v && i < n {
			primes = append(primes, i)
		}
	}
	return primes
}

// Exp computes x to the power of y.
func Exp(x, y int) *big.Int {
	a := big.NewInt(1)
	b := big.NewInt(int64(x))
	for i := 0; i < y; i++ {
		a.Mul(a, b)
	}
	return a
}

// DigitSum sums the digit^p of a given number.
func DigitSum(n, p int) *big.Int {
	s := big.NewInt(0)
	for _, c := range strconv.Itoa(n) {
		i, _ := strconv.Atoi(string(c))
		s.Add(s, Exp(i, p))
	}
	return s
}

// JoinInts joins slice of ints and return it as an int.
func JoinInts(slice []int) int {
	var sum int
	len := len(slice) - 1
	for i, v := range slice {
		p := 1
		for j := 0; j < len-i; j++ {
			p *= 10
		}
		sum += p * v
	}
	return sum
}

// ProdInts computes the product of the slice of ints.
func ProdInts(slice []int) int {
	p := 1
	for _, v := range slice {
		p *= v
	}
	return p
}

// MinInt returns the smaller number of a and b.
func MinInt(a, b int) int {
	if a < b {
		return a
	}
	return b
}

// MaxInt returns the larger number of a and b.
func MaxInt(a, b int) int {
	if a > b {
		return a
	}
	return b
}

// SimplifyFraction simplifies a/b and return the (numerator, denominator).
func SimplifyFraction(a, b int) (int, int) {
	pa := PrimeFactors(a)
	pb := PrimeFactors(b)
	for k, v := range pa {
		v2, ok := pb[k]
		if !ok {
			continue
		}
		m := MinInt(v, v2)
		pa[k] = v - m
		pb[k] = v2 - m
	}
	sa := 1
	for k, v := range pa {
		for i := 0; i < v; i++ {
			sa *= k
		}
	}
	sb := 1
	for k, v := range pb {
		for i := 0; i < v; i++ {
			sb *= k
		}
	}
	return sa, sb
}

// Digits returns the individual digits as a slice of int.
func Digits(n int) []int {
	var d []int
	for n > 0 {
		d = append([]int{n % 10}, d...)
		n /= 10
	}
	return d
}

// DigitsIth returns the i-th digit of a number n.
func DigitsIth(n, i int) int {
	d := Digits(n)
	if i < 0 || i >= len(d) {
		return -1
	}
	return Digits(n)[i]
}

// Factorial returns the fractorial of a number.
func Factorial(n int) *big.Int {
	a := big.NewInt(1)
	for i := 2; i <= n; i++ {
		a.Mul(a, big.NewInt(int64(i)))
	}
	return a
}

// IsPalindromeInt tells if a number is a palindrome.
func IsPalindromeInt(n int) bool {
	return IsPalindromeString(strconv.Itoa(n))
}

// IsPandigital determines if a number is 1 to 9 pandigital.
func IsPandigital(n int) bool {
	d := Digits(n)
	sort.Ints(d)
	a := JoinInts(d)
	return a == 123456789
}
<commit_msg>* generalize IsPandigital<commit_after>package tools

import (
	"math"
	"math/big"
	"sort"
	"strconv"
)

// Sum returns the sum of its argument.
func Sum(a ...int) int {
	var s int
	for _, v := range a {
		s += v
	}
	return s
}

// SqrtInt computes the square root of n and casts to an int.
func SqrtInt(n int) int {
	return int(math.Sqrt(float64(n)))
}

// Divisors returns all the proper divisors of n.
func Divisors(n int) []int {
	d := []int{1}
	for i := 2; i <= SqrtInt(n); i++ {
		if n%i == 0 {
			d = append(d, i)
			if other := n / i; other != i {
				d = append(d, other)
			}
		}
	}
	return d
}

// SumDivisors sums all the proper divisors of n.
func SumDivisors(n int) int {
	return Sum(Divisors(n)...)
}

// Perms return a channel of each permutation of a slice.
func Perms(slice []int) chan []int {
	c := make(chan []int)
	go func() {
		if len(slice) == 1 {
			c <- slice
		} else {
			for i, v := range slice {
				b := append([]int(nil), slice[:i]...)
				b = append(b, slice[i+1:]...)
				for p := range Perms(b) {
					c <- append([]int{v}, p...)
				}
			}
		}
		close(c)
	}()
	return c
}

// Divmod gives the quotient and remainder of integer division.
func Divmod(a, b int) (int, int) {
	return a / b, a % b
}

// PrimeFactors gives the prime factors of an int.
func PrimeFactors(n int) map[int]int {
	factors := make(map[int]int)
	d := 2
	for n > 1 {
		for n%d == 0 {
			n /= d
			factors[d]++
		}
		d++
	}
	return factors
}

// IsPrime determines if a given number is prime.
// https://en.wikipedia.org/wiki/Primality_test
func IsPrime(n int) bool {
	if n <= 1 {
		return false
	}
	if n <= 3 {
		return true
	}
	if n%2 == 0 || n%3 == 0 {
		return false
	}
	b := SqrtInt(n)
	for i := 5; i <= b; i += 6 {
		if n%i == 0 || n%(i+2) == 0 {
			return false
		}
	}
	return true
}

// SievePrime gives all the primes below n via the method of Eratosthenes.
func SievePrime(n int) []int {
	var primes []int
	comp := make([]bool, n+2)
	for i := 2; i <= int(math.Sqrt(float64(n))); i++ {
		for j := i * i; j < n; j += i {
			comp[j] = true
		}
	}
	for i, v := range comp {
		if i > 1 && !v && i < n {
			primes = append(primes, i)
		}
	}
	return primes
}

// Exp computes x to the power of y.
func Exp(x, y int) *big.Int {
	a := big.NewInt(1)
	b := big.NewInt(int64(x))
	for i := 0; i < y; i++ {
		a.Mul(a, b)
	}
	return a
}

// DigitSum sums the digit^p of a given number.
func DigitSum(n, p int) *big.Int {
	s := big.NewInt(0)
	for _, c := range strconv.Itoa(n) {
		i, _ := strconv.Atoi(string(c))
		s.Add(s, Exp(i, p))
	}
	return s
}

// JoinInts joins slice of ints and return it as an int.
func JoinInts(slice []int) int {
	var sum int
	len := len(slice) - 1
	for i, v := range slice {
		p := 1
		for j := 0; j < len-i; j++ {
			p *= 10
		}
		sum += p * v
	}
	return sum
}

// ProdInts computes the product of the slice of ints.
func ProdInts(slice []int) int {
	p := 1
	for _, v := range slice {
		p *= v
	}
	return p
}

// MinInt returns the smaller number of a and b.
func MinInt(a, b int) int {
	if a < b {
		return a
	}
	return b
}

// MaxInt returns the larger number of a and b.
func MaxInt(a, b int) int {
	if a > b {
		return a
	}
	return b
}

// SimplifyFraction simplifies a/b and return the (numerator, denominator).
func SimplifyFraction(a, b int) (int, int) {
	pa := PrimeFactors(a)
	pb := PrimeFactors(b)
	for k, v := range pa {
		v2, ok := pb[k]
		if !ok {
			continue
		}
		m := MinInt(v, v2)
		pa[k] = v - m
		pb[k] = v2 - m
	}
	sa := 1
	for k, v := range pa {
		for i := 0; i < v; i++ {
			sa *= k
		}
	}
	sb := 1
	for k, v := range pb {
		for i := 0; i < v; i++ {
			sb *= k
		}
	}
	return sa, sb
}

// Digits returns the individual digits as a slice of int.
func Digits(n int) []int {
	var d []int
	for n > 0 {
		d = append([]int{n % 10}, d...)
		n /= 10
	}
	return d
}

// DigitsIth returns the i-th digit of a number n.
func DigitsIth(n, i int) int {
	d := Digits(n)
	if i < 0 || i >= len(d) {
		return -1
	}
	return Digits(n)[i]
}

// Factorial returns the fractorial of a number.
func Factorial(n int) *big.Int {
	a := big.NewInt(1)
	for i := 2; i <= n; i++ {
		a.Mul(a, big.NewInt(int64(i)))
	}
	return a
}

// IsPalindromeInt tells if a number is a palindrome.
func IsPalindromeInt(n int) bool {
	return IsPalindromeString(strconv.Itoa(n))
}

// IsPandigital determines if a number is pandigital.
func IsPandigital(n int) bool {
	d := Digits(n)
	sort.Ints(d)
	ans := true
	for i, v := range d {
		if i+1 != v {
			ans = false
			break
		}
	}
	return ans
}
<|endoftext|>


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

package src

import (
	"fmt"
	"reflect"
)

type TypeSpec struct {
	Doc  []string `json:"doc"`
	Name string   `json:"name"`
}

func newTypeSpec(m map[string]interface{}) (*TypeSpec, error) {
	var err error
	errPrefix := "src/type_specifier"
	typespec := TypeSpec{}

	if typespec.Doc, err = extractStringSliceValue("doc", errPrefix, m); err != nil {
		return nil, addDebugInfo(err)
	}

	if typespec.Name, err = extractStringValue("name", errPrefix, m); err != nil {
		return nil, addDebugInfo(err)
	}

	return &typespec, nil
}

func newTypeSpecsSlice(key, errPrefix string, m map[string]interface{}) ([]*TypeSpec, error) {
	var err error
	var s reflect.Value

	typespecsMap, ok := m[key]
	if !ok {
		// XXX It is not possible to add debug info on this error because it is
		// required that this error be en "errNotExist".
		return nil, errNotExist
	}

	if s = reflect.ValueOf(typespecsMap); s.Kind() != reflect.Slice {
		return nil, addDebugInfo(fmt.Errorf(
			"%s: field '%s' is supposed to be a slice", errPrefix, key))
	}

	typespecs := make([]*TypeSpec, s.Len(), s.Len())
	for i := 0; i < s.Len(); i++ {
		typespec := s.Index(i).Interface()

		switch typespec.(type) {
		case map[string]interface{}:
			if typespecs[i], err = newTypeSpec(typespec.(map[string]interface{})); err != nil {
				return nil, addDebugInfo(err)
			}
		default:
			return nil, addDebugInfo(fmt.Errorf(
				"%s: '%s' must be a map[string]interface{}", errPrefix, key))
		}
	}

	return typespecs, nil
}
<commit_msg>src: complete TypeSpec type<commit_after>// Copyright 2014-2015 The DevMine Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package src

import (
	"fmt"
	"reflect"
)

type TypeSpec struct {
	Doc  []string `json:"doc"`
	Name *Ident   `json:"name"`
	Type Expr     `json:"type"`
}

func newTypeSpec(m map[string]interface{}) (*TypeSpec, error) {
	var err error
	errPrefix := "src/type_specifier"
	typespec := TypeSpec{}

	if typespec.Doc, err = extractStringSliceValue("doc", errPrefix, m); err != nil {
		return nil, addDebugInfo(err)
	}

	nameMap, err := extractMapValue("name", errPrefix, m)
	if err != nil {
		return nil, addDebugInfo(err)
	}

	if typespec.Name, err = newIdent(nameMap); err != nil {
		return nil, addDebugInfo(err)
	}

	typeMap, err := extractMapValue("type", errPrefix, m)
	if err != nil {
		return nil, addDebugInfo(err)
	}

	if typespec.Type, err = newExpr(typeMap); err != nil {
		return nil, addDebugInfo(err)
	}

	return &typespec, nil
}

func newTypeSpecsSlice(key, errPrefix string, m map[string]interface{}) ([]*TypeSpec, error) {
	var err error
	var s reflect.Value

	typespecsMap, ok := m[key]
	if !ok {
		// XXX It is not possible to add debug info on this error because it is
		// required that this error be en "errNotExist".
		return nil, errNotExist
	}

	if s = reflect.ValueOf(typespecsMap); s.Kind() != reflect.Slice {
		return nil, addDebugInfo(fmt.Errorf(
			"%s: field '%s' is supposed to be a slice", errPrefix, key))
	}

	typespecs := make([]*TypeSpec, s.Len(), s.Len())
	for i := 0; i < s.Len(); i++ {
		typespec := s.Index(i).Interface()

		switch typespec.(type) {
		case map[string]interface{}:
			if typespecs[i], err = newTypeSpec(typespec.(map[string]interface{})); err != nil {
				return nil, addDebugInfo(err)
			}
		default:
			return nil, addDebugInfo(fmt.Errorf(
				"%s: '%s' must be a map[string]interface{}", errPrefix, key))
		}
	}

	return typespecs, nil
}
<|endoftext|>


<commit_before>package linear_models

import "C"

import (
	"encoding/json"
	"fmt"
	"github.com/sjwhitworth/golearn/base"
	"io/ioutil"
	"os"
	"unsafe"
)

// LinearSVCParams represnts all available LinearSVC options.
//
// SolverKind: can be linear_models.L2_L1LOSS_SVC_DUAL,
// L2R_L2LOSS_SVC_DUAL, L2R_L2LOSS_SVC, L1R_L2LOSS_SVC.
// It must be set via SetKindFromStrings.
//
// ClassWeights describes how each class is weighted, and can
// be used in class-imabalanced scenarios. If this is nil, then
// all classes will be weighted the same unless WeightClassesAutomatically
// is True.
//
// C is a float64 represnenting the misclassification penalty.
//
// Eps is a float64 convergence threshold.
//
// Dual indicates whether the solution is primary or dual.
type LinearSVCParams struct {
	SolverType                 int
	ClassWeights               []float64
	C                          float64
	Eps                        float64
	WeightClassesAutomatically bool
	Dual                       bool
}

// Copy return s a copy of these parameters
func (p *LinearSVCParams) Copy() *LinearSVCParams {
	ret := &LinearSVCParams{
		p.SolverType,
		nil,
		p.C,
		p.Eps,
		p.WeightClassesAutomatically,
		p.Dual,
	}
	if p.ClassWeights != nil {
		ret.ClassWeights = make([]float64, len(p.ClassWeights))
		copy(ret.ClassWeights, p.ClassWeights)
	}
	return ret
}

// SetKindFromStrings configures the solver kind from strings.
// Penalty and Loss parameters can either be l1 or l2.
func (p *LinearSVCParams) SetKindFromStrings(loss, penalty string) error {
	var ret error
	p.SolverType = 0
	// Loss validation
	if loss == "l1" {
	} else if loss == "l2" {
	} else {
		return fmt.Errorf("loss must be \"l1\" or \"l2\"")
	}

	// Penalty validation
	if penalty == "l2" {
		if loss == "l1" {
			if !p.Dual {
				ret = fmt.Errorf("Important: changed to dual form")
			}
			p.SolverType = L2R_L1LOSS_SVC_DUAL
			p.Dual = true
		} else {
			if p.Dual {
				p.SolverType = L2R_L2LOSS_SVC_DUAL
			} else {
				p.SolverType = L2R_L2LOSS_SVC
			}
		}
	} else if penalty == "l1" {
		if loss == "l2" {
			if p.Dual {
				ret = fmt.Errorf("Important: changed to primary form")
			}
			p.Dual = false
			p.SolverType = L1R_L2LOSS_SVC
		} else {
			return fmt.Errorf("Must have L2 loss with L1 penalty")
		}
	} else {
		return fmt.Errorf("Penalty must be \"l1\" or \"l2\"")
	}

	// Final validation
	if p.SolverType == 0 {
		return fmt.Errorf("Invalid parameter combination")
	}
	return ret
}

// convertToNativeFormat converts the LinearSVCParams given into a format
// for liblinear.
func (p *LinearSVCParams) convertToNativeFormat() *Parameter {
	return NewParameter(p.SolverType, p.C, p.Eps)
}

// LinearSVC represents a linear support-vector classifier.
type LinearSVC struct {
	param *Parameter
	model *Model
	Param *LinearSVCParams
}

// NewLinearSVC creates a new support classifier.
//
// loss and penalty: see LinearSVCParams#SetKindFromString
//
// dual: see LinearSVCParams
//
// eps: see LinearSVCParams
//
// C: see LinearSVCParams
func NewLinearSVC(loss, penalty string, dual bool, C float64, eps float64) (*LinearSVC, error) {

	// Convert and check parameters
	params := &LinearSVCParams{0, nil, C, eps, false, dual}
	err := params.SetKindFromStrings(loss, penalty)
	if err != nil {
		return nil, err
	}

	return NewLinearSVCFromParams(params)
}

// NewLinearSVCFromParams constructs a LinearSVC from the given LinearSVCParams structure.
func NewLinearSVCFromParams(params *LinearSVCParams) (*LinearSVC, error) {
	// Construct model
	lr := LinearSVC{}
	lr.param = params.convertToNativeFormat()
	lr.Param = params
	lr.model = nil
	return &lr, nil
}

// Fit automatically weights the class vector (if configured to do so)
// converts the FixedDataGrid into the right format and trains the model.
func (lr *LinearSVC) Fit(X base.FixedDataGrid) error {

	var weightVec []float64
	var weightClasses []C.int

	// Creates the class weighting
	if lr.Param.ClassWeights == nil {
		if lr.Param.WeightClassesAutomatically {
			weightVec = generateClassWeightVectorFromDist(X)
		} else {
			weightVec = generateClassWeightVectorFromFixed(X)
		}
	} else {
		weightVec = lr.Param.ClassWeights
	}

	weightClasses = make([]C.int, len(weightVec))
	for i := range weightVec {
		weightClasses[i] = C.int(i)
	}

	// Convert the problem
	problemVec := convertInstancesToProblemVec(X)
	labelVec := convertInstancesToLabelVec(X)

	// Train
	prob := NewProblem(problemVec, labelVec, 0)
	lr.param.c_param.nr_weight = C.int(len(weightVec))
	lr.param.c_param.weight_label = &(weightClasses[0])
	lr.param.c_param.weight = (*C.double)(unsafe.Pointer(&weightVec[0]))

	//	lr.param.weights = (*C.double)unsafe.Pointer(&(weightVec[0]));
	lr.model = Train(prob, lr.param)
	return nil
}

// Predict issues predictions from a trained LinearSVC.
func (lr *LinearSVC) Predict(X base.FixedDataGrid) (base.FixedDataGrid, error) {

	// Only support 1 class Attribute
	classAttrs := X.AllClassAttributes()
	if len(classAttrs) != 1 {
		panic(fmt.Sprintf("%d Wrong number of classes", len(classAttrs)))
	}
	// Generate return structure
	ret := base.GeneratePredictionVector(X)
	classAttrSpecs := base.ResolveAttributes(ret, classAttrs)

	// Retrieve numeric non-class Attributes
	numericAttrs := base.NonClassFloatAttributes(X)
	numericAttrSpecs := base.ResolveAttributes(X, numericAttrs)

	// Allocate row storage
	row := make([]float64, len(numericAttrSpecs))
	X.MapOverRows(numericAttrSpecs, func(rowBytes [][]byte, rowNo int) (bool, error) {
		for i, r := range rowBytes {
			row[i] = base.UnpackBytesToFloat(r)
		}
		val := Predict(lr.model, row)
		vals := base.PackFloatToBytes(val)
		ret.Set(classAttrSpecs[0], rowNo, vals)
		return true, nil
	})

	return ret, nil
}

func (lr *LinearSVC) GetMetadata() base.ClassifierMetadataV1 {

	params, err := json.Marshal(lr.Param)
	if err != nil {
		panic(err)
	}

	classifierParams := make(map[string]interface{})
	err = json.Unmarshal(params, &classifierParams)
	if err != nil {
		panic(err)
	}

	return base.ClassifierMetadataV1{
		FormatVersion:      1,
		ClassifierName:     "LinearSVC",
		ClassifierVersion:  "1.0",
		ClassifierMetadata: classifierParams,
	}
}

// Save outputs this classifier
func (lr *LinearSVC) Save(filePath string) error {
	writer, err := base.CreateSerializedClassifierStub(filePath, lr.GetMetadata())
	if err != nil {
		return err
	}
	defer func() {
		writer.Close()
	}()
	fmt.Printf("writer: %v", writer)
	return lr.SaveWithPrefix(writer, "")
}

func (lr *LinearSVC) SaveWithPrefix(writer *base.ClassifierSerializer, prefix string) error {
	params, err := json.Marshal(lr.Param)
	if err != nil {
		return base.DescribeError("Error marshalling parameters", err)
	}

	classifierParams := make(map[string]interface{})
	err = json.Unmarshal(params, &classifierParams)
	if err != nil {
		return base.DescribeError("Error marshalling parameters", err)
	}

	f, err := ioutil.TempFile(os.TempDir(), "liblinear")
	defer func() {
		f.Close()
	}()
	err = Export(lr.model, f.Name())
	if err != nil {
		return base.DescribeError("Error exporting model", err)
	}

	f.Seek(0, os.SEEK_SET)
	bytes, err := ioutil.ReadAll(f)
	if err != nil {
		return base.DescribeError("Error reading model in again", err)
	}

	err = writer.WriteBytesForKey(writer.Prefix(prefix, "PARAMETERS"), params)
	if err != nil {
		return base.DescribeError("Error writing model parameters", err)
	}
	writer.WriteBytesForKey(writer.Prefix(prefix, "MODEL"), bytes)
	if err != nil {
		return base.DescribeError("Error writing model", err)
	}

	return nil
}

func (lr *LinearSVC) Load(filePath string) error {
	reader, err := base.ReadSerializedClassifierStub(filePath)
	if err != nil {
		return err
	}
	defer func() {
		reader.Close()
	}()

	return lr.LoadWithPrefix(reader, "")
}

func (lr *LinearSVC) LoadWithPrefix(reader *base.ClassifierDeserializer, prefix string) error {
	err := reader.GetJSONForKey(reader.Prefix(prefix, "PARAMETERS"), &lr.Param)
	if err != nil {
		return base.DescribeError("Error reading PARAMETERS", err)
	}

	modelBytes, err := reader.GetBytesForKey(reader.Prefix(prefix, "MODEL"))
	if err != nil {
		return base.DescribeError("Error reading MODEL", err)
	}

	f, err := ioutil.TempFile(os.TempDir(), "linear")
	defer func() {
		f.Close()
	}()

	f.WriteAt(modelBytes, 0)

	lr.model = &Model{}

	err = Load(lr.model, f.Name())
	if err != nil {
		return base.DescribeError("Unable to reload the model", err)
	}
	return nil
}

// String return a humaan-readable version.
func (lr *LinearSVC) String() string {
	return "LogisticSVC"
}
<commit_msg>recover<commit_after>package linear_models

import "C"

import (
	"encoding/json"
	"fmt"
	"github.com/sjwhitworth/golearn/base"
	"io/ioutil"
	"os"
	"unsafe"
)

// LinearSVCParams represnts all available LinearSVC options.
//
// SolverKind: can be linear_models.L2_L1LOSS_SVC_DUAL,
// L2R_L2LOSS_SVC_DUAL, L2R_L2LOSS_SVC, L1R_L2LOSS_SVC.
// It must be set via SetKindFromStrings.
//
// ClassWeights describes how each class is weighted, and can
// be used in class-imabalanced scenarios. If this is nil, then
// all classes will be weighted the same unless WeightClassesAutomatically
// is True.
//
// C is a float64 represnenting the misclassification penalty.
//
// Eps is a float64 convergence threshold.
//
// Dual indicates whether the solution is primary or dual.
type LinearSVCParams struct {
	SolverType                 int
	ClassWeights               []float64
	C                          float64
	Eps                        float64
	WeightClassesAutomatically bool
	Dual                       bool
}

// Copy return s a copy of these parameters
func (p *LinearSVCParams) Copy() *LinearSVCParams {
	ret := &LinearSVCParams{
		p.SolverType,
		nil,
		p.C,
		p.Eps,
		p.WeightClassesAutomatically,
		p.Dual,
	}
	if p.ClassWeights != nil {
		ret.ClassWeights = make([]float64, len(p.ClassWeights))
		copy(ret.ClassWeights, p.ClassWeights)
	}
	return ret
}

// SetKindFromStrings configures the solver kind from strings.
// Penalty and Loss parameters can either be l1 or l2.
func (p *LinearSVCParams) SetKindFromStrings(loss, penalty string) error {
	var ret error
	p.SolverType = 0
	// Loss validation
	if loss == "l1" {
	} else if loss == "l2" {
	} else {
		return fmt.Errorf("loss must be \"l1\" or \"l2\"")
	}

	// Penalty validation
	if penalty == "l2" {
		if loss == "l1" {
			if !p.Dual {
				ret = fmt.Errorf("Important: changed to dual form")
			}
			p.SolverType = L2R_L1LOSS_SVC_DUAL
			p.Dual = true
		} else {
			if p.Dual {
				p.SolverType = L2R_L2LOSS_SVC_DUAL
			} else {
				p.SolverType = L2R_L2LOSS_SVC
			}
		}
	} else if penalty == "l1" {
		if loss == "l2" {
			if p.Dual {
				ret = fmt.Errorf("Important: changed to primary form")
			}
			p.Dual = false
			p.SolverType = L1R_L2LOSS_SVC
		} else {
			return fmt.Errorf("Must have L2 loss with L1 penalty")
		}
	} else {
		return fmt.Errorf("Penalty must be \"l1\" or \"l2\"")
	}

	// Final validation
	if p.SolverType == 0 {
		return fmt.Errorf("Invalid parameter combination")
	}
	return ret
}

// convertToNativeFormat converts the LinearSVCParams given into a format
// for liblinear.
func (p *LinearSVCParams) convertToNativeFormat() *Parameter {
	return NewParameter(p.SolverType, p.C, p.Eps)
}

// LinearSVC represents a linear support-vector classifier.
type LinearSVC struct {
	param *Parameter
	model *Model
	Param *LinearSVCParams
}

// NewLinearSVC creates a new support classifier.
//
// loss and penalty: see LinearSVCParams#SetKindFromString
//
// dual: see LinearSVCParams
//
// eps: see LinearSVCParams
//
// C: see LinearSVCParams
func NewLinearSVC(loss, penalty string, dual bool, C float64, eps float64) (*LinearSVC, error) {

	// Convert and check parameters
	params := &LinearSVCParams{0, nil, C, eps, false, dual}
	err := params.SetKindFromStrings(loss, penalty)
	if err != nil {
		return nil, err
	}

	return NewLinearSVCFromParams(params)
}

// NewLinearSVCFromParams constructs a LinearSVC from the given LinearSVCParams structure.
func NewLinearSVCFromParams(params *LinearSVCParams) (*LinearSVC, error) {
	// Construct model
	lr := LinearSVC{}
	lr.param = params.convertToNativeFormat()
	lr.Param = params
	lr.model = nil
	return &lr, nil
}

// Fit automatically weights the class vector (if configured to do so)
// converts the FixedDataGrid into the right format and trains the model.
func (lr *LinearSVC) Fit(X base.FixedDataGrid) error {

	var weightVec []float64
	var weightClasses []C.int

	// Creates the class weighting
	if lr.Param.ClassWeights == nil {
		if lr.Param.WeightClassesAutomatically {
			weightVec = generateClassWeightVectorFromDist(X)
		} else {
			weightVec = generateClassWeightVectorFromFixed(X)
		}
	} else {
		weightVec = lr.Param.ClassWeights
	}

	weightClasses = make([]C.int, len(weightVec))
	for i := range weightVec {
		weightClasses[i] = C.int(i)
	}

	// Convert the problem
	problemVec := convertInstancesToProblemVec(X)
	labelVec := convertInstancesToLabelVec(X)

	// Train
	prob := NewProblem(problemVec, labelVec, 0)
	lr.param.c_param.nr_weight = C.int(len(weightVec))
	lr.param.c_param.weight_label = &(weightClasses[0])
	lr.param.c_param.weight = (*C.double)(unsafe.Pointer(&weightVec[0]))

	//	lr.param.weights = (*C.double)unsafe.Pointer(&(weightVec[0]));
	lr.model = Train(prob, lr.param)
	return nil
}

// Predict issues predictions from a trained LinearSVC.
func (lr *LinearSVC) Predict(X base.FixedDataGrid) (base.FixedDataGrid, error) {

	// Only support 1 class Attribute
	classAttrs := X.AllClassAttributes()
	if len(classAttrs) != 1 {
		panic(fmt.Sprintf("%d Wrong number of classes", len(classAttrs)))
	}
	// Generate return structure
	ret := base.GeneratePredictionVector(X)
	classAttrSpecs := base.ResolveAttributes(ret, classAttrs)

	// Retrieve numeric non-class Attributes
	numericAttrs := base.NonClassFloatAttributes(X)
	numericAttrSpecs := base.ResolveAttributes(X, numericAttrs)

	// Allocate row storage
	row := make([]float64, len(numericAttrSpecs))
	X.MapOverRows(numericAttrSpecs, func(rowBytes [][]byte, rowNo int) (bool, error) {
		for i, r := range rowBytes {
			row[i] = base.UnpackBytesToFloat(r)
		}
		val := Predict(lr.model, row)
		vals := base.PackFloatToBytes(val)
		ret.Set(classAttrSpecs[0], rowNo, vals)
		return true, nil
	})

	return ret, nil
}

func (lr *LinearSVC) GetMetadata() base.ClassifierMetadataV1 {

	params, err := json.Marshal(lr.Param)
	if err != nil {
		panic(err)
	}

	classifierParams := make(map[string]interface{})
	err = json.Unmarshal(params, &classifierParams)
	if err != nil {
		panic(err)
	}

	return base.ClassifierMetadataV1{
		FormatVersion:      1,
		ClassifierName:     "LinearSVC",
		ClassifierVersion:  "1.0",
		ClassifierMetadata: classifierParams,
	}
}

// Save outputs this classifier
func (lr *LinearSVC) Save(filePath string) error {
	writer, err := base.CreateSerializedClassifierStub(filePath, lr.GetMetadata())
	if err != nil {
		return err
	}
	defer func() {
		writer.Close()
	}()
	fmt.Printf("writer: %v", writer)
	return lr.SaveWithPrefix(writer, "")
}

func (lr *LinearSVC) SaveWithPrefix(writer *base.ClassifierSerializer, prefix string) error {
	params, err := json.Marshal(lr.Param)
	if err != nil {
		return base.DescribeError("Error marshalling parameters", err)
	}

	classifierParams := make(map[string]interface{})
	err = json.Unmarshal(params, &classifierParams)
	if err != nil {
		return base.DescribeError("Error marshalling parameters", err)
	}

	f, err := ioutil.TempFile(os.TempDir(), "liblinear")
	defer func() {
		f.Close()
	}()

	err = Export(lr.model, f.Name())
	if err != nil {
		return base.DescribeError("Error exporting model", err)
	}

	f.Seek(0, os.SEEK_SET)
	bytes, err := ioutil.ReadAll(f)
	if err != nil {
		return base.DescribeError("Error reading model in again", err)
	}

	err = writer.WriteBytesForKey(writer.Prefix(prefix, "PARAMETERS"), params)
	if err != nil {
		return base.DescribeError("Error writing model parameters", err)
	}
	writer.WriteBytesForKey(writer.Prefix(prefix, "MODEL"), bytes)
	if err != nil {
		return base.DescribeError("Error writing model", err)
	}

	return nil
}

func (lr *LinearSVC) Load(filePath string) error {
	reader, err := base.ReadSerializedClassifierStub(filePath)
	if err != nil {
		return err
	}
	defer func() {
		reader.Close()
	}()

	return lr.LoadWithPrefix(reader, "")
}

func (lr *LinearSVC) LoadWithPrefix(reader *base.ClassifierDeserializer, prefix string) error {
	err := reader.GetJSONForKey(reader.Prefix(prefix, "PARAMETERS"), &lr.Param)
	if err != nil {
		return base.DescribeError("Error reading PARAMETERS", err)
	}

	modelBytes, err := reader.GetBytesForKey(reader.Prefix(prefix, "MODEL"))
	if err != nil {
		return base.DescribeError("Error reading MODEL", err)
	}

	f, err := ioutil.TempFile(os.TempDir(), "linear")
	defer func() {
		f.Close()
	}()

	f.WriteAt(modelBytes, 0)

	lr.model = &Model{}

	err = Load(lr.model, f.Name())
	if err != nil {
		return base.DescribeError("Unable to reload the model", err)
	}
	return nil
}

// String return a humaan-readable version.
func (lr *LinearSVC) String() string {
	return "LogisticSVC"
}
<|endoftext|>


<commit_before>package uefi

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io/ioutil"
	"path/filepath"

	uuid "github.com/linuxboot/fiano/uuid"
)

// FirmwareVolume constants
const (
	FirmwareVolumeFixedHeaderSize  = 56
	FirmwareVolumeMinSize          = FirmwareVolumeFixedHeaderSize + 8 // +8 for the null block that terminates the block list
	FirmwareVolumeExtHeaderMinSize = 20
)

// FVGUIDs holds common FV type names
var FVGUIDs map[uuid.UUID]string

var supportedFVs map[uuid.UUID]bool

// Valid FV GUIDs
var (
	FFS1      *uuid.UUID
	FFS2      *uuid.UUID
	FFS3      *uuid.UUID
	EVSA      *uuid.UUID
	NVAR      *uuid.UUID
	EVSA2     *uuid.UUID
	AppleBoot *uuid.UUID
	PFH1      *uuid.UUID
	PFH2      *uuid.UUID
)

func init() {
	FFS1, _ = uuid.Parse("7a9354d9-0468-444a-81ce-0bf617d890df")
	FFS2, _ = uuid.Parse("8c8ce578-8a3d-4f1c-9935-896185c32dd3")
	FFS3, _ = uuid.Parse("5473c07a-3dcb-4dca-bd6f-1e9689e7349a")
	EVSA, _ = uuid.Parse("fff12b8d-7696-4c8b-a985-2747075b4f50")
	NVAR, _ = uuid.Parse("cef5b9a3-476d-497f-9fdc-e98143e0422c")
	EVSA2, _ = uuid.Parse("00504624-8a59-4eeb-bd0f-6b36e96128e0")
	AppleBoot, _ = uuid.Parse("04adeead-61ff-4d31-b6ba-64f8bf901f5a")
	PFH1, _ = uuid.Parse("16b45da2-7d70-4aea-a58d-760e9ecb841d")
	PFH2, _ = uuid.Parse("e360bdba-c3ce-46be-8f37-b231e5cb9f35")

	// Add names to map
	FVGUIDs = make(map[uuid.UUID]string)
	FVGUIDs[*FFS1] = "FFS1"
	FVGUIDs[*FFS2] = "FFS2"
	FVGUIDs[*FFS3] = "FFS3"
	FVGUIDs[*EVSA] = "NVRAM_EVSA"
	FVGUIDs[*NVAR] = "NVRAM_NVAR"
	FVGUIDs[*EVSA2] = "NVRAM_EVSA2"
	FVGUIDs[*AppleBoot] = "APPLE_BOOT"
	FVGUIDs[*PFH1] = "PFH1"
	FVGUIDs[*PFH2] = "PFH2"

	// These are the FVs we actually try to parse beyond the header
	// We don't parse anything except FFS2 and FFS3
	supportedFVs = make(map[uuid.UUID]bool)
	supportedFVs[*FFS2] = true
	supportedFVs[*FFS3] = true
}

// Block describes number and size of the firmware volume blocks
type Block struct {
	Count uint32
	Size  uint32
}

// FirmwareVolumeFixedHeader contains the fixed fields of a firmware volume
// header
type FirmwareVolumeFixedHeader struct {
	_               [16]uint8
	FileSystemGUID  uuid.UUID
	Length          uint64
	Signature       uint32
	Attributes      uint32 // UEFI PI spec volume 3.2.1 EFI_FIRMWARE_VOLUME_HEADER
	HeaderLen       uint16
	Checksum        uint16
	ExtHeaderOffset uint16
	Reserved        uint8 `json:"-"`
	Revision        uint8
	// _               [3]uint8
}

// FirmwareVolumeExtHeader contains the fields of an extended firmware volume
// header
type FirmwareVolumeExtHeader struct {
	FVName        uuid.UUID
	ExtHeaderSize uint32
}

// FirmwareVolume represents a firmware volume. It combines the fixed header and
// a variable list of blocks
type FirmwareVolume struct {
	FirmwareVolumeFixedHeader
	// there must be at least one that is zeroed and indicates the end of the
	// block list
	// We don't really have to care about blocks because we just read everything in.
	Blocks []Block
	FirmwareVolumeExtHeader
	Files []*File `json:",omitempty"`

	// Variables not in the binary for us to keep track of stuff/print
	DataOffset  uint64
	fvType      string
	buf         []byte
	FVOffset    uint64 // Byte offset from start of BIOS region.
	ExtractPath string
}

// GetErasePolarity gets the erase polarity
func (fv *FirmwareVolume) GetErasePolarity() uint8 {
	if fv.Attributes&0x800 != 0 {
		return 0xFF
	}
	return 0
}

// Extract extracts the Firmware Volume to the directory passed in.
func (fv *FirmwareVolume) Extract(parentPath string) error {
	// We just dump the binary for now
	var err error
	dirPath := filepath.Join(parentPath, fmt.Sprintf("%#x", fv.FVOffset))
	fv.ExtractPath, err = ExtractBinary(fv.buf, dirPath, "fv.bin")
	if err != nil {
		return err
	}

	// Extract all files.
	for _, f := range fv.Files {
		if err = f.Extract(dirPath); err != nil {
			return err
		}
	}

	return nil
}

// Validate Firmware Volume
func (fv *FirmwareVolume) Validate() []error {
	// TODO: Add more verification if needed.
	errs := make([]error, 0)
	// Check for min length
	fvlen := uint64(len(fv.buf))
	// We need this check in case HeaderLen doesn't exist, and bail out early
	if fvlen < FirmwareVolumeMinSize {
		errs = append(errs, fmt.Errorf("length too small!, buffer is only %#x bytes long", fvlen))
		return errs
	}
	// Check header length
	if fv.HeaderLen < FirmwareVolumeMinSize {
		errs = append(errs, fmt.Errorf("header length too small, got: %#x", fv.HeaderLen))
		return errs
	}
	// Check for full header and bail out if its not fully formed.
	if fvlen < uint64(fv.HeaderLen) {
		errs = append(errs, fmt.Errorf("buffer smaller than header!, header is %#x bytes, buffer is %#x bytes",
			fv.HeaderLen, fvlen))
		return errs
	}
	// Do we want to fail in this case? maybe not.
	if FVGUIDs[fv.FileSystemGUID] == "" {
		errs = append(errs, fmt.Errorf("unknown FV type! Guid was %v", fv.FileSystemGUID))
	}
	// UEFI PI spec says version should always be 2
	if fv.Revision != 2 {
		errs = append(errs, fmt.Errorf("revision should be 2, was %v", fv.Revision))
	}
	// Check Signature
	fvSigInt := binary.LittleEndian.Uint32([]byte("_FVH"))
	if fv.Signature != fvSigInt {
		errs = append(errs, fmt.Errorf("signature was not _FVH, got: %#08x", fv.Signature))
	}
	// Check length
	if fv.Length != fvlen {
		errs = append(errs, fmt.Errorf("length mismatch!, header has %#x, buffer is %#x bytes long", fv.Length, fvlen))
	}
	// Check checksum
	sum, err := Checksum16(fv.buf[:fv.HeaderLen])
	if err != nil {
		errs = append(errs, fmt.Errorf("unable to checksum FV header: %v", err))
	} else if sum != 0 {
		errs = append(errs, fmt.Errorf("header did not sum to 0, got: %#x", sum))
	}

	for _, f := range fv.Files {
		errs = append(errs, f.Validate()...)
	}
	return errs
}

func fillFFs(b []byte) {
	for i := range b {
		b[i] = 0xFF
	}
}

func (fv *FirmwareVolume) insertFile(fOffset uint64, alignedOffset uint64, fBuf []byte) error {
	fvLen := uint64(len(fv.buf))
	if alignedOffset > fvLen {
		return fmt.Errorf("insufficient space in %#x bytes FV, files too big, offset was %#x",
			fvLen, alignedOffset)
	}
	// TODO: Change to ErasePolarity
	fillFFs(fv.buf[fOffset:alignedOffset])

	// Check size
	fLen := uint64(len(fBuf))
	if fLen+alignedOffset > fvLen {
		// TODO: Actually loop through and calculate the full size so we know how much to reduce by.
		// For now we just return early
		return fmt.Errorf("insufficient space in %#x bytes FV, files too big, offset was %#x, length was %#x",
			fvLen, alignedOffset, len(fBuf))
	}
	// Overwrite old data in the firmware volume.
	copy(fv.buf[alignedOffset:], fBuf)
	return nil
}

// Assemble assembles the Firmware Volume from the binary file.
// TODO: HANDLE HEADER CHANGES.
// We assume the FV length hasn't changed, and we assume the FV offset is the same as specified in
// the JSON. We also don't check that the extended header or data offset is the same.
// This is not something that's expected to change easily.
func (fv *FirmwareVolume) Assemble() ([]byte, error) {
	var err error
	fv.buf, err = ioutil.ReadFile(fv.ExtractPath)
	if err != nil {
		return nil, err
	}

	if _, ok := supportedFVs[fv.FileSystemGUID]; !ok {
		// we don't support this fv type, just return the raw buffer.
		return fv.buf, nil
	}
	// Make sure we don't go over the size.
	fvLen := uint64(len(fv.buf))
	fOffset := fv.DataOffset
	for _, f := range fv.Files {
		fBuf, err := f.Assemble()
		if err != nil {
			return nil, err
		}
		fLen := uint64(len(fBuf))

		// Pad to the 8 byte alignments.
		alignedOffset := Align8(fOffset)
		// Read out the file alignment requirements
		if alignBase := f.Header.Attributes.GetAlignment(); alignBase != 1 {
			hl := f.HeaderLen()
			// We need to align the data, not the header. This is so terrible.
			dataOffset := Align(alignedOffset+hl, alignBase)
			// Calculate the starting offset of the file
			newOffset := dataOffset - hl
			if gap := (newOffset - alignedOffset); gap >= 8 && gap < FileHeaderMinLength {
				// We need to re align to the next boundary cause we can't put a pad file in here.
				// Who thought this was a good idea?
				dataOffset = Align(dataOffset+1, alignBase)
				newOffset = dataOffset - hl
			}
			if newOffset != alignedOffset {
				// Add a pad file starting from alignedOffset to newOffset
				pf, err := CreatePadFile(newOffset - alignedOffset)
				if err != nil {
					return nil, err
				}
				if err = fv.insertFile(fOffset, alignedOffset, pf.buf); err != nil {
					return nil, err
				}
				// Set up offsets for the actual file
				fOffset = newOffset
			}
			alignedOffset = newOffset
		}
		if err = fv.insertFile(fOffset, alignedOffset, fBuf); err != nil {
			return nil, err
		}
		fOffset = alignedOffset + fLen
	}

	// Fill to the end with FFs
	// TODO: handle ErasePolarity
	if fOffset < fvLen {
		fillFFs(fv.buf[fOffset:fvLen])
	}
	return fv.buf, nil
}

// FindFirmwareVolumeOffset searches for a firmware volume signature, "_FVH"
// using 8-byte alignment. If found, returns the offset from the start of the
// bios region, otherwise returns -1.
func FindFirmwareVolumeOffset(data []byte) int64 {
	if len(data) < 32 {
		return -1
	}
	var (
		offset int64
		fvSig  = []byte("_FVH")
	)
	for offset = 32; offset < int64(len(data)); offset += 8 {
		if bytes.Equal(data[offset:offset+4], fvSig) {
			return offset - 40 // the actual volume starts 40 bytes before the signature
		}
	}
	return -1
}

// NewFirmwareVolume parses a sequence of bytes and returns a FirmwareVolume
// object, if a valid one is passed, or an error
func NewFirmwareVolume(data []byte, fvOffset uint64) (*FirmwareVolume, error) {
	var fv FirmwareVolume

	if len(data) < FirmwareVolumeMinSize {
		return nil, fmt.Errorf("Firmware Volume size too small: expected %v bytes, got %v",
			FirmwareVolumeMinSize,
			len(data),
		)
	}
	reader := bytes.NewReader(data)
	if err := binary.Read(reader, binary.LittleEndian, &fv.FirmwareVolumeFixedHeader); err != nil {
		return nil, err
	}
	// read the block map
	blocks := make([]Block, 0)
	for {
		var block Block
		if err := binary.Read(reader, binary.LittleEndian, &block); err != nil {
			return nil, err
		}
		if block.Count == 0 && block.Size == 0 {
			// found the terminating block
			break
		}
		blocks = append(blocks, block)
	}
	fv.Blocks = blocks

	// Parse the extended header and figure out the start of data
	fv.DataOffset = uint64(fv.HeaderLen)
	if fv.ExtHeaderOffset != 0 && uint64(fv.ExtHeaderOffset) < fv.Length-FirmwareVolumeExtHeaderMinSize {
		// jump to ext header offset.
		r := bytes.NewReader(data[fv.ExtHeaderOffset:])
		if err := binary.Read(r, binary.LittleEndian, &fv.FirmwareVolumeExtHeader); err != nil {
			return nil, fmt.Errorf("unable to parse FV extended header, got: %v", err)
		}
		// TODO: will the ext header ever end before the regular header? I don't believe so. Add a check?
		fv.DataOffset = uint64(fv.ExtHeaderOffset) + uint64(fv.ExtHeaderSize)
	}
	// Make sure DataOffset is 8 byte aligned at least.
	// TODO: handle alignment field in header.
	fv.DataOffset = Align8(fv.DataOffset)

	fv.fvType = FVGUIDs[fv.FileSystemGUID]
	fv.FVOffset = fvOffset

	// slice the buffer
	fv.buf = data[:fv.Length]

	// Parse the files.
	// TODO: handle fv data alignment.
	// Start from the end of the fv header.
	// Test if the fv type is supported.
	if _, ok := supportedFVs[fv.FileSystemGUID]; !ok {
		return &fv, nil
	}
	lh := fv.Length - FileHeaderMinLength
	for offset, prevLen := fv.DataOffset, uint64(0); offset < lh; offset += prevLen {
		offset = Align8(offset)
		file, err := NewFile(data[offset:])
		if err != nil {
			return nil, fmt.Errorf("unable to construct firmware file at offset %#x into FV: %v", offset, err)
		}
		if file == nil {
			// We've reached free space. Terminate
			break
		}
		fv.Files = append(fv.Files, file)
		prevLen = file.Header.ExtendedSize
	}
	return &fv, nil
}
<commit_msg>Some cleanup<commit_after>package uefi

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io/ioutil"
	"path/filepath"

	uuid "github.com/linuxboot/fiano/uuid"
)

// FirmwareVolume constants
const (
	FirmwareVolumeFixedHeaderSize  = 56
	FirmwareVolumeMinSize          = FirmwareVolumeFixedHeaderSize + 8 // +8 for the null block that terminates the block list
	FirmwareVolumeExtHeaderMinSize = 20
)

// Valid FV GUIDs
var (
	FFS1      = uuid.MustParse("7a9354d9-0468-444a-81ce-0bf617d890df")
	FFS2      = uuid.MustParse("8c8ce578-8a3d-4f1c-9935-896185c32dd3")
	FFS3      = uuid.MustParse("5473c07a-3dcb-4dca-bd6f-1e9689e7349a")
	EVSA      = uuid.MustParse("fff12b8d-7696-4c8b-a985-2747075b4f50")
	NVAR      = uuid.MustParse("cef5b9a3-476d-497f-9fdc-e98143e0422c")
	EVSA2     = uuid.MustParse("00504624-8a59-4eeb-bd0f-6b36e96128e0")
	AppleBoot = uuid.MustParse("04adeead-61ff-4d31-b6ba-64f8bf901f5a")
	PFH1      = uuid.MustParse("16b45da2-7d70-4aea-a58d-760e9ecb841d")
	PFH2      = uuid.MustParse("e360bdba-c3ce-46be-8f37-b231e5cb9f35")
)

// FVGUIDs holds common FV type names
var FVGUIDs = map[uuid.UUID]string{
	*FFS1:      "FFS1",
	*FFS2:      "FFS2",
	*FFS3:      "FFS3",
	*EVSA:      "NVRAM_EVSA",
	*NVAR:      "NVRAM_NVAR",
	*EVSA2:     "NVRAM_EVSA2",
	*AppleBoot: "APPLE_BOOT",
	*PFH1:      "PFH1",
	*PFH2:      "PFH2",
}

// These are the FVs we actually try to parse beyond the header
// We don't parse anything except FFS2 and FFS3
var supportedFVs = map[uuid.UUID]bool{
	*FFS2: true,
	*FFS3: true,
}

// Block describes number and size of the firmware volume blocks
type Block struct {
	Count uint32
	Size  uint32
}

// FirmwareVolumeFixedHeader contains the fixed fields of a firmware volume
// header
type FirmwareVolumeFixedHeader struct {
	_               [16]uint8
	FileSystemGUID  uuid.UUID
	Length          uint64
	Signature       uint32
	Attributes      uint32 // UEFI PI spec volume 3.2.1 EFI_FIRMWARE_VOLUME_HEADER
	HeaderLen       uint16
	Checksum        uint16
	ExtHeaderOffset uint16
	Reserved        uint8 `json:"-"`
	Revision        uint8
	// _               [3]uint8
}

// FirmwareVolumeExtHeader contains the fields of an extended firmware volume
// header
type FirmwareVolumeExtHeader struct {
	FVName        uuid.UUID
	ExtHeaderSize uint32
}

// FirmwareVolume represents a firmware volume. It combines the fixed header and
// a variable list of blocks
type FirmwareVolume struct {
	FirmwareVolumeFixedHeader
	// there must be at least one that is zeroed and indicates the end of the
	// block list
	// We don't really have to care about blocks because we just read everything in.
	Blocks []Block
	FirmwareVolumeExtHeader
	Files []*File `json:",omitempty"`

	// Variables not in the binary for us to keep track of stuff/print
	DataOffset  uint64
	fvType      string
	buf         []byte
	FVOffset    uint64 // Byte offset from start of BIOS region.
	ExtractPath string
}

// GetErasePolarity gets the erase polarity
func (fv *FirmwareVolume) GetErasePolarity() uint8 {
	if fv.Attributes&0x800 != 0 {
		return 0xFF
	}
	return 0
}

// Extract extracts the Firmware Volume to the directory passed in.
func (fv *FirmwareVolume) Extract(parentPath string) error {
	// We just dump the binary for now
	var err error
	dirPath := filepath.Join(parentPath, fmt.Sprintf("%#x", fv.FVOffset))
	fv.ExtractPath, err = ExtractBinary(fv.buf, dirPath, "fv.bin")
	if err != nil {
		return err
	}

	// Extract all files.
	for _, f := range fv.Files {
		if err = f.Extract(dirPath); err != nil {
			return err
		}
	}

	return nil
}

// Validate Firmware Volume
func (fv *FirmwareVolume) Validate() []error {
	// TODO: Add more verification if needed.
	errs := make([]error, 0)
	// Check for min length
	fvlen := uint64(len(fv.buf))
	// We need this check in case HeaderLen doesn't exist, and bail out early
	if fvlen < FirmwareVolumeMinSize {
		errs = append(errs, fmt.Errorf("length too small!, buffer is only %#x bytes long", fvlen))
		return errs
	}
	// Check header length
	if fv.HeaderLen < FirmwareVolumeMinSize {
		errs = append(errs, fmt.Errorf("header length too small, got: %#x", fv.HeaderLen))
		return errs
	}
	// Check for full header and bail out if its not fully formed.
	if fvlen < uint64(fv.HeaderLen) {
		errs = append(errs, fmt.Errorf("buffer smaller than header!, header is %#x bytes, buffer is %#x bytes",
			fv.HeaderLen, fvlen))
		return errs
	}
	// Do we want to fail in this case? maybe not.
	if FVGUIDs[fv.FileSystemGUID] == "" {
		errs = append(errs, fmt.Errorf("unknown FV type! Guid was %v", fv.FileSystemGUID))
	}
	// UEFI PI spec says version should always be 2
	if fv.Revision != 2 {
		errs = append(errs, fmt.Errorf("revision should be 2, was %v", fv.Revision))
	}
	// Check Signature
	fvSigInt := binary.LittleEndian.Uint32([]byte("_FVH"))
	if fv.Signature != fvSigInt {
		errs = append(errs, fmt.Errorf("signature was not _FVH, got: %#08x", fv.Signature))
	}
	// Check length
	if fv.Length != fvlen {
		errs = append(errs, fmt.Errorf("length mismatch!, header has %#x, buffer is %#x bytes long", fv.Length, fvlen))
	}
	// Check checksum
	sum, err := Checksum16(fv.buf[:fv.HeaderLen])
	if err != nil {
		errs = append(errs, fmt.Errorf("unable to checksum FV header: %v", err))
	} else if sum != 0 {
		errs = append(errs, fmt.Errorf("header did not sum to 0, got: %#x", sum))
	}

	for _, f := range fv.Files {
		errs = append(errs, f.Validate()...)
	}
	return errs
}

func fillFFs(b []byte) {
	for i := range b {
		b[i] = 0xFF
	}
}

func (fv *FirmwareVolume) insertFile(fOffset uint64, alignedOffset uint64, fBuf []byte) error {
	fvLen := uint64(len(fv.buf))
	if alignedOffset > fvLen {
		return fmt.Errorf("insufficient space in %#x bytes FV, files too big, offset was %#x",
			fvLen, alignedOffset)
	}
	// TODO: Change to ErasePolarity
	fillFFs(fv.buf[fOffset:alignedOffset])

	// Check size
	fLen := uint64(len(fBuf))
	if fLen+alignedOffset > fvLen {
		// TODO: Actually loop through and calculate the full size so we know how much to reduce by.
		// For now we just return early
		return fmt.Errorf("insufficient space in %#x bytes FV, files too big, offset was %#x, length was %#x",
			fvLen, alignedOffset, len(fBuf))
	}
	// Overwrite old data in the firmware volume.
	copy(fv.buf[alignedOffset:], fBuf)
	return nil
}

// Assemble assembles the Firmware Volume from the binary file.
// TODO: HANDLE HEADER CHANGES.
// We assume the FV length hasn't changed, and we assume the FV offset is the same as specified in
// the JSON. We also don't check that the extended header or data offset is the same.
// This is not something that's expected to change easily.
func (fv *FirmwareVolume) Assemble() ([]byte, error) {
	var err error
	fv.buf, err = ioutil.ReadFile(fv.ExtractPath)
	if err != nil {
		return nil, err
	}

	if _, ok := supportedFVs[fv.FileSystemGUID]; !ok {
		// we don't support this fv type, just return the raw buffer.
		return fv.buf, nil
	}
	// Make sure we don't go over the size.
	fvLen := uint64(len(fv.buf))
	fOffset := fv.DataOffset
	for _, f := range fv.Files {
		fBuf, err := f.Assemble()
		if err != nil {
			return nil, err
		}
		fLen := uint64(len(fBuf))

		// Pad to the 8 byte alignments.
		alignedOffset := Align8(fOffset)
		// Read out the file alignment requirements
		if alignBase := f.Header.Attributes.GetAlignment(); alignBase != 1 {
			hl := f.HeaderLen()
			// We need to align the data, not the header. This is so terrible.
			dataOffset := Align(alignedOffset+hl, alignBase)
			// Calculate the starting offset of the file
			newOffset := dataOffset - hl
			if gap := (newOffset - alignedOffset); gap >= 8 && gap < FileHeaderMinLength {
				// We need to re align to the next boundary cause we can't put a pad file in here.
				// Who thought this was a good idea?
				dataOffset = Align(dataOffset+1, alignBase)
				newOffset = dataOffset - hl
			}
			if newOffset != alignedOffset {
				// Add a pad file starting from alignedOffset to newOffset
				pf, err := CreatePadFile(newOffset - alignedOffset)
				if err != nil {
					return nil, err
				}
				if err = fv.insertFile(fOffset, alignedOffset, pf.buf); err != nil {
					return nil, err
				}
				// Set up offsets for the actual file
				fOffset = newOffset
			}
			alignedOffset = newOffset
		}
		if err = fv.insertFile(fOffset, alignedOffset, fBuf); err != nil {
			return nil, err
		}
		fOffset = alignedOffset + fLen
	}

	// Fill to the end with FFs
	// TODO: handle ErasePolarity
	if fOffset < fvLen {
		fillFFs(fv.buf[fOffset:fvLen])
	}
	return fv.buf, nil
}

// FindFirmwareVolumeOffset searches for a firmware volume signature, "_FVH"
// using 8-byte alignment. If found, returns the offset from the start of the
// bios region, otherwise returns -1.
func FindFirmwareVolumeOffset(data []byte) int64 {
	if len(data) < 32 {
		return -1
	}
	var (
		offset int64
		fvSig  = []byte("_FVH")
	)
	for offset = 32; offset < int64(len(data)); offset += 8 {
		if bytes.Equal(data[offset:offset+4], fvSig) {
			return offset - 40 // the actual volume starts 40 bytes before the signature
		}
	}
	return -1
}

// NewFirmwareVolume parses a sequence of bytes and returns a FirmwareVolume
// object, if a valid one is passed, or an error
func NewFirmwareVolume(data []byte, fvOffset uint64) (*FirmwareVolume, error) {
	var fv FirmwareVolume

	if len(data) < FirmwareVolumeMinSize {
		return nil, fmt.Errorf("Firmware Volume size too small: expected %v bytes, got %v",
			FirmwareVolumeMinSize,
			len(data),
		)
	}
	reader := bytes.NewReader(data)
	if err := binary.Read(reader, binary.LittleEndian, &fv.FirmwareVolumeFixedHeader); err != nil {
		return nil, err
	}
	// read the block map
	blocks := make([]Block, 0)
	for {
		var block Block
		if err := binary.Read(reader, binary.LittleEndian, &block); err != nil {
			return nil, err
		}
		if block.Count == 0 && block.Size == 0 {
			// found the terminating block
			break
		}
		blocks = append(blocks, block)
	}
	fv.Blocks = blocks

	// Parse the extended header and figure out the start of data
	fv.DataOffset = uint64(fv.HeaderLen)
	if fv.ExtHeaderOffset != 0 && uint64(fv.ExtHeaderOffset) < fv.Length-FirmwareVolumeExtHeaderMinSize {
		// jump to ext header offset.
		r := bytes.NewReader(data[fv.ExtHeaderOffset:])
		if err := binary.Read(r, binary.LittleEndian, &fv.FirmwareVolumeExtHeader); err != nil {
			return nil, fmt.Errorf("unable to parse FV extended header, got: %v", err)
		}
		// TODO: will the ext header ever end before the regular header? I don't believe so. Add a check?
		fv.DataOffset = uint64(fv.ExtHeaderOffset) + uint64(fv.ExtHeaderSize)
	}
	// Make sure DataOffset is 8 byte aligned at least.
	// TODO: handle alignment field in header.
	fv.DataOffset = Align8(fv.DataOffset)

	fv.fvType = FVGUIDs[fv.FileSystemGUID]
	fv.FVOffset = fvOffset

	// slice the buffer
	fv.buf = data[:fv.Length]

	// Parse the files.
	// TODO: handle fv data alignment.
	// Start from the end of the fv header.
	// Test if the fv type is supported.
	if _, ok := supportedFVs[fv.FileSystemGUID]; !ok {
		return &fv, nil
	}
	lh := fv.Length - FileHeaderMinLength
	for offset, prevLen := fv.DataOffset, uint64(0); offset < lh; offset += prevLen {
		offset = Align8(offset)
		file, err := NewFile(data[offset:])
		if err != nil {
			return nil, fmt.Errorf("unable to construct firmware file at offset %#x into FV: %v", offset, err)
		}
		if file == nil {
			// We've reached free space. Terminate
			break
		}
		fv.Files = append(fv.Files, file)
		prevLen = file.Header.ExtendedSize
	}
	return &fv, nil
}
<|endoftext|>


<commit_before>//fetch prints the content found at a URL
package main

import (
	"os"
	"net/http"
	"fmt"
	"io/ioutil"
)

func main() {
	for _, url := range os.Args[1:] {
		resp, err := http.Get(url)
		if err != nil {
			fmt.Fprintf(os.Stderr, "fetch: %v\n", err)
			os.Exit(1)
		}
		b, err := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if err != nil {
			fmt.Fprintf(os.Stderr, "fetch: reading %s: %v\n", url, err)
			os.Exit(1)
		}
		fmt.Printf("%s", b)
	}
}
<commit_msg>Complete exercises.<commit_after>//fetch prints the content found at a URL
package main

import (
	"os"
	"net/http"
	"fmt"
	"io"
	"strings"
)

func main() {
	for _, url := range os.Args[1:] {
		if !strings.HasPrefix(url, "http://") {
			url = "http://" + url
		}
		resp, err := http.Get(url)
		if err != nil {
			fmt.Fprintf(os.Stderr, "fetch: %v\n", err)
			os.Exit(1)
		}
		_, err = io.Copy(os.Stdout, resp.Body)
		fmt.Fprintf(os.Stdout, "\n\nHTTP Status %v\n", resp.Status)
		resp.Body.Close()
		if err != nil {
			fmt.Fprintf(os.Stderr, "fetch: reading %s: %v\n", url, err)
			os.Exit(1)
		}
	}
}
<|endoftext|>


<commit_before>package proxy

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"time"

	"github.com/fabiolb/fabio/metrics"
)

// conn measures the number of open web socket connections
var conn = metrics.DefaultRegistry.GetCounter("ws.conn")

type dialFunc func(network, address string) (net.Conn, error)

// newRawProxy returns an HTTP handler which forwards data between
// an incoming and outgoing TCP connection including the original request.
// This handler establishes a new outgoing connection per request.
func newRawProxy(host string, dial dialFunc) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		conn.Inc(1)
		defer func() { conn.Inc(-1) }()

		hj, ok := w.(http.Hijacker)
		if !ok {
			http.Error(w, "not a hijacker", http.StatusInternalServerError)
			return
		}

		in, _, err := hj.Hijack()
		if err != nil {
			log.Printf("[ERROR] Hijack error for %s. %s", r.URL, err)
			http.Error(w, "hijack error", http.StatusInternalServerError)
			return
		}
		defer in.Close()

		out, err := dial("tcp", host)
		if err != nil {
			log.Printf("[ERROR] WS error for %s. %s", r.URL, err)
			http.Error(w, "error contacting backend server", http.StatusInternalServerError)
			return
		}
		defer out.Close()

		err = r.Write(out)
		if err != nil {
			log.Printf("[ERROR] Error copying request for %s. %s", r.URL, err)
			http.Error(w, "error copying request", http.StatusInternalServerError)
			return
		}

		// read the initial response to check whether we get an HTTP/1.1 101 ... response
		// to determine whether the handshake worked.
		b := make([]byte, 1024)
		if err := out.SetReadDeadline(time.Now().Add(time.Second)); err != nil {
			log.Printf("[ERROR] Error setting read timeout for %s: %s", r.URL, err)
			http.Error(w, "error setting read timeout", http.StatusInternalServerError)
			return
		}

		n, err := out.Read(b)
		if err != nil {
			log.Printf("[ERROR] Error reading response for %s: %s", r.URL, err)
			http.Error(w, "error reading response", http.StatusInternalServerError)
			return
		}

		b = b[:n]
		if m, err := in.Write(b); err != nil || n != m {
			log.Printf("[ERROR] Error sending header for %s: %s", r.URL, err)
			http.Error(w, "error sending response", http.StatusInternalServerError)
			return
		}

		if !bytes.HasPrefix(b, []byte("HTTP/1.1 101")) {
			fmt.Println("boom")
			log.Printf("[INFO] WS Upgrade failed for %s", r.URL)
			http.Error(w, "error handling ws upgrade", http.StatusInternalServerError)
			return
		}

		errc := make(chan error, 2)
		cp := func(dst io.Writer, src io.Reader) {
			_, err := io.Copy(dst, src)
			errc <- err
		}

		go cp(out, in)
		go cp(in, out)
		err = <-errc
		if err != nil && err != io.EOF {
			log.Printf("[INFO] WS error for %s. %s", r.URL, err)
		}
	})
}
<commit_msg>drop debug output<commit_after>package proxy

import (
	"bytes"
	"io"
	"log"
	"net"
	"net/http"
	"time"

	"github.com/fabiolb/fabio/metrics"
)

// conn measures the number of open web socket connections
var conn = metrics.DefaultRegistry.GetCounter("ws.conn")

type dialFunc func(network, address string) (net.Conn, error)

// newRawProxy returns an HTTP handler which forwards data between
// an incoming and outgoing TCP connection including the original request.
// This handler establishes a new outgoing connection per request.
func newRawProxy(host string, dial dialFunc) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		conn.Inc(1)
		defer func() { conn.Inc(-1) }()

		hj, ok := w.(http.Hijacker)
		if !ok {
			http.Error(w, "not a hijacker", http.StatusInternalServerError)
			return
		}

		in, _, err := hj.Hijack()
		if err != nil {
			log.Printf("[ERROR] Hijack error for %s. %s", r.URL, err)
			http.Error(w, "hijack error", http.StatusInternalServerError)
			return
		}
		defer in.Close()

		out, err := dial("tcp", host)
		if err != nil {
			log.Printf("[ERROR] WS error for %s. %s", r.URL, err)
			http.Error(w, "error contacting backend server", http.StatusInternalServerError)
			return
		}
		defer out.Close()

		err = r.Write(out)
		if err != nil {
			log.Printf("[ERROR] Error copying request for %s. %s", r.URL, err)
			http.Error(w, "error copying request", http.StatusInternalServerError)
			return
		}

		// read the initial response to check whether we get an HTTP/1.1 101 ... response
		// to determine whether the handshake worked.
		b := make([]byte, 1024)
		if err := out.SetReadDeadline(time.Now().Add(time.Second)); err != nil {
			log.Printf("[ERROR] Error setting read timeout for %s: %s", r.URL, err)
			http.Error(w, "error setting read timeout", http.StatusInternalServerError)
			return
		}

		n, err := out.Read(b)
		if err != nil {
			log.Printf("[ERROR] Error reading response for %s: %s", r.URL, err)
			http.Error(w, "error reading response", http.StatusInternalServerError)
			return
		}

		b = b[:n]
		if m, err := in.Write(b); err != nil || n != m {
			log.Printf("[ERROR] Error sending header for %s: %s", r.URL, err)
			http.Error(w, "error sending response", http.StatusInternalServerError)
			return
		}

		if !bytes.HasPrefix(b, []byte("HTTP/1.1 101")) {
			log.Printf("[INFO] WS Upgrade failed for %s", r.URL)
			http.Error(w, "error handling ws upgrade", http.StatusInternalServerError)
			return
		}

		errc := make(chan error, 2)
		cp := func(dst io.Writer, src io.Reader) {
			_, err := io.Copy(dst, src)
			errc <- err
		}

		go cp(out, in)
		go cp(in, out)
		err = <-errc
		if err != nil && err != io.EOF {
			log.Printf("[INFO] WS error for %s. %s", r.URL, err)
		}
	})
}
<|endoftext|>