<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	_ "net/http/pprof"

	"github.com/PuerkitoBio/goquery"
	"github.com/bradfitz/http2"
	"github.com/jackc/pgx"
	_ "github.com/jackc/pgx/stdlib"
	"github.com/jmoiron/sqlx"
)

var (
	pt          = fmt.Printf
	sp          = fmt.Sprintf
	logFilePath = flag.String("log", "", "log file path")
)

func main() {
	flag.Parse()
	defer func() {
		if p := recover(); p != nil && *logFilePath != "" {
			ioutil.WriteFile(*logFilePath, []byte(fmt.Sprintf("%v", p)), 0644)
		}
	}()

	checkErr := func(msg string, err error) {
		if err != nil {
			panic(sp("%s error: %v", msg, err))
		}
	}

	db, err := sqlx.Connect("pgx", "postgres://reus@localhost/bilibili")
	checkErr("connect to psql", err)
	err = db.Ping()
	checkErr("ping database", err)

	get := func(url string) []byte {
		retryCount := 8
	retry:
		client := http.Client{
			Timeout: time.Second * 16,
		}
		pt("get %s\n", url)
		resp, err := client.Get(url)
		if err != nil {
			if retryCount > 0 {
				retryCount--
				time.Sleep(time.Second * 3)
				goto retry
			} else {
				checkErr(sp("get %s", url), err)
			}
		}
		defer resp.Body.Close()
		content, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			if retryCount > 0 {
				retryCount--
				time.Sleep(time.Second * 3)
				goto retry
			} else {
				checkErr(sp("read %s", url), err)
			}
		}
		return content
	}

	bytesToDoc := func(bs []byte) *goquery.Document {
		doc, err := goquery.NewDocumentFromReader(bytes.NewReader(bs))
		checkErr("get document", err)
		return doc
	}

	collectFollowers := func() []string {

	getMaxPage:
		doc := bytesToDoc(get("http://space.bilibili.com/19415/follow.html?page=1"))
		maxPage := doc.Find("ul.page li").Length()
		if maxPage == 0 {
			goto getMaxPage
		}
		users := []string{}
		collectUser := func(url string) {
		getDoc:
			doc := bytesToDoc(get(url))
			entries := doc.Find("div.fanslist ul li div.t a[card]")
			if entries.Length() == 0 {
				goto getDoc
			}
			entries.Each(func(n int, se *goquery.Selection) {
				href, ok := se.Attr("href")
				if !ok {
					panic("invalid entry")
				}
				uid := href[strings.LastIndex(href, "/")+1:]
				users = append(users, uid)
			})
		}
		for i := 1; i <= maxPage; i++ {
			collectUser(sp("http://space.bilibili.com/19415/follow.html?page=%d", i))
		}
		return users
	}

	collectVideo := func(uid string, page int) (int, int) {
		url := sp("http://space.bilibili.com/space?uid=%s&page=%d", uid, page)
		doc := bytesToDoc(get(url))
		entries := doc.Find("div.main_list ul li")
		count := 0
		dup := 0
		entries.Each(func(n int, se *goquery.Selection) {
			titleSe := se.Find("a.title")
			title := titleSe.Text()
			href, ok := titleSe.Attr("href")
			if !ok || len(title) == 0 {
				panic("invalid entry")
			}
			idStr := href[strings.LastIndex(href, "av")+2:]
			idStr = idStr[:len(idStr)-1]
			id, err := strconv.Atoi(idStr)
			imgSe := se.Find("a img")
			image, ok := imgSe.Attr("src")
			if !ok {
				panic("no image")
			}
			_, err = db.Exec(`INSERT INTO video (id, title, image, added, uid)
				VALUES ($1, $2, $3, $4, $5)`, id, title, image, time.Now().Unix(), uid)
			if err != nil {
				if err.(pgx.PgError).Code == "23505" { // dup
					dup++
				} else {
					panic(err)
				}
			}
			count++
		})
		return count, dup
	}

	collectFollowed := func() {
		t0 := time.Now()
		users := collectFollowers()
		for _, uid := range users {
			page := 1
			totalDup := 0
			for {
				count, dup := collectVideo(uid, page)
				if count == 0 {
					break
				}
				totalDup += dup
				if totalDup > 50 {
					break
				}
				page++
			}
		}
		pt("collected in %v\n", time.Now().Sub(t0))
	}

	collectHottest := func() {
		urls := []string{
			"http://www.bilibili.com/video/bagumi_offical_1.html#!order=hot&page=1", // 官方延伸所有新投稿
		}
		end := time.Now()
		start := end.AddDate(0, 0, -7)
		rangeStr := sp("%4d-%02d-%02d~%4d-%02d-%02d", start.Year(), start.Month(), start.Day(),
			end.Year(), end.Month(), end.Day())
		urls = append(urls, sp("http://www.bilibili.com/list/damku-29-1-%s.html", rangeStr)) // 三次元音乐弹幕排序
		urls = append(urls, sp("http://www.bilibili.com/list/damku-17-1-%s.html", rangeStr)) // 单机联机弹幕排序
		urls = append(urls, sp("http://www.bilibili.com/list/damku-37-1-%s.html", rangeStr)) // 纪录片弹幕排序
		urls = append(urls, sp("http://www.bilibili.com/list/damku-51-1-%s.html", rangeStr)) // 动画资讯弹幕排序
		urls = append(urls, sp("http://www.bilibili.com/list/damku-98-1-%s.html", rangeStr)) // 机械弹幕排序
		for _, url := range urls {
			doc := bytesToDoc(get(url))
			entries := doc.Find("ul.vd-list li")
			entries.Each(func(i int, se *goquery.Selection) {
				titleSe := se.Find("a.title")
				title := titleSe.Text()
				href, ok := titleSe.Attr("href")
				if !ok || len(title) == 0 {
					panic(sp("invalid entry in %s # %d", url, i))
				}
				idStr := href[strings.LastIndex(href, "av")+2:]
				idStr = idStr[:len(idStr)-1]
				id, err := strconv.Atoi(idStr)
				if err != nil {
					panic(sp("invalid entry in %s # %d", url, i))
				}
				imgSe := se.Find("a img")
				image, ok := imgSe.Attr("src")
				if !ok {
					panic(sp("invalid entry in %s # %d", url, i))
				}
				//pt("%d %s %s\n", id, title, image)
				_, err = db.Exec(`INSERT INTO video (id, title, image, added)
					VALUES ($1, $2, $3, $4)`, id, title, image, time.Now().Unix())
				if err != nil {
					if err.(pgx.PgError).Code == "23505" { // dup
					} else {
						panic(err)
					}
				}
			})
		}
	}

	go func() {
		for {
			func() {
				defer recover()
				collectHottest()
				collectFollowed()
			}()
			time.Sleep(time.Minute * 5)
		}
	}()

	root := "./react"
	if len(os.Args) > 1 {
		root = os.Args[1]
	}
	root, err = filepath.Abs(root)
	checkErr("get web root dir", err)
	pt("web root %s\n", root)
	http.Handle("/", http.FileServer(http.Dir(root)))

	http.HandleFunc("/newest.json", func(w http.ResponseWriter, req *http.Request) {
		videos := []Video{}
		err := db.Select(&videos, `SELECT id, title, image FROM video
			WHERE view < 1
			ORDER BY id DESC, added DESC LIMIT 50`)
		checkErr("select", err)
		bs, err := json.Marshal(videos)
		checkErr("marshal json", err)
		w.Write(bs)
	})

	http.HandleFunc("/recently.json", func(w http.ResponseWriter, req *http.Request) {
		videos := []Video{}
		err := db.Select(&videos, `SELECT id, title, image FROM video
			WHERE last_visit IS NOT NULL
			ORDER BY last_visit DESC LIMIT 20`)
		checkErr("select", err)
		bs, err := json.Marshal(videos)
		checkErr("marshal json", err)
		w.Write(bs)
	})

	http.HandleFunc("/go", func(w http.ResponseWriter, req *http.Request) {
		idStr := req.FormValue("id")
		id, err := strconv.Atoi(idStr)
		checkErr("parse id", err)
		db.MustExec(`UPDATE video SET
			view = view + 1,
			last_visit = $2
			WHERE id = $1`, id, time.Now().Unix())
		http.Redirect(w, req, sp("http://www.bilibili.com/video/av%d", id), 307)
	})

	http.HandleFunc("/mark", func(w http.ResponseWriter, req *http.Request) {
		idStr := req.FormValue("id")
		id, err := strconv.Atoi(idStr)
		checkErr("parse id", err)
		db.MustExec(`UPDATE video SET
			view = view + 1,
			last_visit = $2
			WHERE id = $1`, id, time.Now().Unix())
		bs, err := json.Marshal(struct{ Ok bool }{true})
		checkErr("marshal json", err)
		w.Write(bs)
	})

	pt("starting http server\n")
	server := http.Server{
		Addr: ":19870",
	}
	http2.ConfigureServer(&server, nil)
	err = server.ListenAndServe()
	checkErr("start http server", err)
}

type Video struct {
	Title string `db:"title" json:"title"`
	Id    int    `db:"id" json:"id"`
	View  int    `db:"view" json:"view"`
	Image string `db:"image" json:"image"`
}
<commit_msg>use mysql<commit_after>package main

import (
	"bytes"
	"database/sql"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	_ "net/http/pprof"

	_ "github.com/go-sql-driver/mysql"
	"github.com/reusee/catch"

	"github.com/PuerkitoBio/goquery"
	"github.com/bradfitz/http2"
)

var (
	pt          = fmt.Printf
	sp          = fmt.Sprintf
	logFilePath = flag.String("log", "", "log file path")
	ce          = catch.PkgChecker("bilibili")
	ct          = catch.Catch
)

