<commit_before>package internal

// ArgType is the type that specifies the command line arguments.
type ArgType struct {
	// Verbose enables verbose output.
	//Verbose bool `arg:"-v,help:toggle verbose"`

	// DSN is the database string (ie, pgsql://user@blah:localhost:5432/dbname?args=)
	DSN string `arg:"positional,required,help:data source name"`

	// Schema is the name of the schema to query.
	Schema string `arg:"-s,help:schema name to generate Go types for"`

	// Out is the output path. If Out is a file, then that will be used as the
	// path. If Out is a directory, then the output file will be
	// Out/<$CWD>.xo.go
	Out string `arg:"-o,help:output path or file name"`

	// Suffix is the output suffix for filenames.
	Suffix string `arg:"-f,help:output file suffix"`

	// SingleFile when toggled changes behavior so that output is to one f ile.
	SingleFile bool `arg:"--single-file,help:toggle single file output"`

	// Package is the name used to generate package headers. If not specified,
	// the name of the output directory will be used instead.
	Package string `arg:"-p,help:package name used in generated Go code"`

	// CustomTypePackage is the Go package name to use for unknown types.
	CustomTypePackage string `arg:"--custom-type-package,-C,help:Go package name to use for custom or unknown types"`

	// Int32Type is the type to assign those discovered as int32 (ie, serial, integer, etc).
	Int32Type string `arg:"--int32-type,-i,help:Go type to assign to integers"`

	// Uint32Type is the type to assign those discovered as uint32.
	Uint32Type string `arg:"--uint32-type,-u,help:Go type to assign to unsigned integers"`

	// IncTypes are the types to include.
	//IncTypes []string `arg:"--include,-t,help:include types"`

	// ExcTypes are the types to exclude.
	//ExcTypes []string `arg:"--exclude,-x,help:exclude types"`

	// QueryMode toggles whether or not to parse a query from stdin.
	QueryMode bool `arg:"--enable-query-mode,-N,help:enable query mode"`

	// Query is the passed query. If not specified, then os.Stdin will be used.
	// cli args take precedence over stdin.
	Query string `arg:"-Q,help:query to generate Go type and func from"`

	// QueryType is the name to give to the Go type generated from the query.
	QueryType string `arg:"--query-type,-T,help:query's generated Go type"`

	// QueryFunc is the name to assign to the generated query func.
	QueryFunc string `arg:"--query-func,-F,help:comment for query's generated Go func"`

	// TypeComment is the type comment for a query.
	QueryTypeComment string `arg:"--comment,help:comment for query's generated Go type"`

	// FuncComment is the func comment to provide the named query.
	QueryFuncComment string `arg:"--func-comment,help:comment for query's generated Go func"`

	// QueryOnlyOne toggles the generated query code to expect only one result.
	QueryOnlyOne bool `arg:"--only-one,-1,help:toggle query's generated Go func to return only one result"`

	// QueryTrim enables triming whitespace on the supplied query.
	QueryTrim bool `arg:"--query-trim,-M,help:toggle trimming of query whitespace in generated Go code"`

	// QueryStrip enables stripping the '::<type> AS <name>' from queries.
	QueryStrip bool `arg:"--query-strip,-B,help:toggle stripping '::type AS name' from query in generated Go code"`

	// QueryParamDelimiter is the delimiter for parameterized values for a query.
	QueryParamDelimiter string `arg:"--query-delimiter,-D,help:delimiter for query's embedded Go parameters"`

	// NoExtra when toggled will not generate certain extras.
	//NoExtra bool `arg:"--no-extra,-Z,help:"disable extra code generation"`

	// Path is the output path, as derived from Out.
	Path string `arg:"-"`

	// Filename is the output filename, as derived from Out.
	Filename string `arg:"-"`
}

// CustomTypePackage is a hack.
var CustomTypePackage = ""
<commit_msg>Fixing some of the arg help text<commit_after>package internal

// ArgType is the type that specifies the command line arguments.
type ArgType struct {
	// Verbose enables verbose output.
	//Verbose bool `arg:"-v,help:toggle verbose"`

	// DSN is the database string (ie, pgsql://user@blah:localhost:5432/dbname?args=)
	DSN string `arg:"positional,required,help:data source name"`

	// Schema is the name of the schema to query.
	Schema string `arg:"-s,help:schema name to generate Go types for"`

	// Out is the output path. If Out is a file, then that will be used as the
	// path. If Out is a directory, then the output file will be
	// Out/<$CWD>.xo.go
	Out string `arg:"-o,help:output path or file name"`

	// Suffix is the output suffix for filenames.
	Suffix string `arg:"-f,help:output file suffix"`

	// SingleFile when toggled changes behavior so that output is to one f ile.
	SingleFile bool `arg:"--single-file,help:toggle single file output"`

	// Package is the name used to generate package headers. If not specified,
	// the name of the output directory will be used instead.
	Package string `arg:"-p,help:package name used in generated Go code"`

	// CustomTypePackage is the Go package name to use for unknown types.
	CustomTypePackage string `arg:"--custom-type-package,-C,help:Go package name to use for custom or unknown types"`

	// Int32Type is the type to assign those discovered as int32 (ie, serial, integer, etc).
	Int32Type string `arg:"--int32-type,-i,help:Go type to assign to integers"`

	// Uint32Type is the type to assign those discovered as uint32.
	Uint32Type string `arg:"--uint32-type,-u,help:Go type to assign to unsigned integers"`

	// IncTypes are the types to include.
	//IncTypes []string `arg:"--include,-t,help:include types"`

	// ExcTypes are the types to exclude.
	//ExcTypes []string `arg:"--exclude,-x,help:exclude types"`

	// QueryMode toggles whether or not to parse a query from stdin.
	QueryMode bool `arg:"--query-mode,-N,help:enable query mode"`

	// Query is the passed query. If not specified, then os.Stdin will be used.
	// cli args take precedence over stdin.
	Query string `arg:"-Q,help:query to generate Go type and func from"`

	// QueryType is the name to give to the Go type generated from the query.
	QueryType string `arg:"--query-type,-T,help:query's generated Go type"`

	// QueryFunc is the name to assign to the generated query func.
	QueryFunc string `arg:"--query-func,-F,help:query's generated Go func name"`

	// QueryOnlyOne toggles the generated query code to expect only one result.
	QueryOnlyOne bool `arg:"--query-only-one,-1,help:toggle query's generated Go func to return only one result"`

	// QueryTrim enables triming whitespace on the supplied query.
	QueryTrim bool `arg:"--query-trim,-M,help:toggle trimming of query whitespace in generated Go code"`

	// QueryStrip enables stripping the '::<type> AS <name>' from queries.
	QueryStrip bool `arg:"--query-strip,-B,help:toggle stripping '::type AS name' from query in generated Go code"`

	// TypeComment is the type comment for a query.
	QueryTypeComment string `arg:"--query-type-comment,help:comment for query's generated Go type"`

	// FuncComment is the func comment to provide the named query.
	QueryFuncComment string `arg:"--query-func-comment,help:comment for query's generated Go func"`

	// QueryParamDelimiter is the delimiter for parameterized values for a query.
	QueryParamDelimiter string `arg:"--query-delimiter,-D,help:delimiter for query's embedded Go parameters"`

	// NoExtra when toggled will not generate certain extras.
	//NoExtra bool `arg:"--no-extra,-Z,help:"disable extra code generation"`

	// Path is the output path, as derived from Out.
	Path string `arg:"-"`

	// Filename is the output filename, as derived from Out.
	Filename string `arg:"-"`
}

// CustomTypePackage is a hack.
var CustomTypePackage = ""
<|endoftext|>


<commit_before>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

package dl

// TODO(adg): refactor this to use the tools/godoc/static template.

const templateHTML = `
{{define "root"}}
<!DOCTYPE html>

<meta charset="utf-8">
<meta name="description" content="Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#00ADD8">
<title>Downloads - The Go Programming Language</title>
<link type="text/css" rel="stylesheet" href="/lib/godoc/style.css">

    <button class="Header-menuButton js-headerMenuButton" aria-label="Main menu" aria-expanded="false">

    </button>

Documents

Packages

The Project

Help

      {{if not .GoogleCN}}

Blog

Play

      {{end}}

        <form class="HeaderSearch" role="search" action="/search">
          <input class="HeaderSearch-input"
                type="search"
                name="q"
                placeholder="Search"
                aria-label="Search"
                autocapitalize="off"
                autocomplete="off"
                autocorrect="off"
                spellcheck="false"
                required>
          <button class="HeaderSearch-submit">
            <svg class="HeaderSearch-icon" width="24" height="24" viewBox="0 0 24 24"><title>Search</title><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
          </button>
        </form>

Downloads

After downloading a binary release suitable for your system,
please follow the installation instructions.

If you are building from source,
follow the source installation instructions.

See the release history for more
information about Go releases.

  As of Go 1.13, the go command by default downloads and authenticates
  modules using the Go module mirror and Go checksum database run by Google. See
  https://proxy.golang.org/privacy
  for privacy information about these services and the
  go command documentation
  for configuration details including how to disable the use of these servers or use
  different ones.

{{with .Featured}}

Featured downloads

{{range .}}
{{template "download" .}}
{{end}}
{{end}}

{{with .Stable}}

Stable versions

{{template "releases" .}}
{{end}}

{{with .Unstable}}

Unstable version

{{template "releases" .}}
{{end}}

{{with .Archive}}

Archived versions ▹

Archived versions ▾

    {{template "releases" .}}

{{end}}

Copyright

Terms of Service

Privacy Policy

Report a website issue

{{end}}

{{define "releases"}}
{{range .}}

{{.Version}} ▹

{{.Version}} ▾

		{{if .Stable}}{{else}}

This is an unstable version of Go. Use with caution.

If you already have Go installed, you can install this version by running:

go get golang.org/dl/{{.Version}}

Then, use the {{.Version}} command instead of the go command to use {{.Version}}.

		{{end}}
		{{template "files" .}}

{{end}}
{{end}}

{{define "files"}}

  File name
  Kind
  OS
  Arch
  Size
  {{/* Use the checksum type of the first file for the column heading. */}}
  {{(index .Files 0).ChecksumType}} Checksum

{{if .SplitPortTable}}
  {{range .Files}}{{if .PrimaryPort}}{{template "file" .}}{{end}}{{end}}

  {{/* TODO(cbro): add a link to an explanatory doc page */}}

Other Ports

  {{range .Files}}{{if not .PrimaryPort}}{{template "file" .}}{{end}}{{end}}
{{else}}
  {{range .Files}}{{template "file" .}}{{end}}
{{end}}

{{end}}

{{define "file"}}

  {{.Filename}}
  {{pretty .Kind}}
  {{.PrettyOS}}
  {{pretty .Arch}}
  {{.PrettySize}}
  <tt>{{.PrettyChecksum}}</tt>

{{end}}

{{define "download"}}

{{.Platform}}

{{with .Requirements}}
{{.}}
{{end}}

  {{.Filename}}
  {{if .Size}}({{.PrettySize}}){{end}}

{{end}}
`
<commit_msg>internal/dl: update webfonts and footer to match base template<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

package dl

// TODO(adg): refactor this to use the tools/godoc/static template.

const templateHTML = `
{{define "root"}}
<!DOCTYPE html>

<meta charset="utf-8">
<meta name="description" content="Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#00ADD8">
<title>Downloads - The Go Programming Language</title>
<link href="https://fonts.googleapis.com/css?family=Work+Sans:600|Roboto:400,700" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Product+Sans&text=Supported%20by%20Google&display=swap" rel="stylesheet">
<link type="text/css" rel="stylesheet" href="/lib/godoc/style.css">

    <button class="Header-menuButton js-headerMenuButton" aria-label="Main menu" aria-expanded="false">

    </button>

Documents

Packages

The Project

Help

      {{if not .GoogleCN}}

Blog

Play

      {{end}}

        <form class="HeaderSearch" role="search" action="/search">
          <input class="HeaderSearch-input"
                type="search"
                name="q"
                placeholder="Search"
                aria-label="Search"
                autocapitalize="off"
                autocomplete="off"
                autocorrect="off"
                spellcheck="false"
                required>
          <button class="HeaderSearch-submit">
            <svg class="HeaderSearch-icon" width="24" height="24" viewBox="0 0 24 24"><title>Search</title><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
          </button>
        </form>

Downloads

After downloading a binary release suitable for your system,
please follow the installation instructions.

If you are building from source,
follow the source installation instructions.

See the release history for more
information about Go releases.

  As of Go 1.13, the go command by default downloads and authenticates
  modules using the Go module mirror and Go checksum database run by Google. See
  https://proxy.golang.org/privacy
  for privacy information about these services and the
  go command documentation
  for configuration details including how to disable the use of these servers or use
  different ones.

{{with .Featured}}

Featured downloads

{{range .}}
{{template "download" .}}
{{end}}
{{end}}

{{with .Stable}}

Stable versions

{{template "releases" .}}
{{end}}

{{with .Unstable}}

Unstable version

{{template "releases" .}}
{{end}}

{{with .Archive}}

Archived versions ▹

Archived versions ▾

    {{template "releases" .}}

{{end}}

Copyright

Terms of Service

Privacy Policy

Report a website issue

    Supported by Google

{{end}}

{{define "releases"}}
{{range .}}

{{.Version}} ▹

{{.Version}} ▾

		{{if .Stable}}{{else}}

This is an unstable version of Go. Use with caution.

If you already have Go installed, you can install this version by running:

go get golang.org/dl/{{.Version}}

Then, use the {{.Version}} command instead of the go command to use {{.Version}}.

		{{end}}
		{{template "files" .}}

{{end}}
{{end}}

{{define "files"}}

  File name
  Kind
  OS
  Arch
  Size
  {{/* Use the checksum type of the first file for the column heading. */}}
  {{(index .Files 0).ChecksumType}} Checksum

{{if .SplitPortTable}}
  {{range .Files}}{{if .PrimaryPort}}{{template "file" .}}{{end}}{{end}}

  {{/* TODO(cbro): add a link to an explanatory doc page */}}

Other Ports

  {{range .Files}}{{if not .PrimaryPort}}{{template "file" .}}{{end}}{{end}}
{{else}}
  {{range .Files}}{{template "file" .}}{{end}}
{{end}}

{{end}}

{{define "file"}}

  {{.Filename}}
  {{pretty .Kind}}
  {{.PrettyOS}}
  {{pretty .Arch}}
  {{.PrettySize}}
  <tt>{{.PrettyChecksum}}</tt>

{{end}}

{{define "download"}}

{{.Platform}}

{{with .Requirements}}
{{.}}
{{end}}

  {{.Filename}}
  {{if .Size}}({{.PrettySize}}){{end}}

{{end}}
`
<|endoftext|>


