<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"strings"

	"golang.org/x/exp/inotify"
	"pault.ag/go/config"
	"pault.ag/go/debian/control"
	"pault.ag/go/mailer"
	"pault.ag/go/reprepro"
)

var enqueuedMailer *mailer.Mailer

var conf = Enqueued{
	Root: ".",
}

type Enqueued struct {
	Root          string `flag:"root" description:"Repo root to watch"`
	Templates     string `flag:"templates" description:"Mail templates"`
	Administrator string `flag:"admin" description:"Admin address"`
}

func Watch(watcher *inotify.Watcher, file os.FileInfo) error {
	if !file.IsDir() {
		return nil
	}

	incoming := path.Join(file.Name(), "incoming")

	if _, err := os.Stat(incoming); os.IsNotExist(err) {
		return err
	}
	/* Sweep existing files in there */

	if err := watcher.Watch(incoming); err != nil {
		return err
	}

	return nil
}

type Upload struct {
	Changes control.Changes
	Repo    reprepro.Repo
	Reason  string
}

func Mail(to []string, template string, data interface{}) {
	if enqueuedMailer != nil {
		if err := enqueuedMailer.Mail(to, template, data); err != nil {
			log.Printf("Error: %s", err)
		}
	}
}

func Process(changesPath string) {
	repoRoot := path.Clean(path.Join(path.Dir(changesPath), ".."))
	pwd, err := os.Getwd()
	if err != nil {
		log.Printf("%s\n", err)
		return
	}
	gnuPGHome := path.Join(pwd, "..", "private", repoRoot, ".gnupg")
	repo := reprepro.NewRepo(repoRoot, fmt.Sprintf("--gnupghome=%s", gnuPGHome))

	changes, err := control.ParseChangesFile(changesPath)
	if err != nil {
		log.Printf("Error: %s\n", err)
	}

	err = repo.Include(changes.Distribution, changesPath)
	if err != nil {
		go Mail([]string{conf.Administrator}, "rejected", &Upload{
			Changes: *changes,
			Repo:    *repo,
			Reason:  err.Error(),
		})

		log.Printf("Error: %s\n", err)
		changes.Remove()
		log.Printf("Removed %s and associated files\n", changesPath)
		return
	}

	log.Printf("Included %s into %s", changes.Source, repo.Basedir)
	go Mail([]string{conf.Administrator}, "accepted", &Upload{
		Changes: *changes,
		Repo:    *repo,
	})
	changes.Remove()
}

func main() {
	flags, err := config.LoadFlags("enqueued", &conf)
	if err != nil {
		log.Fatal(err)
	}
	flags.Parse(os.Args[1:])
	os.Chdir(conf.Root)

	if conf.Templates != "" {
		enqueuedMailer, err = mailer.NewMailer(conf.Templates)
		if err != nil {
			log.Fatal(err)
		}
	}

	files, err := ioutil.ReadDir(conf.Root)
	if err != nil {
		log.Fatal(err)
	}

	watcher, err := inotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}

	for _, file := range files {
		if err := Watch(watcher, file); err != nil {
			log.Fatal(err)
		}
	}

	for {
		select {
		case ev := <-watcher.Event:
			if ev.Mask^inotify.IN_CLOSE_WRITE != 0 ||
				!strings.HasSuffix(ev.Name, ".changes") {
				continue
			}
			Process(ev.Name)
		}
	}
}
<commit_msg>fuck it, always main<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"strings"

	"golang.org/x/exp/inotify"
	"pault.ag/go/config"
	"pault.ag/go/debian/control"
	"pault.ag/go/mailer"
	"pault.ag/go/reprepro"
)

var enqueuedMailer *mailer.Mailer

var conf = Enqueued{
	Root: ".",
}

type Enqueued struct {
	Root          string `flag:"root" description:"Repo root to watch"`
	Templates     string `flag:"templates" description:"Mail templates"`
	Administrator string `flag:"admin" description:"Admin address"`
}

func Watch(watcher *inotify.Watcher, file os.FileInfo) error {
	if !file.IsDir() {
		return nil
	}

	incoming := path.Join(file.Name(), "incoming")

	if _, err := os.Stat(incoming); os.IsNotExist(err) {
		return err
	}
	/* Sweep existing files in there */

	if err := watcher.Watch(incoming); err != nil {
		return err
	}

	return nil
}

type Upload struct {
	Changes control.Changes
	Repo    reprepro.Repo
	Reason  string
}

func Mail(to []string, template string, data interface{}) {
	if enqueuedMailer != nil {
		if err := enqueuedMailer.Mail(to, template, data); err != nil {
			log.Printf("Error: %s", err)
		}
	}
}

func Process(changesPath string) {
	repoRoot := path.Clean(path.Join(path.Dir(changesPath), ".."))
	pwd, err := os.Getwd()
	if err != nil {
		log.Printf("%s\n", err)
		return
	}
	gnuPGHome := path.Join(pwd, "..", "private", repoRoot, ".gnupg")
	repo := reprepro.NewRepo(
		repoRoot,
		"--component=main",
		fmt.Sprintf("--gnupghome=%s", gnuPGHome),
	)

	changes, err := control.ParseChangesFile(changesPath)
	if err != nil {
		log.Printf("Error: %s\n", err)
	}

	err = repo.Include(changes.Distribution, changesPath)
	if err != nil {
		go Mail([]string{conf.Administrator}, "rejected", &Upload{
			Changes: *changes,
			Repo:    *repo,
			Reason:  err.Error(),
		})

		log.Printf("Error: %s\n", err)
		changes.Remove()
		log.Printf("Removed %s and associated files\n", changesPath)
		return
	}

	log.Printf("Included %s into %s", changes.Source, repo.Basedir)
	go Mail([]string{conf.Administrator}, "accepted", &Upload{
		Changes: *changes,
		Repo:    *repo,
	})
	changes.Remove()
}

func main() {
	flags, err := config.LoadFlags("enqueued", &conf)
	if err != nil {
		log.Fatal(err)
	}
	flags.Parse(os.Args[1:])
	os.Chdir(conf.Root)

	if conf.Templates != "" {
		enqueuedMailer, err = mailer.NewMailer(conf.Templates)
		if err != nil {
			log.Fatal(err)
		}
	}

	files, err := ioutil.ReadDir(conf.Root)
	if err != nil {
		log.Fatal(err)
	}

	watcher, err := inotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}

	for _, file := range files {
		if err := Watch(watcher, file); err != nil {
			log.Fatal(err)
		}
	}

	for {
		select {
		case ev := <-watcher.Event:
			if ev.Mask^inotify.IN_CLOSE_WRITE != 0 ||
				!strings.HasSuffix(ev.Name, ".changes") {
				continue
			}
			Process(ev.Name)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All rights reserved.
//
// 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 web

import (
	"html/template"
	"log"
)

// Top provides the standard templates in parsed form
var Top = template.New("top").Funcs(Funcmap)

// TemplateText contains the text of the standard templates.
var TemplateText = map[string]string{

	"didyoumean": `

  <title>Error</title>

{{.Message}}. Did you mean {{.Suggestion}} ?

`,

	"head": `

<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

  `,

	"jsdep": `

`,

	// the template for the search box.
	"searchbox": `
<form action="search">

      <input class="form-control" placeholder="Search for some code..." autofocus
              {{if .Query}}
              value={{.Query}}
              {{end}}
              id="searchbox" type="text" name="q">

        <button class="btn btn-primary">Search</button>

</form>
`,

	"navbar": `

      Zoekt
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse" aria-expanded="false">
        Toggle navigation

      </button>

      <form class="navbar-form navbar-left" action="search">

          <input class="form-control"
                placeholder="Search for some code..." role="search"
                id="navsearchbox" type="text" name="q" autofocus
                {{if .Query}}
                value={{.Query}}
                {{end}}>

Max Results

            <input class="form-control" type="number" id="maxhits" name="num" value="{{.Num}}">

          <button class="btn btn-primary">Search</button>

      </form>

`,
	// search box for the entry page.
	"search": `

{{template "head"}}
<title>Zoekt, en gij zult spinazie eten</title>

      {{template "searchbox" .Last}}

Search examples:

needle

search for "needle"

thread or needle

search for either "thread" or "needle"

class needle

search for files containing both "class" and "needle"

class Needle

search for files containing both "class" (case insensitive) and "Needle" (case sensitive)

class Needle case:yes

search for files containing "class" and "Needle", both case sensitively

"class Needle"

search for files with the phrase "class Needle"

needle -hay

search for files with the word "needle" but not the word "hay"

path file:java

search for the word "path" in files whose name contains "java"

needle lang:python

search for "needle" in Python source code

f:\.c$

search for files whose name ends with ".c"

path -file:java

search for the word "path" excluding files whose name contains "java"

foo.*bar

search for the regular expression "foo.*bar"

-(Path File) Stream

search "Stream", but exclude files containing both "Path" and "File"

-Path\ file Stream

search "Stream", but exclude files containing "Path File"

phone r:droid

search for "phone" in repositories whose name contains "droid"

phone b:master

for Git repos, find "phone" in files in branches whose name contains "master".

phone b:HEAD

for Git repos, find "phone" in the default ('HEAD') branch.

To list repositories, try:

r:droid

list repositories whose name contains "droid".

r:go -r:google

list repositories whose name contains "go" but not "google".

      About

        Used {{HumanUnit .Stats.IndexBytes}} mem for
        {{.Stats.Documents}} documents ({{HumanUnit .Stats.ContentBytes}})
        from {{.Stats.Repos}} repositories.

`,

	"results": `

{{template "head"}}
<title>Results for {{.QueryStr}}</title>

  {{template "navbar" .Last}}

      {{if .Stats.Crashes}}
{{.Stats.Crashes}} shards crashed
{{end}}
      {{ $fileCount := len .FileMatches }}
      Found {{.Stats.MatchCount}} results in {{.Stats.FileCount}} files{{if lt $fileCount .Stats.FileCount}},
        showing top {{ $fileCount }} files (show more).
      {{else}}.{{end}}

    {{range .FileMatches}}

            {{if .URL}}{{else}}{{end}}

              {{.Repo}}:{{.FileName}}:
              [ {{if .Branches}}{{range .Branches}}{{.}},{{end}}{{end}} ]
              {{if .Language}}{{.Language}}{{end}}
              {{if .DuplicateID}}Duplicate result{{end}}

      {{if not .DuplicateID}}

        {{range .Matches}}

{{if .URL}}{{end}}{{.LineNum}}{{if .URL}}{{end}}: {{range .Fragments}}{{.Pre}}{{.Match}}{{.Post}}{{end}}

        {{end}}

      {{end}}

    {{end}}

      Took {{.Stats.Duration}}{{if .Stats.Wait}}(queued: {{.Stats.Wait}}){{end}} for
      {{HumanUnit .Stats.IndexBytesLoaded}}B index data,
      {{.Stats.NgramMatches}} ngram matches,
      {{.Stats.FilesConsidered}} docs considered,
      {{.Stats.FilesLoaded}} docs ({{HumanUnit .Stats.ContentBytesLoaded}}B) loaded,
      {{.Stats.FilesSkipped}} docs skipped

  {{ template "jsdep"}}

`,

	"repolist": `

{{template "head"}}

    {{template "navbar" .Last}}

        Found {{.Stats.Repos}} repositories ({{.Stats.Documents}} files, {{HumanUnit .Stats.ContentBytes}}b content)
        Last updated
        Branches
        Size

      {{range .Repos}}

        {{if .URL}}{{end}}{{.Name}}{{if .URL}}{{end}}
        {{.IndexTime.Format "Jan 02, 2006 15:04"}}

          {{range .Branches}}
          {{if .URL}}<tt>{{end}}{{.Name}}{{if .URL}} </tt>{{end}}
          {{end}}

        {{HumanUnit .Files}} files ({{HumanUnit .Size}})

      {{end}}

  {{ template "jsdep"}}

`,

	"print": `

    <title>{{.Repo}}:{{.Name}}</title>

{{template "searchbox" .Last}}

  <tt>{{.Repo}} : {{.Name}}</tt>

{{ range $index, $ln := .Lines}}

{{Inc $index}}: {{$ln}}

{{end}}

`,

	"about": `

  <title>About zoekt</title>

  This is zoekt (IPA: /zukt/),
  an open-source full text search engine. It's pronounced roughly as you would
  pronounce "zooked" in English.

Used {{HumanUnit .Stats.IndexBytes}} memory for
{{.Stats.Documents}} documents ({{HumanUnit .Stats.ContentBytes}})
from {{.Stats.Repos}} repositories.

{{if .Version}}Zoekt version {{.Version}}, uptime{{else}}Uptime{{end}} {{.Uptime}}

`,
}

func init() {
	for k, v := range TemplateText {
		_, err := Top.New(k).Parse(v)
		if err != nil {
			log.Panicf("parse(%s): %v:", k, err)
		}
	}
}
<commit_msg>web: add the "sym:" operator <commit_after>// Copyright 2016 Google Inc. All rights reserved.
//
// 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 web

import (
	"html/template"
	"log"
)

// Top provides the standard templates in parsed form
var Top = template.New("top").Funcs(Funcmap)

// TemplateText contains the text of the standard templates.
var TemplateText = map[string]string{

	"didyoumean": `

  <title>Error</title>

{{.Message}}. Did you mean {{.Suggestion}} ?

`,

	"head": `

<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

  `,

	"jsdep": `

`,

	// the template for the search box.
	"searchbox": `
<form action="search">

      <input class="form-control" placeholder="Search for some code..." autofocus
              {{if .Query}}
              value={{.Query}}
              {{end}}
              id="searchbox" type="text" name="q">

        <button class="btn btn-primary">Search</button>

</form>
`,

	"navbar": `

      Zoekt
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse" aria-expanded="false">
        Toggle navigation

      </button>

      <form class="navbar-form navbar-left" action="search">

          <input class="form-control"
                placeholder="Search for some code..." role="search"
                id="navsearchbox" type="text" name="q" autofocus
                {{if .Query}}
                value={{.Query}}
                {{end}}>

Max Results

            <input class="form-control" type="number" id="maxhits" name="num" value="{{.Num}}">

          <button class="btn btn-primary">Search</button>

      </form>

`,
	// search box for the entry page.
	"search": `

{{template "head"}}
<title>Zoekt, en gij zult spinazie eten</title>

      {{template "searchbox" .Last}}

Search examples:

needle

search for "needle"

thread or needle

search for either "thread" or "needle"

class needle

search for files containing both "class" and "needle"

class Needle

search for files containing both "class" (case insensitive) and "Needle" (case sensitive)

class Needle case:yes

search for files containing "class" and "Needle", both case sensitively

"class Needle"

search for files with the phrase "class Needle"

needle -hay

search for files with the word "needle" but not the word "hay"

path file:java

search for the word "path" in files whose name contains "java"

needle lang:python

search for "needle" in Python source code

f:\.c$

search for files whose name ends with ".c"

path -file:java

search for the word "path" excluding files whose name contains "java"

foo.*bar

search for the regular expression "foo.*bar"

-(Path File) Stream

search "Stream", but exclude files containing both "Path" and "File"

-Path\ file Stream

search "Stream", but exclude files containing "Path File"

sym:data

search for symbol definitions containing "data"

phone r:droid

search for "phone" in repositories whose name contains "droid"

phone b:master

for Git repos, find "phone" in files in branches whose name contains "master".

phone b:HEAD

for Git repos, find "phone" in the default ('HEAD') branch.

To list repositories, try:

r:droid

list repositories whose name contains "droid".

r:go -r:google

list repositories whose name contains "go" but not "google".

      About

        Used {{HumanUnit .Stats.IndexBytes}} mem for
        {{.Stats.Documents}} documents ({{HumanUnit .Stats.ContentBytes}})
        from {{.Stats.Repos}} repositories.

`,

	"results": `

{{template "head"}}
<title>Results for {{.QueryStr}}</title>

  {{template "navbar" .Last}}

      {{if .Stats.Crashes}}
{{.Stats.Crashes}} shards crashed
{{end}}
      {{ $fileCount := len .FileMatches }}
      Found {{.Stats.MatchCount}} results in {{.Stats.FileCount}} files{{if lt $fileCount .Stats.FileCount}},
        showing top {{ $fileCount }} files (show more).
      {{else}}.{{end}}

    {{range .FileMatches}}

            {{if .URL}}{{else}}{{end}}

              {{.Repo}}:{{.FileName}}:
              [ {{if .Branches}}{{range .Branches}}{{.}},{{end}}{{end}} ]
              {{if .Language}}{{.Language}}{{end}}
              {{if .DuplicateID}}Duplicate result{{end}}

      {{if not .DuplicateID}}

        {{range .Matches}}

{{if .URL}}{{end}}{{.LineNum}}{{if .URL}}{{end}}: {{range .Fragments}}{{.Pre}}{{.Match}}{{.Post}}{{end}}

        {{end}}

      {{end}}

    {{end}}

      Took {{.Stats.Duration}}{{if .Stats.Wait}}(queued: {{.Stats.Wait}}){{end}} for
      {{HumanUnit .Stats.IndexBytesLoaded}}B index data,
      {{.Stats.NgramMatches}} ngram matches,
      {{.Stats.FilesConsidered}} docs considered,
      {{.Stats.FilesLoaded}} docs ({{HumanUnit .Stats.ContentBytesLoaded}}B) loaded,
      {{.Stats.FilesSkipped}} docs skipped

  {{ template "jsdep"}}

`,

	"repolist": `

{{template "head"}}

    {{template "navbar" .Last}}

        Found {{.Stats.Repos}} repositories ({{.Stats.Documents}} files, {{HumanUnit .Stats.ContentBytes}}b content)
        Last updated
        Branches
        Size

      {{range .Repos}}

        {{if .URL}}{{end}}{{.Name}}{{if .URL}}{{end}}
        {{.IndexTime.Format "Jan 02, 2006 15:04"}}

          {{range .Branches}}
          {{if .URL}}<tt>{{end}}{{.Name}}{{if .URL}} </tt>{{end}}
          {{end}}

        {{HumanUnit .Files}} files ({{HumanUnit .Size}})

      {{end}}

  {{ template "jsdep"}}

`,

	"print": `

    <title>{{.Repo}}:{{.Name}}</title>

{{template "searchbox" .Last}}

  <tt>{{.Repo}} : {{.Name}}</tt>

{{ range $index, $ln := .Lines}}

{{Inc $index}}: {{$ln}}

{{end}}

`,

	"about": `

  <title>About zoekt</title>

  This is zoekt (IPA: /zukt/),
  an open-source full text search engine. It's pronounced roughly as you would
  pronounce "zooked" in English.

Used {{HumanUnit .Stats.IndexBytes}} memory for
{{.Stats.Documents}} documents ({{HumanUnit .Stats.ContentBytes}})
from {{.Stats.Repos}} repositories.

{{if .Version}}Zoekt version {{.Version}}, uptime{{else}}Uptime{{end}} {{.Uptime}}

`,
}

func init() {
	for k, v := range TemplateText {
		_, err := Top.New(k).Parse(v)
		if err != nil {
			log.Panicf("parse(%s): %v:", k, err)
		}
	}
}
<|endoftext|>


<commit_before>package web

const (
	indexTemplate string = `
<!DOCTYPE html>

	<meta charset="utf-8">
	<title> Wallboard Control </title>

	Oops, something went wrong with the Wallboard page!

`

	welcomeTemplate string = `
<!DOCTYPE html>

	<meta charset="utf-8">
	<title> Welcome </title>

wbc

		{{ if ne .Client "" }}
Client: {{ .Client }}
{{end}}

IP Addr: {{ .RemoteAddr }}

Add a URL or two and this page will disappear. :)

`
)
<commit_msg>Fix path to welcome page<commit_after>package web

const (
	indexTemplate string = `
<!DOCTYPE html>

	<meta charset="utf-8">
	<title> Wallboard Control </title>

	Oops, something went wrong with the Wallboard page!

`

	welcomeTemplate string = `
<!DOCTYPE html>

	<meta charset="utf-8">
	<title> Welcome </title>

wbc

		{{ if ne .Client "" }}
Client: {{ .Client }}
{{end}}

IP Addr: {{ .RemoteAddr }}

Add a URL or two and this page will disappear. :)

`
)
<|endoftext|>


<commit_before><commit_msg>fmt: fix caching bug in Scan<commit_after><|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"log"
	"math"
	"strconv"

	"github.com/turing-complete/laboratory/src/internal/command"
	"github.com/turing-complete/laboratory/src/internal/config"
	"github.com/turing-complete/laboratory/src/internal/database"
	"github.com/turing-complete/laboratory/src/internal/support"
	"github.com/turing-complete/laboratory/src/internal/system"
	"github.com/turing-complete/laboratory/src/internal/target"
	"github.com/turing-complete/laboratory/src/internal/uncertainty"

	isolver "github.com/turing-complete/laboratory/src/internal/solver"
)

var (
	approximateFile = flag.String("approximate", "", "an output of `approximate` (required)")
	outputFile      = flag.String("o", "", "an output file (required)")
	sampleSeed      = flag.String("s", "", "a seed for generating samples")
	sampleCount     = flag.String("n", "", "the number of samples")
)

type Config *config.Assessment

func main() {
	command.Run(function)
}

func function(config *config.Config) error {
	const (
		maxSteps = 10
	)

	if len(*sampleSeed) > 0 {
		if number, err := strconv.ParseInt(*sampleSeed, 0, 64); err != nil {
			return err
		} else {
			config.Assessment.Seed = number
		}
	}
	if len(*sampleCount) > 0 {
		if number, err := strconv.ParseUint(*sampleCount, 0, 64); err != nil {
			return err
		} else {
			config.Assessment.Samples = uint(number)
		}
	}

	if config.Assessment.Samples == 0 {
		return errors.New("the number of samples should be positive")
	}

	approximate, err := database.Open(*approximateFile)
	if err != nil {
		return err
	}
	defer approximate.Close()

	output, err := database.Create(*outputFile)
	if err != nil {
		return err
	}
	defer output.Close()

	system, err := system.New(&config.System)
	if err != nil {
		return err
	}

	uncertainty1, err := uncertainty.New(system, &config.Uncertainty)
	if err != nil {
		return err
	}

	uncertainty2, err := uncertainty.NewMarginal(system, &config.Uncertainty)
	if err != nil {
		return err
	}

	target1, err := target.New(system, uncertainty1, &config.Target)
	if err != nil {
		return err
	}

	target2, err := target.New(system, uncertainty2, &config.Target)
	if err != nil {
		return err
	}

	ni, no := target1.Dimensions()

	solver, err := isolver.New(ni, no, &config.Solver)
	if err != nil {
		return err
	}

	solution := new(isolver.Solution)
	if err = approximate.Get("solution", solution); err != nil {
		return err
	}

	points := generate(target1, target2, &config.Assessment)

	ns := uint(len(points)) / ni

	log.Printf("Evaluating the surrogate model at %d points...\n", ns)
	log.Printf("%10s %15s\n", "Iteration", "Nodes")

	nk := uint(len(solution.Active))

	steps := make([]uint, nk)
	values := make([]float64, 0, ns*no)

	k, Δ := uint(0), float64(nk-1)/(math.Min(maxSteps, float64(nk))-1)

	for i, na := uint(0), uint(0); i < nk; i++ {
		na += solution.Active[i]
		steps[k] += solution.Active[i]

		if i != uint(float64(k)*Δ+0.5) {
			continue
		}
		k++

		log.Printf("%10d %15d\n", i, na)

		s := *solution
		s.Nodes = na
		s.Indices = s.Indices[:na*ni]
		s.Surpluses = s.Surpluses[:na*no]

		values = append(values, solver.Evaluate(&s, points)...)
	}

	nk, steps = k, steps[:k]

	log.Println("Done.")

	if err := output.Put("solution", *solution); err != nil {
		return err
	}
	if err := output.Put("points", points, ni, ns); err != nil {
		return err
	}
	if err := output.Put("steps", steps); err != nil {
		return err
	}
	if err := output.Put("values", values, no, ns, nk); err != nil {
		return err
	}

	return nil
}

func generate(into, from target.Target, config *config.Assessment) []float64 {
	ns := config.Samples

	nif, _ := from.Dimensions()
	nii, _ := into.Dimensions()

	zf := support.Generate(nif, ns, config.Seed)
	zi := make([]float64, nii*ns)

	for i := uint(0); i < ns; i++ {
		copy(zi[i*nii:(i+1)*nii], into.Inverse(from.Forward(zf[i*nif:(i+1)*nif])))
	}

	return zi
}
<commit_msg>predict: make a cosmetic adjustment<commit_after>package main

import (
	"errors"
	"flag"
	"log"
	"math"
	"strconv"

	"github.com/turing-complete/laboratory/src/internal/command"
	"github.com/turing-complete/laboratory/src/internal/config"
	"github.com/turing-complete/laboratory/src/internal/database"
	"github.com/turing-complete/laboratory/src/internal/support"
	"github.com/turing-complete/laboratory/src/internal/system"
	"github.com/turing-complete/laboratory/src/internal/target"
	"github.com/turing-complete/laboratory/src/internal/uncertainty"

	isolver "github.com/turing-complete/laboratory/src/internal/solver"
)

var (
	approximateFile = flag.String("approximate", "", "an output of `approximate` (required)")
	outputFile      = flag.String("o", "", "an output file (required)")
	sampleSeed      = flag.String("s", "", "a seed for generating samples")
	sampleCount     = flag.String("n", "", "the number of samples")
)

type Config *config.Assessment

func main() {
	command.Run(function)
}

func function(config *config.Config) error {
	const (
		maxSteps = 10
	)

	if len(*sampleSeed) > 0 {
		if number, err := strconv.ParseInt(*sampleSeed, 0, 64); err != nil {
			return err
		} else {
			config.Assessment.Seed = number
		}
	}
	if len(*sampleCount) > 0 {
		if number, err := strconv.ParseUint(*sampleCount, 0, 64); err != nil {
			return err
		} else {
			config.Assessment.Samples = uint(number)
		}
	}

	if config.Assessment.Samples == 0 {
		return errors.New("the number of samples should be positive")
	}

	approximate, err := database.Open(*approximateFile)
	if err != nil {
		return err
	}
	defer approximate.Close()

	output, err := database.Create(*outputFile)
	if err != nil {
		return err
	}
	defer output.Close()

	system, err := system.New(&config.System)
	if err != nil {
		return err
	}

	uncertainty1, err := uncertainty.New(system, &config.Uncertainty)
	if err != nil {
		return err
	}

	uncertainty2, err := uncertainty.NewMarginal(system, &config.Uncertainty)
	if err != nil {
		return err
	}

	target1, err := target.New(system, uncertainty1, &config.Target)
	if err != nil {
		return err
	}

	target2, err := target.New(system, uncertainty2, &config.Target)
	if err != nil {
		return err
	}

	ni, no := target1.Dimensions()

	solver, err := isolver.New(ni, no, &config.Solver)
	if err != nil {
		return err
	}

	solution := new(isolver.Solution)
	if err = approximate.Get("solution", solution); err != nil {
		return err
	}

	ns := config.Assessment.Samples

	points := generate(target1, target2, ns, config.Assessment.Seed)

	log.Printf("Evaluating the surrogate model at %d points...\n", ns)
	log.Printf("%10s %15s\n", "Iteration", "Nodes")

	nk := uint(len(solution.Active))

	steps := make([]uint, nk)
	values := make([]float64, 0, ns*no)

	k, Δ := uint(0), float64(nk-1)/(math.Min(maxSteps, float64(nk))-1)

	for i, na := uint(0), uint(0); i < nk; i++ {
		na += solution.Active[i]
		steps[k] += solution.Active[i]

		if i != uint(float64(k)*Δ+0.5) {
			continue
		}
		k++

		log.Printf("%10d %15d\n", i, na)

		s := *solution
		s.Nodes = na
		s.Indices = s.Indices[:na*ni]
		s.Surpluses = s.Surpluses[:na*no]

		values = append(values, solver.Evaluate(&s, points)...)
	}

	nk, steps = k, steps[:k]

	log.Println("Done.")

	if err := output.Put("solution", *solution); err != nil {
		return err
	}
	if err := output.Put("points", points, ni, ns); err != nil {
		return err
	}
	if err := output.Put("steps", steps); err != nil {
		return err
	}
	if err := output.Put("values", values, no, ns, nk); err != nil {
		return err
	}

	return nil
}

func generate(into, from target.Target, ns uint, seed int64) []float64 {
	nif, _ := from.Dimensions()
	nii, _ := into.Dimensions()

	zf := support.Generate(nif, ns, seed)
	zi := make([]float64, nii*ns)

	for i := uint(0); i < ns; i++ {
		copy(zi[i*nii:(i+1)*nii], into.Inverse(from.Forward(zf[i*nif:(i+1)*nif])))
	}

	return zi
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2015, 2017 Hendrik van Wyk
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of invertergui nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package webgui

import (
	"fmt"
	"github.com/hpdvanwyk/invertergui/datasource"
	"html/template"
	"net/http"
	"sync"
	"time"
)

const (
	Temperature = iota
	Low_battery
	Overload
	Inverter
	Float
	Bulk
	Absorption
	Mains
)

var leds = map[int]string{
	0: "Temperature",
	1: "Low battery",
	2: "Overload",
	3: "Inverter",
	4: "Float",
	5: "Bulk",
	6: "Absorption",
	7: "Mains",
}

type WebGui struct {
	respChan chan statusProcessed
	stopChan chan struct{}
	template *template.Template

	muninRespChan chan muninData
	poller        datasource.DataPoller
	wg            sync.WaitGroup

	pu *prometheusUpdater
}

func NewWebGui(source datasource.DataPoller, batteryCapacity float64) *WebGui {
	w := new(WebGui)
	w.respChan = make(chan statusProcessed)
	w.muninRespChan = make(chan muninData)
	w.stopChan = make(chan struct{})
	var err error
	w.template, err = template.New("thegui").Parse(htmlTemplate)
	if err != nil {
		panic(err)
	}
	w.poller = source
	w.pu = newPrometheusUpdater()

	w.wg.Add(1)
	go w.dataPoll(batteryCapacity)
	return w
}

type templateInput struct {
	Error error

	Date string

	OutCurrent string
	OutVoltage string
	OutPower   string

	InCurrent string
	InVoltage string
	InPower   string

	InMinOut string

	BatVoltage string
	BatCurrent string
	BatPower   string
	BatCharge  string

	InFreq string

	Leds []string
}

func (w *WebGui) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	statusErr := <-w.respChan

	tmpInput := buildTemplateInput(&statusErr, time.Now())

	err := w.template.Execute(rw, tmpInput)
	if err != nil {
		panic(err)
	}
}

func buildTemplateInput(statusErr *statusProcessed, now time.Time) *templateInput {
	status := statusErr.status
	outPower := status.OutVoltage * status.OutCurrent
	inPower := status.InCurrent * status.InVoltage

	tmpInput := &templateInput{
		Error:      statusErr.err,
		Date:       now.Format(time.RFC1123Z),
		OutCurrent: fmt.Sprintf("%.3f", status.OutCurrent),
		OutVoltage: fmt.Sprintf("%.3f", status.OutVoltage),
		OutPower:   fmt.Sprintf("%.3f", outPower),
		InCurrent:  fmt.Sprintf("%.3f", status.InCurrent),
		InVoltage:  fmt.Sprintf("%.3f", status.InVoltage),
		InFreq:     fmt.Sprintf("%.3f", status.InFreq),
		InPower:    fmt.Sprintf("%.3f", inPower),

		InMinOut: fmt.Sprintf("%.3f", inPower-outPower),

		BatCurrent: fmt.Sprintf("%.3f", status.BatCurrent),
		BatVoltage: fmt.Sprintf("%.3f", status.BatVoltage),
		BatPower:   fmt.Sprintf("%.3f", status.BatVoltage*status.BatCurrent),
		BatCharge:  fmt.Sprintf("%.3f", statusErr.chargeLevel),
	}
	if len(status.Leds) == 8 {
		for i := 7; i >= 0; i-- {
			if status.Leds[i] == 1 {
				tmpInput.Leds = append(tmpInput.Leds, leds[i])
			}
		}
	}
	return tmpInput
}

func (w *WebGui) Stop() {
	w.poller.Stop()
	close(w.stopChan)
	w.wg.Wait()
}

type statusProcessed struct {
	status      datasource.MultiplusStatus
	chargeLevel float64
	err         error
}

// dataPoll waits for data from the w.poller channel. It will send its currently stored status
// to respChan if anything reads from it.
func (w *WebGui) dataPoll(batteryCapacity float64) {
	tracker := NewChargeTracker(batteryCapacity)
	pollChan := w.poller.C()
	var statusP statusProcessed
	var muninValues muninData
	for {
		select {
		case s := <-pollChan:
			if s.Err != nil {
				statusP.err = s.Err
			} else {
				statusP.status = s.MpStatus
				statusP.err = nil
				tracker.Update(s.MpStatus.BatCurrent, s.Time)
				if s.MpStatus.Leds[Float] == 1 {
					tracker.Reset()
				}
				statusP.chargeLevel = tracker.CurrentLevel()
				calcMuninValues(&muninValues, &statusP)
				w.pu.updatePrometheus(&statusP)
			}
		case w.respChan <- statusP:
		case w.muninRespChan <- muninValues:
			zeroMuninValues(&muninValues)
		case <-w.stopChan:
			w.wg.Done()
			return
		}
	}
}
<commit_msg>Use time provided by data poller instead of getting time again.<commit_after>/*
Copyright (c) 2015, 2017 Hendrik van Wyk
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of invertergui nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package webgui

import (
	"fmt"
	"github.com/hpdvanwyk/invertergui/datasource"
	"html/template"
	"net/http"
	"sync"
	"time"
)

const (
	Temperature = iota
	Low_battery
	Overload
	Inverter
	Float
	Bulk
	Absorption
	Mains
)

var leds = map[int]string{
	0: "Temperature",
	1: "Low battery",
	2: "Overload",
	3: "Inverter",
	4: "Float",
	5: "Bulk",
	6: "Absorption",
	7: "Mains",
}

type WebGui struct {
	respChan chan statusProcessed
	stopChan chan struct{}
	template *template.Template

	muninRespChan chan muninData
	poller        datasource.DataPoller
	wg            sync.WaitGroup

	pu *prometheusUpdater
}

func NewWebGui(source datasource.DataPoller, batteryCapacity float64) *WebGui {
	w := new(WebGui)
	w.respChan = make(chan statusProcessed)
	w.muninRespChan = make(chan muninData)
	w.stopChan = make(chan struct{})
	var err error
	w.template, err = template.New("thegui").Parse(htmlTemplate)
	if err != nil {
		panic(err)
	}
	w.poller = source
	w.pu = newPrometheusUpdater()

	w.wg.Add(1)
	go w.dataPoll(batteryCapacity)
	return w
}

type templateInput struct {
	Error error

	Date string

	OutCurrent string
	OutVoltage string
	OutPower   string

	InCurrent string
	InVoltage string
	InPower   string

	InMinOut string

	BatVoltage string
	BatCurrent string
	BatPower   string
	BatCharge  string

	InFreq string

	Leds []string
}

func (w *WebGui) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	statusErr := <-w.respChan

	tmpInput := buildTemplateInput(&statusErr, statusErr.timestamp)

	err := w.template.Execute(rw, tmpInput)
	if err != nil {
		panic(err)
	}
}

func buildTemplateInput(statusErr *statusProcessed, now time.Time) *templateInput {
	status := statusErr.status
	outPower := status.OutVoltage * status.OutCurrent
	inPower := status.InCurrent * status.InVoltage

	tmpInput := &templateInput{
		Error:      statusErr.err,
		Date:       now.Format(time.RFC1123Z),
		OutCurrent: fmt.Sprintf("%.3f", status.OutCurrent),
		OutVoltage: fmt.Sprintf("%.3f", status.OutVoltage),
		OutPower:   fmt.Sprintf("%.3f", outPower),
		InCurrent:  fmt.Sprintf("%.3f", status.InCurrent),
		InVoltage:  fmt.Sprintf("%.3f", status.InVoltage),
		InFreq:     fmt.Sprintf("%.3f", status.InFreq),
		InPower:    fmt.Sprintf("%.3f", inPower),

		InMinOut: fmt.Sprintf("%.3f", inPower-outPower),

		BatCurrent: fmt.Sprintf("%.3f", status.BatCurrent),
		BatVoltage: fmt.Sprintf("%.3f", status.BatVoltage),
		BatPower:   fmt.Sprintf("%.3f", status.BatVoltage*status.BatCurrent),
		BatCharge:  fmt.Sprintf("%.3f", statusErr.chargeLevel),
	}
	if len(status.Leds) == 8 {
		for i := 7; i >= 0; i-- {
			if status.Leds[i] == 1 {
				tmpInput.Leds = append(tmpInput.Leds, leds[i])
			}
		}
	}
	return tmpInput
}

func (w *WebGui) Stop() {
	w.poller.Stop()
	close(w.stopChan)
	w.wg.Wait()
}

type statusProcessed struct {
	status      datasource.MultiplusStatus
	chargeLevel float64
	err         error
	timestamp 		time.Time
}

// dataPoll waits for data from the w.poller channel. It will send its currently stored status
// to respChan if anything reads from it.
func (w *WebGui) dataPoll(batteryCapacity float64) {
	tracker := NewChargeTracker(batteryCapacity)
	pollChan := w.poller.C()
	var statusP statusProcessed
	var muninValues muninData
	for {
		select {
		case s := <-pollChan:
			if s.Err != nil {
				statusP.err = s.Err
			} else {
				statusP.status = s.MpStatus
				statusP.err = nil
				statusP.timestamp = s.Time
				tracker.Update(s.MpStatus.BatCurrent, s.Time)
				if s.MpStatus.Leds[Float] == 1 {
					tracker.Reset()
				}
				statusP.chargeLevel = tracker.CurrentLevel()
				calcMuninValues(&muninValues, &statusP)
				w.pu.updatePrometheus(&statusP)
			}
		case w.respChan <- statusP:
		case w.muninRespChan <- muninValues:
			zeroMuninValues(&muninValues)
		case <-w.stopChan:
			w.wg.Done()
			return
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"expvar"
	"fmt"
	"html/template"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/NYTimes/gziphandler"
	"github.com/mat/besticon/besticon"
	"github.com/mat/besticon/besticon/iconserver/assets"
	"github.com/mat/besticon/lettericon"
)

func indexHandler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "" || r.URL.Path == "/" {
		renderHTMLTemplate(w, 200, indexHTML, nil)
	} else {
		renderHTMLTemplate(w, 404, notFoundHTML, nil)
	}
}

func iconsHandler(w http.ResponseWriter, r *http.Request) {
	url := r.FormValue(urlParam)
	if len(url) == 0 {
		http.Redirect(w, r, "/", 302)
		return
	}

	finder := besticon.IconFinder{}

	formats := r.FormValue("formats")
	if formats != "" {
		finder.FormatsAllowed = strings.Split(r.FormValue("formats"), ",")
	}

	e, icons := finder.FetchIcons(url)
	switch {
	case e != nil:
		renderHTMLTemplate(w, 404, iconsHTML, pageInfo{URL: url, Error: e})
	case len(icons) == 0:
		errNoIcons := errors.New("this poor site has no icons at all :-(")
		renderHTMLTemplate(w, 404, iconsHTML, pageInfo{URL: url, Error: errNoIcons})
	default:
		renderHTMLTemplate(w, 200, iconsHTML, pageInfo{Icons: icons, URL: url})
	}
}

func iconHandler(w http.ResponseWriter, r *http.Request) {
	url := r.FormValue("url")
	if len(url) == 0 {
		writeAPIError(w, 400, errors.New("need url parameter"))
		return
	}

	size := r.FormValue("size")
	if size == "" {
		writeAPIError(w, 400, errors.New("need size parameter"))
		return
	}
	minSize, err := strconv.Atoi(size)
	if err != nil || minSize < 0 || minSize > 500 {
		writeAPIError(w, 400, errors.New("bad size parameter"))
		return
	}

	finder := besticon.IconFinder{}
	formats := r.FormValue("formats")
	if formats != "" {
		finder.FormatsAllowed = strings.Split(r.FormValue("formats"), ",")
	}

	finder.FetchIcons(url)

	icon := finder.IconWithMinSize(minSize)
	if icon != nil {
		http.Redirect(w, r, icon.URL, 302)
		return
	}

	fallbackIconURL := r.FormValue("fallback_icon_url")
	if fallbackIconURL != "" {
		http.Redirect(w, r, fallbackIconURL, 302)
		return
	}

	iconColor := finder.MainColorForIcons()
	letter := lettericon.MainLetterFromURL(url)
	redirectPath := lettericon.IconPath(letter, size, iconColor)
	http.Redirect(w, r, redirectPath, 302)
}

func popularHandler(w http.ResponseWriter, r *http.Request) {
	iconSize, err := strconv.Atoi(r.FormValue("iconsize"))
	if iconSize > 500 || iconSize < 10 || err != nil {
		iconSize = 120
	}

	pageInfo := struct {
		URLs        []string
		IconSize    int
		DisplaySize int
	}{
		besticon.PopularSites,
		iconSize,
		iconSize / 2,
	}
	renderHTMLTemplate(w, 200, popularHTML, pageInfo)
}

const (
	urlParam    = "url"
	prettyParam = "pretty"
	maxAge      = "max_age"
)

const defaultMaxAge = time.Duration(604800) * time.Second // 7 days

func alliconsHandler(w http.ResponseWriter, r *http.Request) {
	url := r.FormValue(urlParam)
	if len(url) == 0 {
		errMissingURL := errors.New("need url query parameter")
		writeAPIError(w, 400, errMissingURL)
		return
	}

	finder := besticon.IconFinder{}
	formats := r.FormValue("formats")
	if formats != "" {
		finder.FormatsAllowed = strings.Split(r.FormValue("formats"), ",")
	}

	e, icons := finder.FetchIcons(url)
	if e != nil {
		writeAPIError(w, 404, e)
		return
	}

	pretty, err := strconv.ParseBool(r.FormValue(prettyParam))
	prettyPrint := (err == nil) && pretty

	writeAPIIcons(w, url, icons, prettyPrint)
}

func lettericonHandler(w http.ResponseWriter, r *http.Request) {
	charParam, col, size := lettericon.ParseIconPath(r.URL.Path)
	if charParam != "" {
		w.Header().Add(contentType, imagePNG)
		lettericon.Render(charParam, col, size, w)
	} else {
		writeAPIError(w, 400, errors.New("wrong format for lettericons/ path, must look like lettericons/M-144-EFC25D.png"))
	}
}

func obsoleteAPIHandler(w http.ResponseWriter, r *http.Request) {
	if r.FormValue("i_am_feeling_lucky") == "yes" {
		http.Redirect(w, r, fmt.Sprintf("/icon?size=120&%s", r.URL.RawQuery), 302)
	} else {
		http.Redirect(w, r, fmt.Sprintf("/allicons.json?%s", r.URL.RawQuery), 302)
	}
}

func writeAPIError(w http.ResponseWriter, httpStatus int, e error) {
	data := struct {
		Error string `json:"error"`
	}{
		e.Error(),
	}
	renderJSONResponsePretty(w, httpStatus, data)
}

func writeAPIIcons(w http.ResponseWriter, url string, icons []besticon.Icon, pretty bool) {
	// Don't return whole image data
	newIcons := []besticon.Icon{}
	for _, ico := range icons {
		newIcon := ico
		newIcon.ImageData = nil
		newIcons = append(newIcons, newIcon)
	}

	data := &struct {
		URL   string          `json:"url"`
		Icons []besticon.Icon `json:"icons"`
	}{
		url,
		newIcons,
	}

	if pretty {
		renderJSONResponsePretty(w, 200, data)
	} else {
		renderJSONResponse(w, 200, data)
	}
}

const (
	contentType     = "Content-Type"
	applicationJSON = "application/json"
	imagePNG        = "image/png"
	cacheControl    = "Cache-Control"
)

func renderJSONResponse(w http.ResponseWriter, httpStatus int, data interface{}) {
	w.Header().Add(contentType, applicationJSON)
	w.WriteHeader(httpStatus)
	enc := json.NewEncoder(w)
	enc.Encode(data)
}

func renderJSONResponsePretty(w http.ResponseWriter, httpStatus int, data interface{}) {
	w.Header().Add(contentType, applicationJSON)
	w.WriteHeader(httpStatus)
	b, _ := json.MarshalIndent(data, "", "  ")
	w.Write(b)
}

type pageInfo struct {
	URL   string
	Icons []besticon.Icon
	Error error
}

func (pi pageInfo) Host() string {
	u := pi.URL
	url, _ := url.Parse(u)
	if url != nil && url.Host != "" {
		return url.Host
	}
	return pi.URL
}

func (pi pageInfo) Best() string {
	if len(pi.Icons) > 0 {
		best := pi.Icons[0]
		return best.URL
	}
	return ""
}

func renderHTMLTemplate(w http.ResponseWriter, httpStatus int, templ *template.Template, data interface{}) {
	w.Header().Add(contentType, "text/html; charset=utf-8")
	w.WriteHeader(httpStatus)

	err := templ.Execute(w, data)
	if err != nil {
		err = fmt.Errorf("server: could not generate output: %s", err)
		logger.Print(err)
		w.Write([]byte(err.Error()))
	}
}

func startServer(port string) {
	registerGzipHandler("/", indexHandler)
	registerGzipHandler("/icons", iconsHandler)
	registerHandler("/icon", iconHandler)
	registerGzipHandler("/popular", popularHandler)
	registerGzipHandler("/allicons.json", alliconsHandler)
	registerHandler("/lettericons/", lettericonHandler)
	registerHandler("/api/icons", obsoleteAPIHandler)

	serveAsset("/pure-0.5.0-min.css", "besticon/iconserver/assets/pure-0.5.0-min.css", oneYear)
	serveAsset("/grids-responsive-0.5.0-min.css", "besticon/iconserver/assets/grids-responsive-0.5.0-min.css", oneYear)
	serveAsset("/main-min.css", "besticon/iconserver/assets/main-min.css", oneYear)

	serveAsset("/icon.svg", "besticon/iconserver/assets/icon.svg", oneYear)
	serveAsset("/favicon.ico", "besticon/iconserver/assets/favicon.ico", oneYear)
	serveAsset("/apple-touch-icon.png", "besticon/iconserver/assets/apple-touch-icon.png", oneYear)

	addr := "0.0.0.0:" + port
	logger.Print("Starting server on ", addr, "...")
	e := http.ListenAndServe(addr, newLoggingMux())
	if e != nil {
		logger.Fatalf("cannot start server: %s\n", e)
	}
}

const (
	oneYear = 365 * 24 * 3600
)

func serveAsset(path string, assetPath string, maxAgeSeconds int) {
	registerGzipHandler(path, func(w http.ResponseWriter, r *http.Request) {
		assetInfo, err := assets.AssetInfo(assetPath)
		if err != nil {
			panic(err)
		}

		w.Header().Add(cacheControl, fmt.Sprintf("max-age=%d", maxAgeSeconds))

		http.ServeContent(w, r, assetInfo.Name(), assetInfo.ModTime(),
			bytes.NewReader(assets.MustAsset(assetPath)))
	})
}

func registerHandler(path string, f http.HandlerFunc) {
	http.Handle(path, newExpvarHandler(path, f))
}

func registerGzipHandler(path string, f http.HandlerFunc) {
	http.Handle(path, gziphandler.GzipHandler(newExpvarHandler(path, f)))
}

func main() {
	fmt.Printf("iconserver %s (%s) - https://icons.better-idea.org\n", besticon.VersionString, runtime.Version())
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	startServer(port)
}

func init() {
	indexHTML = templateFromAsset("besticon/iconserver/assets/index.html", "index.html")
	iconsHTML = templateFromAsset("besticon/iconserver/assets/icons.html", "icons.html")
	popularHTML = templateFromAsset("besticon/iconserver/assets/popular.html", "popular.html")
	notFoundHTML = templateFromAsset("besticon/iconserver/assets/not_found.html", "not_found.html")
}

func templateFromAsset(assetPath, templateName string) *template.Template {
	bytes := assets.MustAsset(assetPath)
	return template.Must(template.New(templateName).Funcs(funcMap).Parse(string(bytes)))
}

var indexHTML *template.Template
var iconsHTML *template.Template
var popularHTML *template.Template
var notFoundHTML *template.Template

var funcMap = template.FuncMap{
	"ImgWidth": imgWidth,
}

func imgWidth(i *besticon.Icon) int {
	return i.Width / 2.0
}

func init() {
	cacheSize := os.Getenv("CACHE_SIZE_MB")
	if cacheSize == "" {
		besticon.SetCacheMaxSize(32)
	} else {
		n, _ := strconv.Atoi(cacheSize)
		besticon.SetCacheMaxSize(int64(n))
	}

	if besticon.CacheEnabled() {
		expvar.Publish("cacheBytes", expvar.Func(func() interface{} { return besticon.GetCacheStats().Bytes }))
		expvar.Publish("cacheItems", expvar.Func(func() interface{} { return besticon.GetCacheStats().Items }))
		expvar.Publish("cacheGets", expvar.Func(func() interface{} { return besticon.GetCacheStats().Gets }))
		expvar.Publish("cacheHits", expvar.Func(func() interface{} { return besticon.GetCacheStats().Hits }))
		expvar.Publish("cacheEvictions", expvar.Func(func() interface{} { return besticon.GetCacheStats().Evictions }))
	}
}
<commit_msg>Remove unused constant<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"expvar"
	"fmt"
	"html/template"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strconv"
	"strings"

	"github.com/NYTimes/gziphandler"
	"github.com/mat/besticon/besticon"
	"github.com/mat/besticon/besticon/iconserver/assets"
	"github.com/mat/besticon/lettericon"
)

func indexHandler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "" || r.URL.Path == "/" {
		renderHTMLTemplate(w, 200, indexHTML, nil)
	} else {
		renderHTMLTemplate(w, 404, notFoundHTML, nil)
	}
}

func iconsHandler(w http.ResponseWriter, r *http.Request) {
	url := r.FormValue(urlParam)
	if len(url) == 0 {
		http.Redirect(w, r, "/", 302)
		return
	}

	finder := besticon.IconFinder{}

	formats := r.FormValue("formats")
	if formats != "" {
		finder.FormatsAllowed = strings.Split(r.FormValue("formats"), ",")
	}

	e, icons := finder.FetchIcons(url)
	switch {
	case e != nil:
		renderHTMLTemplate(w, 404, iconsHTML, pageInfo{URL: url, Error: e})
	case len(icons) == 0:
		errNoIcons := errors.New("this poor site has no icons at all :-(")
		renderHTMLTemplate(w, 404, iconsHTML, pageInfo{URL: url, Error: errNoIcons})
	default:
		renderHTMLTemplate(w, 200, iconsHTML, pageInfo{Icons: icons, URL: url})
	}
}

func iconHandler(w http.ResponseWriter, r *http.Request) {
	url := r.FormValue("url")
	if len(url) == 0 {
		writeAPIError(w, 400, errors.New("need url parameter"))
		return
	}

	size := r.FormValue("size")
	if size == "" {
		writeAPIError(w, 400, errors.New("need size parameter"))
		return
	}
	minSize, err := strconv.Atoi(size)
	if err != nil || minSize < 0 || minSize > 500 {
		writeAPIError(w, 400, errors.New("bad size parameter"))
		return
	}

	finder := besticon.IconFinder{}
	formats := r.FormValue("formats")
	if formats != "" {
		finder.FormatsAllowed = strings.Split(r.FormValue("formats"), ",")
	}

	finder.FetchIcons(url)

	icon := finder.IconWithMinSize(minSize)
	if icon != nil {
		http.Redirect(w, r, icon.URL, 302)
		return
	}

	fallbackIconURL := r.FormValue("fallback_icon_url")
	if fallbackIconURL != "" {
		http.Redirect(w, r, fallbackIconURL, 302)
		return
	}

	iconColor := finder.MainColorForIcons()
	letter := lettericon.MainLetterFromURL(url)
	redirectPath := lettericon.IconPath(letter, size, iconColor)
	http.Redirect(w, r, redirectPath, 302)
}

func popularHandler(w http.ResponseWriter, r *http.Request) {
	iconSize, err := strconv.Atoi(r.FormValue("iconsize"))
	if iconSize > 500 || iconSize < 10 || err != nil {
		iconSize = 120
	}

	pageInfo := struct {
		URLs        []string
		IconSize    int
		DisplaySize int
	}{
		besticon.PopularSites,
		iconSize,
		iconSize / 2,
	}
	renderHTMLTemplate(w, 200, popularHTML, pageInfo)
}

const (
	urlParam    = "url"
	prettyParam = "pretty"
	maxAge      = "max_age"
)

func alliconsHandler(w http.ResponseWriter, r *http.Request) {
	url := r.FormValue(urlParam)
	if len(url) == 0 {
		errMissingURL := errors.New("need url query parameter")
		writeAPIError(w, 400, errMissingURL)
		return
	}

	finder := besticon.IconFinder{}
	formats := r.FormValue("formats")
	if formats != "" {
		finder.FormatsAllowed = strings.Split(r.FormValue("formats"), ",")
	}

	e, icons := finder.FetchIcons(url)
	if e != nil {
		writeAPIError(w, 404, e)
		return
	}

	pretty, err := strconv.ParseBool(r.FormValue(prettyParam))
	prettyPrint := (err == nil) && pretty

	writeAPIIcons(w, url, icons, prettyPrint)
}

func lettericonHandler(w http.ResponseWriter, r *http.Request) {
	charParam, col, size := lettericon.ParseIconPath(r.URL.Path)
	if charParam != "" {
		w.Header().Add(contentType, imagePNG)
		lettericon.Render(charParam, col, size, w)
	} else {
		writeAPIError(w, 400, errors.New("wrong format for lettericons/ path, must look like lettericons/M-144-EFC25D.png"))
	}
}

func obsoleteAPIHandler(w http.ResponseWriter, r *http.Request) {
	if r.FormValue("i_am_feeling_lucky") == "yes" {
		http.Redirect(w, r, fmt.Sprintf("/icon?size=120&%s", r.URL.RawQuery), 302)
	} else {
		http.Redirect(w, r, fmt.Sprintf("/allicons.json?%s", r.URL.RawQuery), 302)
	}
}

func writeAPIError(w http.ResponseWriter, httpStatus int, e error) {
	data := struct {
		Error string `json:"error"`
	}{
		e.Error(),
	}
	renderJSONResponsePretty(w, httpStatus, data)
}

func writeAPIIcons(w http.ResponseWriter, url string, icons []besticon.Icon, pretty bool) {
	// Don't return whole image data
	newIcons := []besticon.Icon{}
	for _, ico := range icons {
		newIcon := ico
		newIcon.ImageData = nil
		newIcons = append(newIcons, newIcon)
	}

	data := &struct {
		URL   string          `json:"url"`
		Icons []besticon.Icon `json:"icons"`
	}{
		url,
		newIcons,
	}

	if pretty {
		renderJSONResponsePretty(w, 200, data)
	} else {
		renderJSONResponse(w, 200, data)
	}
}

const (
	contentType     = "Content-Type"
	applicationJSON = "application/json"
	imagePNG        = "image/png"
	cacheControl    = "Cache-Control"
)

func renderJSONResponse(w http.ResponseWriter, httpStatus int, data interface{}) {
	w.Header().Add(contentType, applicationJSON)
	w.WriteHeader(httpStatus)
	enc := json.NewEncoder(w)
	enc.Encode(data)
}

func renderJSONResponsePretty(w http.ResponseWriter, httpStatus int, data interface{}) {
	w.Header().Add(contentType, applicationJSON)
	w.WriteHeader(httpStatus)
	b, _ := json.MarshalIndent(data, "", "  ")
	w.Write(b)
}

type pageInfo struct {
	URL   string
	Icons []besticon.Icon
	Error error
}

func (pi pageInfo) Host() string {
	u := pi.URL
	url, _ := url.Parse(u)
	if url != nil && url.Host != "" {
		return url.Host
	}
	return pi.URL
}

func (pi pageInfo) Best() string {
	if len(pi.Icons) > 0 {
		best := pi.Icons[0]
		return best.URL
	}
	return ""
}

func renderHTMLTemplate(w http.ResponseWriter, httpStatus int, templ *template.Template, data interface{}) {
	w.Header().Add(contentType, "text/html; charset=utf-8")
	w.WriteHeader(httpStatus)

	err := templ.Execute(w, data)
	if err != nil {
		err = fmt.Errorf("server: could not generate output: %s", err)
		logger.Print(err)
		w.Write([]byte(err.Error()))
	}
}

func startServer(port string) {
	registerGzipHandler("/", indexHandler)
	registerGzipHandler("/icons", iconsHandler)
	registerHandler("/icon", iconHandler)
	registerGzipHandler("/popular", popularHandler)
	registerGzipHandler("/allicons.json", alliconsHandler)
	registerHandler("/lettericons/", lettericonHandler)
	registerHandler("/api/icons", obsoleteAPIHandler)

	serveAsset("/pure-0.5.0-min.css", "besticon/iconserver/assets/pure-0.5.0-min.css", oneYear)
	serveAsset("/grids-responsive-0.5.0-min.css", "besticon/iconserver/assets/grids-responsive-0.5.0-min.css", oneYear)
	serveAsset("/main-min.css", "besticon/iconserver/assets/main-min.css", oneYear)

	serveAsset("/icon.svg", "besticon/iconserver/assets/icon.svg", oneYear)
	serveAsset("/favicon.ico", "besticon/iconserver/assets/favicon.ico", oneYear)
	serveAsset("/apple-touch-icon.png", "besticon/iconserver/assets/apple-touch-icon.png", oneYear)

	addr := "0.0.0.0:" + port
	logger.Print("Starting server on ", addr, "...")
	e := http.ListenAndServe(addr, newLoggingMux())
	if e != nil {
		logger.Fatalf("cannot start server: %s\n", e)
	}
}

const (
	oneYear = 365 * 24 * 3600
)

func serveAsset(path string, assetPath string, maxAgeSeconds int) {
	registerGzipHandler(path, func(w http.ResponseWriter, r *http.Request) {
		assetInfo, err := assets.AssetInfo(assetPath)
		if err != nil {
			panic(err)
		}

		w.Header().Add(cacheControl, fmt.Sprintf("max-age=%d", maxAgeSeconds))

		http.ServeContent(w, r, assetInfo.Name(), assetInfo.ModTime(),
			bytes.NewReader(assets.MustAsset(assetPath)))
	})
}

func registerHandler(path string, f http.HandlerFunc) {
	http.Handle(path, newExpvarHandler(path, f))
}

func registerGzipHandler(path string, f http.HandlerFunc) {
	http.Handle(path, gziphandler.GzipHandler(newExpvarHandler(path, f)))
}

func main() {
	fmt.Printf("iconserver %s (%s) - https://icons.better-idea.org\n", besticon.VersionString, runtime.Version())
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	startServer(port)
}

func init() {
	indexHTML = templateFromAsset("besticon/iconserver/assets/index.html", "index.html")
	iconsHTML = templateFromAsset("besticon/iconserver/assets/icons.html", "icons.html")
	popularHTML = templateFromAsset("besticon/iconserver/assets/popular.html", "popular.html")
	notFoundHTML = templateFromAsset("besticon/iconserver/assets/not_found.html", "not_found.html")
}

func templateFromAsset(assetPath, templateName string) *template.Template {
	bytes := assets.MustAsset(assetPath)
	return template.Must(template.New(templateName).Funcs(funcMap).Parse(string(bytes)))
}

var indexHTML *template.Template
var iconsHTML *template.Template
var popularHTML *template.Template
var notFoundHTML *template.Template

var funcMap = template.FuncMap{
	"ImgWidth": imgWidth,
}

func imgWidth(i *besticon.Icon) int {
	return i.Width / 2.0
}

func init() {
	cacheSize := os.Getenv("CACHE_SIZE_MB")
	if cacheSize == "" {
		besticon.SetCacheMaxSize(32)
	} else {
		n, _ := strconv.Atoi(cacheSize)
		besticon.SetCacheMaxSize(int64(n))
	}

	if besticon.CacheEnabled() {
		expvar.Publish("cacheBytes", expvar.Func(func() interface{} { return besticon.GetCacheStats().Bytes }))
		expvar.Publish("cacheItems", expvar.Func(func() interface{} { return besticon.GetCacheStats().Items }))
		expvar.Publish("cacheGets", expvar.Func(func() interface{} { return besticon.GetCacheStats().Gets }))
		expvar.Publish("cacheHits", expvar.Func(func() interface{} { return besticon.GetCacheStats().Hits }))
		expvar.Publish("cacheEvictions", expvar.Func(func() interface{} { return besticon.GetCacheStats().Evictions }))
	}
}
<|endoftext|>


<commit_before>package hhfrag

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"text/tabwriter"

	"github.com/BurntSushi/bcbgo/apps/hhsuite"
	"github.com/BurntSushi/bcbgo/io/hhm"
	"github.com/BurntSushi/bcbgo/io/hhr"
	"github.com/BurntSushi/bcbgo/io/pdb"
	"github.com/BurntSushi/bcbgo/seq"
)

type PDBDatabase hhsuite.Database

func (db PDBDatabase) HHsuite() hhsuite.Database {
	resolved := hhsuite.Database(db).Resolve()
	dbName := path.Base(resolved)
	return hhsuite.Database(path.Join(resolved, dbName))
}

func (db PDBDatabase) PDB() string {
	resolved := hhsuite.Database(db).Resolve()
	return path.Join(resolved, "pdb")
}

type Fragments struct {
	Frags      []Fragment
	Start, End int
}

// better returns true if f1 is 'better' than f2. Otherwise false.
func (f1 Fragments) better(f2 Fragments) bool {
	return len(f1.Frags) >= len(f2.Frags)
}

func (frags Fragments) Write(w io.Writer) {
	tabw := tabwriter.NewWriter(w, 0, 4, 4, ' ', 0)
	fmt.Fprintln(tabw, "Hit\tQuery\tTemplate\tProb\tCorrupt")
	for _, frag := range frags.Frags {
		var corruptStr string
		if frag.IsCorrupt() {
			corruptStr = "\tcorrupt"
		}
		fmt.Fprintf(tabw, "%s\t(%d-%d)\t(%d-%d)\t%f%s\n",
			frag.Template.Name,
			frag.Hit.QueryStart, frag.Hit.QueryEnd,
			frag.Hit.TemplateStart, frag.Hit.TemplateEnd,
			frag.Hit.Prob,
			corruptStr)
	}
	tabw.Flush()
}

func FindFragments(pdbDb PDBDatabase, blits bool,
	queryHHM *hhm.HHM, qs seq.Sequence, start, end int) (*Fragments, error) {

	pre := fmt.Sprintf("bcbgo-hhfrag-hhm-%d-%d_", start, end)
	hhmFile, err := ioutil.TempFile("", pre)
	if err != nil {
		return nil, err
	}
	defer os.Remove(hhmFile.Name())
	hhmName := hhmFile.Name()

	if err := hhm.Write(hhmFile, queryHHM.Slice(start, end)); err != nil {
		return nil, err
	}

	var results *hhr.HHR
	if blits {
		results, err = hhsuite.HHBlitsDefault.Run(pdbDb.HHsuite(), hhmName)
	} else {
		results, err = hhsuite.HHSearchDefault.Run(pdbDb.HHsuite(), hhmName)
	}
	if err != nil {
		return nil, err
	}

	frags := make([]Fragment, len(results.Hits))
	for i, hit := range results.Hits {
		hit.QueryStart += start
		hit.QueryEnd += start
		frag, err := NewFragment(pdbDb, qs, hit)
		if err != nil {
			return nil, err
		}
		frags[i] = frag
	}
	return &Fragments{
		Frags: frags,
		Start: start,
		End:   end,
	}, nil
}

// An HHfrag Fragment corresponds to a match between a portion of a query
// HMM and a portion of a template HMM. The former is represented as a slice
// of a regular sequence, where the latter is represented as an hhsuite hit
// and a list of alpha-carbon atoms corresponding to the matched region.
type Fragment struct {
	Query    seq.Sequence
	Template seq.Sequence
	Hit      hhr.Hit
	CaAtoms  pdb.Atoms
}

// IsCorrupt returns true when a particular fragment could not be paired
// with alpha-carbon positions for every residue in the template strand.
// (This problem stems from the fact that we use SEQRES records for sequence
// information, but not all residues in SEQRES have alpha-carbon ATOM records
// associated with them.)
func (frag Fragment) IsCorrupt() bool {
	return frag.CaAtoms == nil
}

// NewFragment constructs a new fragment from a full query sequence and the
// hit from the HHR file.
//
// Since NewFragment requires access to the raw PDB alpha-carbon atoms (and
// the sequence) of the template hit, you'll also need to pass a path to the
// PDB database. (Which is a directory containing a flat list of all
// PDB files used to construct the corresponding hhblits database.) This
// database is usually located inside the 'pdb' directory contained in the
// corresponding hhsuite database. i.e., $HHLIB/data/pdb-select25/pdb
func NewFragment(
	pdbDb PDBDatabase, qs seq.Sequence, hit hhr.Hit) (Fragment, error) {

	pdbName := getTemplatePdbName(hit.Name)
	pdbEntry, err := pdb.New(path.Join(
		pdbDb.PDB(), fmt.Sprintf("%s.pdb", pdbName)))
	if err != nil {
		return Fragment{}, err
	}

	// Load in the sequence from the PDB file using the SEQRES residues.
	ts, te := hit.TemplateStart, hit.TemplateEnd
	chain := pdbEntry.OneChain()
	tseq := seq.Sequence{
		Name:     pdbName,
		Residues: make([]seq.Residue, te-ts+1),
	}

	// We copy here to avoid pinning pdb.Entry objects.
	copy(tseq.Residues, chain.Sequence[ts-1:te])

	frag := Fragment{
		Query:    qs.Slice(hit.QueryStart-1, hit.QueryEnd),
		Template: tseq,
		Hit:      hit,
		CaAtoms:  nil,
	}

	// We designate "corrupt" if there are any gaps in our alpha-carbon
	// atom list.
	atoms := chain.CaAtomSlice(ts-1, te)
	if atoms == nil {
		return frag, nil
	}

	// One again, we copy to avoid pinning memory.
	frag.CaAtoms = make(pdb.Atoms, len(atoms))
	copy(frag.CaAtoms, atoms)

	return frag, nil
}

func getTemplatePdbName(hitName string) string {
	return strings.SplitN(strings.TrimSpace(hitName), " ", 2)[0]
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}
<commit_msg>More updates for the experiment.<commit_after>package hhfrag

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"text/tabwriter"

	"github.com/BurntSushi/bcbgo/apps/hhsuite"
	"github.com/BurntSushi/bcbgo/io/hhm"
	"github.com/BurntSushi/bcbgo/io/hhr"
	"github.com/BurntSushi/bcbgo/io/pdb"
	"github.com/BurntSushi/bcbgo/seq"
)

type PDBDatabase hhsuite.Database

func (db PDBDatabase) HHsuite() hhsuite.Database {
	resolved := hhsuite.Database(db).Resolve()
	dbName := path.Base(resolved)
	return hhsuite.Database(path.Join(resolved, dbName))
}

func (db PDBDatabase) PDB() string {
	resolved := hhsuite.Database(db).Resolve()
	return path.Join(resolved, "pdb")
}

type Fragments struct {
	Frags      []Fragment
	Start, End int
}

// better returns true if f1 is 'better' than f2. Otherwise false.
func (f1 Fragments) better(f2 Fragments) bool {
	return len(f1.Frags) >= len(f2.Frags)
}

func (frags Fragments) Write(w io.Writer) {
	tabw := tabwriter.NewWriter(w, 0, 4, 4, ' ', 0)
	fmt.Fprintln(tabw, "Hit\tQuery\tTemplate\tProb\tCorrupt")
	for _, frag := range frags.Frags {
		var corruptStr string
		if frag.IsCorrupt() {
			corruptStr = "\tcorrupt"
		}
		fmt.Fprintf(tabw, "%s\t(%d-%d)\t(%d-%d)\t%f%s\n",
			frag.Template.Name,
			frag.Hit.QueryStart, frag.Hit.QueryEnd,
			frag.Hit.TemplateStart, frag.Hit.TemplateEnd,
			frag.Hit.Prob,
			corruptStr)
	}
	tabw.Flush()
}

func FindFragments(pdbDb PDBDatabase, blits bool,
	queryHHM *hhm.HHM, qs seq.Sequence, start, end int) (*Fragments, error) {

	pre := fmt.Sprintf("bcbgo-hhfrag-hhm-%d-%d_", start, end)
	hhmFile, err := ioutil.TempFile("", pre)
	if err != nil {
		return nil, err
	}
	defer os.Remove(hhmFile.Name())
	hhmName := hhmFile.Name()

	if err := hhm.Write(hhmFile, queryHHM.Slice(start, end)); err != nil {
		return nil, err
	}

	var results *hhr.HHR
	if blits {
		results, err = hhsuite.HHBlitsDefault.Run(pdbDb.HHsuite(), hhmName)
	} else {
		results, err = hhsuite.HHSearchDefault.Run(pdbDb.HHsuite(), hhmName)
	}
	if err != nil {
		return nil, err
	}

	frags := make([]Fragment, len(results.Hits))
	for i, hit := range results.Hits {
		hit.QueryStart += start
		hit.QueryEnd += start
		frag, err := NewFragment(pdbDb, qs, hit)
		if err != nil {
			return nil, err
		}
		frags[i] = frag
	}
	return &Fragments{
		Frags: frags,
		Start: start,
		End:   end,
	}, nil
}

// An HHfrag Fragment corresponds to a match between a portion of a query
// HMM and a portion of a template HMM. The former is represented as a slice
// of a regular sequence, where the latter is represented as an hhsuite hit
// and a list of alpha-carbon atoms corresponding to the matched region.
type Fragment struct {
	Query    seq.Sequence
	Template seq.Sequence
	Hit      hhr.Hit
	CaAtoms  pdb.Atoms
}

// IsCorrupt returns true when a particular fragment could not be paired
// with alpha-carbon positions for every residue in the template strand.
// (This problem stems from the fact that we use SEQRES records for sequence
// information, but not all residues in SEQRES have alpha-carbon ATOM records
// associated with them.)
func (frag Fragment) IsCorrupt() bool {
	return frag.CaAtoms == nil
}

// NewFragment constructs a new fragment from a full query sequence and the
// hit from the HHR file.
//
// Since NewFragment requires access to the raw PDB alpha-carbon atoms (and
// the sequence) of the template hit, you'll also need to pass a path to the
// PDB database. (Which is a directory containing a flat list of all
// PDB files used to construct the corresponding hhblits database.) This
// database is usually located inside the 'pdb' directory contained in the
// corresponding hhsuite database. i.e., $HHLIB/data/pdb-select25/pdb
func NewFragment(
	pdbDb PDBDatabase, qs seq.Sequence, hit hhr.Hit) (Fragment, error) {

	pdbName := getTemplatePdbName(hit.Name)
	pdbEntry, err := pdb.New(path.Join(
		pdbDb.PDB(), fmt.Sprintf("%s.pdb", pdbName)))
	if err != nil {
		return Fragment{}, err
	}

	// Load in the sequence from the PDB file using the SEQRES residues.
	ts, te := hit.TemplateStart, hit.TemplateEnd
	chain := pdbEntry.OneChain()
	tseq := seq.Sequence{
		Name:     pdbName,
		Residues: make([]seq.Residue, te-ts+1),
	}

	// We copy here to avoid pinning pdb.Entry objects.
	copy(tseq.Residues, chain.Sequence[ts-1:te])

	frag := Fragment{
		Query:    qs.Slice(hit.QueryStart-1, hit.QueryEnd),
		Template: tseq,
		Hit:      hit,
		CaAtoms:  nil,
	}

	// We designate "corrupt" if the query/template hit regions are of
	// different length. i.e., we don't allow gaps (yet).
	// BUG(burntsushi): Fragments with gaps are marked as corrupt.
	if hit.QueryEnd-hit.QueryStart != hit.TemplateEnd-hit.TemplateStart {
		return frag, nil
	}

	// We also designate "corrupt" if there are any gaps in our alpha-carbon
	// atom list.
	atoms := chain.CaAtomSlice(ts-1, te)
	if atoms == nil {
		return frag, nil
	}

	// One again, we copy to avoid pinning memory.
	frag.CaAtoms = make(pdb.Atoms, len(atoms))
	copy(frag.CaAtoms, atoms)

	return frag, nil
}

func getTemplatePdbName(hitName string) string {
	return strings.SplitN(strings.TrimSpace(hitName), " ", 2)[0]
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}
<|endoftext|>


<commit_before>// json-tidy pretty prints JSON
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"

	"github.com/carlmjohnson/errors"
	"github.com/carlmjohnson/flagext"
)

func main() {
	os.Exit(errors.Execute(Run, nil))
}

func Run(args []string) error {
	fl := flag.NewFlagSet("json-tidy", flag.ContinueOnError)
	prefix := fl.String("prefix", "", "Prefix string")
	indent := fl.String("indent", "\t", "Identation string")
	htmlSafe := fl.Bool("html-safe", false, "Escape special characters for easy embedding in HTML")

	fl.Usage = func() {
		fmt.Fprint(fl.Output(), `Usage of json-tidy:

json-tidy [opts] <file|url|->...
        Gets input (defaults to stdin) and prints clean json to stdout.
`)
		fl.PrintDefaults()
	}
	if err := fl.Parse(args); err != nil {
		return flag.ErrHelp
	}

	args = fl.Args()
	if len(args) == 0 {
		args = []string{flagext.StdIO}
	}
	var errs errors.Slice
	for _, arg := range args {
		errs.Push(tidyPrint(arg, *prefix, *indent, *htmlSafe))
	}
	return errs.Merge()
}

func tidyPrint(arg, prefix, indent string, htmlSafe bool) (err error) {
	src := flagext.FileOrURL(flagext.StdIO, nil)
	if err = src.Set(arg); err != nil {
		return fmt.Errorf("problem with %q: %v\n", arg, err)
	}
	defer errors.Defer(&err, src.Close)

	dec := json.NewDecoder(src)
	dec.UseNumber() // Preserve number formatting

	var data interface{}

	for dec.More() {
		err = dec.Decode(&data)
		if err != nil {
			return fmt.Errorf("problem with %q: %v\n", arg, err)
		}

		enc := json.NewEncoder(os.Stdout)
		enc.SetIndent(prefix, indent)
		enc.SetEscapeHTML(htmlSafe)
		err = enc.Encode(&data)
		if err != nil {
			return fmt.Errorf("problem with %q: %v\n", arg, err)
		}
	}
	return nil
}
<commit_msg>Bug: json.Decoder doesn't report errors from io.Reader<commit_after>// json-tidy pretty prints JSON
package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"

	"github.com/carlmjohnson/errors"
	"github.com/carlmjohnson/flagext"
)

func main() {
	os.Exit(errors.Execute(Run, nil))
}

func Run(args []string) error {
	fl := flag.NewFlagSet("json-tidy", flag.ContinueOnError)
	prefix := fl.String("prefix", "", "Prefix string")
	indent := fl.String("indent", "\t", "Identation string")
	htmlSafe := fl.Bool("html-safe", false, "Escape special characters for easy embedding in HTML")

	fl.Usage = func() {
		fmt.Fprint(fl.Output(), `Usage of json-tidy:

json-tidy [opts] <file|url|->...
        Gets input (defaults to stdin) and prints clean json to stdout.
`)
		fl.PrintDefaults()
	}
	if err := fl.Parse(args); err != nil {
		return flag.ErrHelp
	}

	args = fl.Args()
	if len(args) == 0 {
		args = []string{flagext.StdIO}
	}
	var errs errors.Slice
	for _, arg := range args {
		errs.Push(tidyPrint(arg, *prefix, *indent, *htmlSafe))
	}
	return errs.Merge()
}

func tidyPrint(arg, prefix, indent string, htmlSafe bool) (err error) {
	src := flagext.FileOrURL(flagext.StdIO, nil)
	if err = src.Set(arg); err != nil {
		return fmt.Errorf("problem with %q: %v\n", arg, err)
	}
	defer errors.Defer(&err, src.Close)

	b, err := ioutil.ReadAll(src)
	if err != nil {
		return fmt.Errorf("problem with %q: %v\n", arg, err)
	}

	dec := json.NewDecoder(bytes.NewReader(b))
	dec.UseNumber() // Preserve number formatting

	var data interface{}

	for dec.More() {
		err = dec.Decode(&data)
		if err != nil {
			return fmt.Errorf("problem with %q: %v\n", arg, err)
		}

		enc := json.NewEncoder(os.Stdout)
		enc.SetIndent(prefix, indent)
		enc.SetEscapeHTML(htmlSafe)
		err = enc.Encode(&data)
		if err != nil {
			return fmt.Errorf("problem with %q: %v\n", arg, err)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package judge

import (
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"strings"
	"github.com/alekc/proxy"
)

var hostnameMarkers = []string{"cache",
	"squid",
	"proxy"}

var proxyHeaderMarkers = []string{"Client-Ip",
	"HTTP_CLIENT_IP",
	"FORWARDED",
	"FORWARDED-FOR",
	"FORWARDED-FOR-IP",
	"X-FORWARDED",
	"X-FORWARDED-FOR",
	"PROXY_CONNECTION",
	"Via",
	"X-Proxy-Id",
	"X-Bluecoat-Via",
}

func (self *Judge) Start() {
	http.HandleFunc("/", self.analyzeRequest)
	err := http.ListenAndServe(fmt.Sprintf(self.ListenAddress), nil) // set listen port
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

func (self *Judge) analyzeRequest(w http.ResponseWriter, req *http.Request) {
	//Debug Block
	self.debugLog(formatRequest(req))

	//set up markers
	showsRealIp := false
	showsProxyUsage := false

	result := proxy.NewJudgeTestResult()

	//if cloudflare is supported set the country
	if self.CloudFlareSupport {
		result.Country = req.Header.Get("Cf-Ipcountry")
	}

	//getRealIpFromPost
	result.RealIp = self.getRealIpFromPost(req)
	result.RemoteIp = self.getRemoteIp(req)

	//check hostnames for markers
	if msg := self.CheckReverse(result.RemoteIp.String()); len(msg) > 0 {
		showsProxyUsage = true
		result.AppendMessages(msg)
	}

	//normalize xforwardedFor removing cloudflare and trusted gateways
	self.normalizeXForwardedFor(req)

	//search our ip in all headers
	if msg := self.checkIpInHeaders(req, result.RealIp); len(msg) > 0 {
		showsRealIp = true
		result.AppendMessages(msg)
	}

	//check headers
	if msg := self.hasProxyHeaderMarkings(req); len(msg) > 0 {
		showsProxyUsage = true
		result.AppendMessages(msg)
	}

	//final judgement
	if showsRealIp {
		if showsProxyUsage {
			result.Type = 0
		} else {
			result.Type = 1
		}
	} else {
		if showsProxyUsage {
			result.Type = 2
		} else {
			result.Type = 3
		}
	}

	//todo: write json response to output
	b, err := json.Marshal(&result)
	if err != nil {
		self.debugLog(fmt.Sprintf("Error on json.Marshal: %+v", err))
		http.Error(w, "Error on marshaling", http.StatusInternalServerError)
		return
	}
	w.Write(b)
}

func (self *Judge) checkIpInHeaders(req *http.Request, realIp string) []string {
	msg := make([]string, 0)
	for k, v := range req.Header {
		if strings.Contains(strings.Join(v, ","), realIp) == false {
			continue
		}
		//found our ip in the header
		msg = append(msg, fmt.Sprintf("Found real ip in the header [%s]", k))
	}
	return msg
}

//Normalize X-Forwarded-For header based on cloudflare support and trusted proxies
func (self *Judge) normalizeXForwardedFor(req *http.Request) {
	forwardedFor := make([]string, 0)

	//define acceptable xforwarded for ips
	acceptablesForwardedIps := self.TrustedGatewaysIps
	if self.CloudFlareSupport {
		ip, _, _ := net.SplitHostPort(req.RemoteAddr)
		acceptablesForwardedIps = append(acceptablesForwardedIps, ip)
	}

	//loop through ip and remove those which are acceptable
	for _, tempIp := range strings.Split(req.Header.Get("X-Forwarded-For"), ",") {
		for _, accIp := range acceptablesForwardedIps {
			if tempIp == accIp {
				continue
			}
			forwardedFor = append(forwardedFor, tempIp)
		}
	}
	//if forwardedFor is empty we can safely remove that header from our search
	//it would mean that proxy has not added any new ip
	if len(forwardedFor) == 0 {
		req.Header.Del("x-forwarded-for")
	}
}

//Gets real ip
func (self *Judge) getRealIpFromPost(req *http.Request) string {
	realIp := ""
	if err := req.ParseForm(); err == nil {
		realIp = req.Form.Get("real-ip")
	}
	return realIp
}

//
func (self *Judge) getRemoteIp(req *http.Request) net.IP {
	//get Remote ip. Replace it with cloudflare value if needed
	ip, _, _ := net.SplitHostPort(req.RemoteAddr)
	remoteIp := net.ParseIP(ip)

	//If cloudflare support is enabled, then replace remote ip with
	//contents of CF-Connecting-Ip header
	//Also add current remote ip to the array of ips which have to be removed from
	//forwarded for header
	if self.CloudFlareSupport {
		if ip = req.Header.Get("CF-Connecting-IP"); ip != "" {
			temp := net.ParseIP(ip)
			if temp != nil {
				remoteIp = temp
			}
		}
	}
	return remoteIp
}

func (self *Judge) hasProxyHeaderMarkings(req *http.Request) []string {
	msg := make([]string, 0)
	for _, marker := range proxyHeaderMarkers {
		if req.Header.Get(marker) != "" {
			msg = append(msg, fmt.Sprintf("Header [%s] is present", marker))
		}
	}
	return msg
}

//Checks if name contain certain markers
func (self *Judge) CheckReverse(ip string) []string {
	res := make([]string, 0)
	names, err := net.LookupAddr(ip)
	if err != nil {
		//self.debugLog(fmt.Sprintf("Error on resolving host for '%s' - [%+v]", ip, err))
		return res
	}
	//look for pattern
	fullNames := strings.Join(names, ",")
	for _, mark := range hostnameMarkers {
		if strings.Contains(fullNames, mark) {
			self.debugLog(fmt.Sprintf("Found marker %s in the hostname %s", mark, fullNames))
			res = append(res, fmt.Sprintf("Hostname contains %s", mark))
		}
	}
	return res
}

func (self *Judge) debugLog(msg string) {
	if self.DebugEnabled == false {
		return
	}
	fmt.Println(msg)
}
<commit_msg>fixed wrong response in case we have not transmitted our real ip in post.<commit_after>package judge

import (
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"strings"
	"github.com/alekc/proxy"
)

var hostnameMarkers = []string{"cache",
	"squid",
	"proxy"}

var proxyHeaderMarkers = []string{"Client-Ip",
	"HTTP_CLIENT_IP",
	"FORWARDED",
	"FORWARDED-FOR",
	"FORWARDED-FOR-IP",
	"X-FORWARDED",
	"X-FORWARDED-FOR",
	"PROXY_CONNECTION",
	"Via",
	"X-Proxy-Id",
	"X-Bluecoat-Via",
}

func (self *Judge) Start() {
	http.HandleFunc("/", self.analyzeRequest)
	err := http.ListenAndServe(fmt.Sprintf(self.ListenAddress), nil) // set listen port
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

func (self *Judge) analyzeRequest(w http.ResponseWriter, req *http.Request) {
	//Debug Block
	self.debugLog(formatRequest(req))

	//set up markers
	showsRealIp := false
	showsProxyUsage := false

	result := proxy.NewJudgeTestResult()

	//if cloudflare is supported set the country
	if self.CloudFlareSupport {
		result.Country = req.Header.Get("Cf-Ipcountry")
	}

	//getRealIpFromPost
	result.RealIp = self.getRealIpFromPost(req)
	result.RemoteIp = self.getRemoteIp(req)

	//check hostnames for markers
	if msg := self.CheckReverse(result.RemoteIp.String()); len(msg) > 0 {
		showsProxyUsage = true
		result.AppendMessages(msg)
	}

	//normalize xforwardedFor removing cloudflare and trusted gateways
	self.normalizeXForwardedFor(req)

	//search our ip in all headers
	if result.RealIp != "" {
		if msg := self.checkIpInHeaders(req, result.RealIp); len(msg) > 0 {
			showsRealIp = true
			result.AppendMessages(msg)
		}
	}

	//check headers
	if msg := self.hasProxyHeaderMarkings(req); len(msg) > 0 {
		showsProxyUsage = true
		result.AppendMessages(msg)
	}

	//final judgement
	if showsRealIp {
		if showsProxyUsage {
			result.Type = 0
		} else {
			result.Type = 1
		}
	} else {
		if showsProxyUsage {
			result.Type = 2
		} else {
			result.Type = 3
		}
	}

	//todo: write json response to output
	b, err := json.Marshal(&result)
	if err != nil {
		self.debugLog(fmt.Sprintf("Error on json.Marshal: %+v", err))
		http.Error(w, "Error on marshaling", http.StatusInternalServerError)
		return
	}
	w.Write(b)
}

func (self *Judge) checkIpInHeaders(req *http.Request, realIp string) []string {
	msg := make([]string, 0)
	for k, v := range req.Header {
		if strings.Contains(strings.Join(v, ","), realIp) == false {
			continue
		}
		//found our ip in the header
		msg = append(msg, fmt.Sprintf("Found real ip in the header [%s]", k))
	}
	return msg
}

//Normalize X-Forwarded-For header based on cloudflare support and trusted proxies
func (self *Judge) normalizeXForwardedFor(req *http.Request) {
	forwardedFor := make([]string, 0)

	//define acceptable xforwarded for ips
	acceptablesForwardedIps := self.TrustedGatewaysIps
	if self.CloudFlareSupport {
		ip, _, _ := net.SplitHostPort(req.RemoteAddr)
		acceptablesForwardedIps = append(acceptablesForwardedIps, ip)
	}

	//loop through ip and remove those which are acceptable
	for _, tempIp := range strings.Split(req.Header.Get("X-Forwarded-For"), ",") {
		for _, accIp := range acceptablesForwardedIps {
			if tempIp == accIp {
				continue
			}
			forwardedFor = append(forwardedFor, tempIp)
		}
	}
	//if forwardedFor is empty we can safely remove that header from our search
	//it would mean that proxy has not added any new ip
	if len(forwardedFor) == 0 {
		req.Header.Del("x-forwarded-for")
	}
}

//Gets real ip
func (self *Judge) getRealIpFromPost(req *http.Request) string {
	realIp := ""
	if err := req.ParseForm(); err == nil {
		realIp = req.Form.Get("real-ip")
	}
	return realIp
}

//
func (self *Judge) getRemoteIp(req *http.Request) net.IP {
	//get Remote ip. Replace it with cloudflare value if needed
	ip, _, _ := net.SplitHostPort(req.RemoteAddr)
	remoteIp := net.ParseIP(ip)

	//If cloudflare support is enabled, then replace remote ip with
	//contents of CF-Connecting-Ip header
	//Also add current remote ip to the array of ips which have to be removed from
	//forwarded for header
	if self.CloudFlareSupport {
		if ip = req.Header.Get("CF-Connecting-IP"); ip != "" {
			temp := net.ParseIP(ip)
			if temp != nil {
				remoteIp = temp
			}
		}
	}
	return remoteIp
}

func (self *Judge) hasProxyHeaderMarkings(req *http.Request) []string {
	msg := make([]string, 0)
	for _, marker := range proxyHeaderMarkers {
		if req.Header.Get(marker) != "" {
			msg = append(msg, fmt.Sprintf("Header [%s] is present", marker))
		}
	}
	return msg
}

//Checks if name contain certain markers
func (self *Judge) CheckReverse(ip string) []string {
	res := make([]string, 0)
	names, err := net.LookupAddr(ip)
	if err != nil {
		//self.debugLog(fmt.Sprintf("Error on resolving host for '%s' - [%+v]", ip, err))
		return res
	}
	//look for pattern
	fullNames := strings.Join(names, ",")
	for _, mark := range hostnameMarkers {
		if strings.Contains(fullNames, mark) {
			self.debugLog(fmt.Sprintf("Found marker %s in the hostname %s", mark, fullNames))
			res = append(res, fmt.Sprintf("Hostname contains %s", mark))
		}
	}
	return res
}

func (self *Judge) debugLog(msg string) {
	if self.DebugEnabled == false {
		return
	}
	fmt.Println(msg)
}
<|endoftext|>


<commit_before>package kana

import (
	. "launchpad.net/gocheck"
	"testing"
)

// Hook up gocheck into the "go test" runner.
func Test(t *testing.T) { TestingT(t) }

type KanaSuite struct{}

var _ = Suite(&KanaSuite{})

func (s *KanaSuite) TestHiraganaToRomaji(c *C) {
	// some basic checks
	c.Check(KanaToRomaji("ああいうえお"), Equals, "aaiueo")
	c.Check(KanaToRomaji("かんじ"), Equals, "kanji")
	c.Check(KanaToRomaji("ちゃう"), Equals, "chau")
	c.Check(KanaToRomaji("はんのう"), Equals, "hannou")
	c.Check(KanaToRomaji("きょうじゅ"), Equals, "kyouju")
	c.Check(KanaToRomaji("ぜんいん"), Equals, "zennin")
	c.Check(KanaToRomaji("はんのう"), Equals, "hannnou")
	c.Check(KanaToRomaji("はんおう"), Equals, "hannou")

	// check that spacing is preserved
	c.Check(KanaToRomaji("な\nに	ぬ	ね	の"), Equals, "na\nni	nu	ne	no")

	// check that english text is preserved
	c.Check(KanaToRomaji("ばか dog"), Equals, "baka dog")

	// check double-consonants and long vowels
	c.Check(KanaToRomaji("きった"), Equals, "kitta")
}

func (s *KanaSuite) TestKatakanaToRomaji(c *C) {
	// basic tests
	c.Check(KanaToRomaji("バナナ"), Equals, "banana")
	c.Check(KanaToRomaji("カンジ"), Equals, "kanji")

	// check that r is preferred
	c.Check(KanaToRomaji("テレビ"), Equals, "terebi")

	// check english + katakana mix
	c.Check(KanaToRomaji("baking バナナ pancakes"), Equals, "baking banana pancakes")

	// check that double-consonants and long vowels get converted correctly
	c.Check(KanaToRomaji("ベッド"), Equals, "beddo")
	c.Check(KanaToRomaji("モーター"), Equals, "mo-ta-")

	// check random input
	c.Check(KanaToRomaji("ＣＤプレーヤー"), Equals, "ＣＤpure-ya-")
	c.Check(KanaToRomaji("オーバーヘッドキック"), Equals, "o-ba-heddokikku")
}

func (s *KanaSuite) TestRomajiToKatakana(c *C) {
	// basic tests
	c.Check(RomajiToKatakana("banana"), Equals, "バナナ")
	c.Check(RomajiToKatakana("rajio"), Equals, "ラジオ")
	c.Check(RomajiToKatakana("terebi"), Equals, "テレビ")
	c.Check(RomajiToKatakana("furi-ta-"), Equals, "フリーター")
	c.Check(RomajiToKatakana("fa-suto"), Equals, "ファースト")
	c.Check(RomajiToKatakana("fesutibaru"), Equals, "フェスティバル")
	c.Check(RomajiToKatakana("ryukkusakku"), Equals, "リュックサック")
	c.Check(RomajiToKatakana("myu-jikku"), Equals, "ミュージック")
	c.Check(RomajiToKatakana("nyanda"), Equals, "ニャンダ")
	c.Check(RomajiToKatakana("hyakumeootokage"), Equals, "ヒャクメオオトカゲ")

	// shouldn't do anything:
	c.Check(RomajiToKatakana("ＣＤプレーヤー"), Equals, "ＣＤプレーヤー")
}

func (s *KanaSuite) TestRomajiToHiragana(c *C) {
	c.Check(RomajiToHiragana("banana"), Equals, "ばなな")
	c.Check(RomajiToHiragana("hiragana"), Equals, "ひらがな")
	c.Check(RomajiToHiragana("suppai"), Equals, "すっぱい")
	c.Check(RomajiToHiragana("konnichiha"), Equals, "こんにちは")
	c.Check(RomajiToHiragana("zouryou"), Equals, "ぞうりょう")
	c.Check(RomajiToHiragana("myaku"), Equals, "みゃく")
	c.Check(RomajiToHiragana("nyanko"), Equals, "にゃんこ")
	c.Check(RomajiToHiragana("hyaku"), Equals, "ひゃく")
	c.Check(RomajiToHiragana("motoduku"), Equals, "もとづく")
	c.Check(RomajiToHiragana("zennin"), Equals, "ぜんいん")
	c.Check(RomajiToHiragana("hannnou"), Equals, "はんのう")
	c.Check(RomajiToHiragana("hannou"), Equals, "はんおう")

	// shouldn't do anything:
	c.Check(RomajiToHiragana("ＣＤプレーヤー"), Equals, "ＣＤプレーヤー")
}

func (s *KanaSuite) TestIsLatin(c *C) {
	c.Check(IsLatin("banana"), Equals, true)
	c.Check(IsLatin("a sd ds ds"), Equals, true)
	c.Check(IsLatin("ばなな"), Equals, false)
	c.Check(IsLatin("ファースト"), Equals, false)
	c.Check(IsLatin("myu-jikku"), Equals, true)

	c.Check(IsLatin("ＣＤプレーヤー"), Equals, false)
}

func (s *KanaSuite) TestIsKana(c *C) {
	c.Check(IsKana("ばなな"), Equals, true)
	c.Check(IsKana("ファースト"), Equals, true)
	c.Check(IsKana("test"), Equals, false)
}

func (s *KanaSuite) TestIsKanji(c *C) {
	c.Check(IsKanji("ばなな"), Equals, false)
	c.Check(IsKanji("ファースト"), Equals, false)
	c.Check(IsKanji("test"), Equals, false)
	c.Check(IsKanji("路加"), Equals, true)
	c.Check(IsKanji("減少"), Equals, true)
}

func (s *KanaSuite) TestNormalizeRomaji(c *C) {
	c.Check(NormalizeRomaji("myuujikku"), Equals, "myu-jikku")
	c.Check(NormalizeRomaji("Myūjikku"), Equals, "myu-jikku")
	c.Check(NormalizeRomaji("Banana"), Equals, "banana")
	c.Check(NormalizeRomaji("shitsuree"), Equals, "shitsurei")
	c.Check(NormalizeRomaji("減少"), Equals, "減少")
	c.Check(NormalizeRomaji("myuujikku Myūjikku Banana shitsuree"), Equals, "myu-jikku myu-jikku banana shitsurei")
}
<commit_msg>remove duplicate test<commit_after>package kana

import (
	. "launchpad.net/gocheck"
	"testing"
)

// Hook up gocheck into the "go test" runner.
func Test(t *testing.T) { TestingT(t) }

type KanaSuite struct{}

var _ = Suite(&KanaSuite{})

func (s *KanaSuite) TestHiraganaToRomaji(c *C) {
	// some basic checks
	c.Check(KanaToRomaji("ああいうえお"), Equals, "aaiueo")
	c.Check(KanaToRomaji("かんじ"), Equals, "kanji")
	c.Check(KanaToRomaji("ちゃう"), Equals, "chau")
	c.Check(KanaToRomaji("はんのう"), Equals, "hannou")
	c.Check(KanaToRomaji("きょうじゅ"), Equals, "kyouju")
	c.Check(KanaToRomaji("ぜんいん"), Equals, "zennin")
	c.Check(KanaToRomaji("はんのう"), Equals, "hannnou")

	// check that spacing is preserved
	c.Check(KanaToRomaji("な\nに	ぬ	ね	の"), Equals, "na\nni	nu	ne	no")

	// check that english text is preserved
	c.Check(KanaToRomaji("ばか dog"), Equals, "baka dog")

	// check double-consonants and long vowels
	c.Check(KanaToRomaji("きった"), Equals, "kitta")
}

func (s *KanaSuite) TestKatakanaToRomaji(c *C) {
	// basic tests
	c.Check(KanaToRomaji("バナナ"), Equals, "banana")
	c.Check(KanaToRomaji("カンジ"), Equals, "kanji")

	// check that r is preferred
	c.Check(KanaToRomaji("テレビ"), Equals, "terebi")

	// check english + katakana mix
	c.Check(KanaToRomaji("baking バナナ pancakes"), Equals, "baking banana pancakes")

	// check that double-consonants and long vowels get converted correctly
	c.Check(KanaToRomaji("ベッド"), Equals, "beddo")
	c.Check(KanaToRomaji("モーター"), Equals, "mo-ta-")

	// check random input
	c.Check(KanaToRomaji("ＣＤプレーヤー"), Equals, "ＣＤpure-ya-")
	c.Check(KanaToRomaji("オーバーヘッドキック"), Equals, "o-ba-heddokikku")
}

func (s *KanaSuite) TestRomajiToKatakana(c *C) {
	// basic tests
	c.Check(RomajiToKatakana("banana"), Equals, "バナナ")
	c.Check(RomajiToKatakana("rajio"), Equals, "ラジオ")
	c.Check(RomajiToKatakana("terebi"), Equals, "テレビ")
	c.Check(RomajiToKatakana("furi-ta-"), Equals, "フリーター")
	c.Check(RomajiToKatakana("fa-suto"), Equals, "ファースト")
	c.Check(RomajiToKatakana("fesutibaru"), Equals, "フェスティバル")
	c.Check(RomajiToKatakana("ryukkusakku"), Equals, "リュックサック")
	c.Check(RomajiToKatakana("myu-jikku"), Equals, "ミュージック")
	c.Check(RomajiToKatakana("nyanda"), Equals, "ニャンダ")
	c.Check(RomajiToKatakana("hyakumeootokage"), Equals, "ヒャクメオオトカゲ")

	// shouldn't do anything:
	c.Check(RomajiToKatakana("ＣＤプレーヤー"), Equals, "ＣＤプレーヤー")
}

func (s *KanaSuite) TestRomajiToHiragana(c *C) {
	c.Check(RomajiToHiragana("banana"), Equals, "ばなな")
	c.Check(RomajiToHiragana("hiragana"), Equals, "ひらがな")
	c.Check(RomajiToHiragana("suppai"), Equals, "すっぱい")
	c.Check(RomajiToHiragana("konnichiha"), Equals, "こんにちは")
	c.Check(RomajiToHiragana("zouryou"), Equals, "ぞうりょう")
	c.Check(RomajiToHiragana("myaku"), Equals, "みゃく")
	c.Check(RomajiToHiragana("nyanko"), Equals, "にゃんこ")
	c.Check(RomajiToHiragana("hyaku"), Equals, "ひゃく")
	c.Check(RomajiToHiragana("motoduku"), Equals, "もとづく")
	c.Check(RomajiToHiragana("zennin"), Equals, "ぜんいん")
	c.Check(RomajiToHiragana("hannnou"), Equals, "はんのう")
	c.Check(RomajiToHiragana("hannou"), Equals, "はんおう")

	// shouldn't do anything:
	c.Check(RomajiToHiragana("ＣＤプレーヤー"), Equals, "ＣＤプレーヤー")
}

func (s *KanaSuite) TestIsLatin(c *C) {
	c.Check(IsLatin("banana"), Equals, true)
	c.Check(IsLatin("a sd ds ds"), Equals, true)
	c.Check(IsLatin("ばなな"), Equals, false)
	c.Check(IsLatin("ファースト"), Equals, false)
	c.Check(IsLatin("myu-jikku"), Equals, true)

	c.Check(IsLatin("ＣＤプレーヤー"), Equals, false)
}

func (s *KanaSuite) TestIsKana(c *C) {
	c.Check(IsKana("ばなな"), Equals, true)
	c.Check(IsKana("ファースト"), Equals, true)
	c.Check(IsKana("test"), Equals, false)
}

func (s *KanaSuite) TestIsKanji(c *C) {
	c.Check(IsKanji("ばなな"), Equals, false)
	c.Check(IsKanji("ファースト"), Equals, false)
	c.Check(IsKanji("test"), Equals, false)
	c.Check(IsKanji("路加"), Equals, true)
	c.Check(IsKanji("減少"), Equals, true)
}

func (s *KanaSuite) TestNormalizeRomaji(c *C) {
	c.Check(NormalizeRomaji("myuujikku"), Equals, "myu-jikku")
	c.Check(NormalizeRomaji("Myūjikku"), Equals, "myu-jikku")
	c.Check(NormalizeRomaji("Banana"), Equals, "banana")
	c.Check(NormalizeRomaji("shitsuree"), Equals, "shitsurei")
	c.Check(NormalizeRomaji("減少"), Equals, "減少")
	c.Check(NormalizeRomaji("myuujikku Myūjikku Banana shitsuree"), Equals, "myu-jikku myu-jikku banana shitsurei")
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	. "strings"
	"testing"

	_ "github.com/eaigner/hood"
)

var projectsController *ProjectsController

func init() {
	_db = Setup()
	projectsController = NewProjectsController(_db)
}
func ClearProjects() {
	_db.Query("DELETE FROM projects").Run()
}

func TestCreateProject(t *testing.T) {
	request, _ := http.NewRequest("POST", "/projects", NewReader(`{"name": "Musterprojekt"}`))
	response := httptest.NewRecorder()

	projectsController.CreateProject(response, request)

	decoder := json.NewDecoder(response.Body)

	var project Project
	err := decoder.Decode(&project)

	if err != nil {
		t.Fatalf("Decoding should pass: %v", err)
	}

	if project.Name != "Musterprojekt" {
		t.Fatalf("Name was set improperly. Expected %+v to %+v", "Musterprojekt", project.Name)
	}
	if project.ApiToken == "" {
		t.Fatalf("Expected ApiToken to be set to something")
	}
}
<commit_msg>remove unused hood.Hood<commit_after>package main

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	. "strings"
	"testing"
)

var projectsController *ProjectsController

func init() {
	_db = Setup()
	projectsController = NewProjectsController(_db)
}
func ClearProjects() {
	_db.Query("DELETE FROM projects").Run()
}

func TestCreateProject(t *testing.T) {
	request, _ := http.NewRequest("POST", "/projects", NewReader(`{"name": "Musterprojekt"}`))
	response := httptest.NewRecorder()

	projectsController.CreateProject(response, request)

	decoder := json.NewDecoder(response.Body)

	var project Project
	err := decoder.Decode(&project)

	if err != nil {
		t.Fatalf("Decoding should pass: %v", err)
	}

	if project.Name != "Musterprojekt" {
		t.Fatalf("Name was set improperly. Expected %+v to %+v", "Musterprojekt", project.Name)
	}
	if project.ApiToken == "" {
		t.Fatalf("Expected ApiToken to be set to something")
	}
}
<|endoftext|>


<commit_before>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * promise/error.go                                       *
 *                                                        *
 * promise error for Go.                                  *
 *                                                        *
 * LastModified: Aug 18, 2016                             *
 * Author: Ma Bingyao <andot@hprose.com>                  *
 *                                                        *
\**********************************************************/

package promise

import (
	"fmt"
	"runtime"
)

// IllegalArgumentError represents an error when a function/method has been
// passed an illegal or inappropriate argument.
type IllegalArgumentError string

// Error implements the IllegalArgumentError Error method.
func (e IllegalArgumentError) Error() string {
	return string(e)
}

// TimeoutError represents an error when an operation times out.
type TimeoutError struct{}

// Error implements the TimeoutError Error method.
func (TimeoutError) Error() string {
	return "timeout"
}

// TypeError represents an error when a value is not of the expected type.
type TypeError string

// Error implements the TypeError Error method.
func (e TypeError) Error() string {
	return string(e)
}

// PanicError represents a panic error
type PanicError struct {
	Panic interface{}
	Stack []byte
}

func stack() []byte {
	buf := make([]byte, 1024)
	for {
		n := runtime.Stack(buf, false)
		if n < len(buf) {
			return buf[:n]
		}
		buf = make([]byte, 2*len(buf))
	}
}

// NewPanicError return a panic error
func NewPanicError(v interface{}) *PanicError {
	return &PanicError{v, stack()}
}

// Error implements the PanicError Error method.
func (pe *PanicError) Error() string {
	return fmt.Sprintf("%v", pe.Panic)
}
<commit_msg>Improved stack with byte pool.<commit_after>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * promise/error.go                                       *
 *                                                        *
 * promise error for Go.                                  *
 *                                                        *
 * LastModified: Aug 18, 2016                             *
 * Author: Ma Bingyao <andot@hprose.com>                  *
 *                                                        *
\**********************************************************/

package promise

import (
	"fmt"
	"runtime"

	"github.com/hprose/hprose-golang/io"
)

// IllegalArgumentError represents an error when a function/method has been
// passed an illegal or inappropriate argument.
type IllegalArgumentError string

// Error implements the IllegalArgumentError Error method.
func (e IllegalArgumentError) Error() string {
	return string(e)
}

// TimeoutError represents an error when an operation times out.
type TimeoutError struct{}

// Error implements the TimeoutError Error method.
func (TimeoutError) Error() string {
	return "timeout"
}

// TypeError represents an error when a value is not of the expected type.
type TypeError string

// Error implements the TypeError Error method.
func (e TypeError) Error() string {
	return string(e)
}

// PanicError represents a panic error
type PanicError struct {
	Panic interface{}
	Stack []byte
}

func stack() []byte {
	size := 1024
	buf := io.Alloc(size)
	for {
		n := runtime.Stack(buf, false)
		if n < size {
			return buf[:n]
		}
		io.Recycle(buf)
		buf = io.Alloc(2 * size)
	}
}

// NewPanicError return a panic error
func NewPanicError(v interface{}) *PanicError {
	return &PanicError{v, stack()}
}

// Error implements the PanicError Error method.
func (pe *PanicError) Error() string {
	return fmt.Sprintf("%v", pe.Panic)
}
<|endoftext|>


<commit_before>package lifecycle

import (
	"fmt"
	"net/url"

	"github.com/lxc/lxd/shared/api"
)

// CertificateAction represents a lifecycle event action for Certificates.
type CertificateAction string

// All supported lifecycle events for Certificates.
const (
	CertificateCreated = CertificateAction("created")
	CertificateDeleted = CertificateAction("deleted")
	CertificateUpdated = CertificateAction("updated")
)

// Event creates the lifecycle event for an action on a Certificate.
func (a CertificateAction) Event(fingerprint string, requestor *api.EventLifecycleRequestor, ctx map[string]interface{}) api.EventLifecycle {
	eventType := fmt.Sprintf("certificate-%s", a)

	u := fmt.Sprintf("/1.0/certificates")
	if a != CertificateCreated {
		u = fmt.Sprintf("%s/%s", u, url.PathEscape(fingerprint))
	}

	return api.EventLifecycle{
		Action:    eventType,
		Source:    u,
		Context:   ctx,
		Requestor: requestor,
	}
}
<commit_msg>lxd/lifecycle/certificate: include object in source for created lifecycle events<commit_after>package lifecycle

import (
	"fmt"
	"net/url"

	"github.com/lxc/lxd/shared/api"
)

// CertificateAction represents a lifecycle event action for Certificates.
type CertificateAction string

// All supported lifecycle events for Certificates.
const (
	CertificateCreated = CertificateAction("created")
	CertificateDeleted = CertificateAction("deleted")
	CertificateUpdated = CertificateAction("updated")
)

// Event creates the lifecycle event for an action on a Certificate.
func (a CertificateAction) Event(fingerprint string, requestor *api.EventLifecycleRequestor, ctx map[string]interface{}) api.EventLifecycle {
	eventType := fmt.Sprintf("certificate-%s", a)

	u := fmt.Sprintf("/1.0/certificates/%s", url.PathEscape(fingerprint))

	return api.EventLifecycle{
		Action:    eventType,
		Source:    u,
		Context:   ctx,
		Requestor: requestor,
	}
}
<|endoftext|>