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

package main

import (
	"fmt"
	"os"
	"time"

	"github.com/cheggaaa/pb"
	"github.com/codegangsta/cli"
	"github.com/minio-io/mc/pkg/s3"
)

func printBuckets(v []*s3.Bucket) {
	for _, b := range v {
		msg := fmt.Sprintf("%v %9s %s", b.CreationDate.Local(), "", b.Name)
		info(msg)
	}
}

func printObjects(v []*s3.Item) {
	if len(v) > 0 {
		// Items are already sorted
		for _, b := range v {
			printObject(b.LastModified.Time, b.Size, b.Key)
		}
	}
}

func printObject(date time.Time, v int64, key string) {
	msg := fmt.Sprintf("%v  %9s %s", date.Local(), pb.FormatBytes(v), key)
	info(msg)
}

func doFsList(c *cli.Context) {
	var items []*s3.Item

	s3c, err := getNewClient(c)
	if err != nil {
		fatal(err.Error())
	}
	args, err := parseArgs(c)
	if err != nil {
		fatal(err.Error())
	}
	switch true {
	case args.source.bucket == "": // List all buckets
		buckets, err := s3c.ListBuckets()
		if err != nil {
			fatal(err.Error())
		}
		printBuckets(buckets)
	case args.source.key == "": // List objects in a bucket
		items, _, err = s3c.ListObjects(args.source.bucket, "", "", "", s3.MaxKeys)
		if err != nil {
			fatal(err.Error())
		}
		printObjects(items)
	case args.source.key != "": // List objects matching the key prefix
		var date time.Time
		var size int64

		size, date, err = s3c.Stat(args.source.bucket, args.source.key)
		switch err {
		case nil: // List a single object. Exact key
			printObject(date, size, args.source.key)
		case os.ErrNotExist:
			// List all objects matching the key prefix
			items, _, err = s3c.ListObjects(args.source.bucket, "", args.source.key, "", s3.MaxKeys)
			if err != nil {
				fatal(err.Error())
			}
			if len(items) > 0 {
				printObjects(items)
			} else {
				fatal(os.ErrNotExist.Error())
			}
		default: // Error
			fatal(err.Error())
		}
	default:
		fatal(err.Error())
	}
}
<commit_msg>print ./mc ls in a proper format<commit_after>/*
 * Mini Object Storage, (C) 2014,2015 Minio, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package main

import (
	"fmt"
	"os"
	"time"

	"github.com/cheggaaa/pb"
	"github.com/codegangsta/cli"
	"github.com/minio-io/mc/pkg/s3"
)

const (
	printDate = "2006-01-02 15:04:05 -0700 MST"
)

func printBuckets(v []*s3.Bucket) {
	for _, b := range v {
		msg := fmt.Sprintf("%29s %13s %s", b.CreationDate.Local().Format(printDate), "", b.Name)
		info(msg)
	}
}

func printObjects(v []*s3.Item) {
	if len(v) > 0 {
		// Items are already sorted
		for _, b := range v {
			printObject(b.LastModified.Time, b.Size, b.Key)
		}
	}
}

func printObject(date time.Time, v int64, key string) {
	msg := fmt.Sprintf("%29s %13s %s", date.Local().Format(printDate), pb.FormatBytes(v), key)
	info(msg)
}

func doFsList(c *cli.Context) {
	var items []*s3.Item

	s3c, err := getNewClient(c)
	if err != nil {
		fatal(err.Error())
	}
	args, err := parseArgs(c)
	if err != nil {
		fatal(err.Error())
	}
	switch true {
	case args.source.bucket == "": // List all buckets
		buckets, err := s3c.ListBuckets()
		if err != nil {
			fatal(err.Error())
		}
		printBuckets(buckets)
	case args.source.key == "": // List objects in a bucket
		items, _, err = s3c.ListObjects(args.source.bucket, "", "", "", s3.MaxKeys)
		if err != nil {
			fatal(err.Error())
		}
		printObjects(items)
	case args.source.key != "": // List objects matching the key prefix
		var date time.Time
		var size int64

		size, date, err = s3c.Stat(args.source.bucket, args.source.key)
		switch err {
		case nil: // List a single object. Exact key
			printObject(date, size, args.source.key)
		case os.ErrNotExist:
			// List all objects matching the key prefix
			items, _, err = s3c.ListObjects(args.source.bucket, "", args.source.key, "", s3.MaxKeys)
			if err != nil {
				fatal(err.Error())
			}
			if len(items) > 0 {
				printObjects(items)
			} else {
				fatal(os.ErrNotExist.Error())
			}
		default: // Error
			fatal(err.Error())
		}
	default:
		fatal(err.Error())
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"strings"
	"time"
)

type bp struct {
	Name string
	Id   string
	Kpis []kpi
}

type ServiceStatusProvider interface {
	ServiceStatus(Service) (bool, error)
}

func (bp bp) Status(ssp ServiceStatusProvider) ResultSet {
	rs := ResultSet{
		kind:     "BP",
		name:     bp.Name,
		id:       bp.Id,
		children: []ResultSet{},
	}

	var values []bool
	for _, kpi := range bp.Kpis {
		childRs := kpi.Status(ssp)
		values = append(values, childRs.Bool())
		rs.children = append(rs.children, childRs)
	}

	ok, err := calculate("AND", values)
	rs.status = boolAsStatus(ok)
	if err != nil {
		rs.err = err
		rs.status = StatusUnknown
	}
	return rs
}

type kpi struct {
	Name      string
	Id        string
	Operation string
	Services  []Service
}

func (k kpi) Status(ssp ServiceStatusProvider) ResultSet {
	rs := ResultSet{
		kind:     "KPI",
		name:     k.Name,
		id:       k.Id,
		children: []ResultSet{},
	}

	var values []bool
	for _, s := range k.Services {
		childRs := s.Status(ssp)
		values = append(values, childRs.Bool())
		rs.children = append(rs.children, childRs)
	}

	ok, err := calculate(k.Operation, values)
	rs.status = boolAsStatus(ok)
	if err != nil {
		rs.err = err
		rs.status = StatusUnknown
	}
	return rs
}

type Service struct {
	Host    string
	Service string
}

func (s Service) Status(ssp ServiceStatusProvider) ResultSet {
	name := fmt.Sprintf("%s!%s", s.Host, s.Service)
	rs := ResultSet{
		name: name,
		id:   name,
		kind: "SVC",
	}
	ok, err := ssp.ServiceStatus(s)
	rs.err = err
	if rs.err != nil {
		rs.status = StatusUnknown
	} else if ok {
		rs.status = StatusOK
	} else {
		rs.status = StatusNOK
	}
	return rs
}

type ResultSet struct {
	name     string
	id       string
	kind     string
	status   status
	err      error
	children []ResultSet
}

func (rs ResultSet) PrettyPrint(level int) string {
	ident := strings.Repeat("   ", level)
	out := rs.status.Colorize(fmt.Sprintf("%s%s %s is %v", ident, rs.kind, rs.name, rs.status))
	if rs.err != nil {
		out += fmt.Sprintf(" (Error occured: %s)", rs.err.Error())
	}
	out += "\n"
	for _, childRs := range rs.children {
		out += childRs.PrettyPrint(level + 1)
	}
	return out
}

func (rs ResultSet) AsInflux(nt map[string]string, t time.Time) []point {
	var out []point

	nt[rs.kind] = rs.id
	tags := map[string]string{
		"kind": rs.kind,
	}
	for k, v := range nt {
		tags[k] = v
	}
	fields := map[string]interface{}{
		"status": rs.status.toInt(),
	}
	pt := point{
		series: rs.kind,
		tags:   tags,
		fields: fields,
		time:   t,
	}
	out = append(out, pt)

	for _, childRs := range rs.children {
		out = append(out, childRs.AsInflux(nt, t)...)
	}
	return out
}

func (rs ResultSet) Bool() bool {
	if rs.status == StatusNOK {
		return false
	}
	return true
}
<commit_msg>perform bp checks concurrent concurrent<commit_after>package cmd

import (
	"fmt"
	"strings"
	"time"
)

type bp struct {
	Name string
	Id   string
	Kpis []kpi
}

type ServiceStatusProvider interface {
	ServiceStatus(Service) (bool, error)
}

func (bp bp) Status(ssp ServiceStatusProvider) ResultSet {
	rs := ResultSet{
		kind:     "BP",
		name:     bp.Name,
		id:       bp.Id,
		children: []ResultSet{},
	}

	ch := make(chan *ResultSet)
	var values []bool
	for _, k := range bp.Kpis {
		go func(k kpi, ssp ServiceStatusProvider) {
			childRs := k.Status(ssp)
			ch <- &childRs
		}(k, ssp)
	}

	for {
		select {
		case childRs := <-ch:
			values = append(values, childRs.Bool())
			rs.children = append(rs.children, *childRs)
			if len(values) == len(bp.Kpis) {
				ch = nil
			}
		}
		if ch == nil {
			break
		}
	}

	ok, err := calculate("AND", values)
	rs.status = boolAsStatus(ok)
	if err != nil {
		rs.err = err
		rs.status = StatusUnknown
	}
	return rs
}

type kpi struct {
	Name      string
	Id        string
	Operation string
	Services  []Service
}

func (k kpi) Status(ssp ServiceStatusProvider) ResultSet {
	rs := ResultSet{
		kind:     "KPI",
		name:     k.Name,
		id:       k.Id,
		children: []ResultSet{},
	}

	ch := make(chan *ResultSet)
	var values []bool
	for _, s := range k.Services {
		go func(s Service, ssp ServiceStatusProvider) {
			childRs := s.Status(ssp)
			ch <- &childRs
		}(s, ssp)
	}

	for {
		select {
		case childRs := <-ch:
			values = append(values, childRs.Bool())
			rs.children = append(rs.children, *childRs)
			if len(values) == len(k.Services) {
				ch = nil
			}
		}
		if ch == nil {
			break
		}
	}

	ok, err := calculate(k.Operation, values)
	rs.status = boolAsStatus(ok)
	if err != nil {
		rs.err = err
		rs.status = StatusUnknown
	}
	return rs
}

type Service struct {
	Host    string
	Service string
}

func (s Service) Status(ssp ServiceStatusProvider) ResultSet {
	name := fmt.Sprintf("%s!%s", s.Host, s.Service)
	rs := ResultSet{
		name: name,
		id:   name,
		kind: "SVC",
	}
	ok, err := ssp.ServiceStatus(s)
	rs.err = err
	if rs.err != nil {
		rs.status = StatusUnknown
	} else if ok {
		rs.status = StatusOK
	} else {
		rs.status = StatusNOK
	}
	return rs
}

type ResultSet struct {
	name     string
	id       string
	kind     string
	status   status
	err      error
	children []ResultSet
}

func (rs ResultSet) PrettyPrint(level int) string {
	ident := strings.Repeat("   ", level)
	out := rs.status.Colorize(fmt.Sprintf("%s%s %s is %v", ident, rs.kind, rs.name, rs.status))
	if rs.err != nil {
		out += fmt.Sprintf(" (Error occured: %s)", rs.err.Error())
	}
	out += "\n"
	for _, childRs := range rs.children {
		out += childRs.PrettyPrint(level + 1)
	}
	return out
}

func (rs ResultSet) AsInflux(nt map[string]string, t time.Time) []point {
	var out []point

	nt[rs.kind] = rs.id
	tags := map[string]string{
		"kind": rs.kind,
	}
	for k, v := range nt {
		tags[k] = v
	}
	fields := map[string]interface{}{
		"status": rs.status.toInt(),
	}
	pt := point{
		series: rs.kind,
		tags:   tags,
		fields: fields,
		time:   t,
	}
	out = append(out, pt)

	for _, childRs := range rs.children {
		out = append(out, childRs.AsInflux(nt, t)...)
	}
	return out
}

func (rs ResultSet) Bool() bool {
	if rs.status == StatusNOK {
		return false
	}
	return true
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2017 Jon Carlson.  All rights reserved.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//

package main

import (
	"bytes"
	"database/sql"
	"fmt"
	"github.com/joncrlsn/misc"
	"github.com/joncrlsn/pgutil"
	"sort"
	"strconv"
	"strings"
	"text/template"
)

var (
	columnSqlTemplate = initColumnSqlTemplate()
)

// Initializes the Sql template
func initColumnSqlTemplate() *template.Template {
	sql := `
SELECT table_schema
    , {{if eq $.DbSchema "*" }}table_schema || '.' || {{end}}table_name || '.' || column_name  AS compare_name
	, table_name
    , column_name
    , data_type
    , is_nullable
    , column_default
    , character_maximum_length
    , is_identity
    , identity_generation
FROM information_schema.columns
WHERE is_updatable = 'YES'
{{if eq $.DbSchema "*" }}
AND table_schema NOT LIKE 'pg_%'
AND table_schema <> 'information_schema'
{{else}}
AND table_schema = '{{$.DbSchema}}'
{{end}}
ORDER BY compare_name ASC;
`
	t := template.New("ColumnSqlTmpl")
	template.Must(t.Parse(sql))
	return t
}

var (
	tableColumnSqlTemplate = initTableColumnSqlTemplate()
)

// Initializes the Sql template
func initTableColumnSqlTemplate() *template.Template {
	sql := `
SELECT a.table_schema
    , {{if eq $.DbSchema "*" }}a.table_schema || '.' || {{end}}a.table_name || '.' || column_name  AS compare_name
	, a.table_name
    , column_name
    , data_type
    , is_nullable
    , column_default
    , character_maximum_length
FROM information_schema.columns a
INNER JOIN information_schema.tables b
    ON a.table_schema = b.table_schema AND
       a.table_name = b.table_name AND
       b.table_type = 'BASE TABLE'
WHERE is_updatable = 'YES'
{{if eq $.DbSchema "*" }}
AND a.table_schema NOT LIKE 'pg_%'
AND a.table_schema <> 'information_schema'
{{else}}
AND a.table_schema = '{{$.DbSchema}}'
{{end}}
{{ if $.TableType }}
AND b.table_type = '{{ $.TableType }}'
{{ end }}
ORDER BY compare_name ASC;
`
	t := template.New("ColumnSqlTmpl")
	template.Must(t.Parse(sql))
	return t
}

// ==================================
// Column Rows definition
// ==================================

// ColumnRows is a sortable slice of string maps
type ColumnRows []map[string]string

func (slice ColumnRows) Len() int {
	return len(slice)
}

func (slice ColumnRows) Less(i, j int) bool {
	return slice[i]["compare_name"] < slice[j]["compare_name"]
}

func (slice ColumnRows) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}

// ==================================
// ColumnSchema definition
// (implements Schema -- defined in pgdiff.go)
// ==================================

// ColumnSchema holds a slice of rows from one of the databases as well as
// a reference to the current row of data we're viewing.
type ColumnSchema struct {
	rows   ColumnRows
	rowNum int
	done   bool
}

// get returns the value from the current row for the given key
func (c *ColumnSchema) get(key string) string {
	if c.rowNum >= len(c.rows) {
		return ""
	}
	return c.rows[c.rowNum][key]
}

// NextRow increments the rowNum and tells you whether or not there are more
func (c *ColumnSchema) NextRow() bool {
	if c.rowNum >= len(c.rows)-1 {
		c.done = true
	}
	c.rowNum = c.rowNum + 1
	return !c.done
}

// Compare tells you, in one pass, whether or not the first row matches, is less than, or greater than the second row
func (c *ColumnSchema) Compare(obj interface{}) int {
	c2, ok := obj.(*ColumnSchema)
	if !ok {
		fmt.Println("Error!!!, Compare needs a ColumnSchema instance", c2)
	}

	val := misc.CompareStrings(c.get("compare_name"), c2.get("compare_name"))
	return val
}

// Add prints SQL to add the column
func (c *ColumnSchema) Add() {

	schema := dbInfo2.DbSchema
	if schema == "*" {
		schema = c.get("table_schema")
	}

    // Knowing the version of db2 would eliminate the need for this warning
    if c.get("is_identity") == "YES" {
        fmt.Println("-- WARNING: identity columns are not supported in PostgreSQL versions < 10.")
        fmt.Println("-- Attempting to create identity columns in earlier versions will probably result in errors.")
    }

	if c.get("data_type") == "character varying" {
		maxLength, valid := getMaxLength(c.get("character_maximum_length"))
		if !valid {
			fmt.Printf("ALTER TABLE %s.%s ADD COLUMN %s character varying", schema, c.get("table_name"), c.get("column_name"))
		} else {
			fmt.Printf("ALTER TABLE %s.%s ADD COLUMN %s character varying(%s)", schema, c.get("table_name"), c.get("column_name"), maxLength)
		}
	} else {
		if c.get("data_type") == "ARRAY" {
			fmt.Println("-- Note that adding of array data types are not yet generated properly.")
		}
		fmt.Printf("ALTER TABLE %s.%s ADD COLUMN %s %s", schema, c.get("table_name"), c.get("column_name"), c.get("data_type"))
	}

	if c.get("is_nullable") == "NO" {
		fmt.Printf(" NOT NULL")
	}
	if c.get("column_default") != "null" {
		fmt.Printf(" DEFAULT %s", c.get("column_default"))
	}
    // NOTE: there are more identity column sequence options according to the PostgreSQL
    // CREATE TABLE docs, but these do not appear to be available as of version 10.1
    if c.get("is_identity") == "YES" {
        fmt.Printf(" GENERATED %s AS IDENTITY", c.get("identity_generation"))
    }
	fmt.Printf(";\n")
}

// Drop prints SQL to drop the column
func (c *ColumnSchema) Drop() {
	// if dropping column
	fmt.Printf("ALTER TABLE %s.%s DROP COLUMN IF EXISTS %s;\n", c.get("table_schema"), c.get("table_name"), c.get("column_name"))
}

// Change handles the case where the table and column match, but the details do not
func (c *ColumnSchema) Change(obj interface{}) {
	c2, ok := obj.(*ColumnSchema)
	if !ok {
		fmt.Println("Error!!!, ColumnSchema.Change(obj) needs a ColumnSchema instance", c2)
	}

	// Detect column type change (mostly varchar length, or number size increase)
	// (integer to/from bigint is OK)
	if c.get("data_type") == c2.get("data_type") {
		if c.get("data_type") == "character varying" {
			max1, max1Valid := getMaxLength(c.get("character_maximum_length"))
			max2, max2Valid := getMaxLength(c2.get("character_maximum_length"))
			if !max1Valid && !max2Valid {
				// Leave them alone, they both have undefined max lengths
			} else if (max1Valid || !max2Valid) && (max1 != c2.get("character_maximum_length")) {
				//if !max1Valid {
				//    fmt.Println("-- WARNING: varchar column has no maximum length.  Setting to 1024, which may result in data loss.")
				//}
				max1Int, err1 := strconv.Atoi(max1)
				check("converting string to int", err1)
				max2Int, err2 := strconv.Atoi(max2)
				check("converting string to int", err2)
				if max1Int < max2Int {
					fmt.Println("-- WARNING: The next statement will shorten a character varying column, which may result in data loss.")
				}
				fmt.Printf("-- max1Valid: %v  max2Valid: %v \n", max1Valid, max2Valid)
				fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s TYPE character varying(%s);\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), max1)
			}
		}
	}

	// Code and test a column change from integer to bigint
	if c.get("data_type") != c2.get("data_type") {
		fmt.Printf("-- WARNING: This type change may not work well: (%s to %s).\n", c2.get("data_type"), c.get("data_type"))
		if strings.HasPrefix(c.get("data_type"), "character") {
			max1, max1Valid := getMaxLength(c.get("character_maximum_length"))
			if !max1Valid {
				fmt.Println("-- WARNING: varchar column has no maximum length.  Setting to 1024")
			}
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s TYPE %s(%s);\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), c.get("data_type"), max1)
		} else {
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s TYPE %s;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), c.get("data_type"))
		}
	}

	// Detect column default change (or added, dropped)
	if c.get("column_default") == "null" {
		if c.get("column_default") != "null" {
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s DROP DEFAULT;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"))
		}
	} else if c.get("column_default") != c2.get("column_default") {
		fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s SET DEFAULT %s;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), c.get("column_default"))
	}

    // Detect identity column change
    // Save result to variable instead of printing because order for adding/removing
    // is_nullable affects identity columns
    var identitySql string
    if c.get("is_identity") != c2.get("is_identity") {
        // Knowing the version of db2 would eliminate the need for this warning
        fmt.Println("-- WARNING: identity columns are not supported in PostgreSQL versions < 10.")
        fmt.Println("-- Attempting to create identity columns in earlier versions will probably result in errors.")
        if c.get("is_identity") == "YES" {
            identitySql = fmt.Sprintf("ALTER TABLE \"%s\".\"%s\" ALTER COLUMN \"%s\" ADD GENERATED %s AS IDENTITY;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), c.get("identity_generation"))
        } else {
            identitySql = fmt.Sprintf("ALTER TABLE \"%s\".\"%s\" ALTER COLUMN \"%s\" DROP IDENTITY;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"))
        }
    }

	// Detect not-null and nullable change
	if c.get("is_nullable") != c2.get("is_nullable") {
		if c.get("is_nullable") == "YES" {
            if identitySql != "" {
                fmt.Printf(identitySql)
            }
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s DROP NOT NULL;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"))
		} else {
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s SET NOT NULL;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"))
            if identitySql != "" {
                fmt.Printf(identitySql)
            }
		}
	} else {
        if identitySql != "" {
            fmt.Printf(identitySql)
        }
    }
}

// ==================================
// Standalone Functions
// ==================================

// compare outputs SQL to make the columns match between two databases or schemas
func compare(conn1 *sql.DB, conn2 *sql.DB, tpl *template.Template) {
	buf1 := new(bytes.Buffer)
	tpl.Execute(buf1, dbInfo1)

	buf2 := new(bytes.Buffer)
	tpl.Execute(buf2, dbInfo2)

	rowChan1, _ := pgutil.QueryStrings(conn1, buf1.String())
	rowChan2, _ := pgutil.QueryStrings(conn2, buf2.String())

	//rows1 := make([]map[string]string, 500)
	rows1 := make(ColumnRows, 0)
	for row := range rowChan1 {
		rows1 = append(rows1, row)
	}
	sort.Sort(rows1)

	//rows2 := make([]map[string]string, 500)
	rows2 := make(ColumnRows, 0)
	for row := range rowChan2 {
		rows2 = append(rows2, row)
	}
	sort.Sort(&rows2)

	// We have to explicitly type this as Schema here for some unknown reason
	var schema1 Schema = &ColumnSchema{rows: rows1, rowNum: -1}
	var schema2 Schema = &ColumnSchema{rows: rows2, rowNum: -1}

	// Compare the columns
	doDiff(schema1, schema2)

}

// compareColumns outputs SQL to make the columns match between two databases or schemas
func compareColumns(conn1 *sql.DB, conn2 *sql.DB) {

    compare(conn1, conn2, columnSqlTemplate)

}

// compareColumns outputs SQL to make the tables columns (without views columns) match between two databases or schemas
func compareTableColumns(conn1 *sql.DB, conn2 *sql.DB) {

    compare(conn1, conn2, tableColumnSqlTemplate)

}

// getMaxLength returns the maximum length and whether or not it is valid
func getMaxLength(maxLength string) (string, bool) {

	if maxLength == "null" {
		// default to 1024
		return "1024", false
	}
	return maxLength, true
}
<commit_msg>Fix indentation issues<commit_after>//
// Copyright (c) 2017 Jon Carlson.  All rights reserved.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//

package main

import (
	"bytes"
	"database/sql"
	"fmt"
	"github.com/joncrlsn/misc"
	"github.com/joncrlsn/pgutil"
	"sort"
	"strconv"
	"strings"
	"text/template"
)

var (
	columnSqlTemplate = initColumnSqlTemplate()
)

// Initializes the Sql template
func initColumnSqlTemplate() *template.Template {
	sql := `
SELECT table_schema
    , {{if eq $.DbSchema "*" }}table_schema || '.' || {{end}}table_name || '.' || column_name  AS compare_name
	, table_name
    , column_name
    , data_type
    , is_nullable
    , column_default
    , character_maximum_length
    , is_identity
    , identity_generation
FROM information_schema.columns
WHERE is_updatable = 'YES'
{{if eq $.DbSchema "*" }}
AND table_schema NOT LIKE 'pg_%'
AND table_schema <> 'information_schema'
{{else}}
AND table_schema = '{{$.DbSchema}}'
{{end}}
ORDER BY compare_name ASC;
`
	t := template.New("ColumnSqlTmpl")
	template.Must(t.Parse(sql))
	return t
}

var (
	tableColumnSqlTemplate = initTableColumnSqlTemplate()
)

// Initializes the Sql template
func initTableColumnSqlTemplate() *template.Template {
	sql := `
SELECT a.table_schema
    , {{if eq $.DbSchema "*" }}a.table_schema || '.' || {{end}}a.table_name || '.' || column_name  AS compare_name
	, a.table_name
    , column_name
    , data_type
    , is_nullable
    , column_default
    , character_maximum_length
FROM information_schema.columns a
INNER JOIN information_schema.tables b
    ON a.table_schema = b.table_schema AND
       a.table_name = b.table_name AND
       b.table_type = 'BASE TABLE'
WHERE is_updatable = 'YES'
{{if eq $.DbSchema "*" }}
AND a.table_schema NOT LIKE 'pg_%'
AND a.table_schema <> 'information_schema'
{{else}}
AND a.table_schema = '{{$.DbSchema}}'
{{end}}
{{ if $.TableType }}
AND b.table_type = '{{ $.TableType }}'
{{ end }}
ORDER BY compare_name ASC;
`
	t := template.New("ColumnSqlTmpl")
	template.Must(t.Parse(sql))
	return t
}

// ==================================
// Column Rows definition
// ==================================

// ColumnRows is a sortable slice of string maps
type ColumnRows []map[string]string

func (slice ColumnRows) Len() int {
	return len(slice)
}

func (slice ColumnRows) Less(i, j int) bool {
	return slice[i]["compare_name"] < slice[j]["compare_name"]
}

func (slice ColumnRows) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}

// ==================================
// ColumnSchema definition
// (implements Schema -- defined in pgdiff.go)
// ==================================

// ColumnSchema holds a slice of rows from one of the databases as well as
// a reference to the current row of data we're viewing.
type ColumnSchema struct {
	rows   ColumnRows
	rowNum int
	done   bool
}

// get returns the value from the current row for the given key
func (c *ColumnSchema) get(key string) string {
	if c.rowNum >= len(c.rows) {
		return ""
	}
	return c.rows[c.rowNum][key]
}

// NextRow increments the rowNum and tells you whether or not there are more
func (c *ColumnSchema) NextRow() bool {
	if c.rowNum >= len(c.rows)-1 {
		c.done = true
	}
	c.rowNum = c.rowNum + 1
	return !c.done
}

// Compare tells you, in one pass, whether or not the first row matches, is less than, or greater than the second row
func (c *ColumnSchema) Compare(obj interface{}) int {
	c2, ok := obj.(*ColumnSchema)
	if !ok {
		fmt.Println("Error!!!, Compare needs a ColumnSchema instance", c2)
	}

	val := misc.CompareStrings(c.get("compare_name"), c2.get("compare_name"))
	return val
}

// Add prints SQL to add the column
func (c *ColumnSchema) Add() {

	schema := dbInfo2.DbSchema
	if schema == "*" {
		schema = c.get("table_schema")
	}

	// Knowing the version of db2 would eliminate the need for this warning
	if c.get("is_identity") == "YES" {
		fmt.Println("-- WARNING: identity columns are not supported in PostgreSQL versions < 10.")
		fmt.Println("-- Attempting to create identity columns in earlier versions will probably result in errors.")
	}

	if c.get("data_type") == "character varying" {
		maxLength, valid := getMaxLength(c.get("character_maximum_length"))
		if !valid {
			fmt.Printf("ALTER TABLE %s.%s ADD COLUMN %s character varying", schema, c.get("table_name"), c.get("column_name"))
		} else {
			fmt.Printf("ALTER TABLE %s.%s ADD COLUMN %s character varying(%s)", schema, c.get("table_name"), c.get("column_name"), maxLength)
		}
	} else {
		if c.get("data_type") == "ARRAY" {
			fmt.Println("-- Note that adding of array data types are not yet generated properly.")
		}
		fmt.Printf("ALTER TABLE %s.%s ADD COLUMN %s %s", schema, c.get("table_name"), c.get("column_name"), c.get("data_type"))
	}

	if c.get("is_nullable") == "NO" {
		fmt.Printf(" NOT NULL")
	}
	if c.get("column_default") != "null" {
		fmt.Printf(" DEFAULT %s", c.get("column_default"))
	}
	// NOTE: there are more identity column sequence options according to the PostgreSQL
	// CREATE TABLE docs, but these do not appear to be available as of version 10.1
	if c.get("is_identity") == "YES" {
		fmt.Printf(" GENERATED %s AS IDENTITY", c.get("identity_generation"))
	}
	fmt.Printf(";\n")
}

// Drop prints SQL to drop the column
func (c *ColumnSchema) Drop() {
	// if dropping column
	fmt.Printf("ALTER TABLE %s.%s DROP COLUMN IF EXISTS %s;\n", c.get("table_schema"), c.get("table_name"), c.get("column_name"))
}

// Change handles the case where the table and column match, but the details do not
func (c *ColumnSchema) Change(obj interface{}) {
	c2, ok := obj.(*ColumnSchema)
	if !ok {
		fmt.Println("Error!!!, ColumnSchema.Change(obj) needs a ColumnSchema instance", c2)
	}

	// Detect column type change (mostly varchar length, or number size increase)
	// (integer to/from bigint is OK)
	if c.get("data_type") == c2.get("data_type") {
		if c.get("data_type") == "character varying" {
			max1, max1Valid := getMaxLength(c.get("character_maximum_length"))
			max2, max2Valid := getMaxLength(c2.get("character_maximum_length"))
			if !max1Valid && !max2Valid {
				// Leave them alone, they both have undefined max lengths
			} else if (max1Valid || !max2Valid) && (max1 != c2.get("character_maximum_length")) {
				//if !max1Valid {
				//    fmt.Println("-- WARNING: varchar column has no maximum length.  Setting to 1024, which may result in data loss.")
				//}
				max1Int, err1 := strconv.Atoi(max1)
				check("converting string to int", err1)
				max2Int, err2 := strconv.Atoi(max2)
				check("converting string to int", err2)
				if max1Int < max2Int {
					fmt.Println("-- WARNING: The next statement will shorten a character varying column, which may result in data loss.")
				}
				fmt.Printf("-- max1Valid: %v  max2Valid: %v \n", max1Valid, max2Valid)
				fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s TYPE character varying(%s);\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), max1)
			}
		}
	}

	// Code and test a column change from integer to bigint
	if c.get("data_type") != c2.get("data_type") {
		fmt.Printf("-- WARNING: This type change may not work well: (%s to %s).\n", c2.get("data_type"), c.get("data_type"))
		if strings.HasPrefix(c.get("data_type"), "character") {
			max1, max1Valid := getMaxLength(c.get("character_maximum_length"))
			if !max1Valid {
				fmt.Println("-- WARNING: varchar column has no maximum length.  Setting to 1024")
			}
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s TYPE %s(%s);\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), c.get("data_type"), max1)
		} else {
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s TYPE %s;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), c.get("data_type"))
		}
	}

	// Detect column default change (or added, dropped)
	if c.get("column_default") == "null" {
		if c.get("column_default") != "null" {
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s DROP DEFAULT;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"))
		}
	} else if c.get("column_default") != c2.get("column_default") {
		fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s SET DEFAULT %s;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), c.get("column_default"))
	}

	// Detect identity column change
	// Save result to variable instead of printing because order for adding/removing
	// is_nullable affects identity columns
	var identitySql string
	if c.get("is_identity") != c2.get("is_identity") {
		// Knowing the version of db2 would eliminate the need for this warning
		fmt.Println("-- WARNING: identity columns are not supported in PostgreSQL versions < 10.")
		fmt.Println("-- Attempting to create identity columns in earlier versions will probably result in errors.")
		if c.get("is_identity") == "YES" {
			identitySql = fmt.Sprintf("ALTER TABLE \"%s\".\"%s\" ALTER COLUMN \"%s\" ADD GENERATED %s AS IDENTITY;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), c.get("identity_generation"))
		} else {
			identitySql = fmt.Sprintf("ALTER TABLE \"%s\".\"%s\" ALTER COLUMN \"%s\" DROP IDENTITY;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"))
		}
	}

	// Detect not-null and nullable change
	if c.get("is_nullable") != c2.get("is_nullable") {
		if c.get("is_nullable") == "YES" {
			if identitySql != "" {
				fmt.Printf(identitySql)
			}
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s DROP NOT NULL;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"))
		} else {
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s SET NOT NULL;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"))
			if identitySql != "" {
				fmt.Printf(identitySql)
			}
		}
	} else {
		if identitySql != "" {
			fmt.Printf(identitySql)
		}
	}
}

// ==================================
// Standalone Functions
// ==================================

// compare outputs SQL to make the columns match between two databases or schemas
func compare(conn1 *sql.DB, conn2 *sql.DB, tpl *template.Template) {
	buf1 := new(bytes.Buffer)
	tpl.Execute(buf1, dbInfo1)

	buf2 := new(bytes.Buffer)
	tpl.Execute(buf2, dbInfo2)

	rowChan1, _ := pgutil.QueryStrings(conn1, buf1.String())
	rowChan2, _ := pgutil.QueryStrings(conn2, buf2.String())

	//rows1 := make([]map[string]string, 500)
	rows1 := make(ColumnRows, 0)
	for row := range rowChan1 {
		rows1 = append(rows1, row)
	}
	sort.Sort(rows1)

	//rows2 := make([]map[string]string, 500)
	rows2 := make(ColumnRows, 0)
	for row := range rowChan2 {
		rows2 = append(rows2, row)
	}
	sort.Sort(&rows2)

	// We have to explicitly type this as Schema here for some unknown reason
	var schema1 Schema = &ColumnSchema{rows: rows1, rowNum: -1}
	var schema2 Schema = &ColumnSchema{rows: rows2, rowNum: -1}

	// Compare the columns
	doDiff(schema1, schema2)

}

// compareColumns outputs SQL to make the columns match between two databases or schemas
func compareColumns(conn1 *sql.DB, conn2 *sql.DB) {

    compare(conn1, conn2, columnSqlTemplate)

}

// compareColumns outputs SQL to make the tables columns (without views columns) match between two databases or schemas
func compareTableColumns(conn1 *sql.DB, conn2 *sql.DB) {

    compare(conn1, conn2, tableColumnSqlTemplate)

}

// getMaxLength returns the maximum length and whether or not it is valid
func getMaxLength(maxLength string) (string, bool) {

	if maxLength == "null" {
		// default to 1024
		return "1024", false
	}
	return maxLength, true
}
<|endoftext|>


<commit_before>/*
 * Minio Go Library for Amazon S3 Compatible Cloud Storage (C) 2015 Minio, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package minio

import (
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"encoding/xml"
	"errors"
	"io"
	"regexp"
	"strings"
	"unicode/utf8"
)

// decoder provides a unified decoding method interface
type decoder interface {
	Decode(v interface{}) error
}

// acceptTypeDecoder provide decoded value in given acceptType
func acceptTypeDecoder(body io.Reader, acceptType string, v interface{}) error {
	var d decoder
	switch {
	case acceptType == "application/xml":
		d = xml.NewDecoder(body)
	case acceptType == "application/json":
		d = json.NewDecoder(body)
	default:
		d = xml.NewDecoder(body)
	}
	return d.Decode(v)
}

// urlEncodedName encode the strings from UTF-8 byte representations to HTML hex escape sequences
//
// This is necessary since regular url.Parse() and url.Encode() functions do not support UTF-8
// non english characters cannot be parsed due to the nature in which url.Encode() is written
//
// This function on the other hand is a direct replacement for url.Encode() technique to support
// pretty much every UTF-8 character.
func urlEncodeName(name string) (string, error) {
	// if object matches reserved string, no need to encode them
	reservedNames := regexp.MustCompile("^[a-zA-Z0-9-_.~/]+$")
	if reservedNames.MatchString(name) {
		return name, nil
	}
	var encodedName string
	for _, s := range name {
		if 'A' <= s && s <= 'Z' || 'a' <= s && s <= 'z' || '0' <= s && s <= '9' { // §2.3 Unreserved characters (mark)
			encodedName = encodedName + string(s)
			continue
		}
		switch s {
		case '-', '_', '.', '~', '/': // §2.3 Unreserved characters (mark)
			encodedName = encodedName + string(s)
			continue
		default:
			len := utf8.RuneLen(s)
			if len < 0 {
				return "", errors.New("invalid utf-8")
			}
			u := make([]byte, len)
			utf8.EncodeRune(u, s)
			for _, r := range u {
				hex := hex.EncodeToString([]byte{r})
				encodedName = encodedName + "%" + strings.ToUpper(hex)
			}
		}
	}
	return encodedName, nil
}

// sum256Reader calculate sha256 sum for an input read seeker
func sum256Reader(reader io.ReadSeeker) ([]byte, error) {
	h := sha256.New()
	var err error

	start, _ := reader.Seek(0, 1)
	defer reader.Seek(start, 0)

	for err == nil {
		length := 0
		byteBuffer := make([]byte, 1024*1024)
		length, err = reader.Read(byteBuffer)
		byteBuffer = byteBuffer[0:length]
		h.Write(byteBuffer)
	}

	if err != io.EOF {
		return nil, err
	}

	return h.Sum(nil), nil
}

// sum256 calculate sha256 sum for an input byte array
func sum256(data []byte) []byte {
	hash := sha256.New()
	hash.Write(data)
	return hash.Sum(nil)
}

// sumHMAC calculate hmac between two input byte array
func sumHMAC(key []byte, data []byte) []byte {
	hash := hmac.New(sha256.New, key)
	hash.Write(data)
	return hash.Sum(nil)
}

// sumMD5Reader calculate md5 for an input read seeker of a given size
func sumMD5Reader(body io.ReadSeeker, size int64) ([]byte, error) {
	hasher := md5.New()
	_, err := io.CopyN(hasher, body, size)
	if err != nil {
		return nil, err
	}
	// seek back
	_, err = body.Seek(0, 0)
	if err != nil {
		return nil, err
	}
	// encode the md5 checksum in base64
	return hasher.Sum(nil), nil
}
<commit_msg>Remove dead code sumMD5Reader<commit_after>/*
 * Minio Go Library for Amazon S3 Compatible Cloud Storage (C) 2015 Minio, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package minio

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"encoding/xml"
	"errors"
	"io"
	"regexp"
	"strings"
	"unicode/utf8"
)

// decoder provides a unified decoding method interface
type decoder interface {
	Decode(v interface{}) error
}

// acceptTypeDecoder provide decoded value in given acceptType
func acceptTypeDecoder(body io.Reader, acceptType string, v interface{}) error {
	var d decoder
	switch {
	case acceptType == "application/xml":
		d = xml.NewDecoder(body)
	case acceptType == "application/json":
		d = json.NewDecoder(body)
	default:
		d = xml.NewDecoder(body)
	}
	return d.Decode(v)
}

// urlEncodedName encode the strings from UTF-8 byte representations to HTML hex escape sequences
//
// This is necessary since regular url.Parse() and url.Encode() functions do not support UTF-8
// non english characters cannot be parsed due to the nature in which url.Encode() is written
//
// This function on the other hand is a direct replacement for url.Encode() technique to support
// pretty much every UTF-8 character.
func urlEncodeName(name string) (string, error) {
	// if object matches reserved string, no need to encode them
	reservedNames := regexp.MustCompile("^[a-zA-Z0-9-_.~/]+$")
	if reservedNames.MatchString(name) {
		return name, nil
	}
	var encodedName string
	for _, s := range name {
		if 'A' <= s && s <= 'Z' || 'a' <= s && s <= 'z' || '0' <= s && s <= '9' { // §2.3 Unreserved characters (mark)
			encodedName = encodedName + string(s)
			continue
		}
		switch s {
		case '-', '_', '.', '~', '/': // §2.3 Unreserved characters (mark)
			encodedName = encodedName + string(s)
			continue
		default:
			len := utf8.RuneLen(s)
			if len < 0 {
				return "", errors.New("invalid utf-8")
			}
			u := make([]byte, len)
			utf8.EncodeRune(u, s)
			for _, r := range u {
				hex := hex.EncodeToString([]byte{r})
				encodedName = encodedName + "%" + strings.ToUpper(hex)
			}
		}
	}
	return encodedName, nil
}

// sum256Reader calculate sha256 sum for an input read seeker
func sum256Reader(reader io.ReadSeeker) ([]byte, error) {
	h := sha256.New()
	var err error

	start, _ := reader.Seek(0, 1)
	defer reader.Seek(start, 0)

	for err == nil {
		length := 0
		byteBuffer := make([]byte, 1024*1024)
		length, err = reader.Read(byteBuffer)
		byteBuffer = byteBuffer[0:length]
		h.Write(byteBuffer)
	}

	if err != io.EOF {
		return nil, err
	}

	return h.Sum(nil), nil
}

// sum256 calculate sha256 sum for an input byte array
func sum256(data []byte) []byte {
	hash := sha256.New()
	hash.Write(data)
	return hash.Sum(nil)
}

// sumHMAC calculate hmac between two input byte array
func sumHMAC(key []byte, data []byte) []byte {
	hash := hmac.New(sha256.New, key)
	hash.Write(data)
	return hash.Sum(nil)
}
<|endoftext|>


<commit_before>package kasia

import (
    "io"
    "io/ioutil"
    "os"
    "bytes"
)

// Renderowanie do tekstu lub tablicy bajtow

func (tpl *Template) RenderBytes(ctx ...interface{}) ([]byte, os.Error) {
    var buf bytes.Buffer
    err := tpl.Run(&buf, ctx...)
    if err != nil {
        return nil, err
    }
    return buf.Bytes(), nil
}

func (tpl *Template) RenderString(ctx ...interface{}) (string, os.Error) {
    bytes, err := tpl.RenderBytes(ctx...)
    return string(bytes), err
}

func RenderBytes(txt string, strict bool, ctx ...interface{}) (
        []byte, os.Error) {

    tpl := New()
    tpl. Strict = strict

    err := tpl.Parse(txt)
    if err != nil {
        return nil, err
    }

    return tpl.RenderBytes(ctx...)
}

func RenderString(txt string, strict bool, ctx ...interface{}) (
        string, os.Error) {

    bytes, err := RenderBytes(txt, strict, ctx...)
    return string(bytes), err
}

// Funkcje i metody kompatybilne z Go template

func (tpl *Template) Execute(data interface{}, wr io.Writer) os.Error {
    return tpl.Run(wr, data)
}

func (tpl *Template) ParseFile(filename string) (err os.Error) {
    data, err := ioutil.ReadFile(filename)
    return tpl.Parse(string(data))
}

func Parse(txt string) (tpl *Template, err os.Error) {
    tpl = New()
    err = tpl.Parse(txt)
    if err != nil {
        tpl = nil
    }
    return
}

func ParseFile(filename string) (tpl *Template, err os.Error) {
    tpl = New()
    err = tpl.ParseFile(filename)
    if err != nil {
        tpl = nil
    }
    return
}

// Funkcje i metody kompatybilne z mustache.go

func (tpl *Template) Render(ctx ...interface{}) (out string) {
    var err os.Error
    out, err = tpl.RenderString(ctx...)
    if err != nil {
        panic(err)
    }
    return
}

func Render(txt string, ctx ...interface{}) (out string) {
    var err os.Error
    out, err = RenderString(txt, false, ctx...)
    if err != nil {
        panic(err)
    }
    return
}
<commit_msg>Fixed bug in ParseFile method<commit_after>package kasia

import (
    "io"
    "io/ioutil"
    "os"
    "bytes"
)

// Renderowanie do tekstu lub tablicy bajtow

func (tpl *Template) RenderBytes(ctx ...interface{}) ([]byte, os.Error) {
    var buf bytes.Buffer
    err := tpl.Run(&buf, ctx...)
    if err != nil {
        return nil, err
    }
    return buf.Bytes(), nil
}

func (tpl *Template) RenderString(ctx ...interface{}) (string, os.Error) {
    bytes, err := tpl.RenderBytes(ctx...)
    return string(bytes), err
}

func RenderBytes(txt string, strict bool, ctx ...interface{}) (
        []byte, os.Error) {

    tpl := New()
    tpl. Strict = strict

    err := tpl.Parse(txt)
    if err != nil {
        return nil, err
    }

    return tpl.RenderBytes(ctx...)
}

func RenderString(txt string, strict bool, ctx ...interface{}) (
        string, os.Error) {

    bytes, err := RenderBytes(txt, strict, ctx...)
    return string(bytes), err
}

// Funkcje i metody kompatybilne z Go template

func (tpl *Template) Execute(data interface{}, wr io.Writer) os.Error {
    return tpl.Run(wr, data)
}

func (tpl *Template) ParseFile(filename string) (err os.Error) {
    data, err := ioutil.ReadFile(filename)
    if err != nil {
        return
    }
    return tpl.Parse(string(data))
}

func Parse(txt string) (tpl *Template, err os.Error) {
    tpl = New()
    err = tpl.Parse(txt)
    if err != nil {
        tpl = nil
    }
    return
}

func ParseFile(filename string) (tpl *Template, err os.Error) {
    tpl = New()
    err = tpl.ParseFile(filename)
    if err != nil {
        tpl = nil
    }
    return
}

// Funkcje i metody kompatybilne z mustache.go

func (tpl *Template) Render(ctx ...interface{}) (out string) {
    var err os.Error
    out, err = tpl.RenderString(ctx...)
    if err != nil {
        panic(err)
    }
    return
}

func Render(txt string, ctx ...interface{}) (out string) {
    var err os.Error
    out, err = RenderString(txt, false, ctx...)
    if err != nil {
        panic(err)
    }
    return
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"os"
	"sort"
	"strings"
	"time"
	"unicode/utf8"

	ioutil "io/ioutil"

	"github.com/codegangsta/cli"
	git "github.com/libgit2/git2go"
	"github.com/mgutz/ansi"
)

var (
	Red    string = ansi.ColorCode("red")
	Yellow        = ansi.ColorCode("yellow")
	Green         = ansi.ColorCode("green")
	Reset         = ansi.ColorCode("reset")
	Bold          = ansi.ColorCode("reset+b")
)

const CachePath = ".git/go_gb_cache.json"

func exit(msg string, args ...interface{}) {
	msg = fmt.Sprintf(msg, args...)
	fmt.Println(msg)
	os.Exit(1)
}

func NewRepo() *git.Repository {
	repo, err := git.OpenRepository(".")
	if err != nil {
		wd, _ := os.Getwd()
		exit("Could not open repository at '%s'", wd)
	}
	return repo
}

func NewBranchIterator(repo *git.Repository) *git.BranchIterator {
	i, err := repo.NewBranchIterator(git.BranchLocal)
	if err != nil {
		wd, _ := os.Getwd()
		exit("Failed to list branches for '%s'", wd)
	}
	return i
}

func LookupBaseOid(repo *git.Repository, baseBranchName string) *git.Oid {
	base_branch, err := repo.LookupBranch(baseBranchName, git.BranchLocal)
	if err != nil {
		exit("Error looking up base branch '%s'", baseBranchName)
	}

	return base_branch.Target()
}

type Comparison struct {
	Repo    *git.Repository
	BaseOid *git.Oid
	Branch  *git.Branch
	Oid     *git.Oid

	IsMerged bool
	Ahead    int
	Behind   int
}

func NewComparison(repo *git.Repository, base_oid *git.Oid, branch *git.Branch, store CacheStore) *Comparison {
	c := new(Comparison)

	c.Repo = repo
	c.BaseOid = base_oid

	c.Branch = branch
	c.Oid = branch.Target()

	cache := store[c.CacheKey()]

	if cache != nil {
		c.Ahead = cache.Ahead
		c.Behind = cache.Behind
		c.IsMerged = cache.IsMerged
	} else {
		c.IsMerged = false
		c.Ahead = -1
		c.Behind = -1
	}

	return c
}

func (c *Comparison) Name() string {
	name, err := c.Branch.Name()
	if err != nil {
		exit("Can't get branch name for '%s'", c.Oid)
	}
	return name
}

func (c *Comparison) IsHead() bool {
	head, err := c.Branch.IsHead()
	if err != nil {
		exit("Can't get IsHead for '%s'", c.Name())
	}
	return head
}

func (c *Comparison) Commit() *git.Commit {
	commit, err := c.Repo.LookupCommit(c.Oid)
	if err != nil {
		exit("Could not lookup commit '%s'.", c.Oid.String())
	}
	return commit
}

func (c *Comparison) ColorCode() string {
	hours, _ := time.ParseDuration("336h") // two weeks
	two_weeks := time.Now().Add(-hours)

	if c.IsHead() {
		return Green
	} else if c.When().Before(two_weeks) {
		return Red
	} else {
		return Yellow
	}
}

func (c *Comparison) When() time.Time {
	sig := c.Commit().Committer()
	return sig.When
}

func (c *Comparison) FormattedWhen() string {
	return c.When().Format("2006-01-02 15:04PM")
}

func (c *Comparison) CacheKey() string {
	strs := []string{c.BaseOid.String(), c.Oid.String()}
	return strings.Join(strs, "..")
}

func (c *Comparison) SetIsMerged() {
	if c.Oid.String() == c.BaseOid.String() {
		c.IsMerged = true
	} else {
		merged, err := c.Repo.DescendantOf(c.BaseOid, c.Oid)
		if err != nil {
			exit("Could not get descendant of '%s' and '%s'.", c.BaseOid.String(), c.Oid.String())
		}
		c.IsMerged = merged
	}
}

func (c *Comparison) SetAheadBehind() {
	var err error
	c.Ahead, c.Behind, err = c.Repo.AheadBehind(c.Oid, c.BaseOid)
	if err != nil {
		exit("Error getting ahead/behind", c.BaseOid.String())
	}
}

func (c *Comparison) Execute() {
	if c.Ahead > -1 && c.Behind > -1 {
		return
	}

	c.SetIsMerged()
	c.SetAheadBehind()
}

type Comparisons []*Comparison

func (cs Comparisons) MaxBranchLength() int {
	max := 30

	for _, comp := range cs {
		length := utf8.RuneCountInString(comp.Name())
		if length > max {
			max = length
		}
	}
	return max
}

type ComparisonsByWhen Comparisons

func (a ComparisonsByWhen) Len() int {
	return len(a)
}

func (a ComparisonsByWhen) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a ComparisonsByWhen) Less(i, j int) bool {
	return a[i].When().Unix() < a[j].When().Unix()
}

type CacheStore map[string]*Comparison

func NewCacheStore() CacheStore {
	bits, err := ioutil.ReadFile(CachePath)
	if err != nil {
		// no-op: `cache.json` will be written on exit.
	}

	y := make(CacheStore)
	_ = json.Unmarshal(bits, &y)

	return y
}

func (store *CacheStore) WriteToFile() error {
	b, err := json.Marshal(store)
	if err != nil {
		fmt.Printf("Could not save cache to file.")
	}
	ioutil.WriteFile(CachePath, b, 0644)
	return nil
}

func run(ctx *cli.Context) {
	baseBranch := "master"
	if len(ctx.Args()) > 0 {
		baseBranch = ctx.Args().First()
	}

	if ctx.Bool("clear-cache") {
		os.Remove(CachePath)
	}

	store := NewCacheStore()

	repo := NewRepo()
	branch_iterator := NewBranchIterator(repo)
	base_oid := LookupBaseOid(repo, baseBranch)

	comparisons := make(Comparisons, 0)

	// type BranchIteratorFunc func(*Branch, BranchType) error
	branch_iterator.ForEach(func(branch *git.Branch, btype git.BranchType) error {
		comp := NewComparison(repo, base_oid, branch, store)
		comparisons = append(comparisons, comp)
		return nil
	})

	sort.Sort(ComparisonsByWhen(comparisons))

	branch_length := comparisons.MaxBranchLength()

	for _, comp := range comparisons {
		comp.Execute()

		if comp.Name() == baseBranch {
			fmt.Printf(
				"%s%s%s * %-*s\n",
				Bold,
				comp.ColorCode(),
				comp.FormattedWhen(),
				branch_length, // http://stackoverflow.com/a/28870241
				comp.Name())
			continue
		}

		merged_string := ""
		if comp.IsMerged {
			merged_string = "(merged)"
		}

		if ctx.Int("ahead") != -1 && ctx.Int("ahead") != comp.Ahead {
			continue
		}

		if ctx.Int("behind") != -1 && ctx.Int("behind") != comp.Behind {
			continue
		}

		if ctx.Bool("merged") && !comp.IsMerged {
			continue
		}

		if ctx.Bool("no-merged") && comp.IsMerged {
			continue
		}

		fmt.Printf(
			"%s%s%s | %-*s | behind: %4d | ahead: %4d %s\n",
			Reset,
			comp.ColorCode(),
			comp.FormattedWhen(),
			branch_length, // http://stackoverflow.com/a/28870241
			comp.Name(),
			comp.Behind,
			comp.Ahead,
			merged_string)

		store[comp.CacheKey()] = comp
	}

	store.WriteToFile()
}

func main() {
	app := cli.NewApp()
	app.Name = "gb"
	app.Usage = "A better way to list git branches in your terminal."
	app.Version = "1.0.0"
	app.Action = run

	app.Flags = []cli.Flag{
		cli.IntFlag{Name: "ahead", Value: -1, Usage: "only show branches that are <ahead> commits ahead."},
		cli.IntFlag{Name: "behind", Value: -1, Usage: "only show branches that are <behind> commits behind."},
		cli.BoolFlag{Name: "merged", Usage: "only show branches that are merged."},
		cli.BoolFlag{Name: "no-merged", Usage: "only show branches that are not merged."},
		cli.BoolFlag{Name: "clear-cache", Usage: "clear cache of comparisons."},
	}

	app.Run(os.Args)
}
<commit_msg>Bump version up to 1.1.0<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"os"
	"sort"
	"strings"
	"time"
	"unicode/utf8"

	ioutil "io/ioutil"

	"github.com/codegangsta/cli"
	git "github.com/libgit2/git2go"
	"github.com/mgutz/ansi"
)

var (
	Red    string = ansi.ColorCode("red")
	Yellow        = ansi.ColorCode("yellow")
	Green         = ansi.ColorCode("green")
	Reset         = ansi.ColorCode("reset")
	Bold          = ansi.ColorCode("reset+b")
)

const CachePath = ".git/go_gb_cache.json"

func exit(msg string, args ...interface{}) {
	msg = fmt.Sprintf(msg, args...)
	fmt.Println(msg)
	os.Exit(1)
}

func NewRepo() *git.Repository {
	repo, err := git.OpenRepository(".")
	if err != nil {
		wd, _ := os.Getwd()
		exit("Could not open repository at '%s'", wd)
	}
	return repo
}

func NewBranchIterator(repo *git.Repository) *git.BranchIterator {
	i, err := repo.NewBranchIterator(git.BranchLocal)
	if err != nil {
		wd, _ := os.Getwd()
		exit("Failed to list branches for '%s'", wd)
	}
	return i
}

func LookupBaseOid(repo *git.Repository, baseBranchName string) *git.Oid {
	base_branch, err := repo.LookupBranch(baseBranchName, git.BranchLocal)
	if err != nil {
		exit("Error looking up base branch '%s'", baseBranchName)
	}

	return base_branch.Target()
}

type Comparison struct {
	Repo    *git.Repository
	BaseOid *git.Oid
	Branch  *git.Branch
	Oid     *git.Oid

	IsMerged bool
	Ahead    int
	Behind   int
}

func NewComparison(repo *git.Repository, base_oid *git.Oid, branch *git.Branch, store CacheStore) *Comparison {
	c := new(Comparison)

	c.Repo = repo
	c.BaseOid = base_oid

	c.Branch = branch
	c.Oid = branch.Target()

	cache := store[c.CacheKey()]

	if cache != nil {
		c.Ahead = cache.Ahead
		c.Behind = cache.Behind
		c.IsMerged = cache.IsMerged
	} else {
		c.IsMerged = false
		c.Ahead = -1
		c.Behind = -1
	}

	return c
}

func (c *Comparison) Name() string {
	name, err := c.Branch.Name()
	if err != nil {
		exit("Can't get branch name for '%s'", c.Oid)
	}
	return name
}

func (c *Comparison) IsHead() bool {
	head, err := c.Branch.IsHead()
	if err != nil {
		exit("Can't get IsHead for '%s'", c.Name())
	}
	return head
}

func (c *Comparison) Commit() *git.Commit {
	commit, err := c.Repo.LookupCommit(c.Oid)
	if err != nil {
		exit("Could not lookup commit '%s'.", c.Oid.String())
	}
	return commit
}

func (c *Comparison) ColorCode() string {
	hours, _ := time.ParseDuration("336h") // two weeks
	two_weeks := time.Now().Add(-hours)

	if c.IsHead() {
		return Green
	} else if c.When().Before(two_weeks) {
		return Red
	} else {
		return Yellow
	}
}

func (c *Comparison) When() time.Time {
	sig := c.Commit().Committer()
	return sig.When
}

func (c *Comparison) FormattedWhen() string {
	return c.When().Format("2006-01-02 15:04PM")
}

func (c *Comparison) CacheKey() string {
	strs := []string{c.BaseOid.String(), c.Oid.String()}
	return strings.Join(strs, "..")
}

func (c *Comparison) SetIsMerged() {
	if c.Oid.String() == c.BaseOid.String() {
		c.IsMerged = true
	} else {
		merged, err := c.Repo.DescendantOf(c.BaseOid, c.Oid)
		if err != nil {
			exit("Could not get descendant of '%s' and '%s'.", c.BaseOid.String(), c.Oid.String())
		}
		c.IsMerged = merged
	}
}

func (c *Comparison) SetAheadBehind() {
	var err error
	c.Ahead, c.Behind, err = c.Repo.AheadBehind(c.Oid, c.BaseOid)
	if err != nil {
		exit("Error getting ahead/behind", c.BaseOid.String())
	}
}

func (c *Comparison) Execute() {
	if c.Ahead > -1 && c.Behind > -1 {
		return
	}

	c.SetIsMerged()
	c.SetAheadBehind()
}

type Comparisons []*Comparison

func (cs Comparisons) MaxBranchLength() int {
	max := 30

	for _, comp := range cs {
		length := utf8.RuneCountInString(comp.Name())
		if length > max {
			max = length
		}
	}
	return max
}

type ComparisonsByWhen Comparisons

func (a ComparisonsByWhen) Len() int {
	return len(a)
}

func (a ComparisonsByWhen) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a ComparisonsByWhen) Less(i, j int) bool {
	return a[i].When().Unix() < a[j].When().Unix()
}

type CacheStore map[string]*Comparison

func NewCacheStore() CacheStore {
	bits, err := ioutil.ReadFile(CachePath)
	if err != nil {
		// no-op: `cache.json` will be written on exit.
	}

	y := make(CacheStore)
	_ = json.Unmarshal(bits, &y)

	return y
}

func (store *CacheStore) WriteToFile() error {
	b, err := json.Marshal(store)
	if err != nil {
		fmt.Printf("Could not save cache to file.")
	}
	ioutil.WriteFile(CachePath, b, 0644)
	return nil
}

func run(ctx *cli.Context) {
	baseBranch := "master"
	if len(ctx.Args()) > 0 {
		baseBranch = ctx.Args().First()
	}

	if ctx.Bool("clear-cache") {
		os.Remove(CachePath)
	}

	store := NewCacheStore()

	repo := NewRepo()
	branch_iterator := NewBranchIterator(repo)
	base_oid := LookupBaseOid(repo, baseBranch)

	comparisons := make(Comparisons, 0)

	// type BranchIteratorFunc func(*Branch, BranchType) error
	branch_iterator.ForEach(func(branch *git.Branch, btype git.BranchType) error {
		comp := NewComparison(repo, base_oid, branch, store)
		comparisons = append(comparisons, comp)
		return nil
	})

	sort.Sort(ComparisonsByWhen(comparisons))

	branch_length := comparisons.MaxBranchLength()

	for _, comp := range comparisons {
		comp.Execute()

		if comp.Name() == baseBranch {
			fmt.Printf(
				"%s%s%s * %-*s\n",
				Bold,
				comp.ColorCode(),
				comp.FormattedWhen(),
				branch_length, // http://stackoverflow.com/a/28870241
				comp.Name())
			continue
		}

		merged_string := ""
		if comp.IsMerged {
			merged_string = "(merged)"
		}

		if ctx.Int("ahead") != -1 && ctx.Int("ahead") != comp.Ahead {
			continue
		}

		if ctx.Int("behind") != -1 && ctx.Int("behind") != comp.Behind {
			continue
		}

		if ctx.Bool("merged") && !comp.IsMerged {
			continue
		}

		if ctx.Bool("no-merged") && comp.IsMerged {
			continue
		}

		fmt.Printf(
			"%s%s%s | %-*s | behind: %4d | ahead: %4d %s\n",
			Reset,
			comp.ColorCode(),
			comp.FormattedWhen(),
			branch_length, // http://stackoverflow.com/a/28870241
			comp.Name(),
			comp.Behind,
			comp.Ahead,
			merged_string)

		store[comp.CacheKey()] = comp
	}

	store.WriteToFile()
}

func main() {
	app := cli.NewApp()
	app.Name = "gb"
	app.Usage = "A better way to list git branches in your terminal."
	app.Version = "1.1.0"
	app.Action = run

	app.Flags = []cli.Flag{
		cli.IntFlag{Name: "ahead", Value: -1, Usage: "only show branches that are <ahead> commits ahead."},
		cli.IntFlag{Name: "behind", Value: -1, Usage: "only show branches that are <behind> commits behind."},
		cli.BoolFlag{Name: "merged", Usage: "only show branches that are merged."},
		cli.BoolFlag{Name: "no-merged", Usage: "only show branches that are not merged."},
		cli.BoolFlag{Name: "clear-cache", Usage: "clear cache of comparisons."},
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package xls

import (
	"bytes"
	"encoding/binary"
	"io"
	"log"
	"os"
	"unicode/utf16"
)

//xls workbook type
type WorkBook struct {
	Is5ver   bool
	Type     uint16
	Codepage uint16
	Xfs      []st_xf_data
	Fonts    []Font
	Formats  map[uint16]*Format
	//All the sheets from the workbook
	sheets         []*WorkSheet
	Author         string
	rs             io.ReadSeeker
	sst            []string
	continue_utf16 uint16
	continue_rich  uint16
	continue_apsb  uint32
	dateMode       uint16
}

//read workbook from ole2 file
func newWorkBookFromOle2(rs io.ReadSeeker) *WorkBook {
	wb := new(WorkBook)
	wb.Formats = make(map[uint16]*Format)
	// wb.bts = bts
	wb.rs = rs
	wb.sheets = make([]*WorkSheet, 0)
	wb.Parse(rs)
	return wb
}

func (w *WorkBook) Parse(buf io.ReadSeeker) {
	b := new(bof)
	bof_pre := new(bof)
	// buf := bytes.NewReader(bts)
	offset := 0
	for {
		if err := binary.Read(buf, binary.LittleEndian, b); err == nil {
			bof_pre, b, offset = w.parseBof(buf, b, bof_pre, offset)
		} else {
			break
		}
	}
}

func (w *WorkBook) addXf(xf st_xf_data) {
	w.Xfs = append(w.Xfs, xf)
}

func (w *WorkBook) addFont(font *FontInfo, buf io.ReadSeeker) {
	name, _ := w.get_string(buf, uint16(font.NameB))
	w.Fonts = append(w.Fonts, Font{Info: font, Name: name})
}

func (w *WorkBook) addFormat(format *Format) {
	if w.Formats == nil {
		os.Exit(1)
	}
	w.Formats[format.Head.Index] = format
}

func (wb *WorkBook) parseBof(buf io.ReadSeeker, b *bof, pre *bof, offset_pre int) (after *bof, after_using *bof, offset int) {
	after = b
	after_using = pre
	var bts = make([]byte, b.Size)
	binary.Read(buf, binary.LittleEndian, bts)
	buf_item := bytes.NewReader(bts)
	switch b.Id {
	case 0x809:
		bif := new(biffHeader)
		binary.Read(buf_item, binary.LittleEndian, bif)
		if bif.Ver != 0x600 {
			wb.Is5ver = true
		}
		wb.Type = bif.Type
	case 0x042: // CODEPAGE
		binary.Read(buf_item, binary.LittleEndian, &wb.Codepage)
	case 0x3c: // CONTINUE
		if pre.Id == 0xfc {
			var size uint16
			var err error
			if wb.continue_utf16 >= 1 {
				size = wb.continue_utf16
				wb.continue_utf16 = 0
			} else {
				err = binary.Read(buf_item, binary.LittleEndian, &size)
			}
			for err == nil && offset_pre < len(wb.sst) {
				var str string
				if size > 0 {
					str, err = wb.get_string(buf_item, size)
					wb.sst[offset_pre] = wb.sst[offset_pre] + str
				}

				offset_pre++
				err = binary.Read(buf_item, binary.LittleEndian, &size)
			}
		}
		offset = offset_pre
		after = pre
		after_using = b
	case 0xfc: // SST
		info := new(SstInfo)
		binary.Read(buf_item, binary.LittleEndian, info)
		wb.sst = make([]string, info.Count)
		var size uint16
		var i = 0
		for ; i < int(info.Count); i++ {
			if err := binary.Read(buf_item, binary.LittleEndian, &size); err == nil || err == io.EOF {
				var str string
				str, err = wb.get_string(buf_item, size)
				wb.sst[i] = wb.sst[i] + str
				if err == io.EOF {
					break
				}
			}
		}
		offset = i
	case 0x85: // bOUNDSHEET
		var bs = new(boundsheet)
		binary.Read(buf_item, binary.LittleEndian, bs)
		// different for BIFF5 and BIFF8
		wb.addSheet(bs, buf_item)
	case 0x0e0: // XF
		if wb.Is5ver {
			xf := new(Xf5)
			binary.Read(buf_item, binary.LittleEndian, xf)
			wb.addXf(xf)
		} else {
			xf := new(Xf8)
			binary.Read(buf_item, binary.LittleEndian, xf)
			wb.addXf(xf)
		}
	case 0x031: // FONT
		f := new(FontInfo)
		binary.Read(buf_item, binary.LittleEndian, f)
		wb.addFont(f, buf_item)
	case 0x41E: //FORMAT
		font := new(Format)
		binary.Read(buf_item, binary.LittleEndian, &font.Head)
		font.str, _ = wb.get_string(buf_item, font.Head.Size)
		wb.addFormat(font)
	case 0x22: //DATEMODE
		binary.Read(buf_item, binary.LittleEndian, &wb.dateMode)
	}
	return
}

func (w *WorkBook) get_string(buf io.ReadSeeker, size uint16) (res string, err error) {
	if w.Is5ver {
		var bts = make([]byte, size)
		_, err = buf.Read(bts)
		res = string(bts)
	} else {
		var richtext_num = uint16(0)
		var phonetic_size = uint32(0)
		var flag byte
		err = binary.Read(buf, binary.LittleEndian, &flag)
		if flag&0x8 != 0 {
			err = binary.Read(buf, binary.LittleEndian, &richtext_num)
		} else if w.continue_rich > 0 {
			richtext_num = w.continue_rich
			w.continue_rich = 0
		}
		if flag&0x4 != 0 {
			err = binary.Read(buf, binary.LittleEndian, &phonetic_size)
		} else if w.continue_apsb > 0 {
			phonetic_size = w.continue_apsb
			w.continue_apsb = 0
		}
		if flag&0x1 != 0 {
			var bts = make([]uint16, size)
			var i = uint16(0)
			for ; i < size && err == nil; i++ {
				err = binary.Read(buf, binary.LittleEndian, &bts[i])
			}
			runes := utf16.Decode(bts[:i])
			res = string(runes)
			if i < size {
				w.continue_utf16 = size - i + 1
			}
		} else {
			var bts = make([]byte, size)
			var n int
			n, err = buf.Read(bts)
			if uint16(n) < size {
				w.continue_utf16 = size - uint16(n)
				err = io.EOF
			}

			var bts1 = make([]uint16, size)
			for k, v := range bts[:n] {
				bts1[k] = uint16(v)
			}
			runes := utf16.Decode(bts1)
			res = string(runes)
		}
		if richtext_num > 0 {
			var bts []byte
			var seek_size int64
			if w.Is5ver {
				seek_size = int64(2 * richtext_num)
			} else {
				seek_size = int64(4 * richtext_num)
			}
			bts = make([]byte, seek_size)
			err = binary.Read(buf, binary.LittleEndian, bts)
			if err == io.EOF {
				w.continue_rich = richtext_num
			}

			// err = binary.Read(buf, binary.LittleEndian, bts)
		}
		if phonetic_size > 0 {
			var bts []byte
			bts = make([]byte, phonetic_size)
			err = binary.Read(buf, binary.LittleEndian, bts)
			if err == io.EOF {
				w.continue_apsb = phonetic_size
			}
		}
	}
	return
}

func (w *WorkBook) addSheet(sheet *boundsheet, buf io.ReadSeeker) {
	name, _ := w.get_string(buf, uint16(sheet.Name))
	w.sheets = append(w.sheets, &WorkSheet{bs: sheet, Name: name, wb: w})
}

//reading a sheet from the compress file to memory, you should call this before you try to get anything from sheet
func (w *WorkBook) prepareSheet(sheet *WorkSheet) {
	w.rs.Seek(int64(sheet.bs.Filepos), 0)
	sheet.parse(w.rs)
}

//Get one sheet by its number
func (w *WorkBook) GetSheet(num int) *WorkSheet {
	if num < len(w.sheets) {
		s := w.sheets[num]
		if !s.parsed {
			w.prepareSheet(s)
		}
		return s
	} else {
		return nil
	}
}

//Get the number of all sheets, look into example
func (w *WorkBook) NumSheets() int {
	return len(w.sheets)
}

//helper function to read all cells from file
//Notice: the max value is the limit of the max capacity of lines.
//Warning: the helper function will need big memeory if file is large.
func (w *WorkBook) ReadAllCells(max int) (res [][]string) {
	res = make([][]string, 0)
	for _, sheet := range w.sheets {
		if len(res) < max {
			max = max - len(res)
			w.prepareSheet(sheet)
			if sheet.MaxRow != 0 {
				leng := int(sheet.MaxRow) + 1
				if max < leng {
					leng = max
				}
				temp := make([][]string, leng)
				for k, row := range sheet.Rows {
					data := make([]string, 0)
					if len(row.Cols) > 0 {
						for _, col := range row.Cols {
							if uint16(len(data)) <= col.LastCol() {
								data = append(data, make([]string, col.LastCol()-uint16(len(data))+1)...)
							}
							str := col.String(w)
							for i := uint16(0); i < col.LastCol()-col.FirstCol()+1; i++ {
								data[col.FirstCol()+i] = str[i]
							}
						}
						if leng > int(k) {
							temp[k] = data
						}
					}
				}
				res = append(res, temp...)
			}
		}
	}
	return
}
<commit_msg>fix the unused import<commit_after>package xls

import (
	"bytes"
	"encoding/binary"
	"io"
	"os"
	"unicode/utf16"
)

//xls workbook type
type WorkBook struct {
	Is5ver   bool
	Type     uint16
	Codepage uint16
	Xfs      []st_xf_data
	Fonts    []Font
	Formats  map[uint16]*Format
	//All the sheets from the workbook
	sheets         []*WorkSheet
	Author         string
	rs             io.ReadSeeker
	sst            []string
	continue_utf16 uint16
	continue_rich  uint16
	continue_apsb  uint32
	dateMode       uint16
}

//read workbook from ole2 file
func newWorkBookFromOle2(rs io.ReadSeeker) *WorkBook {
	wb := new(WorkBook)
	wb.Formats = make(map[uint16]*Format)
	// wb.bts = bts
	wb.rs = rs
	wb.sheets = make([]*WorkSheet, 0)
	wb.Parse(rs)
	return wb
}

func (w *WorkBook) Parse(buf io.ReadSeeker) {
	b := new(bof)
	bof_pre := new(bof)
	// buf := bytes.NewReader(bts)
	offset := 0
	for {
		if err := binary.Read(buf, binary.LittleEndian, b); err == nil {
			bof_pre, b, offset = w.parseBof(buf, b, bof_pre, offset)
		} else {
			break
		}
	}
}

func (w *WorkBook) addXf(xf st_xf_data) {
	w.Xfs = append(w.Xfs, xf)
}

func (w *WorkBook) addFont(font *FontInfo, buf io.ReadSeeker) {
	name, _ := w.get_string(buf, uint16(font.NameB))
	w.Fonts = append(w.Fonts, Font{Info: font, Name: name})
}

func (w *WorkBook) addFormat(format *Format) {
	if w.Formats == nil {
		os.Exit(1)
	}
	w.Formats[format.Head.Index] = format
}

func (wb *WorkBook) parseBof(buf io.ReadSeeker, b *bof, pre *bof, offset_pre int) (after *bof, after_using *bof, offset int) {
	after = b
	after_using = pre
	var bts = make([]byte, b.Size)
	binary.Read(buf, binary.LittleEndian, bts)
	buf_item := bytes.NewReader(bts)
	switch b.Id {
	case 0x809:
		bif := new(biffHeader)
		binary.Read(buf_item, binary.LittleEndian, bif)
		if bif.Ver != 0x600 {
			wb.Is5ver = true
		}
		wb.Type = bif.Type
	case 0x042: // CODEPAGE
		binary.Read(buf_item, binary.LittleEndian, &wb.Codepage)
	case 0x3c: // CONTINUE
		if pre.Id == 0xfc {
			var size uint16
			var err error
			if wb.continue_utf16 >= 1 {
				size = wb.continue_utf16
				wb.continue_utf16 = 0
			} else {
				err = binary.Read(buf_item, binary.LittleEndian, &size)
			}
			for err == nil && offset_pre < len(wb.sst) {
				var str string
				if size > 0 {
					str, err = wb.get_string(buf_item, size)
					wb.sst[offset_pre] = wb.sst[offset_pre] + str
				}

				offset_pre++
				err = binary.Read(buf_item, binary.LittleEndian, &size)
			}
		}
		offset = offset_pre
		after = pre
		after_using = b
	case 0xfc: // SST
		info := new(SstInfo)
		binary.Read(buf_item, binary.LittleEndian, info)
		wb.sst = make([]string, info.Count)
		var size uint16
		var i = 0
		for ; i < int(info.Count); i++ {
			if err := binary.Read(buf_item, binary.LittleEndian, &size); err == nil || err == io.EOF {
				var str string
				str, err = wb.get_string(buf_item, size)
				wb.sst[i] = wb.sst[i] + str
				if err == io.EOF {
					break
				}
			}
		}
		offset = i
	case 0x85: // bOUNDSHEET
		var bs = new(boundsheet)
		binary.Read(buf_item, binary.LittleEndian, bs)
		// different for BIFF5 and BIFF8
		wb.addSheet(bs, buf_item)
	case 0x0e0: // XF
		if wb.Is5ver {
			xf := new(Xf5)
			binary.Read(buf_item, binary.LittleEndian, xf)
			wb.addXf(xf)
		} else {
			xf := new(Xf8)
			binary.Read(buf_item, binary.LittleEndian, xf)
			wb.addXf(xf)
		}
	case 0x031: // FONT
		f := new(FontInfo)
		binary.Read(buf_item, binary.LittleEndian, f)
		wb.addFont(f, buf_item)
	case 0x41E: //FORMAT
		font := new(Format)
		binary.Read(buf_item, binary.LittleEndian, &font.Head)
		font.str, _ = wb.get_string(buf_item, font.Head.Size)
		wb.addFormat(font)
	case 0x22: //DATEMODE
		binary.Read(buf_item, binary.LittleEndian, &wb.dateMode)
	}
	return
}

func (w *WorkBook) get_string(buf io.ReadSeeker, size uint16) (res string, err error) {
	if w.Is5ver {
		var bts = make([]byte, size)
		_, err = buf.Read(bts)
		res = string(bts)
	} else {
		var richtext_num = uint16(0)
		var phonetic_size = uint32(0)
		var flag byte
		err = binary.Read(buf, binary.LittleEndian, &flag)
		if flag&0x8 != 0 {
			err = binary.Read(buf, binary.LittleEndian, &richtext_num)
		} else if w.continue_rich > 0 {
			richtext_num = w.continue_rich
			w.continue_rich = 0
		}
		if flag&0x4 != 0 {
			err = binary.Read(buf, binary.LittleEndian, &phonetic_size)
		} else if w.continue_apsb > 0 {
			phonetic_size = w.continue_apsb
			w.continue_apsb = 0
		}
		if flag&0x1 != 0 {
			var bts = make([]uint16, size)
			var i = uint16(0)
			for ; i < size && err == nil; i++ {
				err = binary.Read(buf, binary.LittleEndian, &bts[i])
			}
			runes := utf16.Decode(bts[:i])
			res = string(runes)
			if i < size {
				w.continue_utf16 = size - i + 1
			}
		} else {
			var bts = make([]byte, size)
			var n int
			n, err = buf.Read(bts)
			if uint16(n) < size {
				w.continue_utf16 = size - uint16(n)
				err = io.EOF
			}

			var bts1 = make([]uint16, size)
			for k, v := range bts[:n] {
				bts1[k] = uint16(v)
			}
			runes := utf16.Decode(bts1)
			res = string(runes)
		}
		if richtext_num > 0 {
			var bts []byte
			var seek_size int64
			if w.Is5ver {
				seek_size = int64(2 * richtext_num)
			} else {
				seek_size = int64(4 * richtext_num)
			}
			bts = make([]byte, seek_size)
			err = binary.Read(buf, binary.LittleEndian, bts)
			if err == io.EOF {
				w.continue_rich = richtext_num
			}

			// err = binary.Read(buf, binary.LittleEndian, bts)
		}
		if phonetic_size > 0 {
			var bts []byte
			bts = make([]byte, phonetic_size)
			err = binary.Read(buf, binary.LittleEndian, bts)
			if err == io.EOF {
				w.continue_apsb = phonetic_size
			}
		}
	}
	return
}

func (w *WorkBook) addSheet(sheet *boundsheet, buf io.ReadSeeker) {
	name, _ := w.get_string(buf, uint16(sheet.Name))
	w.sheets = append(w.sheets, &WorkSheet{bs: sheet, Name: name, wb: w})
}

//reading a sheet from the compress file to memory, you should call this before you try to get anything from sheet
func (w *WorkBook) prepareSheet(sheet *WorkSheet) {
	w.rs.Seek(int64(sheet.bs.Filepos), 0)
	sheet.parse(w.rs)
}

//Get one sheet by its number
func (w *WorkBook) GetSheet(num int) *WorkSheet {
	if num < len(w.sheets) {
		s := w.sheets[num]
		if !s.parsed {
			w.prepareSheet(s)
		}
		return s
	} else {
		return nil
	}
}

//Get the number of all sheets, look into example
func (w *WorkBook) NumSheets() int {
	return len(w.sheets)
}

//helper function to read all cells from file
//Notice: the max value is the limit of the max capacity of lines.
//Warning: the helper function will need big memeory if file is large.
func (w *WorkBook) ReadAllCells(max int) (res [][]string) {
	res = make([][]string, 0)
	for _, sheet := range w.sheets {
		if len(res) < max {
			max = max - len(res)
			w.prepareSheet(sheet)
			if sheet.MaxRow != 0 {
				leng := int(sheet.MaxRow) + 1
				if max < leng {
					leng = max
				}
				temp := make([][]string, leng)
				for k, row := range sheet.Rows {
					data := make([]string, 0)
					if len(row.Cols) > 0 {
						for _, col := range row.Cols {
							if uint16(len(data)) <= col.LastCol() {
								data = append(data, make([]string, col.LastCol()-uint16(len(data))+1)...)
							}
							str := col.String(w)
							for i := uint16(0); i < col.LastCol()-col.FirstCol()+1; i++ {
								data[col.FirstCol()+i] = str[i]
							}
						}
						if leng > int(k) {
							temp[k] = data
						}
					}
				}
				res = append(res, temp...)
			}
		}
	}
	return
}
<|endoftext|>


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

package sortutil

import (
	"fmt"
	"io"
	"sort"
)

const panicmsg = "bounds out of range"

// Stat wraps sort.Interface, counting the number of Len, Less, and Swap calls.
// Initialize with `&Stat{I: data}`.
type Stat struct {
	I sort.Interface
	N struct{ Len, Less, Swap int }
}

func (s *Stat) Len() int           { s.N.Len++; return s.I.Len() }
func (s *Stat) Less(i, j int) bool { s.N.Less++; return s.I.Less(i, j) }
func (s *Stat) Swap(i, j int)      { s.N.Swap++; s.I.Swap(i, j) }
func (s *Stat) String() string     { return fmt.Sprintf("%+v", s.N) }

// Log wraps sort.Interface, sending debug messages to the supplied Writer.
// Less and Swap parameters will be space-padded based on the most recent Len
// call. Since writes are not synchronized, a serializing writer should be
// provided when used with concurrent sorting algorithms. A single *Log can be
// reused between separate sorts as long as they do not coincide.
type Log struct {
	I sort.Interface
	W io.Writer
	p int
}

func (l *Log) Len() int {
	r := l.I.Len()
	l.p = 0
	if r > 0 {
		l.p = len(fmt.Sprint(r - 1))
	}
	fmt.Fprint(l.W, "(", l.I, ").Len() [", r, "]\n")
	return r
}

func (l *Log) Less(i, j int) bool {
	r := l.I.Less(i, j)
	fmt.Fprintf(l.W, "(%v).Less(%*d, %*d) [%v]\n", l.I, l.p, i, l.p, j, r)
	return r
}

func (l *Log) Swap(i, j int) {
	v := fmt.Sprint(l.I)
	l.I.Swap(i, j)
	fmt.Fprintf(l.W, "(%v).Swap(%*d, %*d) [%v]\n", v, l.p, i, l.p, j, l.I)
}

func (l *Log) String() string {
	return fmt.Sprint(l.I)
}

// NewSub opaquely wraps a sub-sequence of the provided sort.Interface.
// NewSub(s,i,j) is semantically equivalent to s[i:j], though the underlying
// implementation does not need to involve a slice. j may not exceed s.Len().
func NewSub(s sort.Interface, i, j int) sort.Interface {
	if i < 0 || j < i || j > s.Len() {
		panic(panicmsg)
	} else if v, ok := s.(sub); ok {
		// collapse subs of subs
		return sub{v.s, v.i + i, j - i}
	}
	return sub{s, i, j - i}
}

type sub struct {
	s    sort.Interface
	i, n int
}

func (s sub) Len() int           { return s.n }
func (s sub) Less(i, j int) bool { return s.s.Less(s.i+i, s.i+j) }
func (s sub) Swap(i, j int)      { s.s.Swap(s.i+i, s.i+j) }

// NewRev returns a reverse sorter for any sort.Interface.
// To quickly reverse a sort.Interface relative to its current order, see Reverse.
func NewRev(s sort.Interface) sort.Interface {
	if v, ok := s.(rev); ok {
		return v.Interface
	}
	return rev{s}
}

type rev struct{ sort.Interface }

func (r rev) Less(i, j int) bool { return !r.Interface.Less(i, j) }

// NewProxy sorts comp, duplicating all swaps on each item of data.
// data may be either be empty, or each item must have the same Len as comp.
func NewProxy(comp sort.Interface, data ...sort.Interface) sort.Interface {
	l := comp.Len()
	for _, d := range data {
		if l != d.Len() {
			panic(panicmsg)
		}
	}
	return proxy{comp, data}
}

type proxy struct {
	c sort.Interface
	d []sort.Interface
}

func (p proxy) Len() int           { return p.c.Len() }
func (p proxy) Less(i, j int) bool { return p.c.Less(i, j) }

func (p proxy) Swap(i, j int) {
	p.c.Swap(i, j)
	for _, d := range p.d {
		d.Swap(i, j)
	}
}
<commit_msg>Simplified NewProxy documentation.<commit_after>// Copyright 2013 Kevin Gillette. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sortutil

import (
	"fmt"
	"io"
	"sort"
)

const panicmsg = "bounds out of range"

// Stat wraps sort.Interface, counting the number of Len, Less, and Swap calls.
// Initialize with `&Stat{I: data}`.
type Stat struct {
	I sort.Interface
	N struct{ Len, Less, Swap int }
}

func (s *Stat) Len() int           { s.N.Len++; return s.I.Len() }
func (s *Stat) Less(i, j int) bool { s.N.Less++; return s.I.Less(i, j) }
func (s *Stat) Swap(i, j int)      { s.N.Swap++; s.I.Swap(i, j) }
func (s *Stat) String() string     { return fmt.Sprintf("%+v", s.N) }

// Log wraps sort.Interface, sending debug messages to the supplied Writer.
// Less and Swap parameters will be space-padded based on the most recent Len
// call. Since writes are not synchronized, a serializing writer should be
// provided when used with concurrent sorting algorithms. A single *Log can be
// reused between separate sorts as long as they do not coincide.
type Log struct {
	I sort.Interface
	W io.Writer
	p int
}

func (l *Log) Len() int {
	r := l.I.Len()
	l.p = 0
	if r > 0 {
		l.p = len(fmt.Sprint(r - 1))
	}
	fmt.Fprint(l.W, "(", l.I, ").Len() [", r, "]\n")
	return r
}

func (l *Log) Less(i, j int) bool {
	r := l.I.Less(i, j)
	fmt.Fprintf(l.W, "(%v).Less(%*d, %*d) [%v]\n", l.I, l.p, i, l.p, j, r)
	return r
}

func (l *Log) Swap(i, j int) {
	v := fmt.Sprint(l.I)
	l.I.Swap(i, j)
	fmt.Fprintf(l.W, "(%v).Swap(%*d, %*d) [%v]\n", v, l.p, i, l.p, j, l.I)
}

func (l *Log) String() string {
	return fmt.Sprint(l.I)
}

// NewSub opaquely wraps a sub-sequence of the provided sort.Interface.
// NewSub(s,i,j) is semantically equivalent to s[i:j], though the underlying
// implementation does not need to involve a slice. j may not exceed s.Len().
func NewSub(s sort.Interface, i, j int) sort.Interface {
	if i < 0 || j < i || j > s.Len() {
		panic(panicmsg)
	} else if v, ok := s.(sub); ok {
		// collapse subs of subs
		return sub{v.s, v.i + i, j - i}
	}
	return sub{s, i, j - i}
}

type sub struct {
	s    sort.Interface
	i, n int
}

func (s sub) Len() int           { return s.n }
func (s sub) Less(i, j int) bool { return s.s.Less(s.i+i, s.i+j) }
func (s sub) Swap(i, j int)      { s.s.Swap(s.i+i, s.i+j) }

// NewRev returns a reverse sorter for any sort.Interface.
// To quickly reverse a sort.Interface relative to its current order, see Reverse.
func NewRev(s sort.Interface) sort.Interface {
	if v, ok := s.(rev); ok {
		return v.Interface
	}
	return rev{s}
}

type rev struct{ sort.Interface }

func (r rev) Less(i, j int) bool { return !r.Interface.Less(i, j) }

// NewProxy sorts comp, duplicating all swaps on each item of data.
// Each item in data must have the same Len as comp.
func NewProxy(comp sort.Interface, data ...sort.Interface) sort.Interface {
	l := comp.Len()
	for _, d := range data {
		if l != d.Len() {
			panic(panicmsg)
		}
	}
	return proxy{comp, data}
}

type proxy struct {
	c sort.Interface
	d []sort.Interface
}

func (p proxy) Len() int           { return p.c.Len() }
func (p proxy) Less(i, j int) bool { return p.c.Less(i, j) }

func (p proxy) Swap(i, j int) {
	p.c.Swap(i, j)
	for _, d := range p.d {
		d.Swap(i, j)
	}
}
<|endoftext|>


<commit_before>package main

import "math"
import "fmt"
import "image"
import "os"
import "image/color"
import "image/png"

// vector can represent a point as well, if interpreted as
//  a vector from the origin to a point or 'absolute position vector'.
//  otherwise it represents a 'relative position vector'
type vector struct {
	x, y, z float64
}

type ray struct {
	start vector
	direction vector
}

type camera struct {
	eye vector
	look_at vector
	up vector
}

type screen struct {
	w,h float64
	xres, yres int
}

type sphere struct {
	center vector
	radius float64
	red,blue,green uint8
}

func (s *sphere) getColor(c_ray *ray) (uint8, uint8, uint8, float64, bool) {
	a := c_ray.direction.x * c_ray.direction.x +
		c_ray.direction.y * c_ray.direction.y +
		c_ray.direction.z * c_ray.direction.z
	b := 2.0*((c_ray.start.x-s.center.x)*c_ray.direction.x +
		(c_ray.start.y-s.center.y)*c_ray.direction.y +
		(c_ray.start.z-s.center.z)*c_ray.direction.z)
	c := (c_ray.start.x-s.center.x) * (c_ray.start.x-s.center.x) +
		(c_ray.start.y-s.center.y) * (c_ray.start.y-s.center.y) +
		(c_ray.start.z-s.center.z) * (c_ray.start.z-s.center.z) -
		s.radius * s.radius

	// test with a sphere
	var red,blue,green uint8
	is_hit:=false
	i_test:=b*b-4.0*a*c
	t1,t2,t_closest:=0.0,0.0,0.0
	if i_test > 0.0 {
		red,blue,green=s.red,s.blue,s.green
		is_hit=true
		t1=(-b+math.Sqrt(i_test))/(2.0*a)
		t2=(-b-math.Sqrt(i_test))/(2.0*a)
		if t1 <= 0.0 && t2 <= 0.0 {
			is_hit=false  // it hit behind or on the viewer
		}else if t1 > 0.0 && t2 > 0.0 {
			if t1<t2 {
				t_closest=t1
			}else{
				t_closest=t2
			}
		} else if t1 > 0.0 {
			t_closest = t1
		} else if t2 > 0.0 {
			t_closest = t2
		}
	}
	return red,blue,green,t_closest,is_hit
}

func (v *vector) sub(v1 *vector) vector {
	return vector{v.x-v1.x, v.y-v1.y, v.z-v1.z}
}

func (v *vector) add(v1 *vector) vector {
	return vector{v.x+v1.x, v.y+v1.y, v.z+v1.z}
}

func (v *vector) scalarMult (c float64) vector {
	return vector{c * v.x, c * v.y, c * v.z}
}

func (v *vector) lengthSq() float64 {
	return v.x * v.x  + v.y * v.y + v.z * v.z
}

func (v *vector) length() float64 {
	return math.Sqrt(v.lengthSq())
}

func (v *vector) unit() vector {
	l := v.length()
	return vector{v.x/l, v.y/l, v.z/l}
}

func (v *vector) dot(v1 *vector) float64 {
	return v.x * v1.x + v.y * v1.y + v.z * v1.z
}

func (v1 *vector) cross(v2 *vector) vector {
	return vector{v1.y * v2.z - v2.y * v1.z,
		v2.x * v1.z - v1.x * v2.z,
		v1.x * v2.y - v2.x * v1.y}
}

func main() {
	g_screen := screen{100,100,1000,1000}
	g_camera := camera{vector{0,0,100}, vector{0,0,0}, vector{0,1,0}}

	f, err := os.OpenFile("x.png", os.O_CREATE | os.O_WRONLY, 0666)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	m := image.NewRGBA(image.Rect(0,0,g_screen.xres,g_screen.yres))

	for i:=0; i < g_screen.xres; i++ {
		for j:=0; j < g_screen.yres; j++ {
			a_to_e := g_camera.eye.sub(&g_camera.look_at)
			w := a_to_e.unit()

			up_X_a_to_e := g_camera.up.cross(&a_to_e)
			u := up_X_a_to_e.unit()
			v := w.cross(&u)

			cu := (((2.0*float64(i) + 1.0)/(2.0 * float64(g_screen.xres))) - 0.5) * g_screen.w
			cv := (((2.0*float64(j) + 1.0)/(2.0 * float64(g_screen.yres))) - 0.5) * g_screen.h

			ucu := u.scalarMult(cu)
			ucv := v.scalarMult(cv)
			a_plus_ucu := g_camera.look_at.add(&ucu)
			Pij := a_plus_ucu.add(&ucv)

			e_to_Pij := Pij.sub(&g_camera.eye)

			current_ray := ray{g_camera.eye, e_to_Pij.unit()}

			// put the sphere at the origin
			s := sphere{vector{5.0, 15.0, 0.0}, 5.0, 0, 0, 255}
			s2 := sphere{vector{0.0, 0.0, -15.0}, 15.0, 255, 255, 0}

			red, blue, green, t, is_hit := s.getColor(&current_ray)
			red2, blue2, green2, t2, is_hit2 := s2.getColor(&current_ray)

			if is_hit && is_hit2 {
				if t<t2 {
					m.Set(i,j,color.RGBA{red,blue,green,255})
				}else{
					m.Set(i,j,color.RGBA{red2,blue2,green2,255})
				}
			} else if is_hit {
				m.Set(i,j,color.RGBA{red,blue,green,255})
			} else if is_hit2 {
				m.Set(i,j,color.RGBA{red2,blue2,green2,255})
			} else {
				m.Set(i,j,color.RGBA{0,0,0,255})
			}
		}
	}
	if err=png.Encode(f,m); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}<commit_msg>added lighting<commit_after>package main

import "math"
import "fmt"
import "image"
import "os"
import "image/color"
import "image/png"

// vector can represent a point as well, if interpreted as
//  a vector from the origin to a point or 'absolute position vector'.
//  otherwise it represents a 'relative position vector'
type vector struct {
	x, y, z float64
}

type ray struct {
	start vector
	direction vector
}

type camera struct {
	eye vector
	look_at vector
	up vector
}

type screen struct {
	w,h float64
	xres, yres int
}

type sphere struct {
	center vector
	radius float64
	red,green,blue uint8
}

func getLightedColor(red, green, blue uint8, t float64, c_ray *ray, light, center *vector) (uint8, uint8, uint8){
	dir := c_ray.direction.scalarMult(t)
	point_on_sphere := c_ray.start.add(&dir)

	normal := point_on_sphere.sub(center)
	unormal := normal.unit()

	point_on_sphere_to_light := light.sub(&point_on_sphere)
	upoint_on_sphere_to_light := point_on_sphere_to_light.unit()

	scale := unormal.dot(&upoint_on_sphere_to_light)
	if scale < 0.0 {
		scale = 0.0
	}

	red_light := scale*float64(red) + 50.0
	if red_light > 255.0 {
		red_light = 255.0
	}

	green_light := scale*float64(green) + 50.0
	if green_light > 255.0 {
		green_light = 255.0
	}

	blue_light := scale*float64(blue) + 50.0
	if blue_light > 255.0 {
		blue_light = 255.0
	}

	return uint8(red_light), uint8(green_light), uint8(blue_light)
}

func (s *sphere) getColor(c_ray *ray, light *vector) (uint8, uint8, uint8, float64, bool) {
	a := c_ray.direction.x * c_ray.direction.x +
		c_ray.direction.y * c_ray.direction.y +
		c_ray.direction.z * c_ray.direction.z
	b := 2.0*((c_ray.start.x-s.center.x)*c_ray.direction.x +
		(c_ray.start.y-s.center.y)*c_ray.direction.y +
		(c_ray.start.z-s.center.z)*c_ray.direction.z)
	c := (c_ray.start.x-s.center.x) * (c_ray.start.x-s.center.x) +
		(c_ray.start.y-s.center.y) * (c_ray.start.y-s.center.y) +
		(c_ray.start.z-s.center.z) * (c_ray.start.z-s.center.z) -
		s.radius * s.radius

	// test with a sphere
	is_hit:=false
	i_test:=b*b-4.0*a*c
	t1,t2,t_closest:=0.0,0.0,0.0
	if i_test > 0.0 {
		is_hit=true
		t1=(-b+math.Sqrt(i_test))/(2.0*a)
		t2=(-b-math.Sqrt(i_test))/(2.0*a)
		if t1 <= 0.0 && t2 <= 0.0 {
			is_hit=false  // it hit behind or on the viewer
		}else if t1 > 0.0 && t2 > 0.0 {
			if t1<t2 {
				t_closest=t1
			}else{
				t_closest=t2
			}
		} else if t1 > 0.0 {
			t_closest = t1
		} else if t2 > 0.0 {
			t_closest = t2
		}
	}

	var red,green,blue uint8
	if is_hit {
		red,green,blue=getLightedColor(s.red,s.green,s.blue,t_closest,c_ray, light, &s.center)
	}

	return red,green,blue,t_closest,is_hit
}

func (v *vector) sub(v1 *vector) vector {
	return vector{v.x-v1.x, v.y-v1.y, v.z-v1.z}
}

func (v *vector) add(v1 *vector) vector {
	return vector{v.x+v1.x, v.y+v1.y, v.z+v1.z}
}

func (v *vector) scalarMult (c float64) vector {
	return vector{c * v.x, c * v.y, c * v.z}
}

func (v *vector) lengthSq() float64 {
	return v.x * v.x  + v.y * v.y + v.z * v.z
}

func (v *vector) length() float64 {
	return math.Sqrt(v.lengthSq())
}

func (v *vector) unit() vector {
	l := v.length()
	return vector{v.x/l, v.y/l, v.z/l}
}

func (v *vector) dot(v1 *vector) float64 {
	return v.x * v1.x + v.y * v1.y + v.z * v1.z
}

func (v1 *vector) cross(v2 *vector) vector {
	return vector{v1.y * v2.z - v2.y * v1.z,
		v2.x * v1.z - v1.x * v2.z,
		v1.x * v2.y - v2.x * v1.y}
}

func main() {
	g_screen := screen{100,100,1000,1000}
	g_camera := camera{vector{0,0,100}, vector{0,0,0}, vector{0,1,0}}
	g_light := vector{100,100,100}

	f, err := os.OpenFile("x.png", os.O_CREATE | os.O_WRONLY, 0666)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	m := image.NewRGBA(image.Rect(0,0,g_screen.xres,g_screen.yres))

	for i:=0; i < g_screen.xres; i++ {
		for j:=0; j < g_screen.yres; j++ {
			a_to_e := g_camera.eye.sub(&g_camera.look_at)
			w := a_to_e.unit()

			up_X_a_to_e := g_camera.up.cross(&a_to_e)
			u := up_X_a_to_e.unit()
			v := w.cross(&u)

			cu := (((2.0*float64(i) + 1.0)/(2.0 * float64(g_screen.xres))) - 0.5) * g_screen.w
			cv := (((2.0*float64(j) + 1.0)/(2.0 * float64(g_screen.yres))) - 0.5) * g_screen.h

			ucu := u.scalarMult(cu)
			ucv := v.scalarMult(cv)
			a_plus_ucu := g_camera.look_at.add(&ucu)
			Pij := a_plus_ucu.add(&ucv)

			e_to_Pij := Pij.sub(&g_camera.eye)

			current_ray := ray{g_camera.eye, e_to_Pij.unit()}

			// put the sphere at the origin
			s := sphere{vector{5.0, 15.0, 0.0}, 5.0, 0, 0, 255}
			s2 := sphere{vector{0.0, 0.0, -15.0}, 15.0, 255, 255, 0}

			red, green, blue, t, is_hit := s.getColor(&current_ray, &g_light)
			red2, green2, blue2, t2, is_hit2 := s2.getColor(&current_ray, &g_light)

			if is_hit && is_hit2 {
				if t<t2 {
					m.Set(i,j,color.RGBA{red,green,blue,255})
				}else{
					m.Set(i,j,color.RGBA{red2,green2,blue2,255})
				}
			} else if is_hit {
				m.Set(i,j,color.RGBA{red,green,blue,255})
			} else if is_hit2 {
				m.Set(i,j,color.RGBA{red2,green2,blue2,255})
			} else {
				m.Set(i,j,color.RGBA{0,0,0,255})
			}
		}
	}
	if err=png.Encode(f,m); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}<|endoftext|>