<commit_before>// Package gen provides functions for generating go source code
//
// The gen package provides wrapper functions around the go/ast and
// go/token packages to reduce boilerplate.
package gen

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"go/ast"
	"go/format"
	"go/parser"
	"go/printer"
	"go/token"
	"io"
	"reflect"
	"strconv"
	"strings"

	"golang.org/x/tools/imports"
)

// TypeDecl generates a type declaration with the given name.
func TypeDecl(name *ast.Ident, typ ast.Expr) *ast.GenDecl {
	return &ast.GenDecl{
		Tok: token.TYPE,
		Specs: []ast.Spec{
			&ast.TypeSpec{
				Name: name,
				Type: typ,
			},
		},
	}
}

// Struct creates a struct{} expression. The arguments are a series
// of name/type/tag tuples. Name must be of type *ast.Ident, type
// must be of type ast.Expr, and tag must be of type *ast.BasicLit,
// The number of arguments must be a multiple of 3, or a run-time
// panic will occur.
func Struct(args ...ast.Expr) *ast.StructType {
	fields := new(ast.FieldList)
	if len(args)%3 != 0 {
		panic("Number of args to FieldList must be a multiple of 3, got " + strconv.Itoa(len(args)))
	}
	for i := 0; i < len(args); i += 3 {
		var field ast.Field
		name, typ, tag := args[i], args[i+1], args[i+2]
		if name != nil {
			field.Names = []*ast.Ident{name.(*ast.Ident)}
		}
		if typ != nil {
			field.Type = typ
		}
		if tag != nil {
			field.Tag = tag.(*ast.BasicLit)
		}
		fields.List = append(fields.List, &field)
	}
	return &ast.StructType{Fields: fields}
}

// FieldList generates a field list from strings in the form "[name]
// expr".
func FieldList(fields ...string) (*ast.FieldList, error) {
	result := &ast.FieldList{List: []*ast.Field{}}
	for _, s := range fields {
		parts := strings.SplitN(s, " ", 2)
		if len(parts) == 0 {
			return nil, fmt.Errorf("empty field list item %q", s)
		}
		var names []*ast.Ident
		typeExpr, err := parser.ParseExpr(parts[len(parts)-1])
		if err != nil {
			return nil, fmt.Errorf("could not parse type in %q: %v", s, err)
		}
		if len(parts) > 1 {
			names = []*ast.Ident{ast.NewIdent(parts[0])}
		}
		result.List = append(result.List, &ast.Field{
			Names: names,
			Type:  typeExpr,
		})
	}
	return result, nil
}

// String generates a literal string. If the string contains a double
// quote, backticks are used for quoting instead.
func String(s string) *ast.BasicLit {
	if strings.Contains(s, "\"") && !strings.Contains(s, "`") {
		return &ast.BasicLit{Kind: token.STRING, Value: "`" + s + "`"}
	}
	return &ast.BasicLit{Kind: token.STRING, Value: strconv.Quote(s)}
}

// Public turns a string into a public (uppercase)
// identifier.
func Public(name string) *ast.Ident {
	return ast.NewIdent(strings.Title(name))
}

func constDecl(kind token.Token, args ...string) *ast.GenDecl {
	decl := ast.GenDecl{Tok: token.CONST}

	if len(args)%3 != 0 {
		panic("Number of values passed to ConstString must be a multiple of 3")
	}
	for i := 0; i < len(args); i += 3 {
		name, typ, val := args[i], args[i+1], args[i+2]
		lit := &ast.BasicLit{Kind: kind}
		if kind == token.STRING {
			lit.Value = strconv.Quote(val)
		} else {
			lit.Value = val
		}
		a := &ast.ValueSpec{
			Names:  []*ast.Ident{ast.NewIdent(name)},
			Values: []ast.Expr{lit},
		}
		if typ != "" {
			a.Type = ast.NewIdent(typ)
		}
		decl.Specs = append(decl.Specs, a)
	}

	if len(decl.Specs) > 1 {
		decl.Lparen = 1
	}

	return &decl
}

// SimpleType creates an identifier suitable
// for use as a type expression.
func SimpleType(name string) ast.Expr {
	return ast.NewIdent(name)
}

// ConstInt creates a series of numeric const declarations from
// the name/value pairs in args.
func ConstInt(args ...string) *ast.GenDecl {
	return constDecl(token.INT, args...)
}

// ConstString creates a series of string const declarations from
// the name/value pairs in args.
func ConstString(args ...string) *ast.GenDecl {
	return constDecl(token.STRING, args...)
}

// ConstFloat creates a series of floating-point const
// declarations from the name/value pairs in args.
func ConstFloat(args ...string) *ast.GenDecl {
	return constDecl(token.FLOAT, args...)
}

// ConstChar creates a series of character const
// declarations from the name/value pairs in args.
func ConstChar(args ...string) *ast.GenDecl {
	return constDecl(token.CHAR, args...)
}

// ConstImaginary creates a series of imaginary const
// declarations from the name/value pairs in args.
func ConstImaginary(args ...string) *ast.GenDecl {
	return constDecl(token.IMAG, args...)
}

type Function struct {
	name, receiver, godoc string
	args, returns         []string
	body                  string
}

func Func(name string) *Function {
	return &Function{name: name}
}

// Decl generates Go source for a Func.  an error is returned if the
// body, or parameters cannot be parsed.
func (fn *Function) Decl() (*ast.FuncDecl, error) {
	var err error
	var comments *ast.CommentGroup

	if fn.name == "" {
		return nil, errors.New("function name unset")
	}
	if len(fn.body) == 0 {
		return nil, fmt.Errorf("function body for %s unset")
	}

	if fn.godoc != "" {
		comments = &ast.CommentGroup{List: []*ast.Comment{}}
		for _, line := range strings.Split(fn.godoc, "\n") {
			comments.List = append(comments.List, &ast.Comment{Text: line})
		}
	}
	fl := func(args ...string) (list *ast.FieldList) {
		if len(args) == 0 || len(args[0]) == 0 || err != nil {
			return nil
		}
		list, err = FieldList(args...)
		return list
	}
	args := fl(fn.args...)
	returns := fl(fn.returns...)
	receiver := fl(fn.receiver)
	if err != nil {
		return nil, err
	}
	body, err := parseBlock(fn.body)
	if err != nil {
		return nil, fmt.Errorf("could not parse function body of %s: %v", fn.name, err)
	}
	return &ast.FuncDecl{
		Doc:  comments,
		Recv: receiver,
		Name: ast.NewIdent(fn.name),
		Type: &ast.FuncType{
			Params:  args,
			Results: returns,
		},
		Body: body,
	}, nil
}

// Body sets the body of a function. The body should not include
// enclosing braces.
func (fn *Function) Body(format string, v ...interface{}) *Function {
	fn.body = fmt.Sprintf(format, v...)
	return fn
}

// Returns sets the return values of a function. Each return
// value should be a string matching the Go syntax for a
// single return value.
func (fn *Function) Returns(values ...string) *Function {
	fn.returns = values
	return fn
}

// Comments sets the Godoc comments for the function.
func (fn *Function) Comment(s string) *Function {
	fn.godoc = s
	return fn
}

// Args sets the arguments that a function takes.
func (fn *Function) Args(args ...string) *Function {
	fn.args = args
	return fn
}

// Receiver turns the function into a method operating on
// the specified type.
func (fn *Function) Receiver(receiver string) *Function {
	fn.receiver = receiver
	return fn
}

func parseBlock(s string) (*ast.BlockStmt, error) {
	var buf bytes.Buffer

	fmt.Fprintf(&buf, "package tmp\nfunc _block() {\n%s\n}", s)
	file, err := parser.ParseFile(token.NewFileSet(), "", buf.Bytes(), 0)
	if err != nil {
		return nil, err
	}
	for _, decl := range file.Decls {
		if decl, ok := decl.(*ast.FuncDecl); ok {
			return decl.Body, nil
		}
	}
	return nil, fmt.Errorf("parse error: no function found in %q", buf.Bytes())
}

// ExprString converts an ast.Expr to the Go source it represents.
func ExprString(expr ast.Expr) string {
	var buf bytes.Buffer
	fs := token.NewFileSet()
	printer.Fprint(&buf, fs, expr)
	return buf.String()
}

// TagKey gets the struct tag item with the
// given key.
func TagKey(field *ast.Field, key string) string {
	if field.Tag != nil {
		return ""
	}
	return reflect.StructTag(field.Tag.Value).Get(key)
}

// FormattedSource converts an abstract syntax tree to
// formatted Go source code.
func FormattedSource(file *ast.File) ([]byte, error) {
	var buf bytes.Buffer

	fileset := token.NewFileSet()

	// our *ast.File did not come from a real Go source
	// file. As such, all of its node positions are 0, and
	// the go/printer package will print the package
	// comment between the package statement and
	// the package name. The most straightforward way
	// to work around this is to put the package comment
	// there ourselves.
	if file.Doc != nil {
		for _, v := range file.Doc.List {
			io.WriteString(&buf, v.Text)
			io.WriteString(&buf, "\n")
		}
		file.Doc = nil
	}
	if err := format.Node(&buf, fileset, file); err != nil {
		return nil, err
	}
	out, err := imports.Process("", buf.Bytes(), nil)
	if err != nil {
		return nil, fmt.Errorf("%v in %s", err, buf.String())
	}
	return out, nil
}
<commit_msg>Fix bug in godoc generation of comments for functions<commit_after>// Package gen provides functions for generating go source code
//
// The gen package provides wrapper functions around the go/ast and
// go/token packages to reduce boilerplate.
package gen

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"go/ast"
	"go/format"
	"go/parser"
	"go/printer"
	"go/token"
	"io"
	"reflect"
	"strconv"
	"strings"

	"golang.org/x/tools/imports"
)

// TypeDecl generates a type declaration with the given name.
func TypeDecl(name *ast.Ident, typ ast.Expr) *ast.GenDecl {
	return &ast.GenDecl{
		Tok: token.TYPE,
		Specs: []ast.Spec{
			&ast.TypeSpec{
				Name: name,
				Type: typ,
			},
		},
	}
}

// Struct creates a struct{} expression. The arguments are a series
// of name/type/tag tuples. Name must be of type *ast.Ident, type
// must be of type ast.Expr, and tag must be of type *ast.BasicLit,
// The number of arguments must be a multiple of 3, or a run-time
// panic will occur.
func Struct(args ...ast.Expr) *ast.StructType {
	fields := new(ast.FieldList)
	if len(args)%3 != 0 {
		panic("Number of args to FieldList must be a multiple of 3, got " + strconv.Itoa(len(args)))
	}
	for i := 0; i < len(args); i += 3 {
		var field ast.Field
		name, typ, tag := args[i], args[i+1], args[i+2]
		if name != nil {
			field.Names = []*ast.Ident{name.(*ast.Ident)}
		}
		if typ != nil {
			field.Type = typ
		}
		if tag != nil {
			field.Tag = tag.(*ast.BasicLit)
		}
		fields.List = append(fields.List, &field)
	}
	return &ast.StructType{Fields: fields}
}

// FieldList generates a field list from strings in the form "[name]
// expr".
func FieldList(fields ...string) (*ast.FieldList, error) {
	result := &ast.FieldList{List: []*ast.Field{}}
	for _, s := range fields {
		parts := strings.SplitN(s, " ", 2)
		if len(parts) == 0 {
			return nil, fmt.Errorf("empty field list item %q", s)
		}
		var names []*ast.Ident
		typeExpr, err := parser.ParseExpr(parts[len(parts)-1])
		if err != nil {
			return nil, fmt.Errorf("could not parse type in %q: %v", s, err)
		}
		if len(parts) > 1 {
			names = []*ast.Ident{ast.NewIdent(parts[0])}
		}
		result.List = append(result.List, &ast.Field{
			Names: names,
			Type:  typeExpr,
		})
	}
	return result, nil
}

// String generates a literal string. If the string contains a double
// quote, backticks are used for quoting instead.
func String(s string) *ast.BasicLit {
	if strings.Contains(s, "\"") && !strings.Contains(s, "`") {
		return &ast.BasicLit{Kind: token.STRING, Value: "`" + s + "`"}
	}
	return &ast.BasicLit{Kind: token.STRING, Value: strconv.Quote(s)}
}

// Public turns a string into a public (uppercase)
// identifier.
func Public(name string) *ast.Ident {
	return ast.NewIdent(strings.Title(name))
}

func constDecl(kind token.Token, args ...string) *ast.GenDecl {
	decl := ast.GenDecl{Tok: token.CONST}

	if len(args)%3 != 0 {
		panic("Number of values passed to ConstString must be a multiple of 3")
	}
	for i := 0; i < len(args); i += 3 {
		name, typ, val := args[i], args[i+1], args[i+2]
		lit := &ast.BasicLit{Kind: kind}
		if kind == token.STRING {
			lit.Value = strconv.Quote(val)
		} else {
			lit.Value = val
		}
		a := &ast.ValueSpec{
			Names:  []*ast.Ident{ast.NewIdent(name)},
			Values: []ast.Expr{lit},
		}
		if typ != "" {
			a.Type = ast.NewIdent(typ)
		}
		decl.Specs = append(decl.Specs, a)
	}

	if len(decl.Specs) > 1 {
		decl.Lparen = 1
	}

	return &decl
}

// SimpleType creates an identifier suitable
// for use as a type expression.
func SimpleType(name string) ast.Expr {
	return ast.NewIdent(name)
}

// ConstInt creates a series of numeric const declarations from
// the name/value pairs in args.
func ConstInt(args ...string) *ast.GenDecl {
	return constDecl(token.INT, args...)
}

// ConstString creates a series of string const declarations from
// the name/value pairs in args.
func ConstString(args ...string) *ast.GenDecl {
	return constDecl(token.STRING, args...)
}

// ConstFloat creates a series of floating-point const
// declarations from the name/value pairs in args.
func ConstFloat(args ...string) *ast.GenDecl {
	return constDecl(token.FLOAT, args...)
}

// ConstChar creates a series of character const
// declarations from the name/value pairs in args.
func ConstChar(args ...string) *ast.GenDecl {
	return constDecl(token.CHAR, args...)
}

// ConstImaginary creates a series of imaginary const
// declarations from the name/value pairs in args.
func ConstImaginary(args ...string) *ast.GenDecl {
	return constDecl(token.IMAG, args...)
}

type Function struct {
	name, receiver, godoc string
	args, returns         []string
	body                  string
}

func Func(name string) *Function {
	return &Function{name: name}
}

// Decl generates Go source for a Func.  an error is returned if the
// body, or parameters cannot be parsed.
func (fn *Function) Decl() (*ast.FuncDecl, error) {
	var err error
	var comments *ast.CommentGroup

	if fn.name == "" {
		return nil, errors.New("function name unset")
	}
	if len(fn.body) == 0 {
		return nil, fmt.Errorf("function body for %s unset")
	}

	if fn.godoc != "" {
		comments = &ast.CommentGroup{List: []*ast.Comment{}}
		for _, line := range strings.Split(fn.godoc, "\n") {
			comments.List = append(comments.List, &ast.Comment{
				Text: "// " + line + "\n",
			})
		}
	}
	fl := func(args ...string) (list *ast.FieldList) {
		if len(args) == 0 || len(args[0]) == 0 || err != nil {
			return nil
		}
		list, err = FieldList(args...)
		return list
	}
	args := fl(fn.args...)
	returns := fl(fn.returns...)
	receiver := fl(fn.receiver)
	if err != nil {
		return nil, err
	}
	body, err := parseBlock(fn.body)
	if err != nil {
		return nil, fmt.Errorf("could not parse function body of %s: %v", fn.name, err)
	}
	return &ast.FuncDecl{
		Doc:  comments,
		Recv: receiver,
		Name: ast.NewIdent(fn.name),
		Type: &ast.FuncType{
			Params:  args,
			Results: returns,
		},
		Body: body,
	}, nil
}

// Body sets the body of a function. The body should not include
// enclosing braces.
func (fn *Function) Body(format string, v ...interface{}) *Function {
	fn.body = fmt.Sprintf(format, v...)
	return fn
}

// Returns sets the return values of a function. Each return
// value should be a string matching the Go syntax for a
// single return value.
func (fn *Function) Returns(values ...string) *Function {
	fn.returns = values
	return fn
}

// Comments sets the Godoc comments for the function.
func (fn *Function) Comment(s string) *Function {
	fn.godoc = s
	return fn
}

// Args sets the arguments that a function takes.
func (fn *Function) Args(args ...string) *Function {
	fn.args = args
	return fn
}

// Receiver turns the function into a method operating on
// the specified type.
func (fn *Function) Receiver(receiver string) *Function {
	fn.receiver = receiver
	return fn
}

func parseBlock(s string) (*ast.BlockStmt, error) {
	var buf bytes.Buffer

	fmt.Fprintf(&buf, "package tmp\nfunc _block() {\n%s\n}", s)
	file, err := parser.ParseFile(token.NewFileSet(), "", buf.Bytes(), 0)
	if err != nil {
		return nil, err
	}
	for _, decl := range file.Decls {
		if decl, ok := decl.(*ast.FuncDecl); ok {
			return decl.Body, nil
		}
	}
	return nil, fmt.Errorf("parse error: no function found in %q", buf.Bytes())
}

// ExprString converts an ast.Expr to the Go source it represents.
func ExprString(expr ast.Expr) string {
	var buf bytes.Buffer
	fs := token.NewFileSet()
	printer.Fprint(&buf, fs, expr)
	return buf.String()
}

// TagKey gets the struct tag item with the
// given key.
func TagKey(field *ast.Field, key string) string {
	if field.Tag != nil {
		return ""
	}
	return reflect.StructTag(field.Tag.Value).Get(key)
}

// FormattedSource converts an abstract syntax tree to
// formatted Go source code.
func FormattedSource(file *ast.File) ([]byte, error) {
	var buf bytes.Buffer

	fileset := token.NewFileSet()

	// our *ast.File did not come from a real Go source
	// file. As such, all of its node positions are 0, and
	// the go/printer package will print the package
	// comment between the package statement and
	// the package name. The most straightforward way
	// to work around this is to put the package comment
	// there ourselves.
	if file.Doc != nil {
		for _, v := range file.Doc.List {
			io.WriteString(&buf, v.Text)
			io.WriteString(&buf, "\n")
		}
		file.Doc = nil
	}
	if err := format.Node(&buf, fileset, file); err != nil {
		return nil, err
	}
	out, err := imports.Process("", buf.Bytes(), nil)
	if err != nil {
		return nil, fmt.Errorf("%v in %s", err, buf.String())
	}
	return out, nil
}
<|endoftext|>


<commit_before>package xlsx

import (
	"fmt"
	"math"
	"strconv"
	"strings"
	"time"
)

// CellType is an int type for storing metadata about the data type in the cell.
type CellType int

// Known types for cell values.
const (
	CellTypeString CellType = iota
	CellTypeFormula
	CellTypeNumeric
	CellTypeBool
	CellTypeInline
	CellTypeError
	CellTypeDate
	CellTypeGeneral
)

// Cell is a high level structure intended to provide user access to
// the contents of Cell within an xlsx.Row.
type Cell struct {
	Row      *Row
	Value    string
	formula  string
	style    *Style
	NumFmt   string
	date1904 bool
	Hidden   bool
	HMerge   int
	VMerge   int
	cellType CellType
}

// CellInterface defines the public API of the Cell.
type CellInterface interface {
	String() string
	FormattedValue() string
}

// NewCell creates a cell and adds it to a row.
func NewCell(r *Row) *Cell {
	return &Cell{Row: r}
}

// Merge with other cells, horizontally and/or vertically.
func (c *Cell) Merge(hcells, vcells int) {
	c.HMerge = hcells
	c.VMerge = vcells
}

// Type returns the CellType of a cell. See CellType constants for more details.
func (c *Cell) Type() CellType {
	return c.cellType
}

// SetString sets the value of a cell to a string.
func (c *Cell) SetString(s string) {
	c.Value = s
	c.formula = ""
	c.cellType = CellTypeString
}

// String returns the value of a Cell as a string.
func (c *Cell) String() (string, error) {
	return c.FormattedValue()
}

// SetFloat sets the value of a cell to a float.
func (c *Cell) SetFloat(n float64) {
	c.SetFloatWithFormat(n, builtInNumFmt[builtInNumFmtIndex_GENERAL])
}

/*
	The following are samples of format samples.

	* "0.00e+00"
	* "0", "#,##0"
	* "0.00", "#,##0.00", "@"
	* "#,##0 ;(#,##0)", "#,##0 ;[red](#,##0)"
	* "#,##0.00;(#,##0.00)", "#,##0.00;[red](#,##0.00)"
	* "0%", "0.00%"
	* "0.00e+00", "##0.0e+0"
*/

// SetFloatWithFormat sets the value of a cell to a float and applies
// formatting to the cell.
func (c *Cell) SetFloatWithFormat(n float64, format string) {
	// beauty the output when the float is small enough
	if n != 0 && n < 0.00001 {
		c.Value = strconv.FormatFloat(n, 'e', -1, 64)
	} else {
		c.Value = strconv.FormatFloat(n, 'f', -1, 64)
	}
	c.NumFmt = format
	c.formula = ""
	c.cellType = CellTypeNumeric
}

var timeLocationUTC *time.Location

func init() {
	timeLocationUTC, _ = time.LoadLocation("UTC")
}

func timeToUTCTime(t time.Time) time.Time {
	return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), timeLocationUTC)
}

func timeToExcelTime(t time.Time) float64 {
	return float64(t.Unix())/86400.0 + 25569.0
}

// SetDate sets the value of a cell to a float.
func (c *Cell) SetDate(t time.Time) {
	c.SetDateTimeWithFormat(float64(int64(timeToExcelTime(timeToUTCTime(t)))), builtInNumFmt[14])
}

func (c *Cell) SetDateTime(t time.Time) {
	c.SetDateTimeWithFormat(timeToExcelTime(timeToUTCTime(t)), builtInNumFmt[14])
}

func (c *Cell) SetDateTimeWithFormat(n float64, format string) {
	c.Value = strconv.FormatFloat(n, 'f', -1, 64)
	c.NumFmt = format
	c.formula = ""
	c.cellType = CellTypeDate
}

// Float returns the value of cell as a number.
func (c *Cell) Float() (float64, error) {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return math.NaN(), err
	}
	return f, nil
}

// SetInt64 sets a cell's value to a 64-bit integer.
func (c *Cell) SetInt64(n int64) {
	c.Value = fmt.Sprintf("%d", n)
	c.NumFmt = builtInNumFmt[builtInNumFmtIndex_INT]
	c.formula = ""
	c.cellType = CellTypeNumeric
}

// Int64 returns the value of cell as 64-bit integer.
func (c *Cell) Int64() (int64, error) {
	f, err := strconv.ParseInt(c.Value, 10, 64)
	if err != nil {
		return -1, err
	}
	return f, nil
}

// SetInt sets a cell's value to an integer.
func (c *Cell) SetInt(n int) {
	c.Value = fmt.Sprintf("%d", n)
	c.NumFmt = builtInNumFmt[builtInNumFmtIndex_INT]
	c.formula = ""
	c.cellType = CellTypeNumeric
}

// SetInt sets a cell's value to an integer.
func (c *Cell) SetValue(n interface{}) {
	var s string
	switch n.(type) {
	case time.Time:
		c.SetDateTime(n.(time.Time))
		return
	case int:
		c.setGeneral(fmt.Sprintf("%v", n))
		return
	case int32:
		c.setGeneral(fmt.Sprintf("%v", n))
		return
	case int64:
		c.setGeneral(fmt.Sprintf("%v", n))
		return
	case float32:
		c.setGeneral(fmt.Sprintf("%v", n))
		return
	case float64:
		c.setGeneral(fmt.Sprintf("%v", n))
		return
	case string:
		s = n.(string)
	case []byte:
		s = string(n.([]byte))
	case nil:
		s = ""
	default:
		s = fmt.Sprintf("%v", n)
	}
	c.SetString(s)
}

// SetInt sets a cell's value to an integer.
func (c *Cell) setGeneral(s string) {
	c.Value = s
	c.NumFmt = builtInNumFmt[builtInNumFmtIndex_GENERAL]
	c.formula = ""
	c.cellType = CellTypeGeneral
}

// Int returns the value of cell as integer.
// Has max 53 bits of precision
// See: float64(int64(math.MaxInt))
func (c *Cell) Int() (int, error) {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return -1, err
	}
	return int(f), nil
}

// SetBool sets a cell's value to a boolean.
func (c *Cell) SetBool(b bool) {
	if b {
		c.Value = "1"
	} else {
		c.Value = "0"
	}
	c.cellType = CellTypeBool
}

// Bool returns a boolean from a cell's value.
// TODO: Determine if the current return value is
// appropriate for types other than CellTypeBool.
func (c *Cell) Bool() bool {
	// If bool, just return the value.
	if c.cellType == CellTypeBool {
		return c.Value == "1"
	}
	// If numeric, base it on a non-zero.
	if c.cellType == CellTypeNumeric {
		return c.Value != "0"
	}
	// Return whether there's an empty string.
	return c.Value != ""
}

// SetFormula sets the format string for a cell.
func (c *Cell) SetFormula(formula string) {
	c.formula = formula
	c.cellType = CellTypeFormula
}

// Formula returns the formula string for the cell.
func (c *Cell) Formula() string {
	return c.formula
}

// GetStyle returns the Style associated with a Cell
func (c *Cell) GetStyle() *Style {
	if c.style == nil {
		c.style = NewStyle()
	}
	return c.style
}

// SetStyle sets the style of a cell.
func (c *Cell) SetStyle(style *Style) {
	c.style = style
}

// GetNumberFormat returns the number format string for a cell.
func (c *Cell) GetNumberFormat() string {
	return c.NumFmt
}

func (c *Cell) formatToFloat(format string) (string, error) {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return c.Value, err
	}
	return fmt.Sprintf(format, f), nil
}

func (c *Cell) formatToInt(format string) (string, error) {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return c.Value, err
	}
	return fmt.Sprintf(format, int(f)), nil
}

// FormattedValue returns a value, and possibly an error condition
// from a Cell.  If it is possible to apply a format to the cell
// value, it will do so, if not then an error will be returned, along
// with the raw value of the Cell.
func (c *Cell) FormattedValue() (string, error) {
	var numberFormat = c.GetNumberFormat()
	if isTimeFormat(numberFormat) {
		return parseTime(c)
	}
	switch numberFormat {
	case builtInNumFmt[builtInNumFmtIndex_GENERAL], builtInNumFmt[builtInNumFmtIndex_STRING]:
		return c.Value, nil
	case builtInNumFmt[builtInNumFmtIndex_INT], "#,##0":
		return c.formatToInt("%d")
	case builtInNumFmt[builtInNumFmtIndex_FLOAT], "#,##0.00":
		return c.formatToFloat("%.2f")
	case "#,##0 ;(#,##0)", "#,##0 ;[red](#,##0)":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return c.Value, err
		}
		if f < 0 {
			i := int(math.Abs(f))
			return fmt.Sprintf("(%d)", i), nil
		}
		i := int(f)
		return fmt.Sprintf("%d", i), nil
	case "#,##0.00;(#,##0.00)", "#,##0.00;[red](#,##0.00)":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return c.Value, err
		}
		if f < 0 {
			return fmt.Sprintf("(%.2f)", f), nil
		}
		return fmt.Sprintf("%.2f", f), nil
	case "0%":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return c.Value, err
		}
		f = f * 100
		return fmt.Sprintf("%d%%", int(f)), nil
	case "0.00%":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return c.Value, err
		}
		f = f * 100
		return fmt.Sprintf("%.2f%%", f), nil
	case "0.00e+00", "##0.0e+0":
		return c.formatToFloat("%e")
	}
	return c.Value, nil

}

// parseTime returns a string parsed using time.Time
func parseTime(c *Cell) (string, error) {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return c.Value, err
	}
	val := TimeFromExcelTime(f, c.date1904)
	format := c.GetNumberFormat()

	// Replace Excel placeholders with Go time placeholders.
	// For example, replace yyyy with 2006. These are in a specific order,
	// due to the fact that m is used in month, minute, and am/pm. It would
	// be easier to fix that with regular expressions, but if it's possible
	// to keep this simple it would be easier to maintain.
	// Full-length month and days (e.g. March, Tuesday) have letters in them that would be replaced
	// by other characters below (such as the 'h' in March, or the 'd' in Tuesday) below.
	// First we convert them to arbitrary characters unused in Excel Date formats, and then at the end,
	// turn them to what they should actually be.
	// Based off: http://www.ozgrid.com/Excel/CustomFormats.htm
	replacements := []struct{ xltime, gotime string }{
		{"yyyy", "2006"},
		{"yy", "06"},
		{"mmmm", "%%%%"},
		{"dddd", "&&&&"},
		{"dd", "02"},
		{"d", "2"},
		{"mmm", "Jan"},
		{"mmss", "0405"},
		{"ss", "05"},
		{"hh", "15"},
		{"h", "3"},
		{"mm:", "04:"},
		{":mm", ":04"},
		{"mm", "01"},
		{"am/pm", "pm"},
		{"m/", "1/"},
		{".0", ".9999"},
		{"%%%%", "January"},
		{"&&&&", "Monday"},
	}
	for _, repl := range replacements {
		format = strings.Replace(format, repl.xltime, repl.gotime, 1)
	}
	// If the hour is optional, strip it out, along with the
	// possible dangling colon that would remain.
	if val.Hour() < 1 {
		format = strings.Replace(format, "]:", "]", 1)
		format = strings.Replace(format, "[3]", "", 1)
		format = strings.Replace(format, "[15]", "", 1)
	} else {
		format = strings.Replace(format, "[3]", "3", 1)
		format = strings.Replace(format, "[15]", "15", 1)
	}
	return val.Format(format), nil
}

// isTimeFormat checks whether an Excel format string represents
// a time.Time.
func isTimeFormat(format string) bool {
	dateParts := []string{
		"yy", "hh", "am", "pm", "ss", "mm", ":",
	}
	for _, part := range dateParts {
		if strings.Contains(format, part) {
			return true
		}
	}
	return false
}
<commit_msg>use datetime format for Cell.SetDateTime<commit_after>package xlsx

import (
	"fmt"
	"math"
	"strconv"
	"strings"
	"time"
)

// CellType is an int type for storing metadata about the data type in the cell.
type CellType int

// Known types for cell values.
const (
	CellTypeString CellType = iota
	CellTypeFormula
	CellTypeNumeric
	CellTypeBool
	CellTypeInline
	CellTypeError
	CellTypeDate
	CellTypeGeneral
)

// Cell is a high level structure intended to provide user access to
// the contents of Cell within an xlsx.Row.
type Cell struct {
	Row      *Row
	Value    string
	formula  string
	style    *Style
	NumFmt   string
	date1904 bool
	Hidden   bool
	HMerge   int
	VMerge   int
	cellType CellType
}

// CellInterface defines the public API of the Cell.
type CellInterface interface {
	String() string
	FormattedValue() string
}

// NewCell creates a cell and adds it to a row.
func NewCell(r *Row) *Cell {
	return &Cell{Row: r}
}

// Merge with other cells, horizontally and/or vertically.
func (c *Cell) Merge(hcells, vcells int) {
	c.HMerge = hcells
	c.VMerge = vcells
}

// Type returns the CellType of a cell. See CellType constants for more details.
func (c *Cell) Type() CellType {
	return c.cellType
}

// SetString sets the value of a cell to a string.
func (c *Cell) SetString(s string) {
	c.Value = s
	c.formula = ""
	c.cellType = CellTypeString
}

// String returns the value of a Cell as a string.
func (c *Cell) String() (string, error) {
	return c.FormattedValue()
}

// SetFloat sets the value of a cell to a float.
func (c *Cell) SetFloat(n float64) {
	c.SetFloatWithFormat(n, builtInNumFmt[builtInNumFmtIndex_GENERAL])
}

/*
	The following are samples of format samples.

	* "0.00e+00"
	* "0", "#,##0"
	* "0.00", "#,##0.00", "@"
	* "#,##0 ;(#,##0)", "#,##0 ;[red](#,##0)"
	* "#,##0.00;(#,##0.00)", "#,##0.00;[red](#,##0.00)"
	* "0%", "0.00%"
	* "0.00e+00", "##0.0e+0"
*/

// SetFloatWithFormat sets the value of a cell to a float and applies
// formatting to the cell.
func (c *Cell) SetFloatWithFormat(n float64, format string) {
	// beauty the output when the float is small enough
	if n != 0 && n < 0.00001 {
		c.Value = strconv.FormatFloat(n, 'e', -1, 64)
	} else {
		c.Value = strconv.FormatFloat(n, 'f', -1, 64)
	}
	c.NumFmt = format
	c.formula = ""
	c.cellType = CellTypeNumeric
}

var timeLocationUTC *time.Location

func init() {
	timeLocationUTC, _ = time.LoadLocation("UTC")
}

func timeToUTCTime(t time.Time) time.Time {
	return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), timeLocationUTC)
}

func timeToExcelTime(t time.Time) float64 {
	return float64(t.Unix())/86400.0 + 25569.0
}

// SetDate sets the value of a cell to a float.
func (c *Cell) SetDate(t time.Time) {
	c.SetDateTimeWithFormat(float64(int64(timeToExcelTime(timeToUTCTime(t)))), builtInNumFmt[14])
}

func (c *Cell) SetDateTime(t time.Time) {
	c.SetDateTimeWithFormat(timeToExcelTime(timeToUTCTime(t)), builtInNumFmt[22])
}

func (c *Cell) SetDateTimeWithFormat(n float64, format string) {
	c.Value = strconv.FormatFloat(n, 'f', -1, 64)
	c.NumFmt = format
	c.formula = ""
	c.cellType = CellTypeDate
}

// Float returns the value of cell as a number.
func (c *Cell) Float() (float64, error) {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return math.NaN(), err
	}
	return f, nil
}

// SetInt64 sets a cell's value to a 64-bit integer.
func (c *Cell) SetInt64(n int64) {
	c.Value = fmt.Sprintf("%d", n)
	c.NumFmt = builtInNumFmt[builtInNumFmtIndex_INT]
	c.formula = ""
	c.cellType = CellTypeNumeric
}

// Int64 returns the value of cell as 64-bit integer.
func (c *Cell) Int64() (int64, error) {
	f, err := strconv.ParseInt(c.Value, 10, 64)
	if err != nil {
		return -1, err
	}
	return f, nil
}

// SetInt sets a cell's value to an integer.
func (c *Cell) SetInt(n int) {
	c.Value = fmt.Sprintf("%d", n)
	c.NumFmt = builtInNumFmt[builtInNumFmtIndex_INT]
	c.formula = ""
	c.cellType = CellTypeNumeric
}

// SetInt sets a cell's value to an integer.
func (c *Cell) SetValue(n interface{}) {
	var s string
	switch n.(type) {
	case time.Time:
		c.SetDateTime(n.(time.Time))
		return
	case int:
		c.setGeneral(fmt.Sprintf("%v", n))
		return
	case int32:
		c.setGeneral(fmt.Sprintf("%v", n))
		return
	case int64:
		c.setGeneral(fmt.Sprintf("%v", n))
		return
	case float32:
		c.setGeneral(fmt.Sprintf("%v", n))
		return
	case float64:
		c.setGeneral(fmt.Sprintf("%v", n))
		return
	case string:
		s = n.(string)
	case []byte:
		s = string(n.([]byte))
	case nil:
		s = ""
	default:
		s = fmt.Sprintf("%v", n)
	}
	c.SetString(s)
}

// SetInt sets a cell's value to an integer.
func (c *Cell) setGeneral(s string) {
	c.Value = s
	c.NumFmt = builtInNumFmt[builtInNumFmtIndex_GENERAL]
	c.formula = ""
	c.cellType = CellTypeGeneral
}

// Int returns the value of cell as integer.
// Has max 53 bits of precision
// See: float64(int64(math.MaxInt))
func (c *Cell) Int() (int, error) {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return -1, err
	}
	return int(f), nil
}

// SetBool sets a cell's value to a boolean.
func (c *Cell) SetBool(b bool) {
	if b {
		c.Value = "1"
	} else {
		c.Value = "0"
	}
	c.cellType = CellTypeBool
}

// Bool returns a boolean from a cell's value.
// TODO: Determine if the current return value is
// appropriate for types other than CellTypeBool.
func (c *Cell) Bool() bool {
	// If bool, just return the value.
	if c.cellType == CellTypeBool {
		return c.Value == "1"
	}
	// If numeric, base it on a non-zero.
	if c.cellType == CellTypeNumeric {
		return c.Value != "0"
	}
	// Return whether there's an empty string.
	return c.Value != ""
}

// SetFormula sets the format string for a cell.
func (c *Cell) SetFormula(formula string) {
	c.formula = formula
	c.cellType = CellTypeFormula
}

// Formula returns the formula string for the cell.
func (c *Cell) Formula() string {
	return c.formula
}

// GetStyle returns the Style associated with a Cell
func (c *Cell) GetStyle() *Style {
	if c.style == nil {
		c.style = NewStyle()
	}
	return c.style
}

// SetStyle sets the style of a cell.
func (c *Cell) SetStyle(style *Style) {
	c.style = style
}

// GetNumberFormat returns the number format string for a cell.
func (c *Cell) GetNumberFormat() string {
	return c.NumFmt
}

func (c *Cell) formatToFloat(format string) (string, error) {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return c.Value, err
	}
	return fmt.Sprintf(format, f), nil
}

func (c *Cell) formatToInt(format string) (string, error) {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return c.Value, err
	}
	return fmt.Sprintf(format, int(f)), nil
}

// FormattedValue returns a value, and possibly an error condition
// from a Cell.  If it is possible to apply a format to the cell
// value, it will do so, if not then an error will be returned, along
// with the raw value of the Cell.
func (c *Cell) FormattedValue() (string, error) {
	var numberFormat = c.GetNumberFormat()
	if isTimeFormat(numberFormat) {
		return parseTime(c)
	}
	switch numberFormat {
	case builtInNumFmt[builtInNumFmtIndex_GENERAL], builtInNumFmt[builtInNumFmtIndex_STRING]:
		return c.Value, nil
	case builtInNumFmt[builtInNumFmtIndex_INT], "#,##0":
		return c.formatToInt("%d")
	case builtInNumFmt[builtInNumFmtIndex_FLOAT], "#,##0.00":
		return c.formatToFloat("%.2f")
	case "#,##0 ;(#,##0)", "#,##0 ;[red](#,##0)":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return c.Value, err
		}
		if f < 0 {
			i := int(math.Abs(f))
			return fmt.Sprintf("(%d)", i), nil
		}
		i := int(f)
		return fmt.Sprintf("%d", i), nil
	case "#,##0.00;(#,##0.00)", "#,##0.00;[red](#,##0.00)":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return c.Value, err
		}
		if f < 0 {
			return fmt.Sprintf("(%.2f)", f), nil
		}
		return fmt.Sprintf("%.2f", f), nil
	case "0%":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return c.Value, err
		}
		f = f * 100
		return fmt.Sprintf("%d%%", int(f)), nil
	case "0.00%":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return c.Value, err
		}
		f = f * 100
		return fmt.Sprintf("%.2f%%", f), nil
	case "0.00e+00", "##0.0e+0":
		return c.formatToFloat("%e")
	}
	return c.Value, nil

}

// parseTime returns a string parsed using time.Time
func parseTime(c *Cell) (string, error) {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return c.Value, err
	}
	val := TimeFromExcelTime(f, c.date1904)
	format := c.GetNumberFormat()

	// Replace Excel placeholders with Go time placeholders.
	// For example, replace yyyy with 2006. These are in a specific order,
	// due to the fact that m is used in month, minute, and am/pm. It would
	// be easier to fix that with regular expressions, but if it's possible
	// to keep this simple it would be easier to maintain.
	// Full-length month and days (e.g. March, Tuesday) have letters in them that would be replaced
	// by other characters below (such as the 'h' in March, or the 'd' in Tuesday) below.
	// First we convert them to arbitrary characters unused in Excel Date formats, and then at the end,
	// turn them to what they should actually be.
	// Based off: http://www.ozgrid.com/Excel/CustomFormats.htm
	replacements := []struct{ xltime, gotime string }{
		{"yyyy", "2006"},
		{"yy", "06"},
		{"mmmm", "%%%%"},
		{"dddd", "&&&&"},
		{"dd", "02"},
		{"d", "2"},
		{"mmm", "Jan"},
		{"mmss", "0405"},
		{"ss", "05"},
		{"hh", "15"},
		{"h", "3"},
		{"mm:", "04:"},
		{":mm", ":04"},
		{"mm", "01"},
		{"am/pm", "pm"},
		{"m/", "1/"},
		{".0", ".9999"},
		{"%%%%", "January"},
		{"&&&&", "Monday"},
	}
	for _, repl := range replacements {
		format = strings.Replace(format, repl.xltime, repl.gotime, 1)
	}
	// If the hour is optional, strip it out, along with the
	// possible dangling colon that would remain.
	if val.Hour() < 1 {
		format = strings.Replace(format, "]:", "]", 1)
		format = strings.Replace(format, "[3]", "", 1)
		format = strings.Replace(format, "[15]", "", 1)
	} else {
		format = strings.Replace(format, "[3]", "3", 1)
		format = strings.Replace(format, "[15]", "15", 1)
	}
	return val.Format(format), nil
}

// isTimeFormat checks whether an Excel format string represents
// a time.Time.
func isTimeFormat(format string) bool {
	dateParts := []string{
		"yy", "hh", "am", "pm", "ss", "mm", ":",
	}
	for _, part := range dateParts {
		if strings.Contains(format, part) {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package slack

import (
	"encoding/json"
	"errors"
	"net/url"
	"strings"
)

const (
	DEFAULT_MESSAGE_USERNAME     = ""
	DEFAULT_MESSAGE_ASUSER       = false
	DEFAULT_MESSAGE_PARSE        = ""
	DEFAULT_MESSAGE_LINK_NAMES   = 0
	DEFAULT_MESSAGE_UNFURL_LINKS = false
	DEFAULT_MESSAGE_UNFURL_MEDIA = false
	DEFAULT_MESSAGE_ICON_URL     = ""
	DEFAULT_MESSAGE_ICON_EMOJI   = ""
	DEFAULT_MESSAGE_MARKDOWN     = true
	DEFAULT_MESSAGE_ESCAPE_TEXT  = true
)

type chatResponseFull struct {
	ChannelId string `json:"channel"`
	Timestamp string `json:"ts"`
	Text      string `json:"text"`
	SlackResponse
}

// AttachmentField contains information for an attachment field
// An Attachment can contain multiple of these
type AttachmentField struct {
	Title string `json:"title"`
	Value string `json:"value"`
	Short bool   `json:"short"`
}

// Attachment contains all the information for an attachment
type Attachment struct {
	Fallback string `json:"fallback"`

	Color string `json:"color,omitempty"`

	Pretext string `json:"pretext,omitempty"`

	AuthorName string `json:"author_name,omitempty"`
	AuthorLink string `json:"author_link,omitempty"`
	AuthorIcon string `json:"author_icon,omitempty"`

	Title     string `json:"title,omitempty"`
	TitleLink string `json:"title_link,omitempty"`

	Text string `json:"text"`

	ImageURL string `json:"image_url,omitempty"`

	Fields []AttachmentField `json:"fields,omitempty"`

	MarkdownIn []string `json:"mrkdwn_in,omitempty"`
}

// PostMessageParameters contains all the parameters necessary (including the optional ones) for a PostMessage() request
type PostMessageParameters struct {
	Text        string
	Username    string
	AsUser      bool
	Parse       string
	LinkNames   int
	Attachments []Attachment
	UnfurlLinks bool
	UnfurlMedia bool
	IconURL     string
	IconEmoji   string
	Markdown    bool `json:"mrkdwn,omitempty"`
	EscapeText  bool
}

// NewPostMessageParameters provides an instance of PostMessageParameters with all the sane default values set
func NewPostMessageParameters() PostMessageParameters {
	return PostMessageParameters{
		Username:    DEFAULT_MESSAGE_USERNAME,
		AsUser:      DEFAULT_MESSAGE_ASUSER,
		Parse:       DEFAULT_MESSAGE_PARSE,
		LinkNames:   DEFAULT_MESSAGE_LINK_NAMES,
		Attachments: nil,
		UnfurlLinks: DEFAULT_MESSAGE_UNFURL_LINKS,
		UnfurlMedia: DEFAULT_MESSAGE_UNFURL_MEDIA,
		IconURL:     DEFAULT_MESSAGE_ICON_URL,
		IconEmoji:   DEFAULT_MESSAGE_ICON_EMOJI,
		Markdown:    DEFAULT_MESSAGE_MARKDOWN,
		EscapeText:  DEFAULT_MESSAGE_ESCAPE_TEXT,
	}
}

func chatRequest(path string, values url.Values, debug bool) (*chatResponseFull, error) {
	response := &chatResponseFull{}
	err := parseResponse(path, values, response, debug)
	if err != nil {
		return nil, err
	}
	if !response.Ok {
		return nil, errors.New(response.Error)
	}
	return response, nil
}

// DeleteMessage deletes a message in a channel
func (api *Slack) DeleteMessage(channelId, messageTimestamp string) (string, string, error) {
	values := url.Values{
		"token":   {api.config.token},
		"channel": {channelId},
		"ts":      {messageTimestamp},
	}
	response, err := chatRequest("chat.delete", values, api.debug)
	if err != nil {
		return "", "", err
	}
	return response.ChannelId, response.Timestamp, nil
}

func escapeMessage(message string) string {
	/*
		& replaced with &
		< replaced with <
		> replaced with >
	*/
	replacer := strings.NewReplacer("&", "&", "<", "<", ">", ">")
	return replacer.Replace(message)
}

// PostMessage sends a message to a channel
// Message is escaped by default according to https://api.slack.com/docs/formatting
func (api *Slack) PostMessage(channelId string, text string, params PostMessageParameters) (channel string, timestamp string, err error) {
	if params.EscapeText {
		text = escapeMessage(text)
	}
	values := url.Values{
		"token":   {api.config.token},
		"channel": {channelId},
		"text":    {text},
	}
	if params.Username != DEFAULT_MESSAGE_USERNAME {
		values.Set("username", string(params.Username))
	}
	if params.AsUser != DEFAULT_MESSAGE_ASUSER {
		values.Set("as_user", "true")
	}
	if params.Parse != DEFAULT_MESSAGE_PARSE {
		values.Set("parse", string(params.Parse))
	}
	if params.LinkNames != DEFAULT_MESSAGE_LINK_NAMES {
		values.Set("link_names", "1")
	}
	if params.Attachments != nil {
		attachments, err := json.Marshal(params.Attachments)
		if err != nil {
			return "", "", err
		}
		values.Set("attachments", string(attachments))
	}
	if params.UnfurlLinks != DEFAULT_MESSAGE_UNFURL_LINKS {
		values.Set("unfurl_links", "true")
	}
	if params.UnfurlMedia != DEFAULT_MESSAGE_UNFURL_MEDIA {
		values.Set("unfurl_media", "true")
	}
	if params.IconURL != DEFAULT_MESSAGE_ICON_URL {
		values.Set("icon_url", params.IconURL)
	}
	if params.IconEmoji != DEFAULT_MESSAGE_ICON_EMOJI {
		values.Set("icon_emoji", params.IconEmoji)
	}
	if params.Markdown != DEFAULT_MESSAGE_MARKDOWN {
		values.Set("mrkdwn", "false")
	}

	response, err := chatRequest("chat.postMessage", values, api.debug)
	if err != nil {
		return "", "", err
	}
	return response.ChannelId, response.Timestamp, nil
}

// UpdateMessage updates a message in a channel
func (api *Slack) UpdateMessage(channelId, timestamp, text string) (string, string, string, error) {
	values := url.Values{
		"token":   {api.config.token},
		"channel": {channelId},
		"text":    {escapeMessage(text)},
		"ts":      {timestamp},
	}
	response, err := chatRequest("chat.update", values, api.debug)
	if err != nil {
		return "", "", "", err
	}
	return response.ChannelId, response.Timestamp, response.Text, nil
}
<commit_msg>Make sure we unfurl media by default.<commit_after>package slack

import (
	"encoding/json"
	"errors"
	"net/url"
	"strings"
)

const (
	DEFAULT_MESSAGE_USERNAME     = ""
	DEFAULT_MESSAGE_ASUSER       = false
	DEFAULT_MESSAGE_PARSE        = ""
	DEFAULT_MESSAGE_LINK_NAMES   = 0
	DEFAULT_MESSAGE_UNFURL_LINKS = false
	DEFAULT_MESSAGE_UNFURL_MEDIA = true
	DEFAULT_MESSAGE_ICON_URL     = ""
	DEFAULT_MESSAGE_ICON_EMOJI   = ""
	DEFAULT_MESSAGE_MARKDOWN     = true
	DEFAULT_MESSAGE_ESCAPE_TEXT  = true
)

type chatResponseFull struct {
	ChannelId string `json:"channel"`
	Timestamp string `json:"ts"`
	Text      string `json:"text"`
	SlackResponse
}

// AttachmentField contains information for an attachment field
// An Attachment can contain multiple of these
type AttachmentField struct {
	Title string `json:"title"`
	Value string `json:"value"`
	Short bool   `json:"short"`
}

// Attachment contains all the information for an attachment
type Attachment struct {
	Fallback string `json:"fallback"`

	Color string `json:"color,omitempty"`

	Pretext string `json:"pretext,omitempty"`

	AuthorName string `json:"author_name,omitempty"`
	AuthorLink string `json:"author_link,omitempty"`
	AuthorIcon string `json:"author_icon,omitempty"`

	Title     string `json:"title,omitempty"`
	TitleLink string `json:"title_link,omitempty"`

	Text string `json:"text"`

	ImageURL string `json:"image_url,omitempty"`

	Fields []AttachmentField `json:"fields,omitempty"`

	MarkdownIn []string `json:"mrkdwn_in,omitempty"`
}

// PostMessageParameters contains all the parameters necessary (including the optional ones) for a PostMessage() request
type PostMessageParameters struct {
	Text        string
	Username    string
	AsUser      bool
	Parse       string
	LinkNames   int
	Attachments []Attachment
	UnfurlLinks bool
	UnfurlMedia bool
	IconURL     string
	IconEmoji   string
	Markdown    bool `json:"mrkdwn,omitempty"`
	EscapeText  bool
}

// NewPostMessageParameters provides an instance of PostMessageParameters with all the sane default values set
func NewPostMessageParameters() PostMessageParameters {
	return PostMessageParameters{
		Username:    DEFAULT_MESSAGE_USERNAME,
		AsUser:      DEFAULT_MESSAGE_ASUSER,
		Parse:       DEFAULT_MESSAGE_PARSE,
		LinkNames:   DEFAULT_MESSAGE_LINK_NAMES,
		Attachments: nil,
		UnfurlLinks: DEFAULT_MESSAGE_UNFURL_LINKS,
		UnfurlMedia: DEFAULT_MESSAGE_UNFURL_MEDIA,
		IconURL:     DEFAULT_MESSAGE_ICON_URL,
		IconEmoji:   DEFAULT_MESSAGE_ICON_EMOJI,
		Markdown:    DEFAULT_MESSAGE_MARKDOWN,
		EscapeText:  DEFAULT_MESSAGE_ESCAPE_TEXT,
	}
}

func chatRequest(path string, values url.Values, debug bool) (*chatResponseFull, error) {
	response := &chatResponseFull{}
	err := parseResponse(path, values, response, debug)
	if err != nil {
		return nil, err
	}
	if !response.Ok {
		return nil, errors.New(response.Error)
	}
	return response, nil
}

// DeleteMessage deletes a message in a channel
func (api *Slack) DeleteMessage(channelId, messageTimestamp string) (string, string, error) {
	values := url.Values{
		"token":   {api.config.token},
		"channel": {channelId},
		"ts":      {messageTimestamp},
	}
	response, err := chatRequest("chat.delete", values, api.debug)
	if err != nil {
		return "", "", err
	}
	return response.ChannelId, response.Timestamp, nil
}

func escapeMessage(message string) string {
	/*
		& replaced with &
		< replaced with <
		> replaced with >
	*/
	replacer := strings.NewReplacer("&", "&", "<", "<", ">", ">")
	return replacer.Replace(message)
}

// PostMessage sends a message to a channel
// Message is escaped by default according to https://api.slack.com/docs/formatting
func (api *Slack) PostMessage(channelId string, text string, params PostMessageParameters) (channel string, timestamp string, err error) {
	if params.EscapeText {
		text = escapeMessage(text)
	}
	values := url.Values{
		"token":   {api.config.token},
		"channel": {channelId},
		"text":    {text},
	}
	if params.Username != DEFAULT_MESSAGE_USERNAME {
		values.Set("username", string(params.Username))
	}
	if params.AsUser != DEFAULT_MESSAGE_ASUSER {
		values.Set("as_user", "true")
	}
	if params.Parse != DEFAULT_MESSAGE_PARSE {
		values.Set("parse", string(params.Parse))
	}
	if params.LinkNames != DEFAULT_MESSAGE_LINK_NAMES {
		values.Set("link_names", "1")
	}
	if params.Attachments != nil {
		attachments, err := json.Marshal(params.Attachments)
		if err != nil {
			return "", "", err
		}
		values.Set("attachments", string(attachments))
	}
	if params.UnfurlLinks != DEFAULT_MESSAGE_UNFURL_LINKS {
		values.Set("unfurl_links", "true")
	}
	if params.UnfurlMedia != DEFAULT_MESSAGE_UNFURL_MEDIA {
		values.Set("unfurl_media", "false")
	}
	if params.IconURL != DEFAULT_MESSAGE_ICON_URL {
		values.Set("icon_url", params.IconURL)
	}
	if params.IconEmoji != DEFAULT_MESSAGE_ICON_EMOJI {
		values.Set("icon_emoji", params.IconEmoji)
	}
	if params.Markdown != DEFAULT_MESSAGE_MARKDOWN {
		values.Set("mrkdwn", "false")
	}

	response, err := chatRequest("chat.postMessage", values, api.debug)
	if err != nil {
		return "", "", err
	}
	return response.ChannelId, response.Timestamp, nil
}

// UpdateMessage updates a message in a channel
func (api *Slack) UpdateMessage(channelId, timestamp, text string) (string, string, string, error) {
	values := url.Values{
		"token":   {api.config.token},
		"channel": {channelId},
		"text":    {escapeMessage(text)},
		"ts":      {timestamp},
	}
	response, err := chatRequest("chat.update", values, api.debug)
	if err != nil {
		return "", "", "", err
	}
	return response.ChannelId, response.Timestamp, response.Text, nil
}
<|endoftext|>


<commit_before>package modelhelper

import (
	"fmt"
	"koding/db/models"
	"koding/db/mongodb"
	"labix.org/v2/mgo"
)

var PostCollMap = map[string]string{
	"NewStatusUpdate": "jNewStatusUpdates",
	"StatusUpdate":    "jStatusUpdates",
	"BlogPost":        "jBlogPosts",
	"Discussion":      "jDiscussions",
	"CodeSnip":        "jCodeSnips",
	"Tutorial":        "jTutorials",
}

func GetPostById(id string, postType string) (*models.Post, error) {
	post := new(models.Post)
	coll, err := getPostType(postType)
	if err != nil {
		return post, err
	}
	return post, mongodb.One(coll, id, post)
}

func UpdatePost(p *models.Post, postType string) error {
	query := updateByIdQuery(p.Id.Hex(), p)
	return runQuery(postType, query)
}

func DeletePostById(id string, postType string) error {
	query := deleteByIdQuery(id)
	return runQuery(postType, query)
}

func GetSomePosts(s Selector, o Options, postType string) ([]models.Post, error) {
	posts := make([]models.Post, 0)
	query := func(c *mgo.Collection) error {
		q := c.Find(s)
		decorateQuery(q, o)
		return q.All(&posts)
	}
	return posts, runQuery(postType, query)
}

func CountPosts(s Selector, o Options, postType string) (int, error) {
	var count int
	query := countQuery(s, o, &count)
	return count, runQuery(postType, query)
}

func getPostType(postType string) (string, error) {
	coll, ok := PostCollMap[postType]
	if !ok {
		return coll, fmt.Errorf("Incorrect Post Type: %s", postType)
	}
	return coll, nil
}

func runQuery(postType string, query func(c *mgo.Collection) error) error {
	coll, err := getPostType(postType)
	if err != nil {
		return err
	}
	return mongodb.Run(coll, query)
}
<commit_msg>Migration: PostCollMap names are updated<commit_after>package modelhelper

import (
	"fmt"
	"koding/db/models"
	"koding/db/mongodb"
	"labix.org/v2/mgo"
)

var PostCollMap = map[string]string{
	"JNewStatusUpdate": "jNewStatusUpdates",
	"JStatusUpdate":    "jStatusUpdates",
	"JBlogPost":        "jBlogPosts",
	"JDiscussion":      "jDiscussions",
	"JCodeSnip":        "jCodeSnips",
	"JTutorial":        "jTutorials",
}

func GetPostById(id string, postType string) (*models.Post, error) {
	post := new(models.Post)
	coll, err := getPostType(postType)
	if err != nil {
		return post, err
	}
	return post, mongodb.One(coll, id, post)
}

func UpdatePost(p *models.Post, postType string) error {
	query := updateByIdQuery(p.Id.Hex(), p)
	return runQuery(postType, query)
}

func DeletePostById(id string, postType string) error {
	query := deleteByIdQuery(id)
	return runQuery(postType, query)
}

func GetSomePosts(s Selector, o Options, postType string) ([]models.Post, error) {
	posts := make([]models.Post, 0)
	query := func(c *mgo.Collection) error {
		q := c.Find(s)
		decorateQuery(q, o)
		return q.All(&posts)
	}
	return posts, runQuery(postType, query)
}

func CountPosts(s Selector, o Options, postType string) (int, error) {
	var count int
	query := countQuery(s, o, &count)
	return count, runQuery(postType, query)
}

func getPostType(postType string) (string, error) {
	coll, ok := PostCollMap[postType]
	if !ok {
		return coll, fmt.Errorf("Incorrect Post Type: %s", postType)
	}
	return coll, nil
}

func runQuery(postType string, query func(c *mgo.Collection) error) error {
	coll, err := getPostType(postType)
	if err != nil {
		return err
	}
	return mongodb.Run(coll, query)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/xml"
	"fmt"
	"net"
)

type Query struct {
	XMLName  xml.Name `xml:"query"`
	Xmlns    string   `xml:"xmlns,attr"`
	Username string   `xml:"username"`
	Password string   `xml:"password"`
	Digest   string   `xml:"digest"`
	Resource string   `xml:"resource"`
}

type Iq struct {
	XMLName xml.Name `xml:"iq"`
	Type    string   `xml:"type,attr"`
	Id      string   `xml:"id,attr"`
	Query   Query    `xml:"query"`
}

type Stream struct {
	XMLName xml.Name `xml:"stream:stream"`
	Iq      Iq       `xml:"iq"`
}

type LoginReq struct {
	Iq Iq `xml:"iq"`
}

func Serve(addr string) {
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		// handle error
	}
	for {
		conn, err := ln.Accept()
		if err != nil {
			// handle error
			continue
		}
		go handleConnection(conn)
	}
}

func handleConnection(conn net.Conn) {

    b := xml.NewDecoder(conn)
	fmt.Fprintf(conn, `<?xml version='1.0'?>
		<stream:stream
			from='localhost'
			id='abc123'
			to='james@localhost'
			version='1.0'
			xml:lang='en'
			xmlns='jabber:server'
			xmlns:stream='http://etherx.jabber.org/streams'>`)

	fmt.Fprintf(conn, "<stream:features/>")
	for {
        iqData := new(Iq)
        b.Decode(iqData)
		switch iqData.Type {
            case "get":
                r := &Iq{Id: iqData.Id, Type: "result"}
                r.Query = Query{Xmlns: "jabber:iq:auth"}
                output, _ := xml.Marshal(r)
                fmt.Fprintf(conn, string(output))
            case "set":
                // Need to perform auth lookup here
                i := Iq{Id: iqData.Id, Type: "result"}
                output, _ := xml.Marshal(i)
                fmt.Fprintf(conn, string(output))
            default:
                // Nothing
		}
	}

}
<commit_msg>go fmt<commit_after>package main

import (
	"encoding/xml"
	"fmt"
	"net"
)

type Query struct {
	XMLName  xml.Name `xml:"query"`
	Xmlns    string   `xml:"xmlns,attr"`
	Username string   `xml:"username"`
	Password string   `xml:"password"`
	Digest   string   `xml:"digest"`
	Resource string   `xml:"resource"`
}

type Iq struct {
	XMLName xml.Name `xml:"iq"`
	Type    string   `xml:"type,attr"`
	Id      string   `xml:"id,attr"`
	Query   Query    `xml:"query"`
}

type Stream struct {
	XMLName xml.Name `xml:"stream:stream"`
	Iq      Iq       `xml:"iq"`
}

type LoginReq struct {
	Iq Iq `xml:"iq"`
}

func Serve(addr string) {
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		// handle error
	}
	for {
		conn, err := ln.Accept()
		if err != nil {
			// handle error
			continue
		}
		go handleConnection(conn)
	}
}

func handleConnection(conn net.Conn) {

	b := xml.NewDecoder(conn)
	fmt.Fprintf(conn, `<?xml version='1.0'?>
		<stream:stream
			from='localhost'
			id='abc123'
			to='james@localhost'
			version='1.0'
			xml:lang='en'
			xmlns='jabber:server'
			xmlns:stream='http://etherx.jabber.org/streams'>`)

	fmt.Fprintf(conn, "<stream:features/>")
	for {
		iqData := new(Iq)
		b.Decode(iqData)
		switch iqData.Type {
		case "get":
			r := &Iq{Id: iqData.Id, Type: "result"}
			r.Query = Query{Xmlns: "jabber:iq:auth"}
			output, _ := xml.Marshal(r)
			fmt.Fprintf(conn, string(output))
		case "set":
			// Need to perform auth lookup here
			i := Iq{Id: iqData.Id, Type: "result"}
			output, _ := xml.Marshal(i)
			fmt.Fprintf(conn, string(output))
		default:
			// Nothing
		}
	}

}
<|endoftext|>


<commit_before>/* Simple command line program to crop images

Usage:

$ go run crop.go --height=5000 --width=7000 <path to image1> <path to image 2>

The cropped images will be placed in the same directory as the original images with
the file names being ``cropped_<original_file_name>.<original_extension>``
*/

package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"github.com/oliamb/cutter"
	"image"
	"image/jpeg"
	"image/png"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
)

func validateImageType(imageType string) bool {
	recognizedImageTypes := []string{"image/jpeg", "image/png"}
	for _, t := range recognizedImageTypes {
		if imageType == t {
			return true
		}
	}
	return false
}

/*
cropper() accepts three parameters:

inputFilePath : A string referring to the relative path to the image to crop

cWidth    : An int specifying the desired width of the cropped image

cHeight   : An int specifying the desired height of the cropped image
*/
func cropper(inputFilePath string, cWidth int, cHeight int) {
	imageData, err := ioutil.ReadFile(inputFilePath)
	if err != nil {
		log.Fatal(err)
	}

	imageType := http.DetectContentType(imageData)
	// Check if we can handle this image
	if !validateImageType(imageType) {
		log.Fatal("Cannot handle image of this type")
	}

	// We first decode the image
	reader := bytes.NewReader(imageData)
	img, _, err := image.Decode(reader)
	if err != nil {
		log.Fatal(err)
	}

	// Perform the cropping
	croppedImg, err := cutter.Crop(img, cutter.Config{
		Height: cHeight,
		Width:  cWidth,
	})
	if err != nil {
		log.Fatal(err)
	}

	// Now we encode the cropped image data using the appropriate
	// encoder and save it to a new file

	croppedFileDir, fileName := filepath.Split(inputFilePath)
	croppedFileName := fmt.Sprintf("%scropped_%s", croppedFileDir, fileName)
	croppedFile, err := os.Create(croppedFileName)
	if err != nil {
		log.Fatal(err)
	}
	defer croppedFile.Close()

	croppedFileWriter := bufio.NewWriter(croppedFile)

	// Depending on the image type, we have to choose an appropriate encoder
	if imageType == "image/png" {
		err = png.Encode(croppedFileWriter, croppedImg)
	}
	if imageType == "image/jpeg" {
		// The third argument indicates the quality of the encoding
		// We specify 100 (it can take values in [1,100], inclusive.
		err = jpeg.Encode(croppedFileWriter, croppedImg, &jpeg.Options{100})
	}
	if err != nil {
		log.Fatal(err)
	}
	croppedFileWriter.Flush()
}

func main() {

	// Setup the flags
	cHeight := flag.Int("height", 0, "Crop Height")
	cWidth := flag.Int("width", 0, "Crop Width")
	flag.Parse()

	//Check flags, file name specified
	if *cHeight <= 0 {
		log.Fatal("Must specify the crop height to be a positive integer")
	}

	if *cWidth <= 0 {
		log.Fatal("Must specify the crop width to be a positive integer")
	}

	numImages := len(flag.Args())
	if numImages == 0 {
		log.Fatal("Must specify at least 1 image to crop")
	}

	// Loop over each file, crop and save the cropped image.
	for _, inputFilePath := range flag.Args() {
		cropper(inputFilePath, *cWidth, *cHeight)
	}
}
<commit_msg>Fix comment<commit_after>/* Simple command line program to crop images

Usage:

$ go run crop.go --height=5000 --width=7000 <path to image1> <path to image 2>

The cropped images will be placed in the same directory as the original images with
the file names being cropped_<original_file_name>.<original_extension>
*/

package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"github.com/oliamb/cutter"
	"image"
	"image/jpeg"
	"image/png"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
)

func validateImageType(imageType string) bool {
	recognizedImageTypes := []string{"image/jpeg", "image/png"}
	for _, t := range recognizedImageTypes {
		if imageType == t {
			return true
		}
	}
	return false
}

/*
cropper() accepts three parameters:

inputFilePath : A string referring to the relative path to the image to crop

cWidth    : An int specifying the desired width of the cropped image

cHeight   : An int specifying the desired height of the cropped image
*/
func cropper(inputFilePath string, cWidth int, cHeight int) {
	imageData, err := ioutil.ReadFile(inputFilePath)
	if err != nil {
		log.Fatal(err)
	}

	imageType := http.DetectContentType(imageData)
	// Check if we can handle this image
	if !validateImageType(imageType) {
		log.Fatal("Cannot handle image of this type")
	}

	// We first decode the image
	reader := bytes.NewReader(imageData)
	img, _, err := image.Decode(reader)
	if err != nil {
		log.Fatal(err)
	}

	// Perform the cropping
	croppedImg, err := cutter.Crop(img, cutter.Config{
		Height: cHeight,
		Width:  cWidth,
	})
	if err != nil {
		log.Fatal(err)
	}

	// Now we encode the cropped image data using the appropriate
	// encoder and save it to a new file

	croppedFileDir, fileName := filepath.Split(inputFilePath)
	croppedFileName := fmt.Sprintf("%scropped_%s", croppedFileDir, fileName)
	croppedFile, err := os.Create(croppedFileName)
	if err != nil {
		log.Fatal(err)
	}
	defer croppedFile.Close()

	croppedFileWriter := bufio.NewWriter(croppedFile)

	// Depending on the image type, we have to choose an appropriate encoder
	if imageType == "image/png" {
		err = png.Encode(croppedFileWriter, croppedImg)
	}
	if imageType == "image/jpeg" {
		// The third argument indicates the quality of the encoding
		// We specify 100 (it can take values in [1,100], inclusive.
		err = jpeg.Encode(croppedFileWriter, croppedImg, &jpeg.Options{100})
	}
	if err != nil {
		log.Fatal(err)
	}
	croppedFileWriter.Flush()
}

func main() {

	// Setup the flags
	cHeight := flag.Int("height", 0, "Crop Height")
	cWidth := flag.Int("width", 0, "Crop Width")
	flag.Parse()

	//Check flags, file name specified
	if *cHeight <= 0 {
		log.Fatal("Must specify the crop height to be a positive integer")
	}

	if *cWidth <= 0 {
		log.Fatal("Must specify the crop width to be a positive integer")
	}

	numImages := len(flag.Args())
	if numImages == 0 {
		log.Fatal("Must specify at least 1 image to crop")
	}

	// Loop over each file, crop and save the cropped image.
	for _, inputFilePath := range flag.Args() {
		cropper(inputFilePath, *cWidth, *cHeight)
	}
}
<|endoftext|>


<commit_before>package thermal

import (
	"code.google.com/p/go.crypto/nacl/box"
	"code.google.com/p/go.crypto/nacl/secretbox"
	"code.google.com/p/go.crypto/poly1305"
	"crypto/rand"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"log"
)

// cs3a is an implementation of the NaCl based cipher set 3a
type cs3a struct {
	id             [1]byte
	fingerprintBin []byte
	fingerprintHex string
	publicKey      [32]byte
	privateKey     [32]byte
}

// initialize generates a key pair and sets up the cipher set
func (cs *cs3a) initialize() error {

	// generate the key pair
	publicKey, privateKey, err := box.GenerateKey(rand.Reader)
	if err != nil {
		log.Println("Error generating NaCl keypair in cs3a initialization")
		return err
	}

	// generate the fingerprint hash
	hash256 := sha256.New()
	hash256.Write(publicKey[:])
	fingerprintBin := hash256.Sum(nil)

	// generate the single byte representation of the cipher set
	csid_byte, _ := hex.DecodeString("3a")

	// initialize the struct
	copy(cs.id[:], csid_byte[:])
	cs.fingerprintBin = fingerprintBin
	cs.publicKey = *publicKey
	cs.privateKey = *privateKey

	return nil

}

func (cs *cs3a) String() string {
	return fmt.Sprintf("%x: %x", cs.id, cs.fingerprintBin)
}

func (cs *cs3a) csid() [1]byte {
	return cs.id
}

// fingerprint returns the csid and fingerprint for use in a 'parts' set
func (cs *cs3a) fingerprint() (string, string) {
	return fmt.Sprintf("%x", cs.id), fmt.Sprintf("%x", cs.fingerprintBin)
}

// pubKey returns the cipher set public key
func (cs *cs3a) pubKey() *[32]byte {
	return &cs.publicKey
}

/*
--------------------------------------------------------------------------------
gob encoding/decoding

--------------------------------------------------------------------------------
*/

// GobEncode implements the GobEncoder interface and allows for persisting the cipherset
func (cs *cs3a) GobEncode() ([]byte, error) {

	var encoded_cset []byte

	encoded_cset = append(encoded_cset, cs.id[:]...)
	encoded_cset = append(encoded_cset, cs.publicKey[:]...)
	encoded_cset = append(encoded_cset, cs.privateKey[:]...)

	return encoded_cset, nil

}

/*
--------------------------------------------------------------------------------
The CS3a Open Packet Handshake

The cs3a encryption & decryption of an inner open packet, from the perspective
of the sender and receiver:

Sender:
box.Precompute(senderLineSecret, receiverPublicKey, senderLinePrivateKey)
secretbox.Seal(encInnerPacket, packet, &nonce, senderLineSecret)

Receiver:
box.Precompute(&senderLineSecret, &senderLinePublicKey, &receiverPrivateKey)
secretbox.Open(packet, encInnerPacket, &nonce, &senderLineSecret)

The sender/receiver context helps to highlight the public/private key pairings.

However, the following functions use the context of local switch instance
and remote switch instance instead.
--------------------------------------------------------------------------------
*/

// encryptOpenPacket returns an assembled open packet body and a local line shared secret
func (cs *cs3a) encryptOpenPacketBody(packet []byte, remotePublicKey *[32]byte) (openPacketBody []byte, localLineSecret [32]byte, err error) {

	// switch key pair
	// cs.publicKey and cs.privateKey should already be populated

	// temporary line key pair
	linePublicKey, linePrivateKey, err := box.GenerateKey(rand.Reader)
	if err != nil {
		log.Println("Error generating NaCl keypair for line")
		return openPacketBody, localLineSecret, err
	}

	// Encrypt the inner packet
	var nonce [24]byte
	var encInnerPacket []byte

	box.Precompute(&localLineSecret, remotePublicKey, linePrivateKey)
	encInnerPacket = secretbox.Seal(encInnerPacket, packet, &nonce, &localLineSecret)

	// Generate the mac and assemble the body for the outer packet
	// <mac><local-line-public-key><encrypted-inner-packet-data>
	var macKey [32]byte
	var mac [16]byte
	var openPacketData []byte

	box.Precompute(&macKey, remotePublicKey, &cs.privateKey)
	openPacketData = append(openPacketData, linePublicKey[:]...)
	openPacketData = append(openPacketData, encInnerPacket...)
	poly1305.Sum(&mac, openPacketData, &macKey)

	openPacketBody = append(openPacketBody, mac[:]...)
	openPacketBody = append(openPacketBody, openPacketData...)

	return openPacketBody, localLineSecret, nil

}

// decryptOpenPacket returns an unencrypted inner open packet and a remote line shared secret
func (cs *cs3a) decryptOpenPacketBody(openPacketBody []byte, remotePublicKey *[32]byte) (packet []byte, remoteLineSecret [32]byte, err error) {

	// switch key pair
	// cs.publicKey and cs.privateKey should already be populated

	// Unpack the outer packet body
	// <mac><remote-line-public-key><encrypted-inner-packet-data>
	var mac [16]byte
	var remoteLinePublicKey [32]byte
	var encInnerPacket []byte
	var openPacketData []byte

	copy(mac[:], openPacketBody[:16])
	copy(remoteLinePublicKey[:], openPacketBody[16:48])
	encInnerPacket = append(encInnerPacket, openPacketBody[48:]...)
	openPacketData = append(openPacketData, remoteLinePublicKey[:]...)
	openPacketData = append(openPacketData, encInnerPacket...)

	// Verify the mac
	var authenticated bool
	var macKey [32]byte

	box.Precompute(&macKey, remotePublicKey, &cs.privateKey)
	authenticated = poly1305.Verify(&mac, openPacketData, &macKey)
	if !authenticated {
		msg := "Incoming open packet failed MAC authentication"
		log.Println(msg)
		err = fmt.Errorf(msg)
		return packet, remoteLineSecret, err
	}

	// Decrypt the inner packet
	var nonce [24]byte

	box.Precompute(&remoteLineSecret, &remoteLinePublicKey, &cs.privateKey)
	packet, success := secretbox.Open(packet, encInnerPacket, &nonce, &remoteLineSecret)
	if !success {
		err := fmt.Errorf("Error opening the secretbox")
		return packet, remoteLineSecret, err
	}

	//log.Printf("packet: %x\n", packet)
	return packet, remoteLineSecret, nil
}

/*
--------------------------------------------------------------------------------
The CS3a Line Packet encryption

--------------------------------------------------------------------------------
*/

// generateLineEncryptionKey returns a key suitable for outgoing line packet encryption
func (cs *cs3a) generateLineEncryptionKey(localLineSecret *[32]byte, localLineId, remoteLineId *[16]byte) (key [32]byte) {

	// sha256(local-line-secret, local-line-id, local-line-id)
	hash256 := sha256.New()
	hash256.Write(localLineSecret[:])
	hash256.Write(localLineId[:])
	hash256.Write(remoteLineId[:])
	keyHash := hash256.Sum(nil)

	copy(key[:], keyHash[:])

	return key
}

// generateLineDecryptionKey returns a key suitable for incoming line packet decryption
func (cs *cs3a) generateLineDecryptionKey(remoteLineSecret *[32]byte, localLineId, remoteLineId *[16]byte) (key [32]byte) {

	// sha256(remote-line-secret, remote-line-id, local-line-id)
	hash256 := sha256.New()
	hash256.Write(remoteLineSecret[:])
	hash256.Write(remoteLineId[:])
	hash256.Write(localLineId[:])
	keyBin := hash256.Sum(nil)

	copy(key[:], keyBin[:])

	return key
}

// encryptLinePacket encrypts a channel packet and builds a line packet body
func (cs *cs3a) encryptLinePacketBody(packet []byte, lineEncryptionKey *[32]byte) (linePacketBody []byte, err error) {
	var nonce [24]byte
	var linePacketData []byte

	// encrypt the inner channel packet
	rand.Reader.Read(nonce[:])
	linePacketData = secretbox.Seal(linePacketData, packet, &nonce, lineEncryptionKey)

	// assemble: <nonce><secretbox-ciphertext>
	linePacketBody = append(nonce[:], linePacketData[:]...)

	return linePacketBody, nil
}

// decryptLinePacket returns a decrypted channel packet from a line packet
func (cs *cs3a) decryptLinePacketBody(linePacketBody []byte, lineDecryptionKey *[32]byte) (packet []byte, err error) {
	var nonce [24]byte

	// disassemble: <nonce><secretbox-ciphertext>
	copy(nonce[:], linePacketBody[:24])
	linePacketData := linePacketBody[24:]

	// decrypt the inner channel packet
	packet, success := secretbox.Open(packet, linePacketData, &nonce, lineDecryptionKey)
	if !success {
		err := fmt.Errorf("Error opening the secretbox")
		return packet, err
	}

	return packet, nil
}
<commit_msg>change doc string style<commit_after>package thermal

import (
	"code.google.com/p/go.crypto/nacl/box"
	"code.google.com/p/go.crypto/nacl/secretbox"
	"code.google.com/p/go.crypto/poly1305"
	"crypto/rand"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"log"
)

// cs3a is an implementation of the NaCl based cipher set 3a
type cs3a struct {
	id             [1]byte
	fingerprintBin []byte
	fingerprintHex string
	publicKey      [32]byte
	privateKey     [32]byte
}

// initialize generates a key pair and sets up the cipher set
func (cs *cs3a) initialize() error {

	// generate the key pair
	publicKey, privateKey, err := box.GenerateKey(rand.Reader)
	if err != nil {
		log.Println("Error generating NaCl keypair in cs3a initialization")
		return err
	}

	// generate the fingerprint hash
	hash256 := sha256.New()
	hash256.Write(publicKey[:])
	fingerprintBin := hash256.Sum(nil)

	// generate the single byte representation of the cipher set
	csid_byte, _ := hex.DecodeString("3a")

	// initialize the struct
	copy(cs.id[:], csid_byte[:])
	cs.fingerprintBin = fingerprintBin
	cs.publicKey = *publicKey
	cs.privateKey = *privateKey

	return nil

}

func (cs *cs3a) String() string {
	return fmt.Sprintf("%x: %x", cs.id, cs.fingerprintBin)
}

func (cs *cs3a) csid() [1]byte {
	return cs.id
}

// fingerprint returns the csid and fingerprint for use in a 'parts' set
func (cs *cs3a) fingerprint() (string, string) {
	return fmt.Sprintf("%x", cs.id), fmt.Sprintf("%x", cs.fingerprintBin)
}

// pubKey returns the cipher set public key
func (cs *cs3a) pubKey() *[32]byte {
	return &cs.publicKey
}

//--------------------------------------------------------------------------------
// gob encoding/decoding
//--------------------------------------------------------------------------------

// GobEncode implements the GobEncoder interface and allows for persisting the cipherset
func (cs *cs3a) GobEncode() ([]byte, error) {

	var encoded_cset []byte

	encoded_cset = append(encoded_cset, cs.id[:]...)
	encoded_cset = append(encoded_cset, cs.publicKey[:]...)
	encoded_cset = append(encoded_cset, cs.privateKey[:]...)

	return encoded_cset, nil

}

//--------------------------------------------------------------------------------
// The CS3a Open Packet Handshake
//
// The cs3a encryption & decryption of an inner open packet, from the perspective
// of the sender and receiver:
//
// Sender:
// box.Precompute(senderLineSecret, receiverPublicKey, senderLinePrivateKey)
// secretbox.Seal(encInnerPacket, packet, &nonce, senderLineSecret)
//
// Receiver:
// box.Precompute(&senderLineSecret, &senderLinePublicKey, &receiverPrivateKey)
// secretbox.Open(packet, encInnerPacket, &nonce, &senderLineSecret)
//
// The sender/receiver context helps to highlight the public/private key pairings.
//
// However, the following functions use the context of local switch instance
// and remote switch instance instead.
//--------------------------------------------------------------------------------

// encryptOpenPacket returns an assembled open packet body and a local line shared secret
func (cs *cs3a) encryptOpenPacketBody(packet []byte, remotePublicKey *[32]byte) (openPacketBody []byte, localLineSecret [32]byte, err error) {

	// switch key pair
	// cs.publicKey and cs.privateKey should already be populated

	// temporary line key pair
	linePublicKey, linePrivateKey, err := box.GenerateKey(rand.Reader)
	if err != nil {
		log.Println("Error generating NaCl keypair for line")
		return openPacketBody, localLineSecret, err
	}

	// Encrypt the inner packet
	var nonce [24]byte
	var encInnerPacket []byte

	box.Precompute(&localLineSecret, remotePublicKey, linePrivateKey)
	encInnerPacket = secretbox.Seal(encInnerPacket, packet, &nonce, &localLineSecret)

	// Generate the mac and assemble the body for the outer packet
	// <mac><local-line-public-key><encrypted-inner-packet-data>
	var macKey [32]byte
	var mac [16]byte
	var openPacketData []byte

	box.Precompute(&macKey, remotePublicKey, &cs.privateKey)
	openPacketData = append(openPacketData, linePublicKey[:]...)
	openPacketData = append(openPacketData, encInnerPacket...)
	poly1305.Sum(&mac, openPacketData, &macKey)

	openPacketBody = append(openPacketBody, mac[:]...)
	openPacketBody = append(openPacketBody, openPacketData...)

	return openPacketBody, localLineSecret, nil

}

// decryptOpenPacket returns an unencrypted inner open packet and a remote line shared secret
func (cs *cs3a) decryptOpenPacketBody(openPacketBody []byte, remotePublicKey *[32]byte) (packet []byte, remoteLineSecret [32]byte, err error) {

	// switch key pair
	// cs.publicKey and cs.privateKey should already be populated

	// Unpack the outer packet body
	// <mac><remote-line-public-key><encrypted-inner-packet-data>
	var mac [16]byte
	var remoteLinePublicKey [32]byte
	var encInnerPacket []byte
	var openPacketData []byte

	copy(mac[:], openPacketBody[:16])
	copy(remoteLinePublicKey[:], openPacketBody[16:48])
	encInnerPacket = append(encInnerPacket, openPacketBody[48:]...)
	openPacketData = append(openPacketData, remoteLinePublicKey[:]...)
	openPacketData = append(openPacketData, encInnerPacket...)

	// Verify the mac
	var authenticated bool
	var macKey [32]byte

	box.Precompute(&macKey, remotePublicKey, &cs.privateKey)
	authenticated = poly1305.Verify(&mac, openPacketData, &macKey)
	if !authenticated {
		msg := "Incoming open packet failed MAC authentication"
		log.Println(msg)
		err = fmt.Errorf(msg)
		return packet, remoteLineSecret, err
	}

	// Decrypt the inner packet
	var nonce [24]byte

	box.Precompute(&remoteLineSecret, &remoteLinePublicKey, &cs.privateKey)
	packet, success := secretbox.Open(packet, encInnerPacket, &nonce, &remoteLineSecret)
	if !success {
		err := fmt.Errorf("Error opening the secretbox")
		return packet, remoteLineSecret, err
	}

	//log.Printf("packet: %x\n", packet)
	return packet, remoteLineSecret, nil
}

//--------------------------------------------------------------------------------
// The CS3a Line Packet encryption
//--------------------------------------------------------------------------------

// generateLineEncryptionKey returns a key suitable for outgoing line packet encryption
func (cs *cs3a) generateLineEncryptionKey(localLineSecret *[32]byte, localLineId, remoteLineId *[16]byte) (key [32]byte) {

	// sha256(local-line-secret, local-line-id, local-line-id)
	hash256 := sha256.New()
	hash256.Write(localLineSecret[:])
	hash256.Write(localLineId[:])
	hash256.Write(remoteLineId[:])
	keyHash := hash256.Sum(nil)

	copy(key[:], keyHash[:])

	return key
}

// generateLineDecryptionKey returns a key suitable for incoming line packet decryption
func (cs *cs3a) generateLineDecryptionKey(remoteLineSecret *[32]byte, localLineId, remoteLineId *[16]byte) (key [32]byte) {

	// sha256(remote-line-secret, remote-line-id, local-line-id)
	hash256 := sha256.New()
	hash256.Write(remoteLineSecret[:])
	hash256.Write(remoteLineId[:])
	hash256.Write(localLineId[:])
	keyBin := hash256.Sum(nil)

	copy(key[:], keyBin[:])

	return key
}

// encryptLinePacket encrypts a channel packet and builds a line packet body
func (cs *cs3a) encryptLinePacketBody(packet []byte, lineEncryptionKey *[32]byte) (linePacketBody []byte, err error) {
	var nonce [24]byte
	var linePacketData []byte

	// encrypt the inner channel packet
	rand.Reader.Read(nonce[:])
	linePacketData = secretbox.Seal(linePacketData, packet, &nonce, lineEncryptionKey)

	// assemble: <nonce><secretbox-ciphertext>
	linePacketBody = append(nonce[:], linePacketData[:]...)

	return linePacketBody, nil
}

// decryptLinePacket returns a decrypted channel packet from a line packet
func (cs *cs3a) decryptLinePacketBody(linePacketBody []byte, lineDecryptionKey *[32]byte) (packet []byte, err error) {
	var nonce [24]byte

	// disassemble: <nonce><secretbox-ciphertext>
	copy(nonce[:], linePacketBody[:24])
	linePacketData := linePacketBody[24:]

	// decrypt the inner channel packet
	packet, success := secretbox.Open(packet, linePacketData, &nonce, lineDecryptionKey)
	if !success {
		err := fmt.Errorf("Error opening the secretbox")
		return packet, err
	}

	return packet, nil
}
<|endoftext|>


<commit_before>package csrf

import (
	"crypto/sha1"
	"encoding/base64"
	"errors"
	"io"

	"github.com/dchest/uniuri"
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
)

const (
	csrfSecret = "csrfSecret"
	csrfSalt   = "csrfSalt"
	csrfToken  = "csrfToken"
)

var defaultIgnoreMethods = []string{"GET", "HEAD", "OPTIONS"}

var defaultErrorFunc = func(c *gin.Context) {
	panic(errors.New("CSRF token mismatch"))
}

var defaultTokenGetter = func(c *gin.Context) string {
	r := c.Request

	if t := r.FormValue("_csrf"); len(t) > 0 {
		return t
	} else if t := r.URL.Query().Get("_csrf"); len(t) > 0 {
		return t
	} else if t := r.Header.Get("X-CSRF-TOKEN"); len(t) > 0 {
		return t
	} else if t := r.Header.Get("X-XSRF-TOKEN"); len(t) > 0 {
		return t
	}

	return ""
}

// Options stores configurations for a CSRF middleware.
type Options struct {
	Secret        string
	IgnoreMethods []string
	ErrorFunc     gin.HandlerFunc
	TokenGetter   func(c *gin.Context) string
}

func tokenize(secret, salt string) string {
	h := sha1.New()
	io.WriteString(h, salt+"-"+secret)
	hash := base64.URLEncoding.EncodeToString(h.Sum(nil))

	return hash
}

func inArray(arr []string, value string) bool {
	inarr := false

	for _, v := range arr {
		if v == value {
			inarr = true
			break
		}
	}

	return inarr
}

// Middleware validates CSRF token.
func Middleware(options Options) gin.HandlerFunc {
	ignoreMethods := options.IgnoreMethods
	errorFunc := options.ErrorFunc
	tokenGetter := options.TokenGetter

	if ignoreMethods == nil {
		ignoreMethods = defaultIgnoreMethods
	}

	if errorFunc == nil {
		errorFunc = defaultErrorFunc
	}

	if tokenGetter == nil {
		tokenGetter = defaultTokenGetter
	}

	return func(c *gin.Context) {
		session := sessions.Default(c)
		c.Set(csrfSecret, options.Secret)

		if inArray(ignoreMethods, c.Request.Method) {
			c.Next()
			return
		}

		var salt string

		s, ok := session.Get(csrfSalt).(string)

		if !ok || len(s) == 0 {
			errorFunc(c)
			return
		}

		salt = s

		session.Delete(csrfSalt)

		token := tokenGetter(c)

		if tokenize(options.Secret, salt) != token {
			errorFunc(c)
			return
		}

		c.Next()
	}
}

// GetToken returns a CSRF token.
func GetToken(c *gin.Context) string {
	session := sessions.Default(c)
	secret := c.MustGet(csrfSecret).(string)

	if t, ok := c.Get(csrfToken); ok {
		return t.(string)
	}

	salt := uniuri.New()
	token := tokenize(secret, salt)
	session.Set(csrfSalt, salt)
	session.Save()
	c.Set(csrfToken, token)

	return token
}
<commit_msg>The csrf salt should be created per session instead of per request. It is useful when the user has two tab page in chrome browser.<commit_after>package csrf

import (
	"crypto/sha1"
	"encoding/base64"
	"errors"
	"io"

	"github.com/dchest/uniuri"
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
)

const (
	csrfSecret = "csrfSecret"
	csrfSalt   = "csrfSalt"
	csrfToken  = "csrfToken"
)

var defaultIgnoreMethods = []string{"GET", "HEAD", "OPTIONS"}

var defaultErrorFunc = func(c *gin.Context) {
	panic(errors.New("CSRF token mismatch"))
}

var defaultTokenGetter = func(c *gin.Context) string {
	r := c.Request

	if t := r.FormValue("_csrf"); len(t) > 0 {
		return t
	} else if t := r.URL.Query().Get("_csrf"); len(t) > 0 {
		return t
	} else if t := r.Header.Get("X-CSRF-TOKEN"); len(t) > 0 {
		return t
	} else if t := r.Header.Get("X-XSRF-TOKEN"); len(t) > 0 {
		return t
	}

	return ""
}

// Options stores configurations for a CSRF middleware.
type Options struct {
	Secret        string
	IgnoreMethods []string
	ErrorFunc     gin.HandlerFunc
	TokenGetter   func(c *gin.Context) string
}

func tokenize(secret, salt string) string {
	h := sha1.New()
	io.WriteString(h, salt+"-"+secret)
	hash := base64.URLEncoding.EncodeToString(h.Sum(nil))

	return hash
}

func inArray(arr []string, value string) bool {
	inarr := false

	for _, v := range arr {
		if v == value {
			inarr = true
			break
		}
	}

	return inarr
}

// Middleware validates CSRF token.
func Middleware(options Options) gin.HandlerFunc {
	ignoreMethods := options.IgnoreMethods
	errorFunc := options.ErrorFunc
	tokenGetter := options.TokenGetter

	if ignoreMethods == nil {
		ignoreMethods = defaultIgnoreMethods
	}

	if errorFunc == nil {
		errorFunc = defaultErrorFunc
	}

	if tokenGetter == nil {
		tokenGetter = defaultTokenGetter
	}

	return func(c *gin.Context) {
		session := sessions.Default(c)
		c.Set(csrfSecret, options.Secret)

		if inArray(ignoreMethods, c.Request.Method) {
			c.Next()
			return
		}

		var salt string

		s, ok := session.Get(csrfSalt).(string)

		if !ok || len(s) == 0 {
			errorFunc(c)
			return
		}

		salt = s

		token := tokenGetter(c)

		if tokenize(options.Secret, salt) != token {
			errorFunc(c)
			return
		}

		c.Next()
	}
}

// GetToken returns a CSRF token.
func GetToken(c *gin.Context) string {
	session := sessions.Default(c)
	secret := c.MustGet(csrfSecret).(string)

	if t, ok := c.Get(csrfToken); ok {
		return t.(string)
	}

	salt, ok := session.Get(csrfSalt).(string)
	if ! ok {
		salt := uniuri.New()
		session.Set(csrfSalt, salt)
		session.Save()
	}
	token := tokenize(secret, salt)
	c.Set(csrfToken, token)

	return token
}
<|endoftext|>