<commit_before>package graphics

import (
	"fmt"
	"image"
	"image/draw"
	"io"
	"io/ioutil"
	"log"

	mgl "github.com/go-gl/mathgl/mgl32"
	"github.com/golang/freetype/truetype"
	"github.com/veger/go-graphics/utils"
	"golang.org/x/image/font"
	"golang.org/x/image/math/fixed"
)

// Font provides means to draw text on the screen
//
// It is (currently) intended for UI font (fixed scale, front facing, etc.)
type Font struct {
	engine             *Engine
	face               font.Face
	program            *Program
	recorder           *Recorder
	vbo                *Buffer
	ebo                *ElementBuffer
	projection         mgl.Mat4
	projectionLocation UniformLocation

	size int
}

// NewFont creates a Font instance
func (e *Engine) NewFont(ttf io.Reader, size int) (*Font, error) {
	fData, err := ioutil.ReadAll(ttf)
	if err != nil {
		return nil, fmt.Errorf("could not read font data:: %s", err)
	}

	ttFont, err := truetype.Parse(fData)
	if err != nil {
		return nil, fmt.Errorf("could not parse truetype font: %s", err)
	}

	face := truetype.NewFace(ttFont, &truetype.Options{
		Size:    float64(size),
		DPI:     180,
		Hinting: font.HintingNone,
	})

	program, err := e.NewProgram(vertexShaderFont, fragmentShaderFont)
	if err != nil {
		return nil, err
	}

	recorder, err := e.NewRecorder()
	if err != nil {
		program.Release()
		return nil, err
	}
	recorder.Activate()
	defer recorder.Deactivate()

	// TODO We should use GL_DYNAMIC_DRAW for buffer usage
	vbo, err := e.NewEmptyBuffer(BufferTypeData, 4*4*FloatSize)
	if err != nil {
		recorder.Release()
		program.Release()
		return nil, err
	}

	indicesData := []TriangleIndices{
		TriangleIndices{0, 1, 2},
		TriangleIndices{0, 2, 3},
	}
	ebo, err := e.NewElementBuffer(indicesData)
	if err != nil {
		vbo.Release()
		recorder.Release()
		program.Release()
		return nil, err
	}

	vbo.BindVariable(vertexLayout, 4, 4, 0)
	projectionLocation := program.GetUniformLocation("projection")

	recorder.Deactivate()

	font := &Font{
		engine:             e,
		recorder:           recorder,
		face:               face,
		program:            program,
		vbo:                vbo,
		ebo:                ebo,
		projectionLocation: projectionLocation,

		size: size,
	}

	// TODO Get rid of fixed width/height
	font.UpdateViewport(600, 800)

	return font, nil
}

// Release releases all resources, the font cannot be used afterwards
func (f *Font) Release() {
	f.ebo.Release()
	f.ebo = nil
	f.vbo.Release()
	f.vbo = nil
	f.recorder.Release()
	f.recorder = nil
	f.program.Release()
	f.program = nil
	f.face = nil
	f.engine = nil
}

// UpdateViewport recalculates the projection matrix based on the given viewport dimensions
func (f *Font) UpdateViewport(width, height float32) {
	// Calculate projection
	f.projection = mgl.Ortho(-width, width, -height, height, 0, 1)

	// Udpate projection with view
	// pos := mgl.Vec3{width, height, 0}
	// dir := mgl.Vec3{width, height, -1}
	// up := mgl.Vec3{0, 1, 0}
	// view := mgl.LookAtV(pos, dir, up)
	view := mgl.Ident4()
	view[12] = -width
	view[13] = -height
	f.projection = f.projection.Mul4(view)
}

// Draw renders text at the given coordinates
func (f *Font) Draw(x, y float32, str string) {
	f.face.Metrics()
	// Render text to image
	d := &font.Drawer{
		Src:  image.White,
		Face: f.face,
		Dot: fixed.Point26_6{
			X: fixed.I(0),
			Y: fixed.I(f.size),
		},
	}
	b, _ := d.BoundString(str)

	w := (b.Max.X - b.Min.X).Ceil()
	h := (b.Max.Y - b.Min.Y).Ceil()
	im := image.NewRGBA(image.Rect(0, 0, w, h))
	draw.Draw(im, im.Bounds(), image.Black, image.ZP, draw.Src)
	d.Dst = im
	d.Dot.Y = b.Max.Y - b.Min.Y
	d.DrawString(str)

	// Activate OpenGL stuff
	f.program.Activate()
	f.recorder.Activate()
	defer f.recorder.Deactivate()

	// Create texture and upload
	tex := f.engine.NewTexture(im)
	defer tex.Release()
	tex.Bind()
	defer tex.Unbind()

	// Update vertices to create surface to render the texture
	vertices := [4 * 4]float32{ // 4 * vec4 < vec2 position, vec2 tex>
		x, y + float32(h), 0.0, 0.0,
		x, y, 0.0, 1.0,
		x + float32(w), y, 1.0, 1.0,
		x + float32(w), y + float32(h), 1.0, 0.0,
	}

	data, err := utils.CastToBytes(vertices)
	if err != nil {
		log.Fatalln("CastToBytes failed:", err)
	}
	f.vbo.SetData(0, data)

	f.program.SetUnitformMatrix4(f.projectionLocation, f.projection[:])
	f.ebo.Render()
}

const vertexLayout = 0

const vertexShaderFont = `#version 300 es

layout (location = 0) in vec4 vertex; // <vec2 position, vec2 tex>
out vec2 TexCoord;

uniform mat4 projection;

void main() {
  gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);
  TexCoord = vertex.zw;
}`

const fragmentShaderFont = `#version 300 es
precision mediump float;

in vec2 TexCoord;
out vec4 color;

uniform sampler2D text;

void main()
{
    color = vec4(1.0, 1.0, 1.0, 1.0) * texture(text, TexCoord).r;
}`
<commit_msg>Make bounding box of text slightly larger<commit_after>package graphics

import (
	"fmt"
	"image"
	"image/draw"
	"io"
	"io/ioutil"
	"log"

	mgl "github.com/go-gl/mathgl/mgl32"
	"github.com/golang/freetype/truetype"
	"github.com/veger/go-graphics/utils"
	"golang.org/x/image/font"
	"golang.org/x/image/math/fixed"
)

// Font provides means to draw text on the screen
//
// It is (currently) intended for UI font (fixed scale, front facing, etc.)
type Font struct {
	engine             *Engine
	face               font.Face
	program            *Program
	recorder           *Recorder
	vbo                *Buffer
	ebo                *ElementBuffer
	projection         mgl.Mat4
	projectionLocation UniformLocation

	size int
}

// NewFont creates a Font instance
func (e *Engine) NewFont(ttf io.Reader, size int) (*Font, error) {
	fData, err := ioutil.ReadAll(ttf)
	if err != nil {
		return nil, fmt.Errorf("could not read font data:: %s", err)
	}

	ttFont, err := truetype.Parse(fData)
	if err != nil {
		return nil, fmt.Errorf("could not parse truetype font: %s", err)
	}

	face := truetype.NewFace(ttFont, &truetype.Options{
		Size:    float64(size),
		DPI:     180,
		Hinting: font.HintingNone,
	})

	program, err := e.NewProgram(vertexShaderFont, fragmentShaderFont)
	if err != nil {
		return nil, err
	}

	recorder, err := e.NewRecorder()
	if err != nil {
		program.Release()
		return nil, err
	}
	recorder.Activate()
	defer recorder.Deactivate()

	// TODO We should use GL_DYNAMIC_DRAW for buffer usage
	vbo, err := e.NewEmptyBuffer(BufferTypeData, 4*4*FloatSize)
	if err != nil {
		recorder.Release()
		program.Release()
		return nil, err
	}

	indicesData := []TriangleIndices{
		TriangleIndices{0, 1, 2},
		TriangleIndices{0, 2, 3},
	}
	ebo, err := e.NewElementBuffer(indicesData)
	if err != nil {
		vbo.Release()
		recorder.Release()
		program.Release()
		return nil, err
	}

	vbo.BindVariable(vertexLayout, 4, 4, 0)
	projectionLocation := program.GetUniformLocation("projection")

	recorder.Deactivate()

	font := &Font{
		engine:             e,
		recorder:           recorder,
		face:               face,
		program:            program,
		vbo:                vbo,
		ebo:                ebo,
		projectionLocation: projectionLocation,

		size: size,
	}

	// TODO Get rid of fixed width/height
	font.UpdateViewport(600, 800)

	return font, nil
}

// Release releases all resources, the font cannot be used afterwards
func (f *Font) Release() {
	f.ebo.Release()
	f.ebo = nil
	f.vbo.Release()
	f.vbo = nil
	f.recorder.Release()
	f.recorder = nil
	f.program.Release()
	f.program = nil
	f.face = nil
	f.engine = nil
}

// UpdateViewport recalculates the projection matrix based on the given viewport dimensions
func (f *Font) UpdateViewport(width, height float32) {
	// Calculate projection
	f.projection = mgl.Ortho(-width, width, -height, height, 0, 1)

	// Udpate projection with view
	// pos := mgl.Vec3{width, height, 0}
	// dir := mgl.Vec3{width, height, -1}
	// up := mgl.Vec3{0, 1, 0}
	// view := mgl.LookAtV(pos, dir, up)
	view := mgl.Ident4()
	view[12] = -width
	view[13] = -height
	f.projection = f.projection.Mul4(view)
}

// Draw renders text at the given coordinates
func (f *Font) Draw(x, y float32, str string) {
	f.face.Metrics()
	// Render text to image
	d := &font.Drawer{
		Src:  image.White,
		Face: f.face,
		Dot: fixed.Point26_6{
			X: fixed.I(0),
			Y: fixed.I(f.size),
		},
	}
	b, _ := d.BoundString(str)

	w := b.Max.X.Ceil() - b.Min.X.Floor() + 1
	h := b.Max.Y.Ceil() - b.Min.Y.Floor() + 1
	im := image.NewRGBA(image.Rect(0, 0, w, h))
	draw.Draw(im, im.Bounds(), image.Black, image.ZP, draw.Src)
	d.Dst = im
	d.Dot.Y = b.Max.Y - b.Min.Y
	d.DrawString(str)

	// Activate OpenGL stuff
	f.program.Activate()
	f.recorder.Activate()
	defer f.recorder.Deactivate()

	// Create texture and upload
	tex := f.engine.NewTexture(im)
	defer tex.Release()
	tex.Bind()
	defer tex.Unbind()

	// Update vertices to create surface to render the texture
	vertices := [4 * 4]float32{ // 4 * vec4 < vec2 position, vec2 tex>
		x, y + float32(h), 0.0, 0.0,
		x, y, 0.0, 1.0,
		x + float32(w), y, 1.0, 1.0,
		x + float32(w), y + float32(h), 1.0, 0.0,
	}

	data, err := utils.CastToBytes(vertices)
	if err != nil {
		log.Fatalln("CastToBytes failed:", err)
	}
	f.vbo.SetData(0, data)

	f.program.SetUnitformMatrix4(f.projectionLocation, f.projection[:])
	f.ebo.Render()
}

const vertexLayout = 0

const vertexShaderFont = `#version 300 es

layout (location = 0) in vec4 vertex; // <vec2 position, vec2 tex>
out vec2 TexCoord;

uniform mat4 projection;

void main() {
  gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);
  TexCoord = vertex.zw;
}`

const fragmentShaderFont = `#version 300 es
precision mediump float;

in vec2 TexCoord;
out vec4 color;

uniform sampler2D text;

void main()
{
    color = vec4(1.0, 1.0, 1.0, 1.0) * texture(text, TexCoord).r;
}`
<|endoftext|>


<commit_before>package migrations

import (
	"database/sql"
	"fmt"
	"io/ioutil"
	"os"
	"path"
)