func main() {
	flag.Parse()
	defer func() {
		if p := recover(); p != nil && *logFilePath != "" {
			ioutil.WriteFile(*logFilePath, []byte(fmt.Sprintf("%v", p)), 0644)
		}
	}()

	db, err := sql.Open("mysql", "root@unix(/var/run/mysqld/mysqld.sock)/bilibili?tokudb_commit_sync=off")
	ce(err, "connect to db")

	_, err = db.Exec(`CREATE TABLE IF NOT EXISTS video (
		id INTEGER PRIMARY KEY,
		title TEXT,
		view INTEGER NOT NULL DEFAULT 0,
		last_visit INTEGER,
		image TEXT,
		added INTEGER DEFAULT 0,
		uid CHAR(64)
		) engine=TokuDB`)
	ce(err, "create table")

	get := func(url string) []byte {
		retryCount := 8
	retry:
		client := http.Client{
			Timeout: time.Second * 16,
		}
		pt("get %s\n", url)
		resp, err := client.Get(url)
		if err != nil {
			if retryCount > 0 {
				retryCount--
				time.Sleep(time.Second * 3)
				goto retry
			} else {
				ce(err, sp("get %s", url))
			}
		}
		defer resp.Body.Close()
		content, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			if retryCount > 0 {
				retryCount--
				time.Sleep(time.Second * 3)
				goto retry
			} else {
				ce(err, sp("read %s", url))
			}
		}
		return content
	}

	bytesToDoc := func(bs []byte) *goquery.Document {
		doc, err := goquery.NewDocumentFromReader(bytes.NewReader(bs))
		ce(err, "get document")
		return doc
	}

	collectFollowers := func() []string {

	getMaxPage:
		doc := bytesToDoc(get("http://space.bilibili.com/19415/follow.html?page=1"))
		maxPage := doc.Find("ul.page li").Length()
		if maxPage == 0 {
			goto getMaxPage
		}
		users := []string{}
		collectUser := func(url string) {
		getDoc:
			doc := bytesToDoc(get(url))
			entries := doc.Find("div.fanslist ul li div.t a[card]")
			if entries.Length() == 0 {
				goto getDoc
			}
			entries.Each(func(n int, se *goquery.Selection) {
				href, ok := se.Attr("href")
				if !ok {
					panic("invalid entry")
				}
				uid := href[strings.LastIndex(href, "/")+1:]
				users = append(users, uid)
			})
		}
		for i := 1; i <= maxPage; i++ {
			collectUser(sp("http://space.bilibili.com/19415/follow.html?page=%d", i))
		}
		return users
	}

	collectVideo := func(uid string, page int) int {
		url := sp("http://space.bilibili.com/space?uid=%s&page=%d", uid, page)
		doc := bytesToDoc(get(url))
		entries := doc.Find("div.main_list ul li")
		count := 0
		entries.Each(func(n int, se *goquery.Selection) {
			titleSe := se.Find("a.title")
			title := titleSe.Text()
			href, ok := titleSe.Attr("href")
			if !ok || len(title) == 0 {
				panic("invalid entry")
			}
			idStr := href[strings.LastIndex(href, "av")+2:]
			idStr = idStr[:len(idStr)-1]
			id, err := strconv.Atoi(idStr)
			imgSe := se.Find("a img")
			image, ok := imgSe.Attr("src")
			if !ok {
				panic("no image")
			}
			_, err = db.Exec(`INSERT IGNORE INTO video (id, title, image, added, uid)
				VALUES (?, ?, ?, ?, ?)`, id, title, image, time.Now().Unix(), uid)
			ce(err, "insert")
			count++
		})
		return count
	}

	collectFollowed := func() {
		t0 := time.Now()
		users := collectFollowers()
		for _, uid := range users {
			page := 1
			for page < 50 {
				count := collectVideo(uid, page)
				if count == 0 {
					break
				}
				page++
			}
		}
		pt("collected in %v\n", time.Now().Sub(t0))
	}

	collectHottest := func() {
		urls := []string{
			"http://www.bilibili.com/video/bagumi_offical_1.html#!order=hot&page=1", // 官方延伸所有新投稿
		}
		end := time.Now()
		start := end.AddDate(0, 0, -7)
		rangeStr := sp("%4d-%02d-%02d~%4d-%02d-%02d", start.Year(), start.Month(), start.Day(),
			end.Year(), end.Month(), end.Day())
		urls = append(urls, sp("http://www.bilibili.com/list/damku-29-1-%s.html", rangeStr)) // 三次元音乐弹幕排序
		urls = append(urls, sp("http://www.bilibili.com/list/damku-17-1-%s.html", rangeStr)) // 单机联机弹幕排序
		urls = append(urls, sp("http://www.bilibili.com/list/damku-37-1-%s.html", rangeStr)) // 纪录片弹幕排序
		urls = append(urls, sp("http://www.bilibili.com/list/damku-51-1-%s.html", rangeStr)) // 动画资讯弹幕排序
		urls = append(urls, sp("http://www.bilibili.com/list/damku-98-1-%s.html", rangeStr)) // 机械弹幕排序
		for _, url := range urls {
			doc := bytesToDoc(get(url))
			entries := doc.Find("ul.vd-list li")
			entries.Each(func(i int, se *goquery.Selection) {
				titleSe := se.Find("a.title")
				title := titleSe.Text()
				href, ok := titleSe.Attr("href")
				if !ok || len(title) == 0 {
					panic(sp("invalid entry in %s # %d", url, i))
				}
				idStr := href[strings.LastIndex(href, "av")+2:]
				idStr = idStr[:len(idStr)-1]
				id, err := strconv.Atoi(idStr)
				if err != nil {
					panic(sp("invalid entry in %s # %d", url, i))
				}
				imgSe := se.Find("a img")
				image, ok := imgSe.Attr("src")
				if !ok {
					panic(sp("invalid entry in %s # %d", url, i))
				}
				//pt("%d %s %s\n", id, title, image)
				_, err = db.Exec(`INSERT IGNORE INTO video (id, title, image, added)
					VALUES (?, ?, ?, ?)`, id, title, image, time.Now().Unix())
				ce(err, "insert")
			})
		}
	}

	go func() {
		for {
			func() {
				defer recover()
				collectHottest()
				collectFollowed()
			}()
			time.Sleep(time.Minute * 5)
		}
	}()

	root := "./web"
	if len(os.Args) > 1 {
		root = os.Args[1]
	}
	root, err = filepath.Abs(root)
	ce(err, "get web root dir")
	pt("web root %s\n", root)
	http.Handle("/", http.FileServer(http.Dir(root)))

	http.HandleFunc("/newest.json", func(w http.ResponseWriter, req *http.Request) {
		videos := []Video{}
		rows, err := db.Query(`SELECT id, title, image FROM video
			WHERE view < 1
			ORDER BY id DESC, added DESC LIMIT 50`)
		ce(err, "query")
		for rows.Next() {
			var video Video
			ce(rows.Scan(&video.Id, &video.Title, &video.Image), "scan")
			videos = append(videos, video)
		}
		ce(rows.Err(), "rows")
		bs, err := json.Marshal(videos)
		ce(err, "marshal")
		w.Write(bs)
	})

	http.HandleFunc("/recently.json", func(w http.ResponseWriter, req *http.Request) {
		videos := []Video{}
		rows, err := db.Query(`SELECT id, title, image FROM video
			WHERE last_visit IS NOT NULL
			ORDER BY last_visit DESC LIMIT 20`)
		ce(err, "query")
		for rows.Next() {
			var video Video
			ce(rows.Scan(&video.Id, &video.Title, &video.Image), "scan")
			videos = append(videos, video)
		}
		ce(rows.Err(), "rows")
		bs, err := json.Marshal(videos)
		ce(err, "marshal")
		w.Write(bs)
	})

	http.HandleFunc("/go", func(w http.ResponseWriter, req *http.Request) {
		idStr := req.FormValue("id")
		id, err := strconv.Atoi(idStr)
		ce(err, "parse id")
		_, err = db.Exec(`UPDATE video SET
			view = view + 1,
			last_visit = ?
			WHERE id = ?`, id, time.Now().Unix())
		ce(err, "update")
		http.Redirect(w, req, sp("http://www.bilibili.com/video/av%d", id), 307)
	})

	http.HandleFunc("/mark", func(w http.ResponseWriter, req *http.Request) {
		idStr := req.FormValue("id")
		id, err := strconv.Atoi(idStr)
		ce(err, "parse id")
		_, err = db.Exec(`UPDATE video SET
			view = view + 1,
			last_visit = ?
			WHERE id = ?`, id, time.Now().Unix())
		ce(err, "update")
		bs, err := json.Marshal(struct{ Ok bool }{true})
		ce(err, "marshal json")
		w.Write(bs)
	})

	pt("starting http server\n")
	server := http.Server{
		Addr: ":19870",
	}
	http2.ConfigureServer(&server, nil)
	err = server.ListenAndServe()
	ce(err, "start http server")
}

type Video struct {
	Title string `db:"title" json:"title"`
	Id    int    `db:"id" json:"id"`
	View  int    `db:"view" json:"view"`
	Image string `db:"image" json:"image"`
}
<|endoftext|>


<commit_before>// Copyright The OpenTelemetry 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 zipkin

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"

	export "go.opentelemetry.io/otel/sdk/export/trace"
)

// Exporter exports SpanData to the zipkin collector. It implements
// the SpanBatcher interface, so it needs to be used together with the
// WithBatcher option when setting up the exporter pipeline.
type Exporter struct {
	url         string
	serviceName string
	client      *http.Client
	logger      *log.Logger
}

var (
	_ export.SpanBatcher = &Exporter{}
)

// Options contains configuration for the exporter.
type Options struct {
	client *http.Client
	logger *log.Logger
}

// Option defines a function that configures the exporter.
type Option func(*Options)

// WithLogger configures the exporter to use the passed logger.
func WithLogger(logger *log.Logger) Option {
	return func(opts *Options) {
		opts.logger = logger
	}
}

// WithClient configures the exporter to use the passed HTTP client.
func WithClient(client *http.Client) Option {
	return func(opts *Options) {
		opts.client = client
	}
}

// NewExporter creates a new zipkin exporter.
func NewExporter(collectorURL string, serviceName string, os ...Option) (*Exporter, error) {
	if _, err := url.Parse(collectorURL); err != nil {
		return nil, fmt.Errorf("invalid collector URL: %v", err)
	}
	if serviceName == "" {
		return nil, fmt.Errorf("service name must be non-empty string")
	}
	opts := Options{}
	for _, o := range os {
		o(&opts)
	}
	if opts.client == nil {
		opts.client = http.DefaultClient
	}
	return &Exporter{
		url:         collectorURL,
		client:      opts.client,
		logger:      opts.logger,
		serviceName: serviceName,
	}, nil
}

// ExportSpans is a part of an implementation of the SpanBatcher
// interface.
func (e *Exporter) ExportSpans(ctx context.Context, batch []*export.SpanData) {
	if len(batch) == 0 {
		e.logf("no spans to export")
		return
	}
	models := toZipkinSpanModels(batch, e.serviceName)
	body, err := json.Marshal(models)
	if err != nil {
		e.logf("failed to serialize zipkin models to JSON: %v", err)
		return
	}
	e.logf("about to send a POST request to %s with body %s", e.url, body)
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, e.url, bytes.NewBuffer(body))
	if err != nil {
		e.logf("failed to create request to %s: %v", e.url, err)
		return
	}
	req.Header.Set("Content-Type", "application/json")
	resp, err := e.client.Do(req)
	if err != nil {
		e.logf("request to %s failed: %v", e.url, err)
		return
	}
	e.logf("zipkin responded with status %d", resp.StatusCode)
}

func (e *Exporter) logf(format string, args ...interface{}) {
	if e.logger != nil {
		e.logger.Printf(format, args...)
	}
}
<commit_msg>Ensure zipkin exporter reads and closes response body<commit_after>// Copyright The OpenTelemetry 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 zipkin

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"

	export "go.opentelemetry.io/otel/sdk/export/trace"
)

// Exporter exports SpanData to the zipkin collector. It implements
// the SpanBatcher interface, so it needs to be used together with the
// WithBatcher option when setting up the exporter pipeline.
type Exporter struct {
	url         string
	serviceName string
	client      *http.Client
	logger      *log.Logger
}

var (
	_ export.SpanBatcher = &Exporter{}
)

// Options contains configuration for the exporter.
type Options struct {
	client *http.Client
	logger *log.Logger
}

// Option defines a function that configures the exporter.
type Option func(*Options)

// WithLogger configures the exporter to use the passed logger.
func WithLogger(logger *log.Logger) Option {
	return func(opts *Options) {
		opts.logger = logger
	}
}

// WithClient configures the exporter to use the passed HTTP client.
func WithClient(client *http.Client) Option {
	return func(opts *Options) {
		opts.client = client
	}
}

// NewExporter creates a new zipkin exporter.
func NewExporter(collectorURL string, serviceName string, os ...Option) (*Exporter, error) {
	if _, err := url.Parse(collectorURL); err != nil {
		return nil, fmt.Errorf("invalid collector URL: %v", err)
	}
	if serviceName == "" {
		return nil, fmt.Errorf("service name must be non-empty string")
	}
	opts := Options{}
	for _, o := range os {
		o(&opts)
	}
	if opts.client == nil {
		opts.client = http.DefaultClient
	}
	return &Exporter{
		url:         collectorURL,
		client:      opts.client,
		logger:      opts.logger,
		serviceName: serviceName,
	}, nil
}

// ExportSpans is a part of an implementation of the SpanBatcher
// interface.
func (e *Exporter) ExportSpans(ctx context.Context, batch []*export.SpanData) {
	if len(batch) == 0 {
		e.logf("no spans to export")
		return
	}
	models := toZipkinSpanModels(batch, e.serviceName)
	body, err := json.Marshal(models)
	if err != nil {
		e.logf("failed to serialize zipkin models to JSON: %v", err)
		return
	}
	e.logf("about to send a POST request to %s with body %s", e.url, body)
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, e.url, bytes.NewBuffer(body))
	if err != nil {
		e.logf("failed to create request to %s: %v", e.url, err)
		return
	}
	req.Header.Set("Content-Type", "application/json")
	resp, err := e.client.Do(req)
	if err != nil {
		e.logf("request to %s failed: %v", e.url, err)
		return
	}
	e.logf("zipkin responded with status %d", resp.StatusCode)

	_, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		e.logf("failed to read response body: %v", err)
	}

	err = resp.Body.Close()
	if err != nil {
		e.logf("failed to close response body: %v", err)
	}
}

func (e *Exporter) logf(format string, args ...interface{}) {
	if e.logger != nil {
		e.logger.Printf(format, args...)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"path/filepath"

	"github.com/codegangsta/cli"
)

func main() {
	app := cli.NewApp()
	app.Version = "1.1.0"
	app.Name = filepath.Base(os.Args[0])
	app.Usage = "An automation tool for Go project."
	app.Commands = append(app.Commands, appRun)
	app.Run(os.Args)
}
<commit_msg>add init subcommand.<commit_after>package main

import (
	"os"
	"path/filepath"

	"github.com/codegangsta/cli"
)

func main() {
	app := cli.NewApp()
	app.Version = "1.1.0"
	app.Name = filepath.Base(os.Args[0])
	app.Usage = "An automation tool for Go project."
	app.Commands = append(app.Commands, appRun, initCmd)
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"strings"
	"text/template"

	"gopkg.in/yaml.v2"

	"github.com/juno-lab/argparse"
)

func getTemplate(filename string) (*template.Template, error) {
	content, err := loadFile(filename)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Template file load error: [%v]\n", err))
	}
	tmpl, err := template.New("template").Parse(string(content))
	if err != nil {
		return nil, errors.New(fmt.Sprintf("unable parse data (%v) %q as a template: [%v]\n", filename, string(content), err))
	}
	return tmpl, nil
}

func getConfig(filenames string) (map[string]interface{}, error) {
	buffers := []*bytes.Buffer{}

	if filenames == "<STDIN>" {
		info, _ := os.Stdin.Stat()
		// outMode(info.Mode())
		if (info.Mode() & os.ModeCharDevice) == os.ModeCharDevice {
			return nil, errors.New(fmt.Sprintf("The command is intended to work with pipes\n"))
		} else {
			buffer := bytes.NewBuffer([]byte{})
			reader := bufio.NewReader(os.Stdin)
			for {
				input, err := reader.ReadString('\n')
				if err != nil && err == io.EOF {
					break
				}
				buffer.WriteString(input)
			}
			buffers = append(buffers, buffer)
		}
	} else {
		for _, filename := range strings.Split(filenames, ",") {
			buffer := bytes.NewBuffer([]byte{})
			content, err := loadFile(filename)
			if err != nil {
				return nil, errors.New(fmt.Sprintf("Config file load error: [%v]\n", err))
			}
			buffer.Write(content)
			buffers = append(buffers, buffer)
		}
	}

	config := map[string]interface{}{}
	for _, buffer := range buffers {
		cfg := map[string]interface{}{}
		if err := yaml.Unmarshal(buffer.Bytes(), &cfg); err != nil {
			return nil, errors.New(fmt.Sprintf("Could not parse YAML file: %s\n", err))
		}
		config = mergeMaps(config, cfg)
	}

	return config, nil
}

func outResult(filename string, buffer *bytes.Buffer) {
	outputBuffer := bufio.NewWriter(os.Stdout)
	if filename != "<STDOUT>" {
		f, err := os.Create(filename)
		defer f.Close()
		if err != nil {
			log.Fatalf("Output file create error: [%v]\n", err)
		}
		outputBuffer = bufio.NewWriter(f)
	}

	if _, err := outputBuffer.WriteString(buffer.String()); err != nil {
		fmt.Fprintf(os.Stderr, "Output write error: [%v]\n", err)
		os.Exit(1)
	}
	outputBuffer.Flush()
}

func main() {
	parser, _ := argparse.ArgumentParser()
	parser.AddStringOption("input", "i", "input").Default("<STDIN>")
	parser.AddStringOption("output", "o", "output").Default("<STDOUT>")
	parser.AddStringOption("template", "t", "tmpl").Default("--")
	parser.AddFlagOption("check", "", "check").Default("false").Action(argparse.SET_TRUE)
	parser.AddFlagOption("merge", "", "merge").Default("false").Action(argparse.SET_TRUE)

	args := parser.ParseArgs()

	// if *tmplFile == "" {
	// 	fmt.Fprintf(os.Stderr, "template (-t) file required\n")
	// 	os.Exit(1)
	// }

	var cfg map[string]interface{}
	var err error

	cfg, err = getConfig(args.AsString("input"))
	if err != nil {
		log.Fatal(err.Error())
	}

	correct := true
	buffer := bytes.NewBuffer([]byte{})

	if args.AsFlag("merge") {
		d, err := yaml.Marshal(cfg)
		if err != nil {
			log.Fatal(fmt.Sprintf("Could not create YAML file: %s\n", err))
		}
		buffer.Write(d)
	} else {
		var tmpl *template.Template

		if args.AsString("template") == "--" {
			log.Fatal("ParseArgs: Field [template(-t|--tmpl)] required")
		}
		tmpl, err = getTemplate(args.AsString("template"))
		if err != nil {
			log.Fatal(err.Error())
		}

		if err := tmpl.Execute(buffer, cfg); err != nil {
			log.Fatalf("failed to render template [%s]\n[%s]\n", err, cfg)
		}

		if args.AsFlag("check") {
			strOut := strings.Split(buffer.String(), "\n")

			for posInFile, str := range strOut {
				if i := strings.Index(str, "<no value>"); i != -1 {
					fmt.Fprintf(os.Stderr, "<no value> at %s#%d:%s\n", args.AsString("output"), posInFile, str)
					correct = correct && false
				}
			}

			outYaml := map[string]interface{}{}
			err = yaml.Unmarshal(buffer.Bytes(), &outYaml)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Not valid output yaml: %s", err.Error())
				correct = correct && false
			}
			fmt.Fprintf(os.Stderr, "\n")
		}
	}

	outResult(args.AsString("output"), buffer)

	if !correct {
		os.Exit(1)
	}
}
<commit_msg>template proprocessor fix: multiline strings<commit_after>package main

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"strings"
	"text/template"

	"gopkg.in/yaml.v2"

	"github.com/juno-lab/argparse"
)

func getTemplate(filename string) (*template.Template, error) {
	content, err := loadFile(filename)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Template file load error: [%v]\n", err))
	}
	tmpl, err := template.New("template").Parse(string(content))
	if err != nil {
		return nil, errors.New(fmt.Sprintf("unable parse data (%v) %q as a template: [%v]\n", filename, string(content), err))
	}
	return tmpl, nil
}

func getYamlTemplate(filename string) (map[string]interface{}, error) {
	content, err := loadFile(filename)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Template file load error: [%v]\n", err))
	}

	tmplYaml := map[string]interface{}{}
	err = yaml.Unmarshal(content, &tmplYaml)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Cannot unmarshal yaml.tmpl: %s\n", err.Error())
		fmt.Fprintf(os.Stderr, "yaml:\n%s", string(content))
		log.Fatal("...")
	}
	// outYaml := map[string]interface{}{}
	// err = yaml.Unmarshal(buffer.Bytes(), &outYaml)
	// if err != nil {
	// 	fmt.Fprintf(os.Stderr, "Cannot unmarshal yaml: %s", err.Error())
	// 	fmt.Fprintf(os.Stderr, "yaml:\n%s", buffer.String())
	// 	correct = correct && false
	// }
	// if data, err := yaml.Marshal(outYaml); err != nil {
	// 	fmt.Fprintf(os.Stderr, "Cannot remarshal yaml: %s", err.Error())
	// 	correct = correct && false
	// } else {
	// 	buffer.Reset()
	// 	buffer.Write(data)
	// }
	return tmplYaml, nil
}

func getConfig(filenames string) (map[string]interface{}, error) {
	buffers := []*bytes.Buffer{}

	if filenames == "<STDIN>" {
		info, _ := os.Stdin.Stat()
		// outMode(info.Mode())
		if (info.Mode() & os.ModeCharDevice) == os.ModeCharDevice {
			return nil, errors.New(fmt.Sprintf("The command is intended to work with pipes\n"))
		} else {
			buffer := bytes.NewBuffer([]byte{})
			reader := bufio.NewReader(os.Stdin)
			for {
				input, err := reader.ReadString('\n')
				if err != nil && err == io.EOF {
					break
				}
				buffer.WriteString(input)
			}
			buffers = append(buffers, buffer)
		}
	} else {
		for _, filename := range strings.Split(filenames, ",") {
			buffer := bytes.NewBuffer([]byte{})
			content, err := loadFile(filename)
			if err != nil {
				return nil, errors.New(fmt.Sprintf("Config file load error: [%v]\n", err))
			}
			buffer.Write(content)
			buffers = append(buffers, buffer)
		}
	}

	config := map[string]interface{}{}
	for _, buffer := range buffers {
		cfg := map[string]interface{}{}
		if err := yaml.Unmarshal(buffer.Bytes(), &cfg); err != nil {
			return nil, errors.New(fmt.Sprintf("Could not parse YAML file: %s\n", err))
		}
		config = mergeMaps(config, cfg)
	}

	return config, nil
}

func writeStr(buffer *bytes.Buffer, str string) {
	if strings.TrimSpace(str) != "" {
		buffer.WriteString(str)
		buffer.WriteString("\n")
	}
}

func preprocessYaml(input *bytes.Buffer) *bytes.Buffer {
	buffer := bytes.NewBuffer([]byte{})

	ident := ""
	for _, str := range strings.Split(input.String(), "\n") {
		if strings.HasSuffix(str, "|") {
			ident = "|"
		} else if ident == "|" {
			count := len(str) - len(strings.TrimLeft(str, " "))
			// fmt.Println(str, len(str), len(strings.TrimLeft(str, " ")), count)
			ident = strings.Repeat(" ", count)
			writeStr(buffer, str)
			continue
		} else if ident != "" && (strings.HasPrefix(str, " ") || str == "") {
			ident = ""
		} else {
		}
		if ident != "|" && ident != "" {
			buffer.WriteString(ident)
		}
		writeStr(buffer, str)
	}
	return buffer
}

func outResult(filename string, buffer *bytes.Buffer) {
	outputBuffer := bufio.NewWriter(os.Stdout)
	if filename != "<STDOUT>" {
		f, err := os.Create(filename)
		defer f.Close()
		if err != nil {
			log.Fatalf("Output file create error: [%v]\n", err)
		}
		outputBuffer = bufio.NewWriter(f)
	}

	if _, err := outputBuffer.WriteString(buffer.String()); err != nil {
		fmt.Fprintf(os.Stderr, "Output write error: [%v]\n", err)
		os.Exit(1)
	}
	outputBuffer.Flush()
}

func main() {
	parser, _ := argparse.ArgumentParser()
	parser.AddStringOption("input", "i", "input").Default("<STDIN>")
	parser.AddStringOption("output", "o", "output").Default("<STDOUT>")
	parser.AddStringOption("template", "t", "tmpl").Default("--")
	parser.AddFlagOption("ini", "", "ini").Default("false").Action(argparse.SET_TRUE)
	parser.AddFlagOption("check", "", "check").Default("false").Action(argparse.SET_TRUE)
	parser.AddFlagOption("merge", "", "merge").Default("false").Action(argparse.SET_TRUE)

	args := parser.ParseArgs()

	// if *tmplFile == "" {
	// 	fmt.Fprintf(os.Stderr, "template (-t) file required\n")
	// 	os.Exit(1)
	// }

	var cfg map[string]interface{}
	var err error

	cfg, err = getConfig(args.AsString("input"))
	if err != nil {
		log.Fatal(err.Error())
	}

	correct := true
	buffer := bytes.NewBuffer([]byte{})

	if args.AsFlag("merge") {
		d, err := yaml.Marshal(cfg)
		if err != nil {
			log.Fatal(fmt.Sprintf("Could not create YAML file: %s\n", err))
		}
		buffer.Write(d)
	} else {
		var tmpl *template.Template

		if args.AsString("template") == "--" {
			log.Fatal("ParseArgs: Field [template(-t|--tmpl)] required")
		}
		tmpl, err = getTemplate(args.AsString("template"))
		if err != nil {
			log.Fatal(err.Error())
		}

		// yTmpl, err := getYamlTemplate(args.AsString("template"))
		// if err != nil {
		// 	log.Fatal(err.Error(), yTmpl)
		// }

		if err := tmpl.Execute(buffer, cfg); err != nil {
			log.Fatalf("failed to render template [%s]\n[%s]\n", err, cfg)
		}

		buffer = preprocessYaml(buffer)

		// check yaml
		outYaml := map[string]interface{}{}
		if err = yaml.Unmarshal(buffer.Bytes(), &outYaml); err != nil {
			fmt.Fprintf(os.Stderr, "Not valid output yaml: %s\n", err.Error())
			correct = correct && false
		}

		// check variables
		if args.AsFlag("check") {
			strOut := strings.Split(buffer.String(), "\n")

			for posInFile, str := range strOut {
				if i := strings.Index(str, "<no value>"); i != -1 {
					fmt.Fprintf(os.Stderr, "<no value> at %s#%d:%s\n", args.AsString("output"), posInFile, str)
					correct = correct && false
				}
			}

		}
	}

	outResult(args.AsString("output"), buffer)

	if !correct {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

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

func init() {
	// URLパターンに正規表現は渡せない。
	http.HandleFunc("/count", WordCountHandler)

	// 順番に注意。"/"を先頭に指定すると他のPathがマッチしない。
	http.HandleFunc("/", TopPageHandler)
}

func main() {
	port := 8080
	log.Printf("start server, port %v", port)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%v", port), nil))
}

func TopPageHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")
	w.Write([]byte(`

			<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
			<title>Welcome to kanjo.</title>

Hello, world.

			文字を入力してください。
			<form action="/count" method="GET">
			<input type="text" name="text" size="32">
			<input type="submit">
			</form>

	`))
}

func WordCountHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	// 1. テンプレートエンジンを使って処理するよう変更
	// 2. JSONで返却する機能を追加
	// 3. ファイルを読み取って文字数を数える機能を追加
	// 4. 文字数とバイト数を数えるよう変更

	text := r.FormValue("text")
	count := len(text)

	css := ""
	if count == 0 {
		css = "err"
	}

	content := fmt.Sprintf(`

			<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
			<title>文字数カウント結果</title>

文字数カウント結果

			入力文字: %v

			文字数は: %v

			でした。

			文字を入力してください。
			<form action="/count" method="GET">
			<input type="text" name="text" size="32" class="%v">
			<input type="submit">
			</form>

	`, text, count, css)

	w.Write([]byte(content))
}
<commit_msg>コメント追加<commit_after>package main

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

func init() {
	// URLパターンに正規表現は渡せない。
	http.HandleFunc("/count", WordCountHandler)

	// 順番に注意。"/"を先頭に指定すると他のPathがマッチしない。
	http.HandleFunc("/", TopPageHandler)
}

func main() {
	port := 8080
	log.Printf("start server, port %v", port)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%v", port), nil))
}

func TopPageHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")
	w.Write([]byte(`

			<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
			<title>Welcome to kanjo.</title>

Hello, world.

			文字を入力してください。
			<form action="/count" method="GET">
			<input type="text" name="text" size="32">
			<input type="submit">
			</form>

	`))
}

func WordCountHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	// 1. テンプレートエンジンを使って処理するよう変更
	// 2. JSONで返却する機能を追加
	// 3. ファイルを読み取って文字数を数える機能を追加
	// 4. 文字数とバイト数を数えるよう変更
	// 5. ユニットテストを追加

	text := r.FormValue("text")
	count := len(text)

	css := ""
	if count == 0 {
		css = "err"
	}

	content := fmt.Sprintf(`

			<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
			<title>文字数カウント結果</title>

文字数カウント結果

			入力文字: %v

			文字数は: %v

			でした。

			文字を入力してください。
			<form action="/count" method="GET">
			<input type="text" name="text" size="32" class="%v">
			<input type="submit">
			</form>

	`, text, count, css)

	w.Write([]byte(content))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
)

func shortUsage() {
	os.Stderr.WriteString(`
Usage: vub [OPTION]... URI
Try 'vub --help' for more information.
`[1:])
}

func usage() {
	os.Stderr.WriteString(`
Usage: vub [OPTION]... URI
Install Vim plugin to under the management of vim-unbundle.

URI:
  sunaku/vim-unbundle                    # short URI
  https://github.com/sunaku/vim-unbundle # full URI

Options:
  -f, --filetype=TYPE       installing under the ftbundle/TYPE
  -r, --remove              change the behavior to remove
  -u, --update              change the behavior to clean update
  -v, --verbose             display the process
  -h, --help                show this help message
`[1:])
}

func _main() (code int, err error) {
	var filetype string
	flag.StringVar(&filetype, "f", "", "")
	flag.StringVar(&filetype, "filetype", "", "")

	var removeMode, updateMode bool
	flag.BoolVar(&removeMode, "r", false, "")
	flag.BoolVar(&removeMode, "remove", false, "")
	flag.BoolVar(&updateMode, "u", false, "")
	flag.BoolVar(&updateMode, "update", false, "")

	var verbose bool
	flag.BoolVar(&verbose, "v", false, "")
	flag.BoolVar(&verbose, "verbose", false, "")

	var isHelp bool
	flag.BoolVar(&isHelp, "h", false, "")
	flag.BoolVar(&isHelp, "help", false, "")
	flag.Usage = usage
	flag.Parse()
	switch {
	case isHelp:
		usage()
		return 0, nil
	case flag.NArg() < 1:
		return 2, nil
	case removeMode && updateMode:
		return 2, fmt.Errorf("cannot specify multiple mode")
	}
	uri := flag.Arg(0)

	p, err := NewPackage(uri, filetype)
	if err != nil {
		return 1, err
	}
	p.Verbose(verbose)

	switch {
	case removeMode:
		if err := p.Remove(os.Stdout); err != nil {
			return 1, err
		}
	case updateMode:
		if err := p.Update(os.Stdout); err != nil {
			return 1, err
		}
	default:
		if err := p.Install(os.Stdout); err != nil {
			return 1, err
		}
	}
	return 0, nil
}

func main() {
	code, err := _main()
	if err != nil {
		fmt.Fprintf(os.Stderr, "vub:", err)
	}
	if code == 2 {
		shortUsage()
	}
	os.Exit(code)
}
<commit_msg>Remove _main<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
)

func shortUsage() {
	os.Stderr.WriteString(`
Usage: vub [OPTION]... URI
Try 'vub --help' for more information.
`[1:])
}

func usage() {
	os.Stderr.WriteString(`
Usage: vub [OPTION]... URI
Install Vim plugin to under the management of vim-unbundle.

URI:
  sunaku/vim-unbundle                    # short URI
  https://github.com/sunaku/vim-unbundle # full URI

Options:
  -f, --filetype=TYPE       installing under the ftbundle/TYPE
  -r, --remove              change the behavior to remove
  -u, --update              change the behavior to clean update
  -v, --verbose             display the process
  -h, --help                show this help message
`[1:])
}

func main() {
	var filetype string
	flag.StringVar(&filetype, "f", "", "")
	flag.StringVar(&filetype, "filetype", "", "")

	var removeMode, updateMode bool
	flag.BoolVar(&removeMode, "r", false, "")
	flag.BoolVar(&removeMode, "remove", false, "")
	flag.BoolVar(&updateMode, "u", false, "")
	flag.BoolVar(&updateMode, "update", false, "")

	var verbose bool
	flag.BoolVar(&verbose, "v", false, "")
	flag.BoolVar(&verbose, "verbose", false, "")

	var isHelp bool
	flag.BoolVar(&isHelp, "h", false, "")
	flag.BoolVar(&isHelp, "help", false, "")
	flag.Usage = usage
	flag.Parse()
	switch {
	case isHelp:
		usage()
		os.Exit(0)
	case flag.NArg() < 1:
		shortUsage()
		os.Exit(2)
	case removeMode && updateMode:
		fmt.Fprintln(os.Stderr, "vub:", "cannot specify multiple mode")
		os.Exit(2)
	}
	uri := flag.Arg(0)

	p, err := NewPackage(uri, filetype)
	if err != nil {
		fmt.Fprintln(os.Stderr, "vub:", err)
		os.Exit(1)
	}
	p.Verbose(verbose)

	switch {
	case removeMode:
		err = p.Remove(os.Stdout)
	case updateMode:
		err = p.Update(os.Stdout)
	default:
		err = p.Install(os.Stdout)
	}
	if err != nil {
		fmt.Fprintln(os.Stderr, "vub:", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/pat"
	"github.com/meatballhat/negroni-logrus"
	"github.com/phyber/negroni-gzip/gzip"
	"gitlab.com/mattbostock/timeoff/handler"
)

const (
	assetsPath  = "assets"
	defaultAddr = ":3000"
)

var (
	config = &struct {
		addr    string
		debug   bool
		tlsCert string
		tlsKey  string
	}{
		addr:    os.Getenv("ADDR"),
		debug:   len(os.Getenv("DEBUG")) > 0,
		tlsCert: os.Getenv("TLS_CERT"),
		tlsKey:  os.Getenv("TLS_KEY"),
	}

	mux        = pat.New()
	logHandler = negronilogrus.NewMiddleware()
	log        = logHandler.Logger
)

func init() {
	if config.addr == "" {
		config.addr = defaultAddr
	}

	if config.debug {
		log.Level = logrus.DebugLevel
	}

	handler.SetLogger(log)
}

func main() {
	n := negroni.New()
	n.Use(logHandler) // logger must be first middleware
	n.Use(negroni.NewRecovery())
	n.Use(negroni.NewStatic(http.Dir(assetsPath)))
	n.Use(gzip.Gzip(gzip.BestCompression))

	n.UseHandler(mux)
	registerRoutes()

	log.Infof("Listening on %s", config.addr)

	if config.tlsCert == "" && config.tlsKey == "" {
		log.Warningln(noTLSCertificateError)
		log.Fatal(http.ListenAndServe(config.addr, n))
	} else {
		log.Infoln("Listening with TLS")
		log.Fatal(http.ListenAndServeTLS(config.addr, config.tlsCert, config.tlsKey, n))
	}
}

const noTLSCertificateError = "No TLS certficiate supplied. Consider setting TLS_CERT " +
	"and TLS_KEY environment variables to enable TLS."
<commit_msg>Use empty string comparison rather than len()<commit_after>package main

import (
	"net/http"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/pat"
	"github.com/meatballhat/negroni-logrus"
	"github.com/phyber/negroni-gzip/gzip"
	"gitlab.com/mattbostock/timeoff/handler"
)

const (
	assetsPath  = "assets"
	defaultAddr = ":3000"
)

var (
	config = &struct {
		addr    string
		debug   bool
		tlsCert string
		tlsKey  string
	}{
		addr:    os.Getenv("ADDR"),
		debug:   os.Getenv("DEBUG") != "",
		tlsCert: os.Getenv("TLS_CERT"),
		tlsKey:  os.Getenv("TLS_KEY"),
	}

	mux        = pat.New()
	logHandler = negronilogrus.NewMiddleware()
	log        = logHandler.Logger
)

func init() {
	if config.addr == "" {
		config.addr = defaultAddr
	}

	if config.debug {
		log.Level = logrus.DebugLevel
	}

	handler.SetLogger(log)
}

func main() {
	n := negroni.New()
	n.Use(logHandler) // logger must be first middleware
	n.Use(negroni.NewRecovery())
	n.Use(negroni.NewStatic(http.Dir(assetsPath)))
	n.Use(gzip.Gzip(gzip.BestCompression))

	n.UseHandler(mux)
	registerRoutes()

	log.Infof("Listening on %s", config.addr)

	if config.tlsCert == "" && config.tlsKey == "" {
		log.Warningln(noTLSCertificateError)
		log.Fatal(http.ListenAndServe(config.addr, n))
	} else {
		log.Infoln("Listening with TLS")
		log.Fatal(http.ListenAndServeTLS(config.addr, config.tlsCert, config.tlsKey, n))
	}
}

const noTLSCertificateError = "No TLS certficiate supplied. Consider setting TLS_CERT " +
	"and TLS_KEY environment variables to enable TLS."
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"zetsuboushita.net/vc_file_grouper/handler"
	"zetsuboushita.net/vc_file_grouper/vc"
)

// Main function that starts the program
func main() {

	cmdLang := flag.String("lang", "en", "The language pack to use. 'en' for English, 'zhs' for Chinese. ")
	cmdHelp := flag.Bool("help", false, "Show the help message")
	cmdDbg := flag.Bool("debug", false, "Outputs error message to the standard error console")
	flag.Parse()

	if *cmdHelp {
		usage()
		return
	}

	if !(*cmdDbg) {
		log.SetOutput(ioutil.Discard)
	}

	if cmdLang == nil {
		vc.LangPack = "en"
	} else {
		vc.LangPack = *cmdLang
	}

	if len(flag.Args()) == 0 {
		vc.FilePath = "."
	} else {
		vc.FilePath = filepath.Clean(flag.Args()[0])
	}

	if _, err := os.Stat(vc.FilePath); os.IsNotExist(err) {
		usage()
		vc.Data = &vc.VFile{}
		//return
	} else {
		vc.ReadMasterData(vc.FilePath)
	}

	//main page
	http.HandleFunc("/", handler.MasterDataHandler)
	http.HandleFunc("/css/", handler.CSSHandler)
	//image locations
	http.HandleFunc("/images/card/", handler.ImageCardHandler)
	http.HandleFunc("/images/cardthumb/", handler.ImageCardThumbHandler)
	http.HandleFunc("/images/cardHD/", handler.ImageCardHDHandler)
	http.HandleFunc("/images/cardSD/", handler.ImageCardSDHandler)
	http.HandleFunc("/images/event/", handler.ImageHandlerFor("/event/", "/event/"))
	http.HandleFunc("/images/battle/", handler.ImageHandlerFor("/battle/", "/battle/"))
	http.HandleFunc("/images/garden/", handler.ImageHandlerFor("/garden/", "/garden/"))
	http.HandleFunc("/images/garden/map/", handler.StructureImagesHandler)
	http.HandleFunc("/images/dungeon/", handler.ImageHandlerFor("/dungeon/", "/dungeon/"))
	http.HandleFunc("/images/alliance/", handler.ImageHandlerFor("/alliance/", "/guild/"))
	http.HandleFunc("/images/summon/", handler.ImageHandlerFor("/summon/", "/gacha/"))
	http.HandleFunc("/images/item/", handler.ImageHandlerFor("/item/", "/item/"))
	http.HandleFunc("/images/treasure/", handler.ImageHandlerFor("/treasure/", "/treasure/"))
	http.HandleFunc("/images/navi/", handler.ImageHandlerFor("/navi/", "/navi/"))
	http.HandleFunc("/images/weapon/", handler.ImageHandlerFor("/weapon/", "/weapon/"))
	http.HandleFunc("/images/weaponevent/", handler.ImageHandlerFor("/weaponevent/", "/weaponevent/"))

	// vc master data
	http.HandleFunc("/config/", handler.ConfigHandler)
	//dynamic pages
	http.HandleFunc("/cards/", handler.CardHandler)
	http.HandleFunc("/cards/table/", handler.CardTableHandler)
	http.HandleFunc("/cards/csv/", handler.CardCsvHandler)
	http.HandleFunc("/cards/glrcsv/", handler.CardCsvGLRHandler)
	http.HandleFunc("/cards/detail/", handler.CardDetailHandler)
	http.HandleFunc("/cards/levels/", handler.CardLevelHandler)
	http.HandleFunc("/archwitches/", handler.ArchwitchHandler)
	http.HandleFunc("/characters/", handler.CharacterTableHandler)
	http.HandleFunc("/characters/detail/", handler.CharacterDetailHandler)
	// http.HandleFunc("/character/csv/", handler.CharacterCsvHandler)

	http.HandleFunc("/weapons/", handler.WeaponHandler)
	http.HandleFunc("/weapons/detail/", handler.WeaponDetailHandler)

	http.HandleFunc("/items/", handler.ItemHandler)

	http.HandleFunc("/skills/", handler.SkillTableHandler)
	http.HandleFunc("/skills/csv/", handler.SkillCsvHandler)

	http.HandleFunc("/deckbonus/", handler.DeckBonusHandler)
	http.HandleFunc("/deckbonus/WIKI/", handler.DeckBonusWikiHandler)

	http.HandleFunc("/events/", handler.EventHandler)
	http.HandleFunc("/events/detail/", handler.EventDetailHandler)
	http.HandleFunc("/events/dungeonScenario/", handler.ScenarioHandler("dungeon", "DRV"))
	http.HandleFunc("/events/towerScenario/", handler.ScenarioHandler("tower", "Tower"))
	http.HandleFunc("/events/weaponScenario/", handler.ScenarioHandler("weapon_event", "Weapon Event"))

	http.HandleFunc("/thor/", handler.ThorHandler)

	http.HandleFunc("/maps/", handler.MapHandler)

	http.HandleFunc("/strb/", handler.StrbHandler)

	http.HandleFunc("/garden/structures/", handler.StructureListHandler)
	http.HandleFunc("/garden/structures/detail/", handler.StructureDetailHandler)

	http.HandleFunc("/awakenings/", handler.AwakeningsTableHandler)
	http.HandleFunc("/awakenings/csv/", handler.AwakeningsCsvHandler)

	http.HandleFunc("/decode/", handler.DecodeHandler)

	http.HandleFunc("/raw/", handler.RawDataHandler)
	http.HandleFunc("/raw/KEYS", handler.RawDataKeysHandler)

	http.HandleFunc("/SHUTDOWN/", func(w http.ResponseWriter, r *http.Request) { os.Exit(0) })

	os.Stdout.WriteString("Listening on port 8585. Connect to http://localhost:8585/\nPress <CTRL>+C to stop or close the terminal.\n")
	err := http.ListenAndServe("localhost:8585", nil)
	if err != nil {
		os.Stderr.WriteString(err.Error() + "\n")
	}
}

// Prints useage to the console
func usage() {
	os.Stdout.WriteString(fmt.Sprintf("To use this program you can specify the following command options:\n"+
		"-help\n\tShow this help message\n"+
		"-lang\n\tSelect a language pack to use. 'en' is the default\n"+
		"-debug\n\tOutputs error message to the standard error console\n"+
		"file1\n\tlocation of the VC master data file\n"+
		"example usages:\n\t%[1]s -help\n"+
		"\t%[1]s -lang %[2]s\n"+
		"\t%[1]s \"%[3]s\"\n"+
		"\t%[1]s -lang %[2]s \"%[3]s\"\n",
		os.Args[0],
		"zhs",
		"/path/to/vc/data/file",
	))
}
<commit_msg>fix usage message<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"zetsuboushita.net/vc_file_grouper/handler"
	"zetsuboushita.net/vc_file_grouper/vc"
)

// Main function that starts the program
func main() {

	cmdLang := flag.String("lang", "en", "The language pack to use. 'en' for English, 'zhs' for Chinese. ")
	cmdHelp := flag.Bool("help", false, "Show the help message")
	cmdDbg := flag.Bool("debug", false, "Outputs log messages to the standard console")
	flag.Parse()

	if *cmdHelp {
		usage()
		return
	}

	if !(*cmdDbg) {
		log.SetOutput(ioutil.Discard)
	}

	if cmdLang == nil {
		vc.LangPack = "en"
	} else {
		vc.LangPack = *cmdLang
	}

	if len(flag.Args()) == 0 {
		vc.FilePath = "."
	} else {
		vc.FilePath = filepath.Clean(flag.Args()[0])
	}

	if _, err := os.Stat(vc.FilePath); os.IsNotExist(err) {
		usage()
		vc.Data = &vc.VFile{}
		//return
	} else {
		vc.ReadMasterData(vc.FilePath)
	}

	//main page
	http.HandleFunc("/", handler.MasterDataHandler)
	http.HandleFunc("/css/", handler.CSSHandler)
	//image locations
	http.HandleFunc("/images/card/", handler.ImageCardHandler)
	http.HandleFunc("/images/cardthumb/", handler.ImageCardThumbHandler)
	http.HandleFunc("/images/cardHD/", handler.ImageCardHDHandler)
	http.HandleFunc("/images/cardSD/", handler.ImageCardSDHandler)
	http.HandleFunc("/images/event/", handler.ImageHandlerFor("/event/", "/event/"))
	http.HandleFunc("/images/battle/", handler.ImageHandlerFor("/battle/", "/battle/"))
	http.HandleFunc("/images/garden/", handler.ImageHandlerFor("/garden/", "/garden/"))
	http.HandleFunc("/images/garden/map/", handler.StructureImagesHandler)
	http.HandleFunc("/images/dungeon/", handler.ImageHandlerFor("/dungeon/", "/dungeon/"))
	http.HandleFunc("/images/alliance/", handler.ImageHandlerFor("/alliance/", "/guild/"))
	http.HandleFunc("/images/summon/", handler.ImageHandlerFor("/summon/", "/gacha/"))
	http.HandleFunc("/images/item/", handler.ImageHandlerFor("/item/", "/item/"))
	http.HandleFunc("/images/treasure/", handler.ImageHandlerFor("/treasure/", "/treasure/"))
	http.HandleFunc("/images/navi/", handler.ImageHandlerFor("/navi/", "/navi/"))
	http.HandleFunc("/images/weapon/", handler.ImageHandlerFor("/weapon/", "/weapon/"))
	http.HandleFunc("/images/weaponevent/", handler.ImageHandlerFor("/weaponevent/", "/weaponevent/"))

	// vc master data
	http.HandleFunc("/config/", handler.ConfigHandler)
	//dynamic pages
	http.HandleFunc("/cards/", handler.CardHandler)
	http.HandleFunc("/cards/table/", handler.CardTableHandler)
	http.HandleFunc("/cards/csv/", handler.CardCsvHandler)
	http.HandleFunc("/cards/glrcsv/", handler.CardCsvGLRHandler)
	http.HandleFunc("/cards/detail/", handler.CardDetailHandler)
	http.HandleFunc("/cards/levels/", handler.CardLevelHandler)
	http.HandleFunc("/archwitches/", handler.ArchwitchHandler)
	http.HandleFunc("/characters/", handler.CharacterTableHandler)
	http.HandleFunc("/characters/detail/", handler.CharacterDetailHandler)
	// http.HandleFunc("/character/csv/", handler.CharacterCsvHandler)

	http.HandleFunc("/weapons/", handler.WeaponHandler)
	http.HandleFunc("/weapons/detail/", handler.WeaponDetailHandler)

	http.HandleFunc("/items/", handler.ItemHandler)

	http.HandleFunc("/skills/", handler.SkillTableHandler)
	http.HandleFunc("/skills/csv/", handler.SkillCsvHandler)

	http.HandleFunc("/deckbonus/", handler.DeckBonusHandler)
	http.HandleFunc("/deckbonus/WIKI/", handler.DeckBonusWikiHandler)

	http.HandleFunc("/events/", handler.EventHandler)
	http.HandleFunc("/events/detail/", handler.EventDetailHandler)
	http.HandleFunc("/events/dungeonScenario/", handler.ScenarioHandler("dungeon", "DRV"))
	http.HandleFunc("/events/towerScenario/", handler.ScenarioHandler("tower", "Tower"))
	http.HandleFunc("/events/weaponScenario/", handler.ScenarioHandler("weapon_event", "Weapon Event"))

	http.HandleFunc("/thor/", handler.ThorHandler)

	http.HandleFunc("/maps/", handler.MapHandler)

	http.HandleFunc("/strb/", handler.StrbHandler)

	http.HandleFunc("/garden/structures/", handler.StructureListHandler)
	http.HandleFunc("/garden/structures/detail/", handler.StructureDetailHandler)

	http.HandleFunc("/awakenings/", handler.AwakeningsTableHandler)
	http.HandleFunc("/awakenings/csv/", handler.AwakeningsCsvHandler)

	http.HandleFunc("/decode/", handler.DecodeHandler)

	http.HandleFunc("/raw/", handler.RawDataHandler)
	http.HandleFunc("/raw/KEYS", handler.RawDataKeysHandler)

	http.HandleFunc("/SHUTDOWN/", func(w http.ResponseWriter, r *http.Request) { os.Exit(0) })

	os.Stdout.WriteString("Listening on port 8585. Connect to http://localhost:8585/\nPress <CTRL>+C to stop or close the terminal.\n")
	err := http.ListenAndServe("localhost:8585", nil)
	if err != nil {
		os.Stderr.WriteString(err.Error() + "\n")
	}
}

// Prints useage to the console
func usage() {
	os.Stdout.WriteString(fmt.Sprintf("To use this program you can specify the following command options:\n"+
		"-help\n\tShow this help message\n"+
		"-lang\n\tSelect a language pack to use. 'en' is the default\n"+
		"-debug\n\tOutputs error message to the standard error console\n"+
		"file1\n\tlocation of the VC master data file\n"+
		"example usages:\n\t%[1]s -help\n"+
		"\t%[1]s -lang %[2]s\n"+
		"\t%[1]s \"%[3]s\"\n"+
		"\t%[1]s -lang %[2]s \"%[3]s\"\n",
		os.Args[0],
		"zhs",
		"/path/to/vc/data/file",
	))
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"

	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"
	vision "google.golang.org/api/vision/v1"
)

const (
	SUCCESS = 0
	FAILURE = 1
)

func newVisionService() (*vision.Service, error) {
	ctx := context.Background()

	fn := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")
	if len(fn) == 0 {
		return nil, fmt.Errorf("Unable to get env variable: GOOGLE_APPLICATION_CREDENTIALS")
	}

	b, err := ioutil.ReadFile(fn)
	if err != nil {
		return nil, fmt.Errorf("Unable to read client secret file: %v", err)
	}

	config, err := google.JWTConfigFromJSON(b, vision.CloudPlatformScope)
	if err != nil {
		return nil, fmt.Errorf("Unable to parse client secret file to config: %v", err)
	}
	client := config.Client(ctx)

	srv, err := vision.New(client)
	if err != nil {
		return nil, fmt.Errorf("Unable to retrieve vision Client %v", err)
	}
	return srv, nil
}

func annotateImageRequest(path string) (*vision.AnnotateImageRequest, error) {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("Unable to read an image by file path: %v", err)
	}

	req := &vision.AnnotateImageRequest{
		// Apply image which is encoded by base64.
		Image: &vision.Image{
			Content: base64.StdEncoding.EncodeToString(b),
		},
		// Apply features to indicate what type of image detection.
		Features: []*vision.Feature{
			{
				MaxResults: 10,
				Type:       "FACE_DETECTION",
			},
		},
	}
	return req, nil
}

func run() int {
	// Parse arguments to run this function.
	flag.Parse()
	args := flag.Args()
	if len(args) == 0 {
		log.Printf("Argument is required.")
		return FAILURE
	}

	// Initialize vision service by a credentials json.
	srv, err := newVisionService()
	if err != nil {
		log.Printf("Unable to retrieve vision service: %v\n", err)
		return FAILURE
	}

	// Create request by given argument (last one).
	req, err := annotateImageRequest(args[len(args)-1])
	if err != nil {
		log.Printf("Unable to retrieve image request: %v\n", err)
		return FAILURE
	}

	// To call multiple image annotation requests.
	batch := &vision.BatchAnnotateImagesRequest{
		Requests: []*vision.AnnotateImageRequest{req},
	}

	// Execute the "vision.images.annotate".
	res, err := srv.Images.Annotate(batch).Do()
	if err != nil {
		log.Printf("Unable to execute images annotate requests: %v\n", err)
		return FAILURE
	}

	// FaceAnnotations
	body, err := json.MarshalIndent(res.Responses, "", "  ")
	if err != nil {
		log.Printf("Unable to marshal the response: %v\n", err)
		return FAILURE
	}
	fmt.Println(string(body))

	return SUCCESS
}

func main() {
	os.Exit(run())
}
<commit_msg>Refactor comment<commit_after>package main

import (
	"encoding/base64"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"

	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"
	vision "google.golang.org/api/vision/v1"
)

const (
	SUCCESS = 0
	FAILURE = 1
)

func newVisionService() (*vision.Service, error) {
	ctx := context.Background()

	fn := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")
	if len(fn) == 0 {
		return nil, fmt.Errorf("Unable to get env variable: GOOGLE_APPLICATION_CREDENTIALS")
	}

	b, err := ioutil.ReadFile(fn)
	if err != nil {
		return nil, fmt.Errorf("Unable to read client secret file: %v", err)
	}

	config, err := google.JWTConfigFromJSON(b, vision.CloudPlatformScope)
	if err != nil {
		return nil, fmt.Errorf("Unable to parse client secret file to config: %v", err)
	}
	client := config.Client(ctx)

	srv, err := vision.New(client)
	if err != nil {
		return nil, fmt.Errorf("Unable to retrieve vision Client %v", err)
	}
	return srv, nil
}

func annotateImageRequest(path string) (*vision.AnnotateImageRequest, error) {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("Unable to read an image by file path: %v", err)
	}

	req := &vision.AnnotateImageRequest{
		// Apply image which is encoded by base64.
		Image: &vision.Image{
			Content: base64.StdEncoding.EncodeToString(b),
		},
		// Apply features to indicate what type of image detection.
		Features: []*vision.Feature{
			{
				MaxResults: 10,
				Type:       "FACE_DETECTION",
			},
		},
	}
	return req, nil
}

func run() int {
	// Parse arguments to run this function.
	flag.Parse()
	args := flag.Args()
	if len(args) == 0 {
		log.Printf("Argument is required.")
		return FAILURE
	}

	// Initialize vision service by a credentials json.
	srv, err := newVisionService()
	if err != nil {
		log.Printf("Unable to retrieve vision service: %v\n", err)
		return FAILURE
	}

	// Create request by given argument (last one).
	req, err := annotateImageRequest(args[len(args)-1])
	if err != nil {
		log.Printf("Unable to retrieve image request: %v\n", err)
		return FAILURE
	}

	// To call multiple image annotation requests.
	batch := &vision.BatchAnnotateImagesRequest{
		Requests: []*vision.AnnotateImageRequest{req},
	}

	// Execute the "vision.images.annotate".
	res, err := srv.Images.Annotate(batch).Do()
	if err != nil {
		log.Printf("Unable to execute images annotate requests: %v\n", err)
		return FAILURE
	}

	// Marshal annotations from responses
	body, err := json.MarshalIndent(res.Responses, "", "  ")
	if err != nil {
		log.Printf("Unable to marshal the response: %v\n", err)
		return FAILURE
	}
	fmt.Println(string(body))

	return SUCCESS
}

func main() {
	os.Exit(run())
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/xoriath/alexandria/types"

	"database/sql"

	_ "github.com/mattn/go-sqlite3"

	"encoding/xml"

	"fmt"
	"net/http"

	"sync"
)

var db *sql.DB

func getDb() (db *sql.DB, fresh bool) {
	if db == nil {
		var err error

		db, err = sql.Open("sqlite3", "./keywords.db")
		if err != nil {
			panic(err)
		}

		fresh = true
	}

	fresh = false
	return
}

func prepareDb() {
	db, fresh := getDb()

	if fresh {
		stmt, err := db.Prepare("CREATE TABLE keywords ( keyword varchar(255) PRIMARY KEY, book varchar(49), file varchar(46) )")

		_, err = stmt.Exec()
		if err != nil {
			panic(err)
		}
	}
}

func insertIndexes(indexes *types.Indexes) {
	db, _ := getDb()

	stmt, err := db.Prepare("INSERT OR REPLACE INTO keywords(keyword, book, file) values(?, ?, ?)")
	if err != nil {
		panic(err)
	}

	tx, err := db.Begin()
	if err != nil {
		panic(err)
	}

	for _, index := range indexes.Keywords {
		fmt.Printf("Insert %v (%v:%v)\n", index.Keyword, indexes.BookID, index.File)
		_, err := tx.Stmt(stmt).Exec(index.Keyword, indexes.BookID, index.File)
		if err != nil {
			tx.Rollback()
			fmt.Println("Panic for", indexes.BookID)
		}
	}

	fmt.Println("Commit", indexes.BookID)
	tx.Commit()
}

func fetchIndex(id, version, language string, wg *sync.WaitGroup) {
	defer wg.Done()

	url := fmt.Sprintf("http://content.alexandria.atmel.com/meta/f1/%v-%v-%v.xml", id, language, version)

	resp, err := http.Get(url)
	if err != nil {
		panic(err)
	}

	defer resp.Body.Close()

	decoder := xml.NewDecoder(resp.Body)
	indexes := new(types.Indexes)

	err = decoder.Decode(indexes)
	if err != nil {
		fmt.Println("Failed to parse", url)
		panic(err)
	}

	insertIndexes(indexes)
}

func main() {
	fmt.Println("Prepare DB")
	prepareDb()

	fmt.Println("Fetch index.xml")
	resp, err := http.Get("http://content.alexandria.atmel.com/meta/index.xml")
	if err != nil {
		panic(err)
	}

	defer resp.Body.Close()

	decoder := xml.NewDecoder(resp.Body)
	books := new(types.Books)

	err = decoder.Decode(books)
	if err != nil {
		panic(err)
	}

	fmt.Println("Fetched", len(books.Books), "books")

	var wg sync.WaitGroup

	for _, book := range books.Books {
		wg.Add(1)
		fetchIndex(book.ID, book.Version, book.Language, &wg)
	}

	wg.Wait()
	fmt.Println("Done")
}
<commit_msg>Change db structure, split keywords and files into separate tables<commit_after>package main

import (
	"github.com/xoriath/alexandria/types"

	"database/sql"

	_ "github.com/mattn/go-sqlite3"

	"encoding/xml"

	"fmt"
	"net/http"
)

func getDb() (db *sql.DB, fresh bool) {
	var err error

	db, err = sql.Open("sqlite3", "./keywords.db")
	if err != nil {
		panic(err)
	}

	fresh = true
	return
}

func prepareDb() {
	db, fresh := getDb()

	if fresh {
		createTableStmt := `
			CREATE TABLE files (
				fileid		INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
				book 		VARCHAR(49) NOT NULL,
				file		VARCHAR(46) NOT NULL,

				CONSTRAINT file_constraint UNIQUE (book, file)
			);

			CREATE TABLE keywords (
				keyword 	TEXT NOT NULL,
				file		INTEGER NOT NULL,

				FOREIGN KEY(file) REFERENCES files(fileid)
			);

			CREATE INDEX keywords_index ON keywords(keyword);
			`

		_, err := db.Exec(createTableStmt)

		if err != nil {
			panic(err)
		}
	}
}

func findID(tx *sql.Tx, bookID, file string) (id int64) {

	query := fmt.Sprintf("SELECT fileid FROM files WHERE book = '%v' AND file = '%v'", bookID, file)

	rows, err := tx.Query(query)

	if err != nil {
		fmt.Println(query)
		panic(err)
	}

	for rows.Next() {
		err := rows.Scan(&id)

		if err != nil {
			panic(err)
		}

		break
	}

	fmt.Println("Fetched existing id", id)

	return
}

func insertIndexes(indexes *types.Indexes) {
	db, _ := getDb()

	bookStmt, err := db.Prepare("INSERT INTO files(book, file) values(?, ?)")
	if err != nil {
		panic(err)
	}

	keywordStmt, err := db.Prepare("INSERT INTO keywords(keyword, file) values(?, ?)")
	if err != nil {
		panic(err)
	}

	tx, err := db.Begin()
	if err != nil {
		panic(err)
	}

	idMap := make(map[string]int64)

	for _, index := range indexes.Keywords {
		fmt.Printf("Insert %v (%v:%v)\n", index.Keyword, indexes.BookID, index.File)

		// Check if we have this id already
		id := idMap[indexes.BookID+index.File]
		if id == 0 {
			// Try to insert, will fail if exists due to unique constraint
			res, err := tx.Stmt(bookStmt).Exec(indexes.BookID, index.File)
			if err != nil {
				// unique failed, time to search
				id = findID(tx, indexes.BookID, index.File)
			} else {
				// fetch id that we just inserted
				id, err = res.LastInsertId()
				if err != nil {
					tx.Rollback()
					panic(err)
				}
			}
		}

		idMap[indexes.BookID+index.File] = id

		_, err := tx.Stmt(keywordStmt).Exec(index.Keyword, id)
		if err != nil {
			tx.Rollback()
			fmt.Println("Panic for", indexes.BookID, id)
			panic(err)
		}
	}

	fmt.Println("Commit", indexes.BookID)
	tx.Commit()
}

func fetchIndex(id, version, language string) {

	url := fmt.Sprintf("http://content.alexandria.atmel.com/meta/f1/%v-%v-%v.xml", id, language, version)

	resp, err := http.Get(url)
	if err != nil {
		panic(err)
	}

	defer resp.Body.Close()

	decoder := xml.NewDecoder(resp.Body)
	indexes := new(types.Indexes)

	err = decoder.Decode(indexes)
	if err != nil {
		fmt.Println("Failed to parse", url)
		panic(err)
	}

	insertIndexes(indexes)
}

func main() {
	fmt.Println("Prepare DB")
	prepareDb()

	fmt.Println("Fetch index.xml")
	resp, err := http.Get("http://content.alexandria.atmel.com/meta/index.xml")
	if err != nil {
		panic(err)
	}

	defer resp.Body.Close()

	decoder := xml.NewDecoder(resp.Body)
	books := new(types.Books)

	err = decoder.Decode(books)
	if err != nil {
		panic(err)
	}

	fmt.Println("Fetched", len(books.Books), "books")

	for _, book := range books.Books {
		fetchIndex(book.ID, book.Version, book.Language)
	}

	fmt.Println("Done")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
)

var filename = "gifs.txt"

func main() {
	argsWithoutProg := os.Args[1:]
	if len(argsWithoutProg) < 2 {
		printHelp()
		return
	}

	arg := os.Args[1]
	switch arg {
	case "get":
		get()
		return
	case "add":
		add()
		return
	}
	printHelp()
	return
}

func get() {
	argsWithoutProg := os.Args[1:]
	if len(argsWithoutProg) == 1 {
		printHelp()
		return
	}
}

func add() {
	out, _ := exec.Command("/usr/bin/pbpaste").Output()
	paste := string(out)
	paste = paste + ", " + strings.Join(os.Args[2:], " ") + "\n"
	appendToStorage(paste)
}

func printHelp() {
	fmt.Println("Commands:")
	fmt.Println("gif add description")
	fmt.Println("gif get searchtext")
}

func appendToStorage(v string) {
	f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0600)
	if err != nil {
		panic(err)
	}

	defer f.Close()

	if _, err = f.WriteString(v); err != nil {
		panic(err)
	}
}
<commit_msg>saving the file to home directory<commit_after>package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"os/exec"
	"os/user"
	"strings"
)

var filename = "gifs.txt"

func main() {
	argsWithoutProg := os.Args[1:]
	if len(argsWithoutProg) < 2 {
		printHelp()
		return
	}

	arg := os.Args[1]
	switch arg {
	case "get":
		get()
		return
	case "add":
		add()
		return
	}
	printHelp()
	return
}

func get() {
	readStorage()
}

func add() {
	out, _ := exec.Command("/usr/bin/pbpaste").Output()
	paste := string(out)
	paste = paste + ", " + strings.Join(os.Args[2:], " ") + "\n"
	appendToStorage(paste)
}

func printHelp() {
	fmt.Println("Commands:")
	fmt.Println("gif add description")
	fmt.Println("gif get searchtext")
}

func readStorage() {
	usr, _ := user.Current()
	dir := usr.HomeDir
	f, err := os.OpenFile(dir+"/"+filename, os.O_RDONLY, 0600)

	if err != nil {
		panic(err)
	}

	defer f.Close()

	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		fmt.Println(scanner.Text())
	}

	if err := scanner.Err(); err != nil {
		log.Fatal(err)
	}
}

func appendToStorage(v string) {
	usr, _ := user.Current()
	dir := usr.HomeDir
	f, err := os.OpenFile(dir+"/"+filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
	if err != nil {
		panic(err)
	}

	defer f.Close()

	if _, err = f.WriteString(v); err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/chzyer/readline"
	"strings"
	"os"
	"errors"
)

const (
	Version = "0.0.1"
)

func main() {

	fmt.Println("DSocket is a tools to debug socket, ", Version)

	rl, err := readline.NewEx(&readline.Config{
		Prompt: Color(">>> ", Cyan),
		HistoryFile: "/tmp/dsockert.history",
	})

	if err != nil {
		panic(err)
	}

	defer rl.Close()

	for {
		line, err := rl.Readline()
		if err != nil {
			fmt.Println(err.Error())
			continue
		}

		ins := strings.TrimSpace(line)

		fmt.Println("\t", ins)

		if ins == "exit" || ins == "quit" {
			os.Exit(1)
		}

		if ins == "" {
			continue
		}

		cmds, err := ParseInputArgs(ins)

		if err != nil {
			fmt.Println(Color("\tError", Red), err.Error())
		}

		var e error
		switch cmds[0] {
		case "conn", "connect":
			e = connect(cmds[0], cmds[1:])
		case "rule":
			e = addRule(cmds[0], cmds[1:])
		case "send":
			e = send(cmds[0], cmds[1:])
		default:
			e = errors.New("unsupport" + cmds[0])
		}
		if e != nil {
			fmt.Println("\tError", e.Error())
		}

	}
}

func ParseInputArgs(line string) (args []string, err error) {
	as := make([]string, 0)
	rs := []rune(line)
	res := make([][]rune, 0)
	sub := make([]rune, 0)
	quote := false
	tm := false
	for _, v := range rs {
		if v == '\\' {
			if tm {
				sub = append(sub, v)
				tm = false
			} else {
				tm = true
			}
		} else if v == '"' {
			if tm {
				sub = append(sub, v)
				tm = false
			} else {
				quote = !quote
				if !quote {
					res = append(res, sub)
					sub = make([]rune, 0)
				}
			}
		} else if v == ' ' {
			if tm {
				sub = append(sub, v)
				tm = false
			} else if quote {
				sub = append(sub, v)
			} else {
				if len(sub) != 0 {
					res = append(res, sub)
					sub = make([]rune, 0)
				}
			}
		} else {
			if quote {
				if tm {
					if v == 't' {
						sub = append(sub, []rune{' ', ' ', ' ', ' '}...)
					} else if v == 'n' {
						sub = append(sub, '\n')
					} else {
						sub = append(sub, v)
					}
					tm = false
				} else {
					sub = append(sub, v)
				}
			} else {
				sub = append(sub, v)
			}
		}
	}
	if len(sub) != 0 {
		res = append(res, sub)
	}

	for _, v := range res {
		as = append(as, string(v))
	}
	args = as
	return
}
<commit_msg>remove log<commit_after>package main

import (
	"fmt"
	"github.com/chzyer/readline"
	"strings"
	"os"
	"errors"
)

const (
	Version = "0.0.1"
)

func main() {

	fmt.Println("DSocket is a tools to debug socket, ", Version)

	rl, err := readline.NewEx(&readline.Config{
		Prompt: Color(">>> ", Cyan),
		HistoryFile: "/tmp/dsockert.history",
	})

	if err != nil {
		panic(err)
	}

	defer rl.Close()

	for {
		line, err := rl.Readline()
		if err != nil {
			fmt.Println(err.Error())
			continue
		}

		ins := strings.TrimSpace(line)

		//fmt.Println("\t", ins)

		if ins == "exit" || ins == "quit" {
			os.Exit(1)
		}

		if ins == "" {
			continue
		}

		cmds, err := ParseInputArgs(ins)

		if err != nil {
			fmt.Println(Color("[ERROR:]", Red), err.Error())
		}

		var e error
		switch cmds[0] {
		case "conn", "connect":
			e = connect(cmds[0], cmds[1:])
		case "rule":
			e = addRule(cmds[0], cmds[1:])
		case "send":
			e = send(cmds[0], cmds[1:])
		default:
			e = errors.New("unsupport" + cmds[0])
		}
		if e != nil {
			fmt.Println("[ERROR:]", e.Error())
		}

	}
}

func ParseInputArgs(line string) (args []string, err error) {
	as := make([]string, 0)
	rs := []rune(line)
	res := make([][]rune, 0)
	sub := make([]rune, 0)
	quote := false
	tm := false
	for _, v := range rs {
		if v == '\\' {
			if tm {
				sub = append(sub, v)
				tm = false
			} else {
				tm = true
			}
		} else if v == '"' {
			if tm {
				sub = append(sub, v)
				tm = false
			} else {
				quote = !quote
				if !quote {
					res = append(res, sub)
					sub = make([]rune, 0)
				}
			}
		} else if v == ' ' {
			if tm {
				sub = append(sub, v)
				tm = false
			} else if quote {
				sub = append(sub, v)
			} else {
				if len(sub) != 0 {
					res = append(res, sub)
					sub = make([]rune, 0)
				}
			}
		} else {
			if quote {
				if tm {
					if v == 't' {
						sub = append(sub, []rune{' ', ' ', ' ', ' '}...)
					} else if v == 'n' {
						sub = append(sub, '\n')
					} else {
						sub = append(sub, v)
					}
					tm = false
				} else {
					sub = append(sub, v)
				}
			} else {
				sub = append(sub, v)
			}
		}
	}
	if len(sub) != 0 {
		res = append(res, sub)
	}

	for _, v := range res {
		as = append(as, string(v))
	}
	args = as
	return
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/coreos/nova-agent-watcher/third_party/code.google.com/p/go.exp/fsnotify"
	"github.com/coreos/nova-agent-watcher/third_party/github.com/coreos/coreos-cloudinit/cloudinit"
	"github.com/coreos/nova-agent-watcher/third_party/github.com/coreos/go-systemd/dbus"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

var fileHandlers = map[string]func(string, string) (*cloudinit.CloudConfig, error){
	"/etc/conf.d/net":            handleNet,
	"/root/.ssh/authorized_keys": handleSSH,
	//	"/var/lib/heat-cfntools/cfn-userdata": handleHeatUserData,
}

func main() {
	var watch_dir = flag.String("watch-dir", ".", "Path to watch")
	var scripts_dir = flag.String("scripts-dir", "./scripts", "Path for supporting shell scripts")
	flag.Parse()
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}

	done := make(chan bool)

	// Process events
	go func() {
		for {
			select {
			case ev := <-watcher.Event:
				log.Println("got event", ev)
				if !ev.IsCreate() {
					continue
				}
				err := runEvent(ev.Name, *watch_dir, *scripts_dir)
				if err != nil {
					log.Println("error handling event:", err)
				}
			case err := <-watcher.Error:
				log.Println("error:", err)
				done <- true
			}
		}
	}()

	for k, _ := range fileHandlers {
		full_path := filepath.Join(*watch_dir, k)
		dir_path := filepath.Dir(full_path)
		err = watcher.Watch(dir_path)
		if err != nil {
			log.Println("warn: error setting up watcher (dir doesn't exist?):", err)
		}
		err = runEvent(full_path, *watch_dir, *scripts_dir)
		if err != nil {
			log.Println("warn: initalizing event failed:", err)
		}
	}

	<-done
	watcher.Close()
}

func runEvent(full_path string, watch_dir string, scripts_dir string) error {
	if _, err := os.Stat(full_path); err != nil {
		return err
	}
	file_name, err := filepath.Rel(watch_dir, full_path)
	if err != nil {
		log.Println("error getting relative path for:", full_path)
		return err
	}
	func_key := filepath.Join("/", file_name)
	if err != nil {
		log.Println("error getting joining path for:", full_path)
		return err
	}
	if _, ok := fileHandlers[func_key]; !ok {
		log.Println("no handler found for", func_key)
		return nil
	}
	config, err := fileHandlers[func_key](full_path, scripts_dir)
	if err != nil {
		log.Println("error in handler", err)
		return err
	}
	err = runConfig(config)
	return err
}

func runConfig(config *cloudinit.CloudConfig) error {
	f, err := ioutil.TempFile("", "rackspace-cloudinit-")
	if err != nil {
		return err
	}
	log.Println("writing to:", f.Name())
	_, err = f.WriteString(config.String())
	if err != nil {
		return err
	}
	// systemd-run coreos-cloudinit --file f.Name()
	props := []dbus.Property{
		dbus.PropDescription("Unit generated and executed by coreos-cloudinit on behalf of user"),
		dbus.PropExecStart([]string{"/usr/bin/coreos-cloudinit", "--from-file", f.Name()}, false),
	}

	tmp_file := filepath.Base(f.Name())
	name := fmt.Sprintf("%s.service", tmp_file)
	log.Printf("Creating transient systemd unit '%s'", name)

	conn, err := dbus.New()
	if err != nil {
		return err
	}
	_, err = conn.StartTransientUnit(name, "replace", props...)
	return err
}

func handleNet(file_name string, scripts_dir string) (*cloudinit.CloudConfig, error) {
	contents, err := ioutil.ReadFile(file_name)
	if err != nil {
		log.Println("error: could not read file", err)
		return nil, err
	}
	network_str := string(contents)

	re := regexp.MustCompile("eth[\\d]+")
	eths := re.FindAllString(network_str, -1)

	config := cloudinit.CloudConfig{}

	configured_eths := map[string]bool{}
	for _, eth := range eths {
		// hack to prevent multiple regex matches from creating multiple files
		if configured_eths[eth] {
			continue
		}

		script := filepath.Join(scripts_dir, "gentoo-to-networkd")
		cmd := exec.Command(script, eth, file_name)
		out, err := cmd.CombinedOutput()
		if err != nil {
			log.Println("error: not good output", err)
			return nil, err
		}
		unit := fmt.Sprintf("50-%s.network", eth)
		u := cloudinit.Unit{
			Name:    unit,
			Content: string(out),
		}
		config.Coreos.Units = append(config.Coreos.Units, u)
		configured_eths[eth] = true
	}
	return &config, nil
}
func handleSSH(file_name string, scripts_dir string) (*cloudinit.CloudConfig, error) {
	contents, err := ioutil.ReadFile(file_name)
	if err != nil {
		log.Println("error: could not read file", err)
		return nil, err
	}
	ssh_keys := string(contents)

	re := regexp.MustCompile("ssh-.+\n")
	keys := re.FindAllString(ssh_keys, -1)
	config := cloudinit.CloudConfig{}
	for _, key := range keys {
		key = strings.TrimRight(key, "\n")
		config.SSH_Authorized_Keys = append(config.SSH_Authorized_Keys, key)
	}
	// XXX cloudn't figure out how to combine these regexs. This is needed
	// to match keys that do not end in a newline
	re = regexp.MustCompile("ssh-.+\\z")
	keys = re.FindAllString(ssh_keys, -1)
	for _, key := range keys {
		log.Println(key)
		key = strings.TrimRight(key, "\n")
		config.SSH_Authorized_Keys = append(config.SSH_Authorized_Keys, key)
	}
	return &config, nil
}
<commit_msg>feat(users/hostname): add user handling and new hostname<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/coreos/nova-agent-watcher/third_party/code.google.com/p/go.exp/fsnotify"
	"github.com/coreos/nova-agent-watcher/third_party/github.com/coreos/coreos-cloudinit/cloudinit"
	"github.com/coreos/nova-agent-watcher/third_party/github.com/coreos/go-systemd/dbus"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

var fileHandlers = map[string]func(string, string) (*cloudinit.CloudConfig, error){
	"/etc/conf.d/net":            handleNet,
	"/root/.ssh/authorized_keys": handleSSH,
	"/etc/shadow":                handleShadow,
	"/etc/conf.d/hostname":       handleHostname,
	//	"/var/lib/heat-cfntools/cfn-userdata": handleHeatUserData,
}

func main() {
	var watch_dir = flag.String("watch-dir", ".", "Path to watch")
	var scripts_dir = flag.String("scripts-dir", "./scripts", "Path for supporting shell scripts")
	flag.Parse()
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}

	done := make(chan bool)

	// Process events
	go func() {
		for {
			select {
			case ev := <-watcher.Event:
				log.Println("got event", ev)
				if !ev.IsCreate() {
					continue
				}
				err := runEvent(ev.Name, *watch_dir, *scripts_dir)
				if err != nil {
					log.Println("error handling event:", err)
				}
			case err := <-watcher.Error:
				log.Println("error:", err)
				done <- true
			}
		}
	}()

	for k, _ := range fileHandlers {
		full_path := filepath.Join(*watch_dir, k)
		dir_path := filepath.Dir(full_path)
		err = watcher.Watch(dir_path)
		if err != nil {
			log.Println("warn: error setting up watcher (dir doesn't exist?):", err)
		}
		err = runEvent(full_path, *watch_dir, *scripts_dir)
		if err != nil {
			log.Println("warn: initalizing event failed:", err)
		}
	}

	<-done
	watcher.Close()
}

func runEvent(full_path string, watch_dir string, scripts_dir string) error {
	if _, err := os.Stat(full_path); err != nil {
		return err
	}
	file_name, err := filepath.Rel(watch_dir, full_path)
	if err != nil {
		log.Println("error getting relative path for:", full_path)
		return err
	}
	func_key := filepath.Join("/", file_name)
	if err != nil {
		log.Println("error getting joining path for:", full_path)
		return err
	}
	if _, ok := fileHandlers[func_key]; !ok {
		log.Println("no handler found for", func_key)
		return nil
	}
	config, err := fileHandlers[func_key](full_path, scripts_dir)
	if err != nil {
		log.Println("error in handler", err)
		return err
	}
	err = runConfig(config)
	return err
}

func runConfig(config *cloudinit.CloudConfig) error {
	f, err := ioutil.TempFile("", "rackspace-cloudinit-")
	if err != nil {
		return err
	}
	log.Println("writing to:", f.Name())
	_, err = f.WriteString(config.String())
	if err != nil {
		return err
	}
	// systemd-run coreos-cloudinit --file f.Name()
	props := []dbus.Property{
		dbus.PropDescription("Unit generated and executed by coreos-cloudinit on behalf of user"),
		dbus.PropExecStart([]string{"/usr/bin/coreos-cloudinit", "--from-file", f.Name()}, false),
	}

	tmp_file := filepath.Base(f.Name())
	name := fmt.Sprintf("%s.service", tmp_file)
	log.Printf("Creating transient systemd unit '%s'", name)

	conn, err := dbus.New()
	if err != nil {
		return err
	}
	_, err = conn.StartTransientUnit(name, "replace", props...)
	return err
}

func handleNet(file_name string, scripts_dir string) (*cloudinit.CloudConfig, error) {
	contents, err := ioutil.ReadFile(file_name)
	if err != nil {
		log.Println("error: could not read file", err)
		return nil, err
	}
	network_str := string(contents)

	re := regexp.MustCompile("eth[\\d]+")
	eths := re.FindAllString(network_str, -1)

	config := cloudinit.CloudConfig{}

	configured_eths := map[string]bool{}
	for _, eth := range eths {
		// hack to prevent multiple regex matches from creating multiple files
		if configured_eths[eth] {
			continue
		}

		script := filepath.Join(scripts_dir, "gentoo-to-networkd")
		cmd := exec.Command(script, eth, file_name)
		out, err := cmd.CombinedOutput()
		if err != nil {
			log.Println("error: not good output", err)
			return nil, err
		}
		unit := fmt.Sprintf("50-%s.network", eth)
		u := cloudinit.Unit{
			Name:    unit,
			Content: string(out),
		}
		config.Coreos.Units = append(config.Coreos.Units, u)
		configured_eths[eth] = true
	}
	return &config, nil
}
func handleSSH(file_name string, scripts_dir string) (*cloudinit.CloudConfig, error) {
	contents, err := ioutil.ReadFile(file_name)
	if err != nil {
		log.Println("error: could not read file", err)
		return nil, err
	}
	ssh_keys := string(contents)

	re := regexp.MustCompile("ssh-.+\n")
	keys := re.FindAllString(ssh_keys, -1)
	config := cloudinit.CloudConfig{}
	for _, key := range keys {
		key = strings.TrimRight(key, "\n")
		config.SSHAuthorizedKeys = append(config.SSHAuthorizedKeys, key)
	}
	// XXX cloudn't figure out how to combine these regexs. This is needed
	// to match keys that do not end in a newline
	re = regexp.MustCompile("ssh-.+\\z")
	keys = re.FindAllString(ssh_keys, -1)
	for _, key := range keys {
		log.Println(key)
		key = strings.TrimRight(key, "\n")
		config.SSHAuthorizedKeys = append(config.SSHAuthorizedKeys, key)
	}
	return &config, nil
}
func handleShadow(file_name string, scripts_dir string) (*cloudinit.CloudConfig, error) {
	config := cloudinit.CloudConfig{}
	contents, err := ioutil.ReadFile(file_name)
	if err != nil {
		log.Println("error: could not read file", err)
		return nil, err
	}
	passwd := string(contents)

	// root:$1$NyBnu0Gl$GBoj9u6lx3R8nyqHuxPwz/:15839:0:::::
	re := regexp.MustCompile("root:([^:]+):.+\n")
	keys := re.FindStringSubmatch(passwd)
	if len(keys) == 2 {
		passwd_hash := keys[1]

		// set the password for both users
		root := cloudinit.User{
			Name:         "root",
			PasswordHash: passwd_hash,
		}
		config.Users = append(config.Users, root)
		core := cloudinit.User{
			Name:         "core",
			PasswordHash: passwd_hash,
		}
		config.Users = append(config.Users, core)
	}
	return &config, nil
}
func handleHostname(file_name string, scripts_dir string) (*cloudinit.CloudConfig, error) {
	config := cloudinit.CloudConfig{}
	contents, err := ioutil.ReadFile(file_name)
	if err != nil {
		log.Println("error: could not read file", err)
		return nil, err
	}
	hostname := string(contents)
	// HOSTNAME="polvi-test"
	re := regexp.MustCompile("HOSTNAME=\"(.+)\"")
	keys := re.FindStringSubmatch(hostname)
	if len(keys) == 2 {
		hostname := keys[1]

		config.Hostname = hostname
	}

	return &config, nil
}
<|endoftext|>