const (
	// MigrationCreateMessagesAM06MessagesCreateSQL the messages create sql
	MigrationCreateMessagesAM06MessagesCreateSQL = "create table messages (messageID text primary key not null, orderID text, message_type integer, message blob, peerID text, url text, acknowledged bool, tries integer, created_at integer, updated_at integer);"
	// MigrationCreateMessagesAM06CreateIndexMessagesSQLMessageID the messages index on messageID sql
	MigrationCreateMessagesAM06CreateIndexMessagesSQLMessageID = "create index index_messages_messageID on messages (messageID);"
	// MigrationCreateMessagesAM06CreateIndexMessagesSQLOrderIDMType the messages composite index on orderID and messageType create sql
	MigrationCreateMessagesAM06CreateIndexMessagesSQLOrderIDMType = "create index index_messages_orderIDmType on messages (orderID, message_type);"
	// MigrationCreateMessagesAM06CreateIndexMessagesSQLPeerIDMType the messages composite index on peerID and messageType create sql
	MigrationCreateMessagesAM06CreateIndexMessagesSQLPeerIDMType = "create index index_messages_peerIDmType on messages (peerID, message_type);"
	// MigrationCreateMessagesAM06MessagesDeleteSQL the messages delete sql
	MigrationCreateMessagesAM06MessagesDeleteSQL = "drop table if exists messages;"
	// MigrationCreateMessagesAM06CreateIndexMessagesSQLMessageID delete the messages index on messageID sql
	MigrationCreateMessagesAM06DeleteIndexMessagesSQLMessageID = "drop index if exists index_messages_messageID;"
	// MigrationCreateMessagesAM06CreateIndexMessagesSQLOrderIDMType delete the messages composite index on orderID and messageType create sql
	MigrationCreateMessagesAM06DeleteIndexMessagesSQLOrderIDMType = "drop index if exists index_messages_orderIDmType;"
	// MigrationCreateMessagesAM06CreateIndexMessagesSQLPeerIDMType delete the messages composite index on peerID and messageType create sql
	MigrationCreateMessagesAM06DeleteIndexMessagesSQLPeerIDMType = "drop index if exists index_messages_peerIDmType;"
	// MigrationCreateMessagesAM06UpVer set the repo Up version
	MigrationCreateMessagesAM06UpVer = "25"
	// MigrationCreateMessagesAM06DownVer set the repo Down version
	MigrationCreateMessagesAM06DownVer = "24"
)

// MigrationCreateMessagesAM06  local migration struct
type MigrationCreateMessagesAM06 struct{}

// Migration024  migration struct
type Migration024 struct {
	MigrationCreateMessagesAM06
}

func createMessages(repoPath, databasePassword, rVer string, testnetEnabled bool) error {
	var (
		databaseFilePath    string
		repoVersionFilePath = path.Join(repoPath, "repover")
	)
	if testnetEnabled {
		databaseFilePath = path.Join(repoPath, "datastore", "testnet.db")
	} else {
		databaseFilePath = path.Join(repoPath, "datastore", "mainnet.db")
	}

	db, err := sql.Open("sqlite3", databaseFilePath)
	if err != nil {
		return err
	}
	defer db.Close()
	if databasePassword != "" {
		p := fmt.Sprintf("pragma key = '%s';", databasePassword)
		_, err := db.Exec(p)
		if err != nil {
			return err
		}
	}

	tx, err := db.Begin()
	if err != nil {
		return err
	}
	if _, err = tx.Exec(MigrationCreateMessagesAM06MessagesCreateSQL); err != nil {
		tx.Rollback()
		return err
	}
	if _, err = tx.Exec(MigrationCreateMessagesAM06CreateIndexMessagesSQLMessageID); err != nil {
		tx.Rollback()
		return err
	}
	if _, err = tx.Exec(MigrationCreateMessagesAM06CreateIndexMessagesSQLOrderIDMType); err != nil {
		tx.Rollback()
		return err
	}
	if _, err = tx.Exec(MigrationCreateMessagesAM06CreateIndexMessagesSQLPeerIDMType); err != nil {
		tx.Rollback()
		return err
	}
	if err = tx.Commit(); err != nil {
		return err
	}

	// Bump schema version
	err = ioutil.WriteFile(repoVersionFilePath, []byte(rVer), os.ModePerm)
	if err != nil {
		return err
	}
	return nil
}

func deleteMessages(repoPath, databasePassword, rVer string, testnetEnabled bool) error {
	var (
		databaseFilePath    string
		repoVersionFilePath = path.Join(repoPath, "repover")
	)
	if testnetEnabled {
		databaseFilePath = path.Join(repoPath, "datastore", "testnet.db")
	} else {
		databaseFilePath = path.Join(repoPath, "datastore", "mainnet.db")
	}

	db, err := sql.Open("sqlite3", databaseFilePath)
	if err != nil {
		return err
	}
	defer db.Close()
	if databasePassword != "" {
		p := fmt.Sprintf("pragma key = '%s';", databasePassword)
		_, err := db.Exec(p)
		if err != nil {
			return err
		}
	}

	tx, err := db.Begin()
	if err != nil {
		return err
	}
	if _, err = tx.Exec(MigrationCreateMessagesAM06DeleteIndexMessagesSQLMessageID); err != nil {
		tx.Rollback()
		return err
	}
	if _, err = tx.Exec(MigrationCreateMessagesAM06DeleteIndexMessagesSQLOrderIDMType); err != nil {
		tx.Rollback()
		return err
	}
	if _, err = tx.Exec(MigrationCreateMessagesAM06DeleteIndexMessagesSQLPeerIDMType); err != nil {
		tx.Rollback()
		return err
	}
	if _, err = tx.Exec(MigrationCreateMessagesAM06MessagesDeleteSQL); err != nil {
		tx.Rollback()
		return err
	}
	if err = tx.Commit(); err != nil {
		return err
	}

	// Bump schema version
	err = ioutil.WriteFile(repoVersionFilePath, []byte(rVer), os.ModePerm)
	if err != nil {
		return err
	}
	return nil
}

// Up the migration Up code
func (MigrationCreateMessagesAM06) Up(repoPath, databasePassword string, testnetEnabled bool) error {
	return createMessages(repoPath, databasePassword, MigrationCreateMessagesAM06UpVer, testnetEnabled)
}

// Down the migration Down code
func (MigrationCreateMessagesAM06) Down(repoPath, databasePassword string, testnetEnabled bool) error {
	return deleteMessages(repoPath, databasePassword, MigrationCreateMessagesAM06DownVer, testnetEnabled)
}
<commit_msg>lint fix<commit_after>package migrations

import (
	"database/sql"
	"fmt"
	"io/ioutil"
	"os"
	"path"
)

const (
	// MigrationCreateMessagesAM06MessagesCreateSQL the messages create sql
	MigrationCreateMessagesAM06MessagesCreateSQL = "create table messages (messageID text primary key not null, orderID text, message_type integer, message blob, peerID text, url text, acknowledged bool, tries integer, created_at integer, updated_at integer);"
	// MigrationCreateMessagesAM06CreateIndexMessagesSQLMessageID the messages index on messageID sql
	MigrationCreateMessagesAM06CreateIndexMessagesSQLMessageID = "create index index_messages_messageID on messages (messageID);"
	// MigrationCreateMessagesAM06CreateIndexMessagesSQLOrderIDMType the messages composite index on orderID and messageType create sql
	MigrationCreateMessagesAM06CreateIndexMessagesSQLOrderIDMType = "create index index_messages_orderIDmType on messages (orderID, message_type);"
	// MigrationCreateMessagesAM06CreateIndexMessagesSQLPeerIDMType the messages composite index on peerID and messageType create sql
	MigrationCreateMessagesAM06CreateIndexMessagesSQLPeerIDMType = "create index index_messages_peerIDmType on messages (peerID, message_type);"
	// MigrationCreateMessagesAM06MessagesDeleteSQL the messages delete sql
	MigrationCreateMessagesAM06MessagesDeleteSQL = "drop table if exists messages;"
	// MigrationCreateMessagesAM06DeleteIndexMessagesSQLMessageID delete the messages index on messageID sql
	MigrationCreateMessagesAM06DeleteIndexMessagesSQLMessageID = "drop index if exists index_messages_messageID;"
	// MigrationCreateMessagesAM06DeleteIndexMessagesSQLOrderIDMType delete the messages composite index on orderID and messageType create sql
	MigrationCreateMessagesAM06DeleteIndexMessagesSQLOrderIDMType = "drop index if exists index_messages_orderIDmType;"
	// MigrationCreateMessagesAM06DeleteIndexMessagesSQLPeerIDMType delete the messages composite index on peerID and messageType create sql
	MigrationCreateMessagesAM06DeleteIndexMessagesSQLPeerIDMType = "drop index if exists index_messages_peerIDmType;"
	// MigrationCreateMessagesAM06UpVer set the repo Up version
	MigrationCreateMessagesAM06UpVer = "25"
	// MigrationCreateMessagesAM06DownVer set the repo Down version
	MigrationCreateMessagesAM06DownVer = "24"
)

// MigrationCreateMessagesAM06  local migration struct
type MigrationCreateMessagesAM06 struct{}

// Migration024  migration struct
type Migration024 struct {
	MigrationCreateMessagesAM06
}

func createMessages(repoPath, databasePassword, rVer string, testnetEnabled bool) error {
	var (
		databaseFilePath    string
		repoVersionFilePath = path.Join(repoPath, "repover")
	)
	if testnetEnabled {
		databaseFilePath = path.Join(repoPath, "datastore", "testnet.db")
	} else {
		databaseFilePath = path.Join(repoPath, "datastore", "mainnet.db")
	}

	db, err := sql.Open("sqlite3", databaseFilePath)
	if err != nil {
		return err
	}
	defer db.Close()
	if databasePassword != "" {
		p := fmt.Sprintf("pragma key = '%s';", databasePassword)
		_, err := db.Exec(p)
		if err != nil {
			return err
		}
	}

	tx, err := db.Begin()
	if err != nil {
		return err
	}
	if _, err = tx.Exec(MigrationCreateMessagesAM06MessagesCreateSQL); err != nil {
		tx.Rollback()
		return err
	}
	if _, err = tx.Exec(MigrationCreateMessagesAM06CreateIndexMessagesSQLMessageID); err != nil {
		tx.Rollback()
		return err
	}
	if _, err = tx.Exec(MigrationCreateMessagesAM06CreateIndexMessagesSQLOrderIDMType); err != nil {
		tx.Rollback()
		return err
	}
	if _, err = tx.Exec(MigrationCreateMessagesAM06CreateIndexMessagesSQLPeerIDMType); err != nil {
		tx.Rollback()
		return err
	}
	if err = tx.Commit(); err != nil {
		return err
	}

	// Bump schema version
	err = ioutil.WriteFile(repoVersionFilePath, []byte(rVer), os.ModePerm)
	if err != nil {
		return err
	}
	return nil
}

func deleteMessages(repoPath, databasePassword, rVer string, testnetEnabled bool) error {
	var (
		databaseFilePath    string
		repoVersionFilePath = path.Join(repoPath, "repover")
	)
	if testnetEnabled {
		databaseFilePath = path.Join(repoPath, "datastore", "testnet.db")
	} else {
		databaseFilePath = path.Join(repoPath, "datastore", "mainnet.db")
	}

	db, err := sql.Open("sqlite3", databaseFilePath)
	if err != nil {
		return err
	}
	defer db.Close()
	if databasePassword != "" {
		p := fmt.Sprintf("pragma key = '%s';", databasePassword)
		_, err := db.Exec(p)
		if err != nil {
			return err
		}
	}

	tx, err := db.Begin()
	if err != nil {
		return err
	}
	if _, err = tx.Exec(MigrationCreateMessagesAM06DeleteIndexMessagesSQLMessageID); err != nil {
		tx.Rollback()
		return err
	}
	if _, err = tx.Exec(MigrationCreateMessagesAM06DeleteIndexMessagesSQLOrderIDMType); err != nil {
		tx.Rollback()
		return err
	}
	if _, err = tx.Exec(MigrationCreateMessagesAM06DeleteIndexMessagesSQLPeerIDMType); err != nil {
		tx.Rollback()
		return err
	}
	if _, err = tx.Exec(MigrationCreateMessagesAM06MessagesDeleteSQL); err != nil {
		tx.Rollback()
		return err
	}
	if err = tx.Commit(); err != nil {
		return err
	}

	// Bump schema version
	err = ioutil.WriteFile(repoVersionFilePath, []byte(rVer), os.ModePerm)
	if err != nil {
		return err
	}
	return nil
}

// Up the migration Up code
func (MigrationCreateMessagesAM06) Up(repoPath, databasePassword string, testnetEnabled bool) error {
	return createMessages(repoPath, databasePassword, MigrationCreateMessagesAM06UpVer, testnetEnabled)
}

// Down the migration Down code
func (MigrationCreateMessagesAM06) Down(repoPath, databasePassword string, testnetEnabled bool) error {
	return deleteMessages(repoPath, databasePassword, MigrationCreateMessagesAM06DownVer, testnetEnabled)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"html"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

const HN_API_URL = "https://hacker-news.firebaseio.com/v0/item/%s.json"
const DELETED = "-Deleted-"

type item struct {
	// Reference: https://github.com/HackerNews/API
	Id          int    // The item's unique id.
	Deleted     bool   // true if the item is deleted.
	Type        string // The type of item. One of "job", "story", "comment", "poll", or "pollopt".
	By          string // The username of the item's author.
	Time        int64  // Creation date of the item, in Unix Time.
	Text        string // The comment, story or poll text. HTML.
	Dead        bool   // true if the item is dead.
	Parent      int    // The item's parent. For comments, either another comment or the relevant story. For pollopts, the relevant poll.
	Kids        []int  // The ids of the item's comments, in ranked display order.
	Url         string // The URL of the story.
	Score       int    // The story's score, or the votes for a pollopt.
	Title       string // The title of the story, poll or job.
	Parts       []int  // A list of related pollopts, in display order.
	Descendants int    // In the case of stories or polls, the total comment count.
}

func (i *item) Poster() string {
	if i.Deleted {
		return DELETED
	}
	return i.By
}

func (i *item) Recipient() string {
	return "everyone@example.com"
}

func (i *item) Subject() (subject string) {
	if i.Deleted {
		subject = DELETED
		return
	}
	if len(i.Title) == 0 {
		s := i.Text
		if len(s) > 80 {
			s = s[0:80]
		}
		subject = strings.Replace(s, "\n", " ", -1)
	} else {
		subject = i.Title
	}
	subject = html.UnescapeString(subject)
	return
}

func (i *item) Body() (body string) {
	if len(i.Text) == 0 {
		body = i.Url
	} else {
		body = i.Text
	}
	body = html.UnescapeString(body)
	body = strings.Replace(body, "<p>", "\n\n", -1)
	return
}

var c int64 = 0

func (i *item) SortDate() int64 {
	c++
	return c
}

func (i *item) Date() int64 {
	return i.Time
}

func (i *item) MessageId() string {
	return fmt.Sprintf("<hackernews-%d>", i.Id)
}

func (i *item) Points() int {
	return i.Score
}

func (i *item) Children() (idStr []string) {
	for _, v := range i.Kids {
		idStr = append(idStr, strconv.Itoa(v))
	}
	return
}

func (i *item) PostType() string {
	return i.Type
}

func (i *item) Removed() bool {
	return i.Deleted
}

func GetHNPost(url *url.URL) Post {
	idStr := url.Query().Get("id")
	if len(idStr) == 0 {
		return nil
	}

	item, err := fetchHNPost(idStr)
	if err != nil {
		bail("%v", err)
	}
	return item
}

func fetchHNPost(id string) (r *item, err error) {
	if rr, exist := postCache.Items[id]; exist {
		return rr, nil
	}
	url := fmt.Sprintf(HN_API_URL, id)
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	verbose("%v", url)
	body, err := ioutil.ReadAll(resp.Body)
	err = json.Unmarshal(body, &r)
	if err != nil {
		return nil, err
	}
	verbose("\t%d bytes", len(body))
	if _, exist := postCache.Items[id]; !exist {
		postCache.Items[id] = r
	}
	return r, nil
}
<commit_msg>item.Subject(): Trim using unicode-aware method<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"html"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

const HN_API_URL = "https://hacker-news.firebaseio.com/v0/item/%s.json"
const DELETED = "-Deleted-"

type item struct {
	// Reference: https://github.com/HackerNews/API
	Id          int    // The item's unique id.
	Deleted     bool   // true if the item is deleted.
	Type        string // The type of item. One of "job", "story", "comment", "poll", or "pollopt".
	By          string // The username of the item's author.
	Time        int64  // Creation date of the item, in Unix Time.
	Text        string // The comment, story or poll text. HTML.
	Dead        bool   // true if the item is dead.
	Parent      int    // The item's parent. For comments, either another comment or the relevant story. For pollopts, the relevant poll.
	Kids        []int  // The ids of the item's comments, in ranked display order.
	Url         string // The URL of the story.
	Score       int    // The story's score, or the votes for a pollopt.
	Title       string // The title of the story, poll or job.
	Parts       []int  // A list of related pollopts, in display order.
	Descendants int    // In the case of stories or polls, the total comment count.
}

func (i *item) Poster() string {
	if i.Deleted {
		return DELETED
	}
	return i.By
}

func (i *item) Recipient() string {
	return "everyone@example.com"
}

func (i *item) Subject() (subject string) {
	if i.Deleted {
		subject = DELETED
		return
	}
	if len(i.Title) == 0 {
		s := i.Text
		if len(s) > 80 {
			s = string([]rune(s)[0:80])
		}
		subject = strings.Replace(s, "\n", " ", -1)
	} else {
		subject = i.Title
	}
	subject = html.UnescapeString(subject)
	return
}

func (i *item) Body() (body string) {
	if len(i.Text) == 0 {
		body = i.Url
	} else {
		body = i.Text
	}
	body = html.UnescapeString(body)
	body = strings.Replace(body, "<p>", "\n\n", -1)
	return
}

var c int64 = 0

func (i *item) SortDate() int64 {
	c++
	return c
}

func (i *item) Date() int64 {
	return i.Time
}

func (i *item) MessageId() string {
	return fmt.Sprintf("<hackernews-%d>", i.Id)
}

func (i *item) Points() int {
	return i.Score
}

func (i *item) Children() (idStr []string) {
	for _, v := range i.Kids {
		idStr = append(idStr, strconv.Itoa(v))
	}
	return
}

func (i *item) PostType() string {
	return i.Type
}

func (i *item) Removed() bool {
	return i.Deleted
}

func GetHNPost(url *url.URL) Post {
	idStr := url.Query().Get("id")
	if len(idStr) == 0 {
		return nil
	}

	item, err := fetchHNPost(idStr)
	if err != nil {
		bail("%v", err)
	}
	return item
}

func fetchHNPost(id string) (r *item, err error) {
	if rr, exist := postCache.Items[id]; exist {
		return rr, nil
	}
	url := fmt.Sprintf(HN_API_URL, id)
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	verbose("%v", url)
	body, err := ioutil.ReadAll(resp.Body)
	err = json.Unmarshal(body, &r)
	if err != nil {
		return nil, err
	}
	verbose("\t%d bytes", len(body))
	if _, exist := postCache.Items[id]; !exist {
		postCache.Items[id] = r
	}
	return r, nil
}
<|endoftext|>


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

package SymbolTable

import (
	"container/vector";
	"unicode";
	"utf8";
)

type Type struct;

// ----------------------------------------------------------------------------
// Support

func assert(pred bool) {
	if !pred {
		panic("assertion failed");
	}
}

// ----------------------------------------------------------------------------
// Objects

// Object represents a language object, such as a constant, variable, type, etc.

const /* kind */ (
	BADOBJ = iota;  // error handling
	NONE;  // kind unknown
	CONST; TYPE; VAR; FIELD; FUNC; BUILTIN; PACKAGE; LABEL;
	END;  // end of scope (import/export only)
)

func KindStr(kind int) string {
	switch kind {
	case BADOBJ: return "BADOBJ";
	case NONE: return "NONE";
	case CONST: return "CONST";
	case TYPE: return "TYPE";
	case VAR: return "VAR";
	case FIELD: return "FIELD";
	case FUNC: return "FUNC";
	case BUILTIN: return "BUILTIN";
	case PACKAGE: return "PACKAGE";
	case LABEL: return "LABEL";
	case END: return "END";
	}
	return "<unknown Object kind>";
}

type Object struct {
	Id int;  // unique id

	Pos int;  // source position (< 0 if unknown position)
	Kind int;  // object kind
	Ident string;
	Typ *Type;  // nil for packages
	Pnolev int;  // >= 0: package no., <= 0: function nesting level, 0: global level
}

func (obj *Object) IsExported() bool {
	switch obj.Kind {
	case NONE /* FUNC for now */, CONST, TYPE, VAR, FUNC:
		ch, size := utf8.DecodeRuneInString(obj.Ident);
		return unicode.IsUpper(ch);
	}
	return false;
}

func (obj* Object) String() string {
	if obj != nil {
		return
			"Object(" +
			KindStr(obj.Kind) + ", " +
			obj.Ident +
			")";
	}
	return "nil";
}

var Universe_void_typ *Type  // initialized by Universe to Universe.void_typ
var objectId int;

func NewObject(pos, kind int, ident string) *Object {
	obj := new(Object);
	obj.Id = objectId;
	objectId++;

	obj.Pos = pos;
	obj.Kind = kind;
	obj.Ident = ident;
	obj.Typ = Universe_void_typ;  // TODO would it be better to use nil instead?
	obj.Pnolev = 0;

	return obj;
}

// ----------------------------------------------------------------------------
// Scopes

type Scope struct {
	Parent *Scope;
	entries map[string] *Object;
}

func NewScope(parent *Scope) *Scope {
	scope := new(Scope);
	scope.Parent = parent;
	scope.entries = make(map[string] *Object, 8);
	return scope;
}

func (scope *Scope) LookupLocal(ident string) *Object {
	obj, found := scope.entries[ident];
	if found {
		return obj;
	}
	return nil;
}

func (scope *Scope) Lookup(ident string) *Object {
	for scope != nil {
		obj := scope.LookupLocal(ident);
		if obj != nil {
			return obj;
		}
		scope = scope.Parent;
	}
	return nil;
}

func (scope *Scope) add(obj *Object) {
	scope.entries[obj.Ident] = obj;
}

func (scope *Scope) Insert(obj *Object) {
	if scope.LookupLocal(obj.Ident) != nil {
		panic("obj already inserted");
	}
	scope.add(obj);
}

func (scope *Scope) InsertImport(obj *Object) *Object {
	 p := scope.LookupLocal(obj.Ident);
	 if p == nil {
		scope.add(obj);
		p = obj;
	 }
	 return p;
}

func (scope *Scope) Print() {
	print("scope {");
	for key := range scope.entries {
		print("\n  ", key);
	}
	print("\n}\n");
}

// ----------------------------------------------------------------------------
// Types

const /* form */ (
	// internal types
	// We should never see one of these.
	UNDEF = iota;

	// VOID types are used when we don't have a type. Never exported.
	// (exported type forms must be > 0)
	VOID;

	// BADTYPE types are compatible with any type and don't cause further errors.
	// They are introduced only as a result of an error in the source code. A
	// correct program cannot have BAD types.
	BADTYPE;

	// FORWARD types are forward-declared (incomplete) types. They can only
	// be used as element types of pointer types and must be resolved before
	// their internals are accessible.
	FORWARD;

	// TUPLE types represent multi-valued result types of functions and
	// methods.
	TUPLE;

	// The type of nil.
	NIL;

	// A type name
	TYPENAME;

	// basic types
	BOOL; UINT; INT; FLOAT; STRING; INTEGER;

	// composite types
	ALIAS; ARRAY; STRUCT; INTERFACE; MAP; CHANNEL; FUNCTION; METHOD; POINTER;

	// open-ended parameter type
	ELLIPSIS
)

func FormStr(form int) string {
	switch form {
	case VOID: return "VOID";
	case BADTYPE: return "BADTYPE";
	case FORWARD: return "FORWARD";
	case TUPLE: return "TUPLE";
	case NIL: return "NIL";
	case TYPENAME: return "TYPENAME";
	case BOOL: return "BOOL";
	case UINT: return "UINT";
	case INT: return "INT";
	case FLOAT: return "FLOAT";
	case STRING: return "STRING";
	case ALIAS: return "ALIAS";
	case ARRAY: return "ARRAY";
	case STRUCT: return "STRUCT";
	case INTERFACE: return "INTERFACE";
	case MAP: return "MAP";
	case CHANNEL: return "CHANNEL";
	case FUNCTION: return "FUNCTION";
	case METHOD: return "METHOD";
	case POINTER: return "POINTER";
	case ELLIPSIS: return "ELLIPSIS";
	}
	return "<unknown Type form>";
}

const /* channel mode */ (
	FULL = iota;
	SEND;
	RECV;
)

type Type struct {
	Id int;  // unique id

	Ref int;  // for exporting only: >= 0 means already exported
	Form int;  // type form
	Size int;  // size in bytes
	Obj *Object;  // primary type object or nil
	Scope *Scope;  // locals, fields & methods

	// syntactic components
	Pos int;  // source position (< 0 if unknown position)
	Len int;  // array length
	Mode int;  // channel mode
	Key *Type;  // receiver type or map key
	Elt *Type;  // type name type, array, map, channel or pointer element type, function result type
	List *vector.Vector; End int;  // struct fields, interface methods, function parameters
}

var typeId int;

func NewType(pos, form int) *Type {
	typ := new(Type);
	typ.Id = typeId;
	typeId++;

	typ.Ref = -1;  // not yet exported
	typ.Pos = pos;
	typ.Form = form;

	return typ;
}

func (typ* Type) String() string {
	if typ != nil {
		return
			"Type(" +
			FormStr(typ.Form) +
			")";
	}
	return "nil";
}

// ----------------------------------------------------------------------------
// Universe scope

var (
	Universe *Scope;
	PredeclaredTypes vector.Vector;

	// internal types
	Void_typ,
	Bad_typ,
	Nil_typ,

	// basic types
	Bool_typ,
	Uint8_typ,
	Uint16_typ,
	Uint32_typ,
	Uint64_typ,
	Int8_typ,
	Int16_typ,
	Int32_typ,
	Int64_typ,
	Float32_typ,
	Float64_typ,
	Float80_typ,
	String_typ,
	Integer_typ,

	// convenience types
	Byte_typ,
	Uint_typ,
	Int_typ,
	Float_typ,
	Uintptr_typ *Type;

	True_obj,
	False_obj,
	Iota_obj,
	Nil_obj *Object;
)

func declObj(kind int, ident string, typ *Type) *Object {
	obj := NewObject(-1 /* no source pos */, kind, ident);
	obj.Typ = typ;
	if kind == TYPE && typ.Obj == nil {
		typ.Obj = obj;  // set primary type object
	}
	Universe.Insert(obj);
	return obj
}

func declType(form int, ident string, size int) *Type {
  typ := NewType(-1 /* no source pos */, form);
  typ.Size = size;
  return declObj(TYPE, ident, typ).Typ;
}

func register(typ *Type) *Type {
	typ.Ref = PredeclaredTypes.Len();
	PredeclaredTypes.Push(typ);
	return typ;
}

func init() {
	Universe = NewScope(nil);  // universe has no parent
	PredeclaredTypes.Init(32);

	// Interal types
	Void_typ = NewType(-1 /* no source pos */, VOID);
	Universe_void_typ = Void_typ;
	Bad_typ = NewType(-1 /* no source pos */, BADTYPE);
	Nil_typ = NewType(-1 /* no source pos */, NIL);

	// Basic types
	Bool_typ = register(declType(BOOL, "bool", 1));
	Uint8_typ = register(declType(UINT, "uint8", 1));
	Uint16_typ = register(declType(UINT, "uint16", 2));
	Uint32_typ = register(declType(UINT, "uint32", 4));
	Uint64_typ = register(declType(UINT, "uint64", 8));
	Int8_typ = register(declType(INT, "int8", 1));
	Int16_typ = register(declType(INT, "int16", 2));
	Int32_typ = register(declType(INT, "int32", 4));
	Int64_typ = register(declType(INT, "int64", 8));
	Float32_typ = register(declType(FLOAT, "float32", 4));
	Float64_typ = register(declType(FLOAT, "float64", 8));
	Float80_typ = register(declType(FLOAT, "float80", 10));
	String_typ = register(declType(STRING, "string", 8));
	Integer_typ = register(declType(INTEGER, "integer", 8));

	// All but 'byte' should be platform-dependent, eventually.
	Byte_typ = register(declType(UINT, "byte", 1));
	Uint_typ = register(declType(UINT, "uint", 4));
	Int_typ = register(declType(INT, "int", 4));
	Float_typ = register(declType(FLOAT, "float", 4));
	Uintptr_typ = register(declType(UINT, "uintptr", 8));

	// Predeclared constants
	True_obj = declObj(CONST, "true", Bool_typ);
	False_obj = declObj(CONST, "false", Bool_typ);
	Iota_obj = declObj(CONST, "iota", Int_typ);
	Nil_obj = declObj(CONST, "nil", Nil_typ);

	// Builtin functions
	declObj(BUILTIN, "len", Void_typ);
	declObj(BUILTIN, "new", Void_typ);
	declObj(BUILTIN, "panic", Void_typ);
	declObj(BUILTIN, "print", Void_typ);

	// scope.Print();
}
<commit_msg>fix to be able to run full gofmt test<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package SymbolTable

import (
	"container/vector";
	"unicode";
	"utf8";
)

// ----------------------------------------------------------------------------
// Support

func assert(pred bool) {
	if !pred {
		panic("assertion failed");
	}
}

// ----------------------------------------------------------------------------
// Objects

// Object represents a language object, such as a constant, variable, type, etc.

const /* kind */ (
	BADOBJ = iota;  // error handling
	NONE;  // kind unknown
	CONST; TYPE; VAR; FIELD; FUNC; BUILTIN; PACKAGE; LABEL;
	END;  // end of scope (import/export only)
)

func KindStr(kind int) string {
	switch kind {
	case BADOBJ: return "BADOBJ";
	case NONE: return "NONE";
	case CONST: return "CONST";
	case TYPE: return "TYPE";
	case VAR: return "VAR";
	case FIELD: return "FIELD";
	case FUNC: return "FUNC";
	case BUILTIN: return "BUILTIN";
	case PACKAGE: return "PACKAGE";
	case LABEL: return "LABEL";
	case END: return "END";
	}
	return "<unknown Object kind>";
}

type Object struct {
	Id int;  // unique id

	Pos int;  // source position (< 0 if unknown position)
	Kind int;  // object kind
	Ident string;
	Typ *Type;  // nil for packages
	Pnolev int;  // >= 0: package no., <= 0: function nesting level, 0: global level
}

func (obj *Object) IsExported() bool {
	switch obj.Kind {
	case NONE /* FUNC for now */, CONST, TYPE, VAR, FUNC:
		ch, size := utf8.DecodeRuneInString(obj.Ident);
		return unicode.IsUpper(ch);
	}
	return false;
}

func (obj* Object) String() string {
	if obj != nil {
		return
			"Object(" +
			KindStr(obj.Kind) + ", " +
			obj.Ident +
			")";
	}
	return "nil";
}

var Universe_void_typ *Type  // initialized by Universe to Universe.void_typ
var objectId int;

func NewObject(pos, kind int, ident string) *Object {
	obj := new(Object);
	obj.Id = objectId;
	objectId++;

	obj.Pos = pos;
	obj.Kind = kind;
	obj.Ident = ident;
	obj.Typ = Universe_void_typ;  // TODO would it be better to use nil instead?
	obj.Pnolev = 0;

	return obj;
}

// ----------------------------------------------------------------------------
// Scopes

type Scope struct {
	Parent *Scope;
	entries map[string] *Object;
}

func NewScope(parent *Scope) *Scope {
	scope := new(Scope);
	scope.Parent = parent;
	scope.entries = make(map[string] *Object, 8);
	return scope;
}

func (scope *Scope) LookupLocal(ident string) *Object {
	obj, found := scope.entries[ident];
	if found {
		return obj;
	}
	return nil;
}

func (scope *Scope) Lookup(ident string) *Object {
	for scope != nil {
		obj := scope.LookupLocal(ident);
		if obj != nil {
			return obj;
		}
		scope = scope.Parent;
	}
	return nil;
}

func (scope *Scope) add(obj *Object) {
	scope.entries[obj.Ident] = obj;
}

func (scope *Scope) Insert(obj *Object) {
	if scope.LookupLocal(obj.Ident) != nil {
		panic("obj already inserted");
	}
	scope.add(obj);
}

func (scope *Scope) InsertImport(obj *Object) *Object {
	 p := scope.LookupLocal(obj.Ident);
	 if p == nil {
		scope.add(obj);
		p = obj;
	 }
	 return p;
}

func (scope *Scope) Print() {
	print("scope {");
	for key := range scope.entries {
		print("\n  ", key);
	}
	print("\n}\n");
}

// ----------------------------------------------------------------------------
// Types

const /* form */ (
	// internal types
	// We should never see one of these.
	UNDEF = iota;

	// VOID types are used when we don't have a type. Never exported.
	// (exported type forms must be > 0)
	VOID;

	// BADTYPE types are compatible with any type and don't cause further errors.
	// They are introduced only as a result of an error in the source code. A
	// correct program cannot have BAD types.
	BADTYPE;

	// FORWARD types are forward-declared (incomplete) types. They can only
	// be used as element types of pointer types and must be resolved before
	// their internals are accessible.
	FORWARD;

	// TUPLE types represent multi-valued result types of functions and
	// methods.
	TUPLE;

	// The type of nil.
	NIL;

	// A type name
	TYPENAME;

	// basic types
	BOOL; UINT; INT; FLOAT; STRING; INTEGER;

	// composite types
	ALIAS; ARRAY; STRUCT; INTERFACE; MAP; CHANNEL; FUNCTION; METHOD; POINTER;

	// open-ended parameter type
	ELLIPSIS
)

func FormStr(form int) string {
	switch form {
	case VOID: return "VOID";
	case BADTYPE: return "BADTYPE";
	case FORWARD: return "FORWARD";
	case TUPLE: return "TUPLE";
	case NIL: return "NIL";
	case TYPENAME: return "TYPENAME";
	case BOOL: return "BOOL";
	case UINT: return "UINT";
	case INT: return "INT";
	case FLOAT: return "FLOAT";
	case STRING: return "STRING";
	case ALIAS: return "ALIAS";
	case ARRAY: return "ARRAY";
	case STRUCT: return "STRUCT";
	case INTERFACE: return "INTERFACE";
	case MAP: return "MAP";
	case CHANNEL: return "CHANNEL";
	case FUNCTION: return "FUNCTION";
	case METHOD: return "METHOD";
	case POINTER: return "POINTER";
	case ELLIPSIS: return "ELLIPSIS";
	}
	return "<unknown Type form>";
}

const /* channel mode */ (
	FULL = iota;
	SEND;
	RECV;
)

type Type struct {
	Id int;  // unique id

	Ref int;  // for exporting only: >= 0 means already exported
	Form int;  // type form
	Size int;  // size in bytes
	Obj *Object;  // primary type object or nil
	Scope *Scope;  // locals, fields & methods

	// syntactic components
	Pos int;  // source position (< 0 if unknown position)
	Len int;  // array length
	Mode int;  // channel mode
	Key *Type;  // receiver type or map key
	Elt *Type;  // type name type, array, map, channel or pointer element type, function result type
	List *vector.Vector; End int;  // struct fields, interface methods, function parameters
}

var typeId int;

func NewType(pos, form int) *Type {
	typ := new(Type);
	typ.Id = typeId;
	typeId++;

	typ.Ref = -1;  // not yet exported
	typ.Pos = pos;
	typ.Form = form;

	return typ;
}

func (typ* Type) String() string {
	if typ != nil {
		return
			"Type(" +
			FormStr(typ.Form) +
			")";
	}
	return "nil";
}

// ----------------------------------------------------------------------------
// Universe scope

var (
	Universe *Scope;
	PredeclaredTypes vector.Vector;

	// internal types
	Void_typ,
	Bad_typ,
	Nil_typ,

	// basic types
	Bool_typ,
	Uint8_typ,
	Uint16_typ,
	Uint32_typ,
	Uint64_typ,
	Int8_typ,
	Int16_typ,
	Int32_typ,
	Int64_typ,
	Float32_typ,
	Float64_typ,
	Float80_typ,
	String_typ,
	Integer_typ,

	// convenience types
	Byte_typ,
	Uint_typ,
	Int_typ,
	Float_typ,
	Uintptr_typ *Type;

	True_obj,
	False_obj,
	Iota_obj,
	Nil_obj *Object;
)

func declObj(kind int, ident string, typ *Type) *Object {
	obj := NewObject(-1 /* no source pos */, kind, ident);
	obj.Typ = typ;
	if kind == TYPE && typ.Obj == nil {
		typ.Obj = obj;  // set primary type object
	}
	Universe.Insert(obj);
	return obj
}

func declType(form int, ident string, size int) *Type {
  typ := NewType(-1 /* no source pos */, form);
  typ.Size = size;
  return declObj(TYPE, ident, typ).Typ;
}

func register(typ *Type) *Type {
	typ.Ref = PredeclaredTypes.Len();
	PredeclaredTypes.Push(typ);
	return typ;
}

func init() {
	Universe = NewScope(nil);  // universe has no parent
	PredeclaredTypes.Init(32);

	// Interal types
	Void_typ = NewType(-1 /* no source pos */, VOID);
	Universe_void_typ = Void_typ;
	Bad_typ = NewType(-1 /* no source pos */, BADTYPE);
	Nil_typ = NewType(-1 /* no source pos */, NIL);

	// Basic types
	Bool_typ = register(declType(BOOL, "bool", 1));
	Uint8_typ = register(declType(UINT, "uint8", 1));
	Uint16_typ = register(declType(UINT, "uint16", 2));
	Uint32_typ = register(declType(UINT, "uint32", 4));
	Uint64_typ = register(declType(UINT, "uint64", 8));
	Int8_typ = register(declType(INT, "int8", 1));
	Int16_typ = register(declType(INT, "int16", 2));
	Int32_typ = register(declType(INT, "int32", 4));
	Int64_typ = register(declType(INT, "int64", 8));
	Float32_typ = register(declType(FLOAT, "float32", 4));
	Float64_typ = register(declType(FLOAT, "float64", 8));
	Float80_typ = register(declType(FLOAT, "float80", 10));
	String_typ = register(declType(STRING, "string", 8));
	Integer_typ = register(declType(INTEGER, "integer", 8));

	// All but 'byte' should be platform-dependent, eventually.
	Byte_typ = register(declType(UINT, "byte", 1));
	Uint_typ = register(declType(UINT, "uint", 4));
	Int_typ = register(declType(INT, "int", 4));
	Float_typ = register(declType(FLOAT, "float", 4));
	Uintptr_typ = register(declType(UINT, "uintptr", 8));

	// Predeclared constants
	True_obj = declObj(CONST, "true", Bool_typ);
	False_obj = declObj(CONST, "false", Bool_typ);
	Iota_obj = declObj(CONST, "iota", Int_typ);
	Nil_obj = declObj(CONST, "nil", Nil_typ);

	// Builtin functions
	declObj(BUILTIN, "len", Void_typ);
	declObj(BUILTIN, "new", Void_typ);
	declObj(BUILTIN, "panic", Void_typ);
	declObj(BUILTIN, "print", Void_typ);

	// scope.Print();
}
<|endoftext|>


<commit_before>package gtk

// #include <gtk/gtk.h>
// #include "gtk.go.h"
import "C"
import (
	"errors"
	"unsafe"

	"github.com/gotk3/gotk3/glib"
)

func init() {
	tm := []glib.TypeMarshaler{
		{glib.Type(C.gtk_combo_box_get_type()), marshalComboBox},
		{glib.Type(C.gtk_combo_box_text_get_type()), marshalComboBoxText},
	}

	glib.RegisterGValueMarshalers(tm)

	WrapMap["GtkComboBox"] = wrapComboBox
	WrapMap["GtkComboBoxText"] = wrapComboBoxText
}

/*
 * GtkComboBox
 */

// ComboBox is a representation of GTK's GtkComboBox.
type ComboBox struct {
	Bin

	// Interfaces
	CellLayout
}

// native returns a pointer to the underlying GtkComboBox.
func (v *ComboBox) native() *C.GtkComboBox {
	if v == nil || v.GObject == nil {
		return nil
	}
	p := unsafe.Pointer(v.GObject)
	return C.toGtkComboBox(p)
}

func (v *ComboBox) toCellLayout() *C.GtkCellLayout {
	if v == nil {
		return nil
	}
	return C.toGtkCellLayout(unsafe.Pointer(v.GObject))
}

func marshalComboBox(p uintptr) (interface{}, error) {
	c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBox(obj), nil
}

func wrapComboBox(obj *glib.Object) *ComboBox {
	cl := wrapCellLayout(obj)
	return &ComboBox{Bin{Container{Widget{glib.InitiallyUnowned{obj}}}}, *cl}
}

// ComboBoxNew() is a wrapper around gtk_combo_box_new().
func ComboBoxNew() (*ComboBox, error) {
	c := C.gtk_combo_box_new()
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBox(obj), nil
}

// ComboBoxNewWithEntry() is a wrapper around gtk_combo_box_new_with_entry().
func ComboBoxNewWithEntry() (*ComboBox, error) {
	c := C.gtk_combo_box_new_with_entry()
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBox(obj), nil
}

// ComboBoxNewWithModel() is a wrapper around gtk_combo_box_new_with_model().
func ComboBoxNewWithModel(model ITreeModel) (*ComboBox, error) {
	c := C.gtk_combo_box_new_with_model(model.toTreeModel())
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBox(obj), nil
}

// GetActive() is a wrapper around gtk_combo_box_get_active().
func (v *ComboBox) GetActive() int {
	c := C.gtk_combo_box_get_active(v.native())
	return int(c)
}

// SetActive() is a wrapper around gtk_combo_box_set_active().
func (v *ComboBox) SetActive(index int) {
	C.gtk_combo_box_set_active(v.native(), C.gint(index))
}

// GetActiveIter is a wrapper around gtk_combo_box_get_active_iter().
func (v *ComboBox) GetActiveIter() (*TreeIter, error) {
	var cIter C.GtkTreeIter
	c := C.gtk_combo_box_get_active_iter(v.native(), &cIter)
	if !gobool(c) {
		return nil, errors.New("unable to get active iter")
	}
	return &TreeIter{cIter}, nil
}

// SetActiveIter is a wrapper around gtk_combo_box_set_active_iter().
func (v *ComboBox) SetActiveIter(iter *TreeIter) {
	var cIter *C.GtkTreeIter
	if iter != nil {
		cIter = &iter.GtkTreeIter
	}
	C.gtk_combo_box_set_active_iter(v.native(), cIter)
}

// GetEntryTextColumn is a wrapper around gtk_combo_box_get_entry_text_column()
func (v *ComboBox) GetEntryTextColumn() int {
	c := C.gtk_combo_box_get_entry_text_column(v.native())
	return int(c)
}

// SetEntryTextColumn is a wrapper around gtk_combo_box_set_entry_text_column()
func (v *ComboBox) SetEntryTextColumn(textColumn int) {
	C.gtk_combo_box_set_entry_text_column(v.native(), C.gint(textColumn))
}

// GetActiveID is a wrapper around gtk_combo_box_get_active_id().
func (v *ComboBox) GetActiveID() string {
	c := C.gtk_combo_box_get_active_id(v.native())
	return C.GoString((*C.char)(c))
}

// SetActiveID is a wrapper around gtk_combo_box_set_active_id().
func (v *ComboBox) SetActiveID(id string) bool {
	cid := C.CString(id)
	defer C.free(unsafe.Pointer(cid))
	c := C.gtk_combo_box_set_active_id(v.native(), (*C.gchar)(cid))
	return gobool(c)
}

// GetModel is a wrapper around gtk_combo_box_get_model().
func (v *ComboBox) GetModel() (*TreeModel, error) {
	c := C.gtk_combo_box_get_model(v.native())
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapTreeModel(obj), nil
}

// SetModel is a wrapper around gtk_combo_box_set_model().
func (v *ComboBox) SetModel(model ITreeModel) {
	var mptr *C.GtkTreeModel
	if model != nil {
		mptr = model.toTreeModel()
	}
	C.gtk_combo_box_set_model(v.native(), mptr)
}

func (v *ComboBox) Popup() {
	C.gtk_combo_box_popup(v.native())
}

func (v *ComboBox) Popdown() {
	C.gtk_combo_box_popdown(v.native())
}

// GetIDColumn is a wrapper around gtk_combo_box_get_id_column()
func (v *ComboBox) GetIDColumn() int {
	c := C.gtk_combo_box_get_id_column(v.native())
	return int(c)
}

// SetIDColumn is a wrapper around gtk_combo_box_set_id_column()
func (v *ComboBox) SetIDColumn(idColumn int) {
	C.gtk_combo_box_set_id_column(v.native(), C.gint(idColumn))
}

/*
 * GtkComboBoxText
 */

// ComboBoxText is a representation of GTK's GtkComboBoxText.
type ComboBoxText struct {
	ComboBox
}

// native returns a pointer to the underlying GtkComboBoxText.
func (v *ComboBoxText) native() *C.GtkComboBoxText {
	if v == nil || v.GObject == nil {
		return nil
	}
	p := unsafe.Pointer(v.GObject)
	return C.toGtkComboBoxText(p)
}

func marshalComboBoxText(p uintptr) (interface{}, error) {
	c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBoxText(obj), nil
}

func wrapComboBoxText(obj *glib.Object) *ComboBoxText {
	return &ComboBoxText{*wrapComboBox(obj)}
}

// ComboBoxTextNew is a wrapper around gtk_combo_box_text_new().
func ComboBoxTextNew() (*ComboBoxText, error) {
	c := C.gtk_combo_box_text_new()
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBoxText(obj), nil
}

// ComboBoxTextNewWithEntry is a wrapper around gtk_combo_box_text_new_with_entry().
func ComboBoxTextNewWithEntry() (*ComboBoxText, error) {
	c := C.gtk_combo_box_text_new_with_entry()
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBoxText(obj), nil
}

// Append is a wrapper around gtk_combo_box_text_append().
func (v *ComboBoxText) Append(id, text string) {
	cid := C.CString(id)
	ctext := C.CString(text)
	defer C.free(unsafe.Pointer(cid))
	defer C.free(unsafe.Pointer(ctext))
	C.gtk_combo_box_text_append(v.native(), (*C.gchar)(cid), (*C.gchar)(ctext))
}

// Prepend is a wrapper around gtk_combo_box_text_prepend().
func (v *ComboBoxText) Prepend(id, text string) {
	cid := C.CString(id)
	ctext := C.CString(text)
	defer C.free(unsafe.Pointer(cid))
	defer C.free(unsafe.Pointer(ctext))
	C.gtk_combo_box_text_prepend(v.native(), (*C.gchar)(cid), (*C.gchar)(ctext))
}

// Insert is a wrapper around gtk_combo_box_text_insert().
func (v *ComboBoxText) Insert(position int, id, text string) {
	cid := C.CString(id)
	ctext := C.CString(text)
	defer C.free(unsafe.Pointer(cid))
	defer C.free(unsafe.Pointer(ctext))
	C.gtk_combo_box_text_insert(v.native(), C.gint(position), (*C.gchar)(cid), (*C.gchar)(ctext))
}

// AppendText is a wrapper around gtk_combo_box_text_append_text().
func (v *ComboBoxText) AppendText(text string) {
	cstr := C.CString(text)
	defer C.free(unsafe.Pointer(cstr))
	C.gtk_combo_box_text_append_text(v.native(), (*C.gchar)(cstr))
}

// PrependText is a wrapper around gtk_combo_box_text_prepend_text().
func (v *ComboBoxText) PrependText(text string) {
	cstr := C.CString(text)
	defer C.free(unsafe.Pointer(cstr))
	C.gtk_combo_box_text_prepend_text(v.native(), (*C.gchar)(cstr))
}

// InsertText is a wrapper around gtk_combo_box_text_insert_text().
func (v *ComboBoxText) InsertText(position int, text string) {
	cstr := C.CString(text)
	defer C.free(unsafe.Pointer(cstr))
	C.gtk_combo_box_text_insert_text(v.native(), C.gint(position), (*C.gchar)(cstr))
}

// Remove is a wrapper around gtk_combo_box_text_remove().
func (v *ComboBoxText) Remove(position int) {
	C.gtk_combo_box_text_remove(v.native(), C.gint(position))
}

// RemoveAll is a wrapper around gtk_combo_box_text_remove_all().
func (v *ComboBoxText) RemoveAll() {
	C.gtk_combo_box_text_remove_all(v.native())
}

// GetActiveText is a wrapper around gtk_combo_box_text_get_active_text().
func (v *ComboBoxText) GetActiveText() string {
	c := (*C.char)(C.gtk_combo_box_text_get_active_text(v.native()))
	defer C.free(unsafe.Pointer(c))
	return C.GoString(c)
}
<commit_msg>convenience func GetEntry() added<commit_after>package gtk

// #include <gtk/gtk.h>
// #include "gtk.go.h"
import "C"
import (
	"errors"
	"unsafe"

	"github.com/gotk3/gotk3/glib"
)

func init() {
	tm := []glib.TypeMarshaler{
		{glib.Type(C.gtk_combo_box_get_type()), marshalComboBox},
		{glib.Type(C.gtk_combo_box_text_get_type()), marshalComboBoxText},
	}

	glib.RegisterGValueMarshalers(tm)

	WrapMap["GtkComboBox"] = wrapComboBox
	WrapMap["GtkComboBoxText"] = wrapComboBoxText
}

/*
 * GtkComboBox
 */

// ComboBox is a representation of GTK's GtkComboBox.
type ComboBox struct {
	Bin

	// Interfaces
	CellLayout
}

// native returns a pointer to the underlying GtkComboBox.
func (v *ComboBox) native() *C.GtkComboBox {
	if v == nil || v.GObject == nil {
		return nil
	}
	p := unsafe.Pointer(v.GObject)
	return C.toGtkComboBox(p)
}

func (v *ComboBox) toCellLayout() *C.GtkCellLayout {
	if v == nil {
		return nil
	}
	return C.toGtkCellLayout(unsafe.Pointer(v.GObject))
}

func marshalComboBox(p uintptr) (interface{}, error) {
	c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBox(obj), nil
}

func wrapComboBox(obj *glib.Object) *ComboBox {
	cl := wrapCellLayout(obj)
	return &ComboBox{Bin{Container{Widget{glib.InitiallyUnowned{obj}}}}, *cl}
}

// ComboBoxNew() is a wrapper around gtk_combo_box_new().
func ComboBoxNew() (*ComboBox, error) {
	c := C.gtk_combo_box_new()
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBox(obj), nil
}

// ComboBoxNewWithEntry() is a wrapper around gtk_combo_box_new_with_entry().
func ComboBoxNewWithEntry() (*ComboBox, error) {
	c := C.gtk_combo_box_new_with_entry()
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBox(obj), nil
}

// ComboBoxNewWithModel() is a wrapper around gtk_combo_box_new_with_model().
func ComboBoxNewWithModel(model ITreeModel) (*ComboBox, error) {
	c := C.gtk_combo_box_new_with_model(model.toTreeModel())
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBox(obj), nil
}

// GetActive() is a wrapper around gtk_combo_box_get_active().
func (v *ComboBox) GetActive() int {
	c := C.gtk_combo_box_get_active(v.native())
	return int(c)
}

// SetActive() is a wrapper around gtk_combo_box_set_active().
func (v *ComboBox) SetActive(index int) {
	C.gtk_combo_box_set_active(v.native(), C.gint(index))
}

// GetActiveIter is a wrapper around gtk_combo_box_get_active_iter().
func (v *ComboBox) GetActiveIter() (*TreeIter, error) {
	var cIter C.GtkTreeIter
	c := C.gtk_combo_box_get_active_iter(v.native(), &cIter)
	if !gobool(c) {
		return nil, errors.New("unable to get active iter")
	}
	return &TreeIter{cIter}, nil
}

// SetActiveIter is a wrapper around gtk_combo_box_set_active_iter().
func (v *ComboBox) SetActiveIter(iter *TreeIter) {
	var cIter *C.GtkTreeIter
	if iter != nil {
		cIter = &iter.GtkTreeIter
	}
	C.gtk_combo_box_set_active_iter(v.native(), cIter)
}

// GetEntry is a convenience func to get the Entry within the ComboBox.
// If the Combobox does not contain an Entry, an error is returned.
func (v *ComboBox) GetEntry() (*Entry, error) {
	hasEntry := C.gtk_combo_box_get_has_entry(v.native())
	if hasEntry == C.FALSE {
		return nil, errors.New("combobox has no entry")
	}
	bin := &v.Bin
	widget, err := bin.GetChild()
	if err != nil {
		return nil, err
	}
	obj := glib.Take(unsafe.Pointer(widget.GObject))
	return wrapEntry(obj), nil
}

// GetEntryTextColumn is a wrapper around gtk_combo_box_get_entry_text_column()
func (v *ComboBox) GetEntryTextColumn() int {
	c := C.gtk_combo_box_get_entry_text_column(v.native())
	return int(c)
}

// SetEntryTextColumn is a wrapper around gtk_combo_box_set_entry_text_column()
func (v *ComboBox) SetEntryTextColumn(textColumn int) {
	C.gtk_combo_box_set_entry_text_column(v.native(), C.gint(textColumn))
}

// GetActiveID is a wrapper around gtk_combo_box_get_active_id().
func (v *ComboBox) GetActiveID() string {
	c := C.gtk_combo_box_get_active_id(v.native())
	return C.GoString((*C.char)(c))
}

// SetActiveID is a wrapper around gtk_combo_box_set_active_id().
func (v *ComboBox) SetActiveID(id string) bool {
	cid := C.CString(id)
	defer C.free(unsafe.Pointer(cid))
	c := C.gtk_combo_box_set_active_id(v.native(), (*C.gchar)(cid))
	return gobool(c)
}

// GetModel is a wrapper around gtk_combo_box_get_model().
func (v *ComboBox) GetModel() (*TreeModel, error) {
	c := C.gtk_combo_box_get_model(v.native())
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapTreeModel(obj), nil
}

// SetModel is a wrapper around gtk_combo_box_set_model().
func (v *ComboBox) SetModel(model ITreeModel) {
	var mptr *C.GtkTreeModel
	if model != nil {
		mptr = model.toTreeModel()
	}
	C.gtk_combo_box_set_model(v.native(), mptr)
}

func (v *ComboBox) Popup() {
	C.gtk_combo_box_popup(v.native())
}

func (v *ComboBox) Popdown() {
	C.gtk_combo_box_popdown(v.native())
}

// GetIDColumn is a wrapper around gtk_combo_box_get_id_column()
func (v *ComboBox) GetIDColumn() int {
	c := C.gtk_combo_box_get_id_column(v.native())
	return int(c)
}

// SetIDColumn is a wrapper around gtk_combo_box_set_id_column()
func (v *ComboBox) SetIDColumn(idColumn int) {
	C.gtk_combo_box_set_id_column(v.native(), C.gint(idColumn))
}

/*
 * GtkComboBoxText
 */

// ComboBoxText is a representation of GTK's GtkComboBoxText.
type ComboBoxText struct {
	ComboBox
}

// native returns a pointer to the underlying GtkComboBoxText.
func (v *ComboBoxText) native() *C.GtkComboBoxText {
	if v == nil || v.GObject == nil {
		return nil
	}
	p := unsafe.Pointer(v.GObject)
	return C.toGtkComboBoxText(p)
}

func marshalComboBoxText(p uintptr) (interface{}, error) {
	c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBoxText(obj), nil
}

func wrapComboBoxText(obj *glib.Object) *ComboBoxText {
	return &ComboBoxText{*wrapComboBox(obj)}
}

// ComboBoxTextNew is a wrapper around gtk_combo_box_text_new().
func ComboBoxTextNew() (*ComboBoxText, error) {
	c := C.gtk_combo_box_text_new()
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBoxText(obj), nil
}

// ComboBoxTextNewWithEntry is a wrapper around gtk_combo_box_text_new_with_entry().
func ComboBoxTextNewWithEntry() (*ComboBoxText, error) {
	c := C.gtk_combo_box_text_new_with_entry()
	if c == nil {
		return nil, nilPtrErr
	}
	obj := glib.Take(unsafe.Pointer(c))
	return wrapComboBoxText(obj), nil
}

// Append is a wrapper around gtk_combo_box_text_append().
func (v *ComboBoxText) Append(id, text string) {
	cid := C.CString(id)
	ctext := C.CString(text)
	defer C.free(unsafe.Pointer(cid))
	defer C.free(unsafe.Pointer(ctext))
	C.gtk_combo_box_text_append(v.native(), (*C.gchar)(cid), (*C.gchar)(ctext))
}

// Prepend is a wrapper around gtk_combo_box_text_prepend().
func (v *ComboBoxText) Prepend(id, text string) {
	cid := C.CString(id)
	ctext := C.CString(text)
	defer C.free(unsafe.Pointer(cid))
	defer C.free(unsafe.Pointer(ctext))
	C.gtk_combo_box_text_prepend(v.native(), (*C.gchar)(cid), (*C.gchar)(ctext))
}

// Insert is a wrapper around gtk_combo_box_text_insert().
func (v *ComboBoxText) Insert(position int, id, text string) {
	cid := C.CString(id)
	ctext := C.CString(text)
	defer C.free(unsafe.Pointer(cid))
	defer C.free(unsafe.Pointer(ctext))
	C.gtk_combo_box_text_insert(v.native(), C.gint(position), (*C.gchar)(cid), (*C.gchar)(ctext))
}

// AppendText is a wrapper around gtk_combo_box_text_append_text().
func (v *ComboBoxText) AppendText(text string) {
	cstr := C.CString(text)
	defer C.free(unsafe.Pointer(cstr))
	C.gtk_combo_box_text_append_text(v.native(), (*C.gchar)(cstr))
}

// PrependText is a wrapper around gtk_combo_box_text_prepend_text().
func (v *ComboBoxText) PrependText(text string) {
	cstr := C.CString(text)
	defer C.free(unsafe.Pointer(cstr))
	C.gtk_combo_box_text_prepend_text(v.native(), (*C.gchar)(cstr))
}

// InsertText is a wrapper around gtk_combo_box_text_insert_text().
func (v *ComboBoxText) InsertText(position int, text string) {
	cstr := C.CString(text)
	defer C.free(unsafe.Pointer(cstr))
	C.gtk_combo_box_text_insert_text(v.native(), C.gint(position), (*C.gchar)(cstr))
}

// Remove is a wrapper around gtk_combo_box_text_remove().
func (v *ComboBoxText) Remove(position int) {
	C.gtk_combo_box_text_remove(v.native(), C.gint(position))
}

// RemoveAll is a wrapper around gtk_combo_box_text_remove_all().
func (v *ComboBoxText) RemoveAll() {
	C.gtk_combo_box_text_remove_all(v.native())
}

// GetActiveText is a wrapper around gtk_combo_box_text_get_active_text().
func (v *ComboBoxText) GetActiveText() string {
	c := (*C.char)(C.gtk_combo_box_text_get_active_text(v.native()))
	defer C.free(unsafe.Pointer(c))
	return C.GoString(c)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
    "html/template"
    "log"
	"strings"
    "net/http"
	//"strconv"
	"time"
	"io/ioutil"

	"main/locdata"

	"github.com/golang/protobuf/proto"
    "github.com/gorilla/mux"
)

var err error

type Page struct {
    Title string
}

func main() {
	router := mux.NewRouter().StrictSlash(true)
    router.HandleFunc("/", Index)
	router.HandleFunc("/locations", GetAllLocations)
	router.HandleFunc("/locations/{latitude1}/{longitude1}/{latitude2}/{longitude2}", GetLocations)

	router.PathPrefix("/").Handler(http.FileServer(http.Dir("/home")))

	http.Handle("/", router)
    log.Fatal(http.ListenAndServe(":80", router))
}

func Index(w http.ResponseWriter, r *http.Request) {
	t, _ := template.ParseFiles("/home/tpl/index.html")
	p := &Page{Title: "Homepage"}
	t.Execute(w, p)
}

func GetAllLocations(w http.ResponseWriter, r *http.Request) {
	t0 := time.Now()

	requestStr := fmt.Sprintf("http://heatmap-endpoint.salscode.com/locations/")
	resp, err := http.Get(requestStr)
	checkErr(err)

	locResp, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()

	locations := &locdata.LocDisplayData{}

	err = proto.Unmarshal(locResp, locations)
	checkErr(err)

	printLocations(w, locations)

	t1 := time.Now()
    fmt.Printf("The call took %v to run.\n", t1.Sub(t0))
}

func GetLocations(w http.ResponseWriter, r *http.Request) {
	t0 := time.Now()

	vars := mux.Vars(r)

	requestStr := fmt.Sprintf("http://heatmap-endpoint.salscode.com/locations/%s/%s/%s/%s/", vars["latitude1"], vars["longitude1"], vars["latitude2"], vars["longitude2"])
	resp, err := http.Get(requestStr)
	checkErr(err)

	locResp, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()

	locations := &locdata.LocDisplayData{}

	err = proto.Unmarshal(locResp, locations)
	checkErr(err)

	printLocations(w, locations)

	t1 := time.Now()
    fmt.Printf("The call took %v to run.\n", t1.Sub(t0))
}

func printLocations(w http.ResponseWriter, locations *locdata.LocDisplayData) {
	var locStr string = "";
	for _, each := range locations.Lldata {
		str := strings.Replace(fmt.Sprintf(*locations.Coordformat, *each.Latitude, *each.Longitude, *each.Intensity), " ", "", -1)
        locStr += str
	}

	fmt.Fprintf(w, "// %d Locations\n", *locations.Count)
    fmt.Fprintf(w, "var locations = [%s];", locStr)
}

func checkErr(inerr error) {
    if inerr != nil {
        panic(inerr)
    }
}<commit_msg>Add Basic Test<commit_after>package main

import (
	"fmt"
    "html/template"
    "log"
	"io"
	"strings"
    "net/http"
	//"strconv"
	"time"
	"io/ioutil"

	"main/locdata"

	"github.com/golang/protobuf/proto"
    "github.com/gorilla/mux"
)

var err error

type Page struct {
    Title string
}

func main() {
	router := mux.NewRouter().StrictSlash(true)
    router.HandleFunc("/", Index)
	router.HandleFunc("/test", GetTest)
	router.HandleFunc("/locations", GetAllLocations)
	router.HandleFunc("/locations/{latitude1}/{longitude1}/{latitude2}/{longitude2}", GetLocations)

	router.PathPrefix("/").Handler(http.FileServer(http.Dir("/home")))

	http.Handle("/", router)
    log.Fatal(http.ListenAndServe(":80", router))
}

func Index(w http.ResponseWriter, r *http.Request) {
	t, _ := template.ParseFiles("/home/tpl/index.html")
	p := &Page{Title: "Homepage"}
	t.Execute(w, p)
}

func GetTest(w http.ResponseWriter, r *http.Request) {
	// Test all locations at endpoint
	io.WriteString(w, "All location test.\n")
	requestStrAll := fmt.Sprintf("http://heatmap-endpoint.salscode.com/locations/")
	respAll, err := http.Get(requestStrAll)
	checkErr(err)

	locRespAll, err := ioutil.ReadAll(respAll.Body)
	respAll.Body.Close()

	locationsAll := &locdata.LocDisplayData{}

	err = proto.Unmarshal(locRespAll, locationsAll)
	checkErr(err)

	if len(locationsAll.Lldata) <= 0 {
		fmt.Fprintf(w, "Invalid location count of: %d\n", len(locationsAll.Lldata))
	} else {
		fmt.Fprintf(w, "Valid location count of: %d\n", len(locationsAll.Lldata))
	}

	io.WriteString(w, "\n")

	// Test subset of locations at endpoint
	io.WriteString(w, "Location subset test.\n")
	requestStr := fmt.Sprintf("http://heatmap-endpoint.salscode.com/locations/28.7098/43.6917/-96.1083/-61.1499/")
	resp, err := http.Get(requestStr)
	checkErr(err)

	locResp, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()

	locations := &locdata.LocDisplayData{}

	err = proto.Unmarshal(locResp, locations)
	checkErr(err)

	if len(locations.Lldata) <= 0 {
		fmt.Fprintf(w, "Invalid location count of: %d\n", len(locations.Lldata))
	} else {
		fmt.Fprintf(w, "Valid location count of: %d\n", len(locations.Lldata))
	}

	io.WriteString(w, "\n")
}

func GetAllLocations(w http.ResponseWriter, r *http.Request) {
	t0 := time.Now()

	requestStr := fmt.Sprintf("http://heatmap-endpoint.salscode.com/locations/")
	resp, err := http.Get(requestStr)
	checkErr(err)

	locResp, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()

	locations := &locdata.LocDisplayData{}

	err = proto.Unmarshal(locResp, locations)
	checkErr(err)

	printLocations(w, locations)

	t1 := time.Now()
    fmt.Printf("The call took %v to run.\n", t1.Sub(t0))
}

func GetLocations(w http.ResponseWriter, r *http.Request) {
	t0 := time.Now()

	vars := mux.Vars(r)

	requestStr := fmt.Sprintf("http://heatmap-endpoint.salscode.com/locations/%s/%s/%s/%s/", vars["latitude1"], vars["longitude1"], vars["latitude2"], vars["longitude2"])
	resp, err := http.Get(requestStr)
	checkErr(err)

	locResp, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()

	locations := &locdata.LocDisplayData{}

	err = proto.Unmarshal(locResp, locations)
	checkErr(err)

	printLocations(w, locations)

	t1 := time.Now()
    fmt.Printf("The call took %v to run.\n", t1.Sub(t0))
}

func printLocations(w http.ResponseWriter, locations *locdata.LocDisplayData) {
	var locStr string = "";
	for _, each := range locations.Lldata {
		str := strings.Replace(fmt.Sprintf(*locations.Coordformat, *each.Latitude, *each.Longitude, *each.Intensity), " ", "", -1)
        locStr += str
	}

	fmt.Fprintf(w, "// %d Locations\n", *locations.Count)
    fmt.Fprintf(w, "var locations = [%s];", locStr)
}

func checkErr(inerr error) {
    if inerr != nil {
        panic(inerr)
    }
}<|endoftext|>


<commit_before>package brocadevtm

import (
	"fmt"
	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/sky-uk/go-brocade-vtm/api/dns_zone_file"
	"github.com/sky-uk/go-rest-api"
	"regexp"
	"testing"
)

func TestAccBrocadeVTMDNSZoneFileBasic(t *testing.T) {

	randomInt := acctest.RandInt()
	dnsZoneFileName := fmt.Sprintf("acctest_brocadevtm_dns_zone_file-%d", randomInt)
	dnsZoneFileResourceName := "brocadevtm_dns_zone_file.acctest"
	fmt.Printf("\n\nDNS zone file is %s.\n\n", dnsZoneFileName)

	resource.Test(t, resource.TestCase{
		PreCheck: func() {
			testAccPreCheck(t)
		},
		Providers: testAccProviders,
		CheckDestroy: func(state *terraform.State) error {
			return testAccBrocadeVTMDNSZoneFileCheckDestroy(state, dnsZoneFileName)
		},
		Steps: []resource.TestStep{
			{
				Config:      testAccBrocadeVTMDNSZoneFileNoNameTemplate(),
				ExpectError: regexp.MustCompile(`required field is not set`),
			},
			{
				Config: testAccBrocadeDNSZoneFileCreateTemplate(dnsZoneFileName),
				Check: resource.ComposeTestCheckFunc(
					testAccBrocadeVTMDNSZoneFileExists(dnsZoneFileName, dnsZoneFileResourceName),
					resource.TestCheckResourceAttr(dnsZoneFileResourceName, "name", dnsZoneFileName),
					resource.TestCheckResourceAttr(dnsZoneFileResourceName, "dns_zone_file", "$TTL 3600\n"+
						"@\t\t\t\t30\tIN\tSOA\tns1.example.com. hostmaster.isp.sky.com. (\n"+
						"\t\t\t\t\t\t\t01\t; serial\n"+
						"\t\t\t\t\t\t\t3600\t; refresh after 1 hour\n"+
						"\t\t\t\t\t\t\t300\t; retry after 5 minutes\n"+
						"\t\t\t\t\t\t\t1209600\t; expire after 2 weeks\n"+
						"\t\t\t\t\t\t\t30)\t; minimum TTL of 30 seconds\n"+
						"@\t\t\t\t30\tIN\tNS\tns1.example.com.\n"+
						"ns1\t\t\t\t30\tIN\tA\t10.0.0.2\n"+
						"example-service\t\t\t60\tIN\tA\t10.1.0.2\n"+
						"\t\t\t\t60\tIN\tA\t10.1.1.2\n"+
						"another-example-service\t\t60\tIN\tA\t10.2.0.2\n"+
						"\t\t\t\t60\tIN\tA\t10.2.1.2\n"),
				),
			},
			{
				Config: testAccBrocadeDNSZoneFileUpdateTemplate(dnsZoneFileName),
				Check: resource.ComposeTestCheckFunc(
					testAccBrocadeVTMDNSZoneFileExists(dnsZoneFileName, dnsZoneFileResourceName),
					resource.TestCheckResourceAttr(dnsZoneFileResourceName, "name", dnsZoneFileName),
					resource.TestCheckResourceAttr(dnsZoneFileResourceName, "dns_zone_file", "$TTL 3600\n"+
						"@ \t\t\t\t30\tIN \tSOA \tns2.example.com. hostmaster.isp.sky.com. (\n"+
						"\t\t\t\t\t\t\t02\t; serial\n"+
						"\t\t\t\t\t\t\t3600\t; refresh after 1 hour\n"+
						"\t\t\t\t\t\t\t300\t; retry after 5 minutes\n"+
						"\t\t\t\t\t\t\t1209600\t; expire after 2 weeks\n"+
						"\t\t\t\t\t\t\t30)\t; minimum TTL of 30 seconds\n"+
						"@\t\t\t\t30\tIN\tNS\tns2.example.com.\n"+
						"ns1\t\t\t\t30\tIN\tA\t10.10.0.2\nexample-service\t\t\t60\tIN\tA\t10.11.0.2\n"+
						"\t\t\t\t60\tIN\tA\t10.11.1.2\n"+
						"another-example-service\t\t60\tIN\tA\t10.12.0.2\n"+
						"\t\t\t\t60\tIN\tA\t10.12.1.2\n"),
				),
			},
		},
	})
}

func testAccBrocadeVTMDNSZoneFileCheckDestroy(state *terraform.State, name string) error {

	vtmClient := testAccProvider.Meta().(*rest.Client)

	for _, rs := range state.RootModule().Resources {
		if rs.Type != "brocadevtm_dns_zone_file" {
			continue
		}
		if id, ok := rs.Primary.Attributes["id"]; ok && id != "" {
			return nil
		}
		api := dnsZoneFile.NewGetAll()
		err := vtmClient.Do(api)
		if err != nil {
			return fmt.Errorf("Brocade vTM DNS Zone File - error occurred whilst retrieving a list of all DNS zone files")
		}
		for _, dnsZoneFile := range api.ResponseObject().(*dnsZoneFile.DNSZoneFiles).Children {
			if dnsZoneFile.Name == name {
				return fmt.Errorf("Brocade vTM DNS zone file %s still exists", name)
			}
		}
	}
	return nil
}

func testAccBrocadeVTMDNSZoneFileExists(dnsZoneFileName, dnsZoneResourceName string) resource.TestCheckFunc {
	return func(state *terraform.State) error {

		rs, ok := state.RootModule().Resources[dnsZoneResourceName]
		if !ok {
			return fmt.Errorf("\nBrocade vTM DNS zone file %s wasn't found in resources", dnsZoneFileName)
		}
		if rs.Primary.ID == "" {
			return fmt.Errorf("\nBrocade vTM DNS zone file ID not set for %s in resources", dnsZoneFileName)
		}

		vtmClient := testAccProvider.Meta().(*rest.Client)
		api := dnsZoneFile.NewGetAll()
		err := vtmClient.Do(api)
		if err != nil {
			return fmt.Errorf("Error: %+v", err)
		}
		for _, dnsZoneFile := range api.ResponseObject().(*dnsZoneFile.DNSZoneFiles).Children {
			if dnsZoneFile.Name == dnsZoneFileName {
				return nil
			}
		}
		return fmt.Errorf("Brocade vTM DNS zone file %s not found on remote vTM", dnsZoneFileName)
	}
}

func testAccBrocadeVTMDNSZoneFileNoNameTemplate() string {
	return fmt.Sprintf(`
resource "brocadevtm_dns_zone_file" "acctest" {

}
`)
}

func testAccBrocadeDNSZoneFileCreateTemplate(name string) string {
	return fmt.Sprintf(`
resource "brocadevtm_dns_zone_file" "acctest" {
  name = "%s"
  dns_zone_file = <<DNS_ZONE_FILE
$TTL 3600
@				30	IN	SOA	ns1.example.com. hostmaster.isp.sky.com. (
							01	; serial
							3600	; refresh after 1 hour
							300	; retry after 5 minutes
							1209600	; expire after 2 weeks
							30)	; minimum TTL of 30 seconds
@				30	IN	NS	ns1.example.com.
ns1				30	IN	A	10.0.0.2
example-service			60	IN	A	10.1.0.2
				60	IN	A	10.1.1.2
another-example-service		60	IN	A	10.2.0.2
				60	IN	A	10.2.1.2
DNS_ZONE_FILE
}
`, name)
}

func testAccBrocadeDNSZoneFileUpdateTemplate(name string) string {
	return fmt.Sprintf(`
resource "brocadevtm_dns_zone_file" "acctest" {
  name = "%s"
  dns_zone_file = <<DNS_ZONE_FILE
$TTL 3600
@ 				30	IN 	SOA 	ns2.example.com. hostmaster.isp.sky.com. (
							02	; serial
							3600	; refresh after 1 hour
							300	; retry after 5 minutes
							1209600	; expire after 2 weeks
							30)	; minimum TTL of 30 seconds
@				30	IN	NS	ns2.example.com.
ns1				30	IN	A	10.10.0.2
example-service			60	IN	A	10.11.0.2
				60	IN	A	10.11.1.2
another-example-service		60	IN	A	10.12.0.2
				60	IN	A	10.12.1.2
DNS_ZONE_FILE
}
`, name)
}
<commit_msg>Changed test to use regex pattern for zone file test<commit_after>package brocadevtm

import (
	"fmt"
	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/sky-uk/go-brocade-vtm/api/dns_zone_file"
	"github.com/sky-uk/go-rest-api"
	"regexp"
	"testing"
)

func TestAccBrocadeVTMDNSZoneFileBasic(t *testing.T) {

	randomInt := acctest.RandInt()
	dnsZoneFileName := fmt.Sprintf("acctest_brocadevtm_dns_zone_file-%d", randomInt)
	dnsZoneFileResourceName := "brocadevtm_dns_zone_file.acctest"
	fmt.Printf("\n\nDNS zone file is %s.\n\n", dnsZoneFileName)

	resource.Test(t, resource.TestCase{
		PreCheck: func() {
			testAccPreCheck(t)
		},
		Providers: testAccProviders,
		CheckDestroy: func(state *terraform.State) error {
			return testAccBrocadeVTMDNSZoneFileCheckDestroy(state, dnsZoneFileName)
		},
		Steps: []resource.TestStep{
			{
				Config:      testAccBrocadeVTMDNSZoneFileNoNameTemplate(),
				ExpectError: regexp.MustCompile(`required field is not set`),
			},
			{
				Config: testAccBrocadeDNSZoneFileCreateTemplate(dnsZoneFileName),
				Check: resource.ComposeTestCheckFunc(
					testAccBrocadeVTMDNSZoneFileExists(dnsZoneFileName, dnsZoneFileResourceName),
					resource.TestCheckResourceAttr(dnsZoneFileResourceName, "name", dnsZoneFileName),
					resource.TestMatchResourceAttr(dnsZoneFileResourceName,  "dns_zone_file", regexp.MustCompile(`example-service`)),
				),
			},
			{
				Config: testAccBrocadeDNSZoneFileUpdateTemplate(dnsZoneFileName),
				Check: resource.ComposeTestCheckFunc(
					testAccBrocadeVTMDNSZoneFileExists(dnsZoneFileName, dnsZoneFileResourceName),
					resource.TestCheckResourceAttr(dnsZoneFileResourceName, "name", dnsZoneFileName),
					resource.TestMatchResourceAttr(dnsZoneFileResourceName,  "dns_zone_file", regexp.MustCompile(``)),
					resource.TestMatchResourceAttr(dnsZoneFileResourceName,  "dns_zone_file", regexp.MustCompile(`updated-example-service`)),
				),
			},
		},
	})
}

func testAccBrocadeVTMDNSZoneFileCheckDestroy(state *terraform.State, name string) error {

	vtmClient := testAccProvider.Meta().(*rest.Client)

	for _, rs := range state.RootModule().Resources {
		if rs.Type != "brocadevtm_dns_zone_file" {
			continue
		}
		if id, ok := rs.Primary.Attributes["id"]; ok && id != "" {
			return nil
		}
		api := dnsZoneFile.NewGetAll()
		err := vtmClient.Do(api)
		if err != nil {
			return fmt.Errorf("Brocade vTM DNS Zone File - error occurred whilst retrieving a list of all DNS zone files")
		}
		for _, dnsZoneFile := range api.ResponseObject().(*dnsZoneFile.DNSZoneFiles).Children {
			if dnsZoneFile.Name == name {
				return fmt.Errorf("Brocade vTM DNS zone file %s still exists", name)
			}
		}
	}
	return nil
}

func testAccBrocadeVTMDNSZoneFileExists(dnsZoneFileName, dnsZoneResourceName string) resource.TestCheckFunc {
	return func(state *terraform.State) error {

		rs, ok := state.RootModule().Resources[dnsZoneResourceName]
		if !ok {
			return fmt.Errorf("\nBrocade vTM DNS zone file %s wasn't found in resources", dnsZoneFileName)
		}
		if rs.Primary.ID == "" {
			return fmt.Errorf("\nBrocade vTM DNS zone file ID not set for %s in resources", dnsZoneFileName)
		}

		vtmClient := testAccProvider.Meta().(*rest.Client)
		api := dnsZoneFile.NewGetAll()
		err := vtmClient.Do(api)
		if err != nil {
			return fmt.Errorf("Error: %+v", err)
		}
		for _, dnsZoneFile := range api.ResponseObject().(*dnsZoneFile.DNSZoneFiles).Children {
			if dnsZoneFile.Name == dnsZoneFileName {
				return nil
			}
		}
		return fmt.Errorf("Brocade vTM DNS zone file %s not found on remote vTM", dnsZoneFileName)
	}
}

func testAccBrocadeVTMDNSZoneFileNoNameTemplate() string {
	return fmt.Sprintf(`
resource "brocadevtm_dns_zone_file" "acctest" {

}
`)
}

func testAccBrocadeDNSZoneFileCreateTemplate(name string) string {
	return fmt.Sprintf(`
resource "brocadevtm_dns_zone_file" "acctest" {
  name = "%s"
  dns_zone_file = <<DNS_ZONE_FILE
$TTL 3600
@				30	IN	SOA	ns1.example.com. hostmaster.isp.sky.com. (
							01	; serial
							3600	; refresh after 1 hour
							300	; retry after 5 minutes
							1209600	; expire after 2 weeks
							30)	; minimum TTL of 30 seconds
@				30	IN	NS	ns1.example.com.
ns1				30	IN	A	10.0.0.2
example-service			60	IN	A	10.1.0.2
				60	IN	A	10.1.1.2
another-example-service		60	IN	A	10.2.0.2
				60	IN	A	10.2.1.2
DNS_ZONE_FILE
}
`, name)
}

func testAccBrocadeDNSZoneFileUpdateTemplate(name string) string {
	return fmt.Sprintf(`
resource "brocadevtm_dns_zone_file" "acctest" {
  name = "%s"
  dns_zone_file = <<DNS_ZONE_FILE
$TTL 3600
@ 				30	IN 	SOA 	ns2.example.com. hostmaster.isp.sky.com. (
							02	; serial
							3600	; refresh after 1 hour
							300	; retry after 5 minutes
							1209600	; expire after 2 weeks
							30)	; minimum TTL of 30 seconds
@				30	IN	NS	ns2.example.com.
ns1				30	IN	A	10.100.0.2
updated-example-service		30	IN	A	10.110.0.2
				30	IN	A	10.110.1.2
another-example-service		30	IN	A	10.120.0.2
				30	IN	A	10.120.1.2
DNS_ZONE_FILE
}
`, name)
}
<|endoftext|>


<commit_before>// Copyright 2016 The LUCI Authors.
//
// 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 (
	"encoding/json"
	"fmt"
	"strconv"

	"github.com/google/uuid"
	"github.com/maruel/subcommands"

	"go.chromium.org/luci/auth"
	"go.chromium.org/luci/common/api/buildbucket/buildbucket/v1"
	"go.chromium.org/luci/common/cli"
	"go.chromium.org/luci/common/errors"
	"go.chromium.org/luci/common/logging"
)

func cmdPutBatch(defaultAuthOpts auth.Options) *subcommands.Command {
	return &subcommands.Command{
		UsageLine: `put [flags] <JSON request>...`,
		ShortDesc: "schedule builds",
		LongDesc: "Schedule builds. \n" +
			"See https://godoc.org/go.chromium.org/luci/common/api/" +
			"buildbucket/buildbucket/v1#ApiPutBatchRequestMessage " +
			"for JSON request message schema.",
		CommandRun: func() subcommands.CommandRun {
			c := &putBatchRun{}
			c.SetDefaultFlags(defaultAuthOpts)
			return c
		},
	}
}

type putBatchRun struct {
	baseCommandRun
}

func parsePutRequest(args []string, prefixFunc func() (string, error)) (*buildbucket.ApiPutBatchRequestMessage, error) {
	if len(args) <= 0 {
		return nil, fmt.Errorf("missing parameter: <JSON Request>")
	}

	req := &buildbucket.ApiPutBatchRequestMessage{}
	opIDPrefix := ""
	for i, a := range args {
		// verify that args are valid here before sending the request.
		putReq := &buildbucket.ApiPutRequestMessage{}
		if err := json.Unmarshal([]byte(a), putReq); err != nil {
			return nil, errors.Annotate(err, "invalid build request #%d", i).Err()
		}
		if putReq.ClientOperationId == "" {
			if opIDPrefix == "" {
				var err error
				opIDPrefix, err = prefixFunc()
				if err != nil {
					return nil, err
				}
			}
			putReq.ClientOperationId = opIDPrefix + "-" + strconv.Itoa(i)
		}
		req.Builds = append(req.Builds, putReq)
	}

	return req, nil
}

func (r *putBatchRun) Run(a subcommands.Application, args []string, env subcommands.Env) int {
	ctx := cli.GetContext(a, r, env)

	req, err := parsePutRequest(args, func() (string, error) {
		id, err := uuid.NewRandom()
		return id.String(), err
	})
	if err != nil {
		return r.done(ctx, err)
	}

	client, err := r.createClient(ctx)
	if err != nil {
		return r.done(ctx, err)
	}

	resBytes, err := client.call(ctx, "PUT", "builds/batch", req)
	if err != nil {
		return r.done(ctx, err)
	}

	var res buildbucket.ApiPutBatchResponseMessage
	if err := json.Unmarshal(resBytes, &res); err != nil {
		return r.done(ctx, err)
	}

	hasErrors := false

	if res.Error != nil {
		hasErrors = true
		logging.Errorf(ctx, "Failed to schedule builds (reason: %s): %s",
			res.Error.Reason, res.Error.Message)
	}

	for i, r := range res.Results {
		if r.Error != nil {
			hasErrors = true
			logging.Errorf(ctx, "Failed to schedule build #%d (reason: %s): %s\n",
				i, r.Error.Reason, r.Error.Message)
		}
	}
	if hasErrors {
		return 1
	}

	fmt.Printf("%s\n", resBytes)
	return 0

}
<commit_msg>[buildbucket] Always print response<commit_after>// Copyright 2016 The LUCI Authors.
//
// 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 (
	"encoding/json"
	"fmt"
	"strconv"

	"github.com/google/uuid"
	"github.com/maruel/subcommands"

	"go.chromium.org/luci/auth"
	"go.chromium.org/luci/common/api/buildbucket/buildbucket/v1"
	"go.chromium.org/luci/common/cli"
	"go.chromium.org/luci/common/errors"
	"go.chromium.org/luci/common/logging"
)

func cmdPutBatch(defaultAuthOpts auth.Options) *subcommands.Command {
	return &subcommands.Command{
		UsageLine: `put [flags] <JSON request>...`,
		ShortDesc: "schedule builds",
		LongDesc: "Schedule builds. \n" +
			"See https://godoc.org/go.chromium.org/luci/common/api/" +
			"buildbucket/buildbucket/v1#ApiPutBatchRequestMessage " +
			"for JSON request message schema.",
		CommandRun: func() subcommands.CommandRun {
			c := &putBatchRun{}
			c.SetDefaultFlags(defaultAuthOpts)
			return c
		},
	}
}

type putBatchRun struct {
	baseCommandRun
}

func parsePutRequest(args []string, prefixFunc func() (string, error)) (*buildbucket.ApiPutBatchRequestMessage, error) {
	if len(args) <= 0 {
		return nil, fmt.Errorf("missing parameter: <JSON Request>")
	}

	req := &buildbucket.ApiPutBatchRequestMessage{}
	opIDPrefix := ""
	for i, a := range args {
		// verify that args are valid here before sending the request.
		putReq := &buildbucket.ApiPutRequestMessage{}
		if err := json.Unmarshal([]byte(a), putReq); err != nil {
			return nil, errors.Annotate(err, "invalid build request #%d", i).Err()
		}
		if putReq.ClientOperationId == "" {
			if opIDPrefix == "" {
				var err error
				opIDPrefix, err = prefixFunc()
				if err != nil {
					return nil, err
				}
			}
			putReq.ClientOperationId = opIDPrefix + "-" + strconv.Itoa(i)
		}
		req.Builds = append(req.Builds, putReq)
	}

	return req, nil
}

func (r *putBatchRun) Run(a subcommands.Application, args []string, env subcommands.Env) int {
	ctx := cli.GetContext(a, r, env)

	req, err := parsePutRequest(args, func() (string, error) {
		id, err := uuid.NewRandom()
		return id.String(), err
	})
	if err != nil {
		return r.done(ctx, err)
	}

	client, err := r.createClient(ctx)
	if err != nil {
		return r.done(ctx, err)
	}

	resBytes, err := client.call(ctx, "PUT", "builds/batch", req)
	if err != nil {
		return r.done(ctx, err)
	}

	fmt.Printf("%s\n", resBytes)

	var res buildbucket.ApiPutBatchResponseMessage
	if err := json.Unmarshal(resBytes, &res); err != nil {
		return r.done(ctx, err)
	}

	hasErrors := false

	if res.Error != nil {
		hasErrors = true
		logging.Errorf(ctx, "Failed to schedule builds (reason: %s): %s",
			res.Error.Reason, res.Error.Message)
	}

	for i, r := range res.Results {
		if r.Error != nil {
			hasErrors = true
			logging.Errorf(ctx, "Failed to schedule build #%d (reason: %s): %s\n",
				i, r.Error.Reason, r.Error.Message)
		}
	}

	if hasErrors {
		return 1
	}
	return 0
}
<|endoftext|>