<commit_before>package goquant

/*
#cgo CFLAGS: -I ${SRCDIR}/lib
#cgo LDFLAGS: ${SRCDIR}/lib/libimagequant.a /usr/local/lib/librwpng.so
#include "goquant.h"
*/
import "C"
import (
	"log"
	"unsafe"
)

func Quantize(img_buff *[]byte) {
	in_image_size := len(*img_buff)
	out_image_size := C.size_t(0)

	log.Println("IN Image size: ", in_image_size)
	b := *img_buff

	bu := C.custom_create(unsafe.Pointer(&b[0]), C.int(in_image_size), &out_image_size)
	log.Println("OUT Image size: ", out_image_size)

	log.Println("Fetch out image from C to Go bytes")
	*img_buff = C.GoBytes(unsafe.Pointer(bu), C.int(out_image_size))

	log.Println("Free C object")
	C.free(unsafe.Pointer(bu))
}
<commit_msg>Changed cflags<commit_after>package goquant

/*
#cgo CFLAGS: -I ${SRCDIR}/src
#cgo CFLAGS: -I ${SRCDIR}/src/lib
#cgo LDFLAGS: -L /usr/local/lib -limagequant -lrwpng
#include "goquant.h"
*/
import "C"
import (
	"log"
	"unsafe"
)

func Quantize(img_buff *[]byte) {
	in_image_size := len(*img_buff)
	out_image_size := C.size_t(0)

	log.Println("IN Image size: ", in_image_size)
	b := *img_buff

	bu := C.custom_create(unsafe.Pointer(&b[0]), C.int(in_image_size), &out_image_size)
	log.Println("OUT Image size: ", out_image_size)

	log.Println("Fetch out image from C to Go bytes")
	*img_buff = C.GoBytes(unsafe.Pointer(bu), C.int(out_image_size))

	log.Println("Free C object")
	C.free(unsafe.Pointer(bu))
}
<|endoftext|>


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

package gui

import (
	"image"
	"image/color"
	"image/png"
	"os"
	"sort"

	"github.com/zagrodzki/goscope/scope"
)

type aggrPoint struct {
	sumY  int
	sizeY int
}

func (p aggrPoint) add(y int) aggrPoint {
	p.sumY += y
	p.sizeY++
	return p
}

func (p aggrPoint) toPoint(x int) image.Point {
	return image.Point{x, p.sumY / p.sizeY}
}

// ChannelYRange represents a y-range of samples to be plotted
type ZeroAndScale struct {
	// the position of Y=0 (0 <= Zero <= 1) given as
	// the fraction of the window height counting from the top
	Zero float64
	// scale of the plot in sample units per pixel
	Scale float64
}

func samplesToPoints(samples []scope.Sample, zeroAndScale ZeroAndScale, start, end image.Point) []image.Point {
	if len(samples) == 0 {
		return nil
	}

	sampleMaxY := zeroAndScale.Zero * zeroAndScale.Scale
	sampleMinY := (zeroAndScale.Zero - 1) * zeroAndScale.Scale
	sampleWidthX := float64(len(samples) - 1)
	sampleWidthY := sampleMaxY - sampleMinY

	pixelStartX := float64(start.X)
	pixelEndY := float64(end.Y)
	pixelWidthX := float64(end.X - start.X)
	pixelWidthY := float64(end.Y - start.Y)

	aggrPoints := make(map[int]aggrPoint)
	for i, y := range samples {
		mapX := int(pixelStartX + float64(i)/sampleWidthX*pixelWidthX)
		mapY := int(pixelEndY - float64(y-scope.Sample(sampleMinY))/sampleWidthY*pixelWidthY)
		aggrPoints[mapX] = aggrPoints[mapX].add(mapY)
	}
	var points []image.Point
	for x, p := range aggrPoints {
		points = append(points, p.toPoint(x))
	}

	return points
}

// Plot represents the entire plotting area.
type Plot struct {
	*image.RGBA
}

// Fill fills the plot with a color.
func (plot Plot) Fill(col color.RGBA) {
	bounds := plot.Bounds()
	for i := bounds.Min.X; i < bounds.Max.X; i++ {
		for j := bounds.Min.Y; j < bounds.Max.Y; j++ {
			plot.Set(i, j, col)
		}
	}
}

func isInside(x, y int, start, end image.Point) bool {
	return x >= start.X && x <= end.X && y >= start.Y && y <= end.Y
}

// DrawLine draws a straight line from pixel p1 to p2.
// Only the line fragment inside the image rectangle defined by
// starting (upper left) and ending (lower right) pixel is drawn.
func (plot Plot) DrawLine(p1, p2 image.Point, start, end image.Point, col color.RGBA) {
	if p1.X == p2.X { // vertical line
		for i := min(p1.Y, p2.Y); i <= max(p1.Y, p2.Y); i++ {
			plot.Set(p1.X, i, col)
		}
		return
	}

	// Calculating the parameters of the equation
	// of the straight line (in the form y=a*x+b)
	// passing through p1 and p2.

	// slope of the line
	a := float64(p1.Y-p2.Y) / float64(p1.X-p2.X)
	// intercept of the line
	b := float64(p1.Y) - float64(p1.X)*a

	// To avoid visual "gaps" between the pixels we switch on,
	// we draw the line in one of two ways.
	if abs(p1.X-p2.X) >= abs(p1.Y-p2.Y) {
		// If the line is more horizontal than vertical,
		// for every pixel column between p1 and p2
		// we find and switch on the pixel closest to y=a*x+b
		for i := min(p1.X, p2.X); i <= max(p1.X, p2.X); i++ {
			y := int(a*float64(i) + b)
			if isInside(i, y, start, end) {
				plot.Set(i, y, col)
			}
		}
	} else {
		// If the line is more vertical than horizontal,
		// for every pixel row between p1 and p2
		// we find and switch on the pixel closest to y=a*x+b
		for i := min(p1.Y, p2.Y); i <= max(p1.Y, p2.Y); i++ {
			x := int((float64(i) - b) / a)
			if isInside(x, i, start, end) {
				plot.Set(x, i, col)
			}
		}
	}
}

// DrawSamples draws samples in the image rectangle defined by
// starting (upper left) and ending (lower right) pixel.
func (plot Plot) DrawSamples(samples []scope.Sample, zeroAndScale ZeroAndScale, start, end image.Point, col color.RGBA) {
	points := samplesToPoints(samples, zeroAndScale, start, end)
	sort.Sort(pointsByX(points))
	for i := 1; i < len(points); i++ {
		plot.DrawLine(points[i-1], points[i], start, end, col)
	}
}

// DrawAll draws samples from all the channels into one image.
func (plot Plot) DrawAll(samples map[scope.ChanID][]scope.Sample, zas map[scope.ChanID]ZeroAndScale, cols map[scope.ChanID]color.RGBA) {
	b := plot.Bounds()
	x1 := b.Min.X + 10
	x2 := b.Max.X - 10
	y1 := b.Min.Y + 10
	y2 := b.Min.Y + 10 + int((b.Max.Y-b.Min.Y-10*(len(samples)+1))/len(samples))
	step := y2 - b.Min.Y
	for id, v := range samples {
		plot.DrawSamples(v, zas[id], image.Point{x1, y1}, image.Point{x2, y2}, cols[id])
		y1 = y1 + step
		y2 = y2 + step
	}
}

// CreatePlot plots samples from the device.
func CreatePlot(dev scope.Device, zas map[scope.ChanID]ZeroAndScale) (Plot, error) {
	plot := Plot{image.NewRGBA(image.Rect(0, 0, 800, 600))}

	data, stop, err := dev.StartSampling()
	defer stop()
	if err != nil {
		return plot, err
	}
	samples := (<-data).Samples

	colWhite := color.RGBA{255, 255, 255, 255}
	colRed := color.RGBA{255, 0, 0, 255}
	colGreen := color.RGBA{0, 255, 0, 255}
	colBlue := color.RGBA{0, 0, 255, 255}
	colBlack := color.RGBA{0, 0, 0, 255}
	chanCols := [4]color.RGBA{colRed, colGreen, colBlue, colBlack}

	plot.Fill(colWhite)

	cols := make(map[scope.ChanID]color.RGBA)
	next := 0
	for _, id := range dev.Channels() {
		if _, exists := zas[id]; !exists {
			zas[id] = ZeroAndScale{0.5, 2}
		}
		cols[id] = chanCols[next]
		next = (next + 1) % 4
	}
	plot.DrawAll(samples, zas, cols)
	return plot, nil
}

// PlotToPng creates a plot of the samples from the device
// and saves it as PNG.
func PlotToPng(dev scope.Device, zas map[scope.ChanID]ZeroAndScale, outputFile string) error {
	plot, err := CreatePlot(dev, zas)
	if err != nil {
		return err
	}

	f, err := os.Create(outputFile)
	if err != nil {
		return err
	}
	defer f.Close()
	png.Encode(f, plot)
	return nil
}

type pointsByX []image.Point

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

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

func (a pointsByX) Less(i, j int) bool {
	return a[i].X < a[j].X
}

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
}

func abs(a int) int {
	if a < 0 {
		return -a
	}
	return a
}
<commit_msg>comment corrected<commit_after>//  Copyright 2016 The goscope Authors
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

package gui

import (
	"image"
	"image/color"
	"image/png"
	"os"
	"sort"

	"github.com/zagrodzki/goscope/scope"
)

type aggrPoint struct {
	sumY  int
	sizeY int
}

func (p aggrPoint) add(y int) aggrPoint {
	p.sumY += y
	p.sizeY++
	return p
}

func (p aggrPoint) toPoint(x int) image.Point {
	return image.Point{x, p.sumY / p.sizeY}
}

// ZeroAndScale represents the position of zero and the scale of the plot
type ZeroAndScale struct {
	// the position of Y=0 (0 <= Zero <= 1) given as
	// the fraction of the window height counting from the top
	Zero float64
	// scale of the plot in sample units per pixel
	Scale float64
}

func samplesToPoints(samples []scope.Sample, zeroAndScale ZeroAndScale, start, end image.Point) []image.Point {
	if len(samples) == 0 {
		return nil
	}

	sampleMaxY := zeroAndScale.Zero * zeroAndScale.Scale
	sampleMinY := (zeroAndScale.Zero - 1) * zeroAndScale.Scale
	sampleWidthX := float64(len(samples) - 1)
	sampleWidthY := sampleMaxY - sampleMinY

	pixelStartX := float64(start.X)
	pixelEndY := float64(end.Y)
	pixelWidthX := float64(end.X - start.X)
	pixelWidthY := float64(end.Y - start.Y)

	aggrPoints := make(map[int]aggrPoint)
	for i, y := range samples {
		mapX := int(pixelStartX + float64(i)/sampleWidthX*pixelWidthX)
		mapY := int(pixelEndY - float64(y-scope.Sample(sampleMinY))/sampleWidthY*pixelWidthY)
		aggrPoints[mapX] = aggrPoints[mapX].add(mapY)
	}
	var points []image.Point
	for x, p := range aggrPoints {
		points = append(points, p.toPoint(x))
	}

	return points
}

// Plot represents the entire plotting area.
type Plot struct {
	*image.RGBA
}

// Fill fills the plot with a color.
func (plot Plot) Fill(col color.RGBA) {
	bounds := plot.Bounds()
	for i := bounds.Min.X; i < bounds.Max.X; i++ {
		for j := bounds.Min.Y; j < bounds.Max.Y; j++ {
			plot.Set(i, j, col)
		}
	}
}

func isInside(x, y int, start, end image.Point) bool {
	return x >= start.X && x <= end.X && y >= start.Y && y <= end.Y
}

// DrawLine draws a straight line from pixel p1 to p2.
// Only the line fragment inside the image rectangle defined by
// starting (upper left) and ending (lower right) pixel is drawn.
func (plot Plot) DrawLine(p1, p2 image.Point, start, end image.Point, col color.RGBA) {
	if p1.X == p2.X { // vertical line
		for i := min(p1.Y, p2.Y); i <= max(p1.Y, p2.Y); i++ {
			plot.Set(p1.X, i, col)
		}
		return
	}

	// Calculating the parameters of the equation
	// of the straight line (in the form y=a*x+b)
	// passing through p1 and p2.

	// slope of the line
	a := float64(p1.Y-p2.Y) / float64(p1.X-p2.X)
	// intercept of the line
	b := float64(p1.Y) - float64(p1.X)*a

	// To avoid visual "gaps" between the pixels we switch on,
	// we draw the line in one of two ways.
	if abs(p1.X-p2.X) >= abs(p1.Y-p2.Y) {
		// If the line is more horizontal than vertical,
		// for every pixel column between p1 and p2
		// we find and switch on the pixel closest to y=a*x+b
		for i := min(p1.X, p2.X); i <= max(p1.X, p2.X); i++ {
			y := int(a*float64(i) + b)
			if isInside(i, y, start, end) {
				plot.Set(i, y, col)
			}
		}
	} else {
		// If the line is more vertical than horizontal,
		// for every pixel row between p1 and p2
		// we find and switch on the pixel closest to y=a*x+b
		for i := min(p1.Y, p2.Y); i <= max(p1.Y, p2.Y); i++ {
			x := int((float64(i) - b) / a)
			if isInside(x, i, start, end) {
				plot.Set(x, i, col)
			}
		}
	}
}

// DrawSamples draws samples in the image rectangle defined by
// starting (upper left) and ending (lower right) pixel.
func (plot Plot) DrawSamples(samples []scope.Sample, zeroAndScale ZeroAndScale, start, end image.Point, col color.RGBA) {
	points := samplesToPoints(samples, zeroAndScale, start, end)
	sort.Sort(pointsByX(points))
	for i := 1; i < len(points); i++ {
		plot.DrawLine(points[i-1], points[i], start, end, col)
	}
}

// DrawAll draws samples from all the channels into one image.
func (plot Plot) DrawAll(samples map[scope.ChanID][]scope.Sample, zas map[scope.ChanID]ZeroAndScale, cols map[scope.ChanID]color.RGBA) {
	b := plot.Bounds()
	x1 := b.Min.X + 10
	x2 := b.Max.X - 10
	y1 := b.Min.Y + 10
	y2 := b.Min.Y + 10 + int((b.Max.Y-b.Min.Y-10*(len(samples)+1))/len(samples))
	step := y2 - b.Min.Y
	for id, v := range samples {
		plot.DrawSamples(v, zas[id], image.Point{x1, y1}, image.Point{x2, y2}, cols[id])
		y1 = y1 + step
		y2 = y2 + step
	}
}

// CreatePlot plots samples from the device.
func CreatePlot(dev scope.Device, zas map[scope.ChanID]ZeroAndScale) (Plot, error) {
	plot := Plot{image.NewRGBA(image.Rect(0, 0, 800, 600))}

	data, stop, err := dev.StartSampling()
	defer stop()
	if err != nil {
		return plot, err
	}
	samples := (<-data).Samples

	colWhite := color.RGBA{255, 255, 255, 255}
	colRed := color.RGBA{255, 0, 0, 255}
	colGreen := color.RGBA{0, 255, 0, 255}
	colBlue := color.RGBA{0, 0, 255, 255}
	colBlack := color.RGBA{0, 0, 0, 255}
	chanCols := [4]color.RGBA{colRed, colGreen, colBlue, colBlack}

	plot.Fill(colWhite)

	cols := make(map[scope.ChanID]color.RGBA)
	next := 0
	for _, id := range dev.Channels() {
		if _, exists := zas[id]; !exists {
			zas[id] = ZeroAndScale{0.5, 2}
		}
		cols[id] = chanCols[next]
		next = (next + 1) % 4
	}
	plot.DrawAll(samples, zas, cols)
	return plot, nil
}

// PlotToPng creates a plot of the samples from the device
// and saves it as PNG.
func PlotToPng(dev scope.Device, zas map[scope.ChanID]ZeroAndScale, outputFile string) error {
	plot, err := CreatePlot(dev, zas)
	if err != nil {
		return err
	}

	f, err := os.Create(outputFile)
	if err != nil {
		return err
	}
	defer f.Close()
	png.Encode(f, plot)
	return nil
}

type pointsByX []image.Point

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

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

func (a pointsByX) Less(i, j int) bool {
	return a[i].X < a[j].X
}

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
}

func abs(a int) int {
	if a < 0 {
		return -a
	}
	return a
}
<|endoftext|>


<commit_before>/*
   Copyright (c) 2016 Lachlan Evenson

   Permission is hereby granted, free of charge, to any person obtaining
   a copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the Software
   is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
   OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

package main

import (
	"fmt"
	"net/http"
)

var html = `

        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Croc Hunter</title>
        <link rel='stylesheet' href='/static/game.css'/>

    	<canvas id="canvasBg" width="800" height="490" ></canvas>
    	<canvas id="canvasEnemy" width="800" height="500" ></canvas>
    	<canvas id="canvasJet" width="800" height="500" ></canvas>
        <canvas id="canvasHud" width="800" height="500" ></canvas>

		Hostname: %s

		Version: %s

		Powered By: %s

`

func httpHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, html, hostname, release, powered)
}
<commit_msg>bumped js version<commit_after>/*
   Copyright (c) 2016 Lachlan Evenson

   Permission is hereby granted, free of charge, to any person obtaining
   a copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the Software
   is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
   OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

package main

import (
	"fmt"
	"net/http"
)

var html = `

        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Croc Hunter</title>
        <link rel='stylesheet' href='/static/game.css'/>

    	<canvas id="canvasBg" width="800" height="490" ></canvas>
    	<canvas id="canvasEnemy" width="800" height="500" ></canvas>
    	<canvas id="canvasJet" width="800" height="500" ></canvas>
        <canvas id="canvasHud" width="800" height="500" ></canvas>

		Hostname: %s

		Version: %s

		Powered By: %s

`

func httpHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, html, hostname, release, powered)
}
<|endoftext|>


<commit_before>package main

import (
	"ieveapi/apicache"
	"log"
	"net/http"
	"path"
	"runtime"
	"strings"
	"time"
)

type APIHandler struct{}

func (a APIHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	req.ParseForm()
	url := path.Clean(req.URL.Path)

	if url == "/stats" {
		LogStats()
		w.Write([]byte(""))
		return
	}

	w.Header().Add("Content-Type", "text/xml")
	if _, valid := validPages[strings.ToLower(url)]; !valid {
		log.Printf("Invalid URL %s - %s", url, req.Form)
		w.WriteHeader(404)
		w.Write(apicache.SynthesizeAPIError(404, "Invalid API page.", 24*time.Hour))
		return
	}

	params := make(map[string]string)
	for key, val := range req.Form {
		params[key] = val[0]
	}

	data, code, err := APIReq(url, params)
	if err != nil {
		log.Printf("Handler Error: %s", err)
	}

	w.WriteHeader(code)
	w.Write(data)
}

func LogStats() {
	PrintWorkerStats()
	dc.LogStats()

	LogMemStats()
	runtime.GC()
	log.Printf("Running GC...")
	LogMemStats()
}

func LogMemStats() {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)
	log.Printf("Alloc: %dkb Sys: %dkb", m.Alloc/1024, m.Sys/1024)
	log.Printf("HeapAlloc: %dkb HeapSys: %dkb", m.HeapAlloc/1024, m.HeapSys/1024)
}

var validPages = map[string]bool{
	"/account/accountstatus.xml.aspx":       true,
	"/account/apikeyinfo.xml.aspx":          true,
	"/account/characters.xml.aspx":          true,
	"/char/accountbalance.xml.aspx":         true,
	"/char/assetlist.xml.aspx":              true,
	"/char/calendareventattendees.xml.aspx": true,
	"/char/charactersheet.xml.aspx":         true,
	"/char/contactlist.xml.aspx":            true,
	"/char/contactnotifications.xml.aspx":   true,
	"/char/contracts.xml.aspx":              true,
	"/char/contractitems.xml.aspx":          true,
	"/char/contractbids.xml.aspx":           true,
	"/char/facwarstats.xml.aspx":            true,
	"/char/industryjobs.xml.aspx":           true,
	"/char/killlog.xml.aspx":                true,
	"/char/locations.xml.aspx":              true,
	"/char/mailbodies.xml.aspx":             true,
	"/char/mailinglists.xml.aspx":           true,
	"/char/mailmessages.xml.aspx":           true,
	"/char/marketorders.xml.aspx":           true,
	"/char/medals.xml.aspx":                 true,
	"/char/notifications.xml.aspx":          true,
	"/char/notificationtexts.xml.aspx":      true,
	"/char/research.xml.aspx":               true,
	"/char/skillintraining.xml.aspx":        true,
	"/char/skillqueue.xml.aspx":             true,
	"/char/standings.xml.aspx":              true,
	"/char/upcomingcalendarevents.xml.aspx": true,
	"/char/walletjournal.xml.aspx":          true,
	"/char/wallettransactions.xml.aspx":     true,
	"/corp/accountbalance.xml.aspx":         true,
	"/corp/assetlist.xml.aspx":              true,
	"/corp/contactlist.xml.aspx":            true,
	"/corp/containerlog.xml.aspx":           true,
	"/corp/contracts.xml.aspx":              true,
	"/corp/contractitems.xml.aspx":          true,
	"/corp/contractbids.xml.aspx":           true,
	"/corp/corporationsheet.xml.aspx":       true,
	"/corp/facwarstats.xml.aspx":            true,
	"/corp/industryjobs.xml.aspx":           true,
	"/corp/killlog.xml.aspx":                true,
	"/corp/locations.xml.aspx":              true,
	"/corp/marketorders.xml.aspx":           true,
	"/corp/medals.xml.aspx":                 true,
	"/corp/membermedals.xml.aspx":           true,
	"/corp/membersecurity.xml.aspx":         true,
	"/corp/membersecuritylog.xml.aspx":      true,
	"/corp/membertracking.xml.aspx":         true,
	"/corp/outpostlist.xml.aspx":            true,
	"/corp/outpostservicedetail.xml.aspx":   true,
	"/corp/shareholders.xml.aspx":           true,
	"/corp/standings.xml.aspx":              true,
	"/corp/starbasedetail.xml.aspx":         true,
	"/corp/starbaselist.xml.aspx":           true,
	"/corp/titles.xml.aspx":                 true,
	"/corp/walletjournal.xml.aspx":          true,
	"/corp/wallettransactions.xml.aspx":     true,
	"/eve/alliancelist.xml.aspx":            true,
	"/eve/certificatetree.xml.aspx":         true,
	"/eve/characterid.xml.aspx":             true,
	"/eve/characterinfo.xml.aspx":           true,
	"/eve/charactername.xml.aspx":           true,
	"/eve/conquerablestationlist.xml.aspx":  true,
	"/eve/errorlist.xml.aspx":               true,
	"/eve/facwarstats.xml.aspx":             true,
	"/eve/facwartopstats.xml.aspx":          true,
	"/eve/reftypes.xml.aspx":                true,
	"/eve/skilltree.xml.aspx":               true,
	"/eve/typename.xml.aspx":                true,
	"/map/facwarsystems.xml.aspx":           true,
	"/map/jumps.xml.aspx":                   true,
	"/map/kills.xml.aspx":                   true,
	"/map/sovereignty.xml.aspx":             true,
	"/map/sovereigntystatus.xml.aspx":       true,
	"/server/serverstatus.xml.aspx":         true,
	"/api/calllist.xml.aspx":                true,
}
<commit_msg>removed arbitrary GC call<commit_after>package main

import (
	"ieveapi/apicache"
	"log"
	"net/http"
	"path"
	"runtime"
	"strings"
	"time"
)

type APIHandler struct{}

func (a APIHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	req.ParseForm()
	url := path.Clean(req.URL.Path)

	if url == "/stats" {
		LogStats()
		w.Write([]byte(""))
		return
	}

	w.Header().Add("Content-Type", "text/xml")
	if _, valid := validPages[strings.ToLower(url)]; !valid {
		log.Printf("Invalid URL %s - %s", url, req.Form)
		w.WriteHeader(404)
		w.Write(apicache.SynthesizeAPIError(404, "Invalid API page.", 24*time.Hour))
		return
	}

	params := make(map[string]string)
	for key, val := range req.Form {
		params[key] = val[0]
	}

	data, code, err := APIReq(url, params)
	if err != nil {
		log.Printf("Handler Error: %s", err)
	}

	w.WriteHeader(code)
	w.Write(data)
}

func LogStats() {
	PrintWorkerStats()
	dc.LogStats()
	LogMemStats()
}

func LogMemStats() {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)
	log.Printf("Alloc: %dkb Sys: %dkb", m.Alloc/1024, m.Sys/1024)
	log.Printf("HeapAlloc: %dkb HeapSys: %dkb", m.HeapAlloc/1024, m.HeapSys/1024)
}

var validPages = map[string]bool{
	"/account/accountstatus.xml.aspx":       true,
	"/account/apikeyinfo.xml.aspx":          true,
	"/account/characters.xml.aspx":          true,
	"/char/accountbalance.xml.aspx":         true,
	"/char/assetlist.xml.aspx":              true,
	"/char/calendareventattendees.xml.aspx": true,
	"/char/charactersheet.xml.aspx":         true,
	"/char/contactlist.xml.aspx":            true,
	"/char/contactnotifications.xml.aspx":   true,
	"/char/contracts.xml.aspx":              true,
	"/char/contractitems.xml.aspx":          true,
	"/char/contractbids.xml.aspx":           true,
	"/char/facwarstats.xml.aspx":            true,
	"/char/industryjobs.xml.aspx":           true,
	"/char/killlog.xml.aspx":                true,
	"/char/locations.xml.aspx":              true,
	"/char/mailbodies.xml.aspx":             true,
	"/char/mailinglists.xml.aspx":           true,
	"/char/mailmessages.xml.aspx":           true,
	"/char/marketorders.xml.aspx":           true,
	"/char/medals.xml.aspx":                 true,
	"/char/notifications.xml.aspx":          true,
	"/char/notificationtexts.xml.aspx":      true,
	"/char/research.xml.aspx":               true,
	"/char/skillintraining.xml.aspx":        true,
	"/char/skillqueue.xml.aspx":             true,
	"/char/standings.xml.aspx":              true,
	"/char/upcomingcalendarevents.xml.aspx": true,
	"/char/walletjournal.xml.aspx":          true,
	"/char/wallettransactions.xml.aspx":     true,
	"/corp/accountbalance.xml.aspx":         true,
	"/corp/assetlist.xml.aspx":              true,
	"/corp/contactlist.xml.aspx":            true,
	"/corp/containerlog.xml.aspx":           true,
	"/corp/contracts.xml.aspx":              true,
	"/corp/contractitems.xml.aspx":          true,
	"/corp/contractbids.xml.aspx":           true,
	"/corp/corporationsheet.xml.aspx":       true,
	"/corp/facwarstats.xml.aspx":            true,
	"/corp/industryjobs.xml.aspx":           true,
	"/corp/killlog.xml.aspx":                true,
	"/corp/locations.xml.aspx":              true,
	"/corp/marketorders.xml.aspx":           true,
	"/corp/medals.xml.aspx":                 true,
	"/corp/membermedals.xml.aspx":           true,
	"/corp/membersecurity.xml.aspx":         true,
	"/corp/membersecuritylog.xml.aspx":      true,
	"/corp/membertracking.xml.aspx":         true,
	"/corp/outpostlist.xml.aspx":            true,
	"/corp/outpostservicedetail.xml.aspx":   true,
	"/corp/shareholders.xml.aspx":           true,
	"/corp/standings.xml.aspx":              true,
	"/corp/starbasedetail.xml.aspx":         true,
	"/corp/starbaselist.xml.aspx":           true,
	"/corp/titles.xml.aspx":                 true,
	"/corp/walletjournal.xml.aspx":          true,
	"/corp/wallettransactions.xml.aspx":     true,
	"/eve/alliancelist.xml.aspx":            true,
	"/eve/certificatetree.xml.aspx":         true,
	"/eve/characterid.xml.aspx":             true,
	"/eve/characterinfo.xml.aspx":           true,
	"/eve/charactername.xml.aspx":           true,
	"/eve/conquerablestationlist.xml.aspx":  true,
	"/eve/errorlist.xml.aspx":               true,
	"/eve/facwarstats.xml.aspx":             true,
	"/eve/facwartopstats.xml.aspx":          true,
	"/eve/reftypes.xml.aspx":                true,
	"/eve/skilltree.xml.aspx":               true,
	"/eve/typename.xml.aspx":                true,
	"/map/facwarsystems.xml.aspx":           true,
	"/map/jumps.xml.aspx":                   true,
	"/map/kills.xml.aspx":                   true,
	"/map/sovereignty.xml.aspx":             true,
	"/map/sovereigntystatus.xml.aspx":       true,
	"/server/serverstatus.xml.aspx":         true,
	"/api/calllist.xml.aspx":                true,
}
<|endoftext|>


<commit_before>package pi

import "net/http"

// HandlerFunction represents the function called when the specified route is reached.
type HandlerFunction func(*RequestContext) error

// FileServeHandler registers the specified folder to be served on the specified route.
// For example:
//	p := pi.New()
//	p.Route("/image", pi.FileServeHandler("/var/www/public/images"))
//	p.ListenAndServe(":8080")
//
func FileServeHandler(path string) HandlerFunction {
	return func(c *RequestContext) error {
		file := c.R.URL.Query().Get(":file")
		if file != "" {
			http.ServeFile(c.W, c.R, path)
		} else {
			http.ServeFile(c.W, c.R, path+"/"+file)
		}
		return nil
	}
}
<commit_msg>Updated doc again<commit_after>package pi

import "net/http"

// HandlerFunction represents the function called when the specified route is reached.
type HandlerFunction func(*RequestContext) error

// FileServeHandler registers the specified folder to be served on the specified route.
// For example:
//
//		p := pi.New()
//		p.Route("/image").Get(pi.FileServeHandler("/var/www/public/images"))
//		p.ListenAndServe(":8080")
//
// Or:
//
//		p := pi.New()
//		p.Route("/image/{file}").Get(pi.FileServeHandler("/var/www/public/images"))
//		p.ListenAndServe(":8080")
//
func FileServeHandler(path string) HandlerFunction {
	return func(c *RequestContext) error {
		file := c.R.URL.Query().Get(":file")
		if file != "" {
			http.ServeFile(c.W, c.R, path)
		} else {
			http.ServeFile(c.W, c.R, path+"/"+file)
		}
		return nil
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"github.com/golang/groupcache"
	"github.com/gorilla/mux"
	"io"
	"math/rand"
	"net/http"
	"os"
	"time"
	"vip/fetch"
)

type UploadResponse struct {
	Url string `json:"url"`
}

type verifyAuth func(http.ResponseWriter, *http.Request)

func (h verifyAuth) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Enable cross-origin requests
	if domain := os.Getenv("ALLOWED_ORIGIN"); domain != "" {
		if origin := r.Header.Get("Origin"); origin == domain {
			w.Header().Set("Access-Control-Allow-Origin", origin)
			w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
			w.Header().Set("Access-Control-Allow-Headers",
				"Accept, Content-Type, Content-Length, Accept-Encoding, X-Vip-Token, Authorization")
		}
	} else {
		auth := r.Header.Get("X-Vip-Token")
		if auth != authToken {
			w.WriteHeader(http.StatusUnauthorized)
			return
		}
	}

	if r.Method == "OPTIONS" {
		return
	}

	h(w, r)
}

func fileKey(bucket string) string {
	seed := rand.New(rand.NewSource(time.Now().UnixNano()))
	key := fmt.Sprintf("%d-%s-%d", seed.Int63(), bucket, time.Now().UnixNano())

	hash := md5.New()
	io.WriteString(hash, key)
	return fmt.Sprintf("%x", hash.Sum(nil))
}

func handleImageRequest(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		w.WriteHeader(http.StatusMethodNotAllowed)
	}

	w.Header().Set("Cache-Control", "public, max-age=31536000")

	// Client is checking for a cached URI, assume it is valid
	// and return a 304
	if r.Header.Get("If-Modified-Since") != "" {
		w.WriteHeader(http.StatusNotModified)
		return
	}

	gc := fetch.RequestContext(r)

	var data []byte
	err := cache.Get(gc, gc.CacheKey(), groupcache.AllocatingByteSliceSink(&data))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	w.Header().Set("Content-Type", http.DetectContentType(data))
	http.ServeContent(w, r, gc.ImageId, time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), bytes.NewReader(data))
}

func handleUpload(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}

	vars := mux.Vars(r)
	bucket := vars["bucket_id"]

	// Set a hard 5mb limit on files
	if r.ContentLength > 5<<20 {
		w.WriteHeader(http.StatusRequestEntityTooLarge)
		return
	}

	key := fileKey(bucket)
	err := storage.PutReader(bucket, key, r.Body,
		r.ContentLength, r.Header.Get("Content-Type"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer r.Body.Close()

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	uri := r.URL

	if r.URL.Host == "" {
		uri.Host = os.Getenv("URI_HOSTNAME")
		if *secure {
			uri.Scheme = "https"
		} else {
			uri.Scheme = "http"
		}
	}

	uri.Path = fmt.Sprintf("%s/%s", bucket, key)

	w.Header().Set("Content-Type", "application/json")

	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(UploadResponse{
		Url: uri.String(),
	})
}

func handlePing(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, "pong")
}
<commit_msg>Add error message for 413 response<commit_after>package main

import (
	"bytes"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"github.com/golang/groupcache"
	"github.com/gorilla/mux"
	"io"
	"math/rand"
	"net/http"
	"os"
	"time"
	"vip/fetch"
)

type UploadResponse struct {
	Url string `json:"url"`
}

type verifyAuth func(http.ResponseWriter, *http.Request)

func (h verifyAuth) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Enable cross-origin requests
	if domain := os.Getenv("ALLOWED_ORIGIN"); domain != "" {
		if origin := r.Header.Get("Origin"); origin == domain {
			w.Header().Set("Access-Control-Allow-Origin", origin)
			w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
			w.Header().Set("Access-Control-Allow-Headers",
				"Accept, Content-Type, Content-Length, Accept-Encoding, X-Vip-Token, Authorization")
		}
	} else {
		auth := r.Header.Get("X-Vip-Token")
		if auth != authToken {
			w.WriteHeader(http.StatusUnauthorized)
			return
		}
	}

	if r.Method == "OPTIONS" {
		return
	}

	h(w, r)
}

func fileKey(bucket string) string {
	seed := rand.New(rand.NewSource(time.Now().UnixNano()))
	key := fmt.Sprintf("%d-%s-%d", seed.Int63(), bucket, time.Now().UnixNano())

	hash := md5.New()
	io.WriteString(hash, key)
	return fmt.Sprintf("%x", hash.Sum(nil))
}

func handleImageRequest(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		w.WriteHeader(http.StatusMethodNotAllowed)
	}

	w.Header().Set("Cache-Control", "public, max-age=31536000")

	// Client is checking for a cached URI, assume it is valid
	// and return a 304
	if r.Header.Get("If-Modified-Since") != "" {
		w.WriteHeader(http.StatusNotModified)
		return
	}

	gc := fetch.RequestContext(r)

	var data []byte
	err := cache.Get(gc, gc.CacheKey(), groupcache.AllocatingByteSliceSink(&data))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	w.Header().Set("Content-Type", http.DetectContentType(data))
	http.ServeContent(w, r, gc.ImageId, time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), bytes.NewReader(data))
}

func handleUpload(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}

	vars := mux.Vars(r)
	bucket := vars["bucket_id"]

	// Set a hard 5mb limit on files
	limit := 5
	if r.ContentLength > limit<<20 {
		errMsg := fmt.Printf("The file size limit is %dMB.\n", limit)
		http.Error(w, errMsg, http.StatusRequestEntityTooLarge)
		return
	}

	key := fileKey(bucket)
	err := storage.PutReader(bucket, key, r.Body,
		r.ContentLength, r.Header.Get("Content-Type"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer r.Body.Close()

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	uri := r.URL

	if r.URL.Host == "" {
		uri.Host = os.Getenv("URI_HOSTNAME")
		if *secure {
			uri.Scheme = "https"
		} else {
			uri.Scheme = "http"
		}
	}

	uri.Path = fmt.Sprintf("%s/%s", bucket, key)

	w.Header().Set("Content-Type", "application/json")

	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(UploadResponse{
		Url: uri.String(),
	})
}

func handlePing(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, "pong")
}
<|endoftext|>


<commit_before>// Naive implementation of Hashmap data structure.
package ghost

import (
	"errors"
	"sync"
)

const (
	initSize  uint32  = 64   // Default number of buckets
	threshold float32 = 0.75 // Threshold load factor to rehash table
)

type node struct {
	Key string
	Val string
}

type bucket struct {
	vector
}

type hashMap struct {
	Count   uint32 // Number of elements in hashmap
	CountMu sync.Mutex
	Size    uint32       // Number of buckets in hashmap
	buckets []bucket     // Array of indiviual buckets in hashmap
	locks   []sync.Mutex // Array of locks. Used to syncronize bucket access
}

func NewHashMap() *hashMap {
	newTable := &hashMap{}

	newTable.buckets = make([]bucket, initSize)

	newTable.locks = make([]sync.Mutex, initSize)

	newTable.Size = initSize

	return newTable
}

// Set or update key.
func (h *hashMap) Set(key, val string) {
	if h.loadFactor() >= threshold {
		h.rehash()
	}

	index := h.getIndex(key)

	h.acquire(index)

	bucketIndex := h.buckets[index].Find(key)

	if bucketIndex < 0 {
		h.buckets[index].Push(node{key, val})

		h.CountMu.Lock()
		h.Count++
		h.CountMu.Unlock()
	} else {
		h.buckets[index].Nodes[bucketIndex].Val = val
	}

	h.release(index)
}

// Get element from the hashmap.
// Return error if value is not found.
func (h *hashMap) Get(key string) (string, error) {
	index := h.getIndex(key)

	h.acquire(index)

	bucketIndex := h.buckets[index].Find(key)

	if bucketIndex < 0 {
		h.release(index)
		return "", errors.New("No value")
	} else {
		val := h.buckets[index].Nodes[bucketIndex].Val
		h.release(index)

		return val, nil
	}
}

// Delete element from the hashmap.
func (h *hashMap) Del(key string) {
	index := h.getIndex(key)

	h.acquire(index)

	bucketIndex := h.buckets[index].Find(key)

	if bucketIndex < 0 {
		return
	}

	h.buckets[index].Pop(bucketIndex)

	h.CountMu.Lock()
	h.Count--
	h.CountMu.Unlock()

	h.release(index)
}

// Get current load factor.
func (h *hashMap) loadFactor() float32 {
	h.CountMu.Lock()
	factor := float32(h.Count) / float32(h.Size)
	h.CountMu.Unlock()

	return factor
}

// Acquire control on the bucket.
func (h *hashMap) acquire(index uint32) {
	h.locks[index%uint32(len(h.locks))].Lock()
}

// Release control on the bucket.
func (h *hashMap) release(index uint32) {
	h.locks[index%uint32(len(h.locks))].Unlock()
}

// Allocate new bigger hashmap and rehash all keys.
func (h *hashMap) rehash() {
	oldSize := h.Size

	for i := 0; i < len(h.locks); i++ {
		h.locks[i].Lock()
	}

	if oldSize != h.Size {
		return // Someone beat us to it
	}

	h.Size <<= 1
	newBuckets := make([]bucket, h.Size)

	for n := range h.nodes() {
		newBuckets[h.getIndex(n.Key)].Push(n)
	}

	h.buckets = newBuckets

	for i := len(h.locks) - 1; i >= 0; i-- {
		h.locks[i].Unlock()
	}
}

// Navigate through all nodes
func (h *hashMap) nodes() <-chan node {
	ch := make(chan node)

	go func() {
		for _, b := range h.buckets {
			for i := 0; i < b.count; i++ {
				ch <- b.Nodes[i]
			}
		}
		close(ch)
	}()

	return ch
}

// Get index of bucket key belongs to.
func (h *hashMap) getIndex(key string) uint32 {
	return FNV1a_32([]byte(key)) % h.Size
}
<commit_msg>Fix hashmap rehash method<commit_after>// Naive implementation of Hashmap data structure.
package ghost

import (
	"errors"
	"sync"
)

const (
	initSize  uint32  = 64   // Default number of buckets
	threshold float32 = 0.75 // Threshold load factor to rehash table
)

type node struct {
	Key string
	Val string
}

type bucket struct {
	vector
}

type hashMap struct {
	Count   uint32 // Number of elements in hashmap
	CountMu sync.Mutex
	Size    uint32       // Number of buckets in hashmap
	buckets []bucket     // Array of indiviual buckets in hashmap
	locks   []sync.Mutex // Array of locks. Used to syncronize bucket access
}

func NewHashMap() *hashMap {
	newTable := &hashMap{}

	newTable.buckets = make([]bucket, initSize)

	newTable.locks = make([]sync.Mutex, initSize)

	newTable.Size = initSize

	return newTable
}

// Set or update key.
func (h *hashMap) Set(key, val string) {
	if h.loadFactor() >= threshold {
		h.rehash()
	}

	index := h.getIndex(key)

	h.acquire(index)

	bucketIndex := h.buckets[index].Find(key)

	if bucketIndex < 0 {
		h.buckets[index].Push(node{key, val})

		h.CountMu.Lock()
		h.Count++
		h.CountMu.Unlock()
	} else {
		h.buckets[index].Nodes[bucketIndex].Val = val
	}

	h.release(index)
}

// Get element from the hashmap.
// Return error if value is not found.
func (h *hashMap) Get(key string) (string, error) {
	index := h.getIndex(key)

	h.acquire(index)

	bucketIndex := h.buckets[index].Find(key)

	if bucketIndex < 0 {
		h.release(index)
		return "", errors.New("No value")
	} else {
		val := h.buckets[index].Nodes[bucketIndex].Val
		h.release(index)

		return val, nil
	}
}

// Delete element from the hashmap.
func (h *hashMap) Del(key string) {
	index := h.getIndex(key)

	h.acquire(index)

	bucketIndex := h.buckets[index].Find(key)

	if bucketIndex < 0 {
		return
	}

	h.buckets[index].Pop(bucketIndex)

	h.CountMu.Lock()
	h.Count--
	h.CountMu.Unlock()

	h.release(index)
}

// Get current load factor.
func (h *hashMap) loadFactor() float32 {
	h.CountMu.Lock()
	factor := float32(h.Count) / float32(h.Size)
	h.CountMu.Unlock()

	return factor
}

// Acquire control on the bucket.
func (h *hashMap) acquire(index uint32) {
	h.locks[index%uint32(len(h.locks))].Lock()
}

// Release control on the bucket.
func (h *hashMap) release(index uint32) {
	h.locks[index%uint32(len(h.locks))].Unlock()
}

func (h *hashMap) acquireAll() {
	for i := 0; i < len(h.locks); i++ {
		h.locks[i].Lock()
	}
}

func (h *hashMap) releaseAll() {
	for i := len(h.locks) - 1; i >= 0; i-- {
		h.locks[i].Unlock()
	}
}

// Allocate new bigger hashmap and rehash all keys.
func (h *hashMap) rehash() {
	oldSize := h.Size

	h.acquireAll()

	if oldSize != h.Size {
		h.releaseAll()
		return // Someone beat us to it
	}

	h.Size <<= 1
	newBuckets := make([]bucket, h.Size)

	for n := range h.nodes() {
		newBuckets[h.getIndex(n.Key)].Push(n)
	}

	h.buckets = newBuckets

	h.releaseAll()
}

// Navigate through all nodes
func (h *hashMap) nodes() <-chan node {
	ch := make(chan node)

	go func() {
		for _, b := range h.buckets {
			for i := 0; i < b.count; i++ {
				ch <- b.Nodes[i]
			}
		}
		close(ch)
	}()

	return ch
}

// Get index of bucket key belongs to.
func (h *hashMap) getIndex(key string) uint32 {
	return FNV1a_32([]byte(key)) % h.Size
}
<|endoftext|>


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

package hdiutil

import (
	"fmt"
	"strconv"
	"strings"
)

// Usage: hdiutil <verb> <options>
// <verb> is one of the following:
// help                    flatten
// attach                  imageinfo
// detach                  internet-enable
// eject                   isencrypted
// verify                  makehybrid
// create                  mount
// compact                 mountvol
// convert                 unmount
// burn                    plugins
// info                    resize
// checksum                segment
// chpass                  pmap
// erasekeys               udifderez
// unflatten               udifrez
// help                       display more detailed help

// EncryptionType specify a particular type of encryption.
type EncryptionType int

const (
	// AES128 use AES cipher running in CBC mode on 512-byte blocks with a 128-bit key (recommended).
	AES128 EncryptionType = 1 << iota
	// AES256 use AES cipher running in CBC mode on 512-byte blocks with a 256-bit key (more secure, but slower).
	AES256
)

func (e EncryptionType) String() string {
	switch e {
	case AES128:
		return "AES-128"
	case AES256:
		return "AES-256"
	}
	return fmt.Sprintf("EncryptionType(%d)", e)
}

func (e EncryptionType) attachFlag() []string { return stringFlag(e.String(), "encryption") }

type plist bool

func (p plist) attachFlag() []string { return boolFlag(bool(p), "plist") }

type puppetstrings bool

func (p puppetstrings) attachFlag() []string { return boolFlag(bool(p), "puppetstrings") }

// Srcimagekey specify a key/value pair for the disk image recognition system. (-imagekey is normally a synonym)
type Srcimagekey map[string]string

// Tgtimagekey specify a key/value pair for any image created. (-imagekey is only a synonym if there is no input image).
type Tgtimagekey map[string]string

// Encryption specify a particular type of encryption or, if not specified, the default encryption algorithm.
//
// As of OS X 10.7, the default algorithm is the AES cipher running in CBC mode on 512-byte blocks with a 128-bit key.
type Encryption EncryptionType

type stdinpass bool

func (s stdinpass) attachFlag() []string { return boolFlag(bool(s), "stdinpass") }

type agentpass bool

// Recover specify a keychain containing the secret corresponding to the certificate specified with -certificate when the image was created.
type Recover string

func (r Recover) attachFlag() []string { return stringFlag(string(r), "recover") }

// Certificate specify a secondary access certificate for an encrypted image.
// cert_file must be DER-encoded certificate data, which can be created by Keychain Access or openssl(1).
type Certificate string

// Pubkey specify a list of public keys, identified by their hexadecimal hashes, to be used to protect the encrypted image being created.
type Pubkey []string

// Cacert specify a certificate authority certificate.
// cert can be either a PEM file or a directory of certificates processed by c_rehash(1).
//
// See also --capath and --cacert in curl(1).
type Cacert string

type insecurehttp bool

// Shadow use a shadow file in conjunction with the data in the primary image file.
// This option prevents modification of the original image and allows read-only images to be attached read/write.
//
// When blocks are being read from the image, blocks present in the shadow file override blocks in the base image.
// All data written to an attached device will be redirected to the shadow file.
// If not specified, shadowfile defaults to image.shadow.
// If the shadow file does not exist, it is created.
//
// hdiutil verbs taking images as input accept -shadow, -cacert, and -insecurehttp.
type Shadow string

func (s Shadow) attachFlag() []string { return stringFlag(string(s), "shadow") }

type verbose bool

func (v verbose) attachFlag() []string { return boolFlag(bool(v), "verbose") }
func (v verbose) detachFlag() []string { return boolFlag(bool(v), "verbose") }

type quiet bool

func (q quiet) attachFlag() []string { return boolFlag(bool(q), "quiet") }
func (q quiet) detachFlag() []string { return boolFlag(bool(q), "quiet") }

type debug bool

func (d debug) attachFlag() []string { return boolFlag(bool(d), "debug") }
func (d debug) detachFlag() []string { return boolFlag(bool(d), "debug") }

const (
	// Plist provide result output in plist format.
	// Other programs invoking hdiutil are expected to use -plist rather than try to parse the human-readable output.
	//
	// The usual output is consistent but generally unstructured.
	Plist plist = true

	// Puppetstrings provide progress output that is easy for another program to parse.
	// PERCENTAGE outputs can include the value -1 which means hdiutil is performing an operation that will take an indeterminate amount of time to complete.
	//
	// Any program trying to interpret hdiutil's progress should use -puppetstrings.
	Puppetstrings puppetstrings = true

	// Stdinpass read a null-terminated passphrase from standard input.
	// If the standard input is a tty, the passphrase will be read with readpassphrase(3).
	// Otherwise, the password is read from stdin.
	//
	// -stdinpass replaces -passphrase which has been deprecated.
	// -passphrase is insecure because its argument appears in the output of ps(1) where it is visible to other users and processes on the system.
	Stdinpass stdinpass = true

	// Agentpass force the default behavior of prompting for a passphrase.
	//
	// Useful with -pubkey to create an image protected by both a passphrase and a public key.
	Agentpass agentpass = true

	// Insecurehttp ignore SSL host validation failures.
	// Useful for self-signed servers for which the appropriate certificates are unavailable or if access to a server is desired when the server name doesn't match what is in the certificate.
	Insecurehttp insecurehttp = true

	// Verbose be verbose: produce extra progress output and error diagnostics.
	//
	// This option can help the user decipher why a particular operation failed.
	// At a minimum, the probing of any specified images will be detailed.
	Verbose verbose = true

	// Quiet close stdout and stderr, leaving only hdiutil's exit status to indicate success or failure.
	// No /dev entries or mount points will be printed.
	//
	// -debug and -verbose disable -quiet.
	Quiet quiet = true

	// Debug be very verbose.
	//
	// This option is good if a large amount of progress information is needed.
	// As of Mac OS X 10.6, -debug enables -verbose.
	Debug debug = true
)

// RawDeviceNode return the raw device node from the deviceNode.
func RawDeviceNode(deviceNode string) string {
	return strings.Replace(deviceNode, "disk", "rdisk", 1)
}

// DeviceNumber return the device number from the deviceNode.
func DeviceNumber(deviceNode string) int {
	n, err := strconv.Atoi(strings.TrimPrefix(deviceNode, "/dev/disk"))
	if err != nil {
		return 0
	}
	return n
}
<commit_msg>hdiutil: add BUG comment<commit_after>// Copyright 2017 The go-darwin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package hdiutil

import (
	"fmt"
	"strconv"
	"strings"
)

// Usage: hdiutil <verb> <options>
// <verb> is one of the following:
// help                    flatten
// attach                  imageinfo
// detach                  internet-enable
// eject                   isencrypted
// verify                  makehybrid
// create                  mount
// compact                 mountvol
// convert                 unmount
// burn                    plugins
// info                    resize
// checksum                segment
// chpass                  pmap
// erasekeys               udifderez
// unflatten               udifrez
// help                       display more detailed help

// EncryptionType specify a particular type of encryption.
type EncryptionType int

const (
	// AES128 use AES cipher running in CBC mode on 512-byte blocks with a 128-bit key (recommended).
	AES128 EncryptionType = 1 << iota
	// AES256 use AES cipher running in CBC mode on 512-byte blocks with a 256-bit key (more secure, but slower).
	AES256
)

func (e EncryptionType) String() string {
	switch e {
	case AES128:
		return "AES-128"
	case AES256:
		return "AES-256"
	}
	return fmt.Sprintf("EncryptionType(%d)", e)
}

func (e EncryptionType) attachFlag() []string { return stringFlag(e.String(), "encryption") }

type plist bool

func (p plist) attachFlag() []string { return boolFlag(bool(p), "plist") }

type puppetstrings bool

func (p puppetstrings) attachFlag() []string { return boolFlag(bool(p), "puppetstrings") }

// Srcimagekey specify a key/value pair for the disk image recognition system. (-imagekey is normally a synonym)
type Srcimagekey map[string]string

// Tgtimagekey specify a key/value pair for any image created. (-imagekey is only a synonym if there is no input image).
type Tgtimagekey map[string]string

// Encryption specify a particular type of encryption or, if not specified, the default encryption algorithm.
//
// As of OS X 10.7, the default algorithm is the AES cipher running in CBC mode on 512-byte blocks with a 128-bit key.
type Encryption EncryptionType

type stdinpass bool

func (s stdinpass) attachFlag() []string { return boolFlag(bool(s), "stdinpass") }

type agentpass bool

// Recover specify a keychain containing the secret corresponding to the certificate specified with -certificate when the image was created.
type Recover string

func (r Recover) attachFlag() []string { return stringFlag(string(r), "recover") }

// Certificate specify a secondary access certificate for an encrypted image.
// cert_file must be DER-encoded certificate data, which can be created by Keychain Access or openssl(1).
type Certificate string

// Pubkey specify a list of public keys, identified by their hexadecimal hashes, to be used to protect the encrypted image being created.
type Pubkey []string

// Cacert specify a certificate authority certificate.
// cert can be either a PEM file or a directory of certificates processed by c_rehash(1).
//
// See also --capath and --cacert in curl(1).
type Cacert string

type insecurehttp bool

// Shadow use a shadow file in conjunction with the data in the primary image file.
// This option prevents modification of the original image and allows read-only images to be attached read/write.
//
// When blocks are being read from the image, blocks present in the shadow file override blocks in the base image.
// All data written to an attached device will be redirected to the shadow file.
// If not specified, shadowfile defaults to image.shadow.
// If the shadow file does not exist, it is created.
//
// hdiutil verbs taking images as input accept -shadow, -cacert, and -insecurehttp.
type Shadow string

func (s Shadow) attachFlag() []string { return stringFlag(string(s), "shadow") }

type verbose bool

func (v verbose) attachFlag() []string { return boolFlag(bool(v), "verbose") }
func (v verbose) detachFlag() []string { return boolFlag(bool(v), "verbose") }

type quiet bool

func (q quiet) attachFlag() []string { return boolFlag(bool(q), "quiet") }
func (q quiet) detachFlag() []string { return boolFlag(bool(q), "quiet") }

type debug bool

func (d debug) attachFlag() []string { return boolFlag(bool(d), "debug") }
func (d debug) detachFlag() []string { return boolFlag(bool(d), "debug") }

const (
	// Plist provide result output in plist format.
	// Other programs invoking hdiutil are expected to use -plist rather than try to parse the human-readable output.
	//
	// The usual output is consistent but generally unstructured.
	Plist plist = true

	// Puppetstrings provide progress output that is easy for another program to parse.
	// PERCENTAGE outputs can include the value -1 which means hdiutil is performing an operation that will take an indeterminate amount of time to complete.
	//
	// Any program trying to interpret hdiutil's progress should use -puppetstrings.
	Puppetstrings puppetstrings = true

	// Stdinpass read a null-terminated passphrase from standard input.
	// If the standard input is a tty, the passphrase will be read with readpassphrase(3).
	// Otherwise, the password is read from stdin.
	//
	// -stdinpass replaces -passphrase which has been deprecated.
	// -passphrase is insecure because its argument appears in the output of ps(1) where it is visible to other users and processes on the system.
	Stdinpass stdinpass = true

	// Agentpass force the default behavior of prompting for a passphrase.
	//
	// Useful with -pubkey to create an image protected by both a passphrase and a public key.
	Agentpass agentpass = true

	// Insecurehttp ignore SSL host validation failures.
	// Useful for self-signed servers for which the appropriate certificates are unavailable or if access to a server is desired when the server name doesn't match what is in the certificate.
	Insecurehttp insecurehttp = true

	// Verbose be verbose: produce extra progress output and error diagnostics.
	//
	// This option can help the user decipher why a particular operation failed.
	// At a minimum, the probing of any specified images will be detailed.
	// BUG(zchee): not exit hdiutil command if set.
	Verbose verbose = true

	// Quiet close stdout and stderr, leaving only hdiutil's exit status to indicate success or failure.
	// No /dev entries or mount points will be printed.
	//
	// -debug and -verbose disable -quiet.
	// BUG(zchee): not get the command result such as device node path when attach.
	Quiet quiet = true

	// Debug be very verbose.
	//
	// This option is good if a large amount of progress information is needed.
	// As of Mac OS X 10.6, -debug enables -verbose.
	// BUG(zchee): not exit hdiutil command if set.
	Debug debug = true
)

// RawDeviceNode return the raw device node from the deviceNode.
func RawDeviceNode(deviceNode string) string {
	return strings.Replace(deviceNode, "disk", "rdisk", 1)
}

// DeviceNumber return the device number from the deviceNode.
func DeviceNumber(deviceNode string) int {
	n, err := strconv.Atoi(strings.TrimPrefix(deviceNode, "/dev/disk"))
	if err != nil {
		return 0
	}
	return n
}
<|endoftext|>


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

package readline

/*
#include <stdlib.h>
//#include <readline/history.h>
#include <editline/readline.h>
*/
import "C"

import (
	"fmt"
	//	"os"
	"strings"
	"syscall"
	"unicode"
	"unsafe"
)

// UsingHistory begins a session in which the history functions might be used. This initializes the interactive variables.
// (See using_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX2)
func UsingHistory() {
	C.using_history()
}

// AddHistory places string at the end of the history list.
// Blank lines are discarded.
// (See add_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX5)
func AddHistory(line string) {
	if len(line) == 0 || len(strings.TrimSpace(line)) == 0 {
		return
	}
	if unicode.IsSpace(rune(line[0])) { // ignorespace
		return
	}
	if prev, err := GetHistory(-1); err == nil && prev == line { // ignore consecutive dups
		return
	}
	cline := C.CString(line)
	C.add_history(cline)
	C.free(unsafe.Pointer(cline))
}

// ReadHistory adds the content of filename to the history list, a line at a time.
// If filename is "", then read from '~/.history'.
// (See read_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX27)
func ReadHistory(filename string) (bool, error) {
	var cfilename *C.char
	if len(filename) != 0 {
		cfilename = C.CString(filename)
	}
	err := C.read_history(cfilename)
	if cfilename != nil {
		C.free(unsafe.Pointer(cfilename))
	}
	if err != 0 {
		e := syscall.Errno(err)
		if e == syscall.ENOENT { // ignored when the file doesn't exist.
			return false, nil
		}
		return false, e
	}
	return true, nil
}

// WriteHistory writes the current history to filename, overwriting filename if necessary.
// If filename is "", then write the history list to `~/.history'.
// (See write_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX29)
func WriteHistory(filename string) error {
	if HistoryLength() <= 0 {
		return nil
	}
	var cfilename *C.char
	if len(filename) != 0 {
		cfilename = C.CString(filename)
	}
	err := C.write_history(cfilename)
	if cfilename != nil {
		C.free(unsafe.Pointer(cfilename))
	}
	if err != 0 {
		return syscall.Errno(err)
	}
	return nil
}

// AppendHistory appends the last nelements of the history list to filename.
// If filename is "", then append to `~/.history'.
// (See append_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX30)
/* not supported by editline
func AppendHistory(nelements int, filename string) error {
	if HistoryLength() == 0 {
		return nil
	}
	// Checks if the file exists. If not, creates it.
	f, err := os.Open(filename)
	if os.IsNotExist(err) {
		f, err = os.Create(filename)
	}
	if err != nil {
		return err
	}
	if err = f.Close(); err != nil {
		return err
	}

	var cfilename *C.char
	if len(filename) != 0 {
		cfilename = C.CString(filename)
	}
	cerr := C.append_history(C.int(nelements), cfilename)
	if cfilename != nil {
		C.free(unsafe.Pointer(cfilename))
	}
	if cerr != 0 {
		return syscall.Errno(cerr)
	}
	return nil
}
*/

// TruncateHistoryFile truncates the history file filename, leaving only the last nlines lines.
// If filename is "", then `~/.history' is truncated.
// (See history_truncate_file http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX31)
func TruncateHistoryFile(filename string, nlines int32) error {
	var cfilename *C.char
	if len(filename) != 0 {
		cfilename = C.CString(filename)
	}
	err := C.history_truncate_file(cfilename, C.int(nlines))
	if cfilename != nil {
		C.free(unsafe.Pointer(cfilename))
	}
	if err != 0 {
		return syscall.Errno(err)
	}
	return nil
}

// ClearHistory clears the history list by deleting all the entries.
// (See clear_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX10)
func ClearHistory() {
	C.clear_history()
}

// StifleHistory cuts off the history list, remembering only the last max entries.
// (See stifle_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX11)
func StifleHistory(max int32) {
	C.stifle_history(C.int(max))
}

// UnstifleHistory stops stifling the history.
// This returns the previously-set maximum number of history entries (as set by StifleHistory()).
// The value is positive if the history was stifled, negative if it wasn't.
// (See unstifle_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX12)
func UnstifleHistory() int32 {
	return int32(C.unstifle_history())
}

// IsHistoryStifled says if the history is stifled.
// (See history_is_stifled http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX13)
func IsHistoryStifled() bool {
	return C.history_is_stifled() != 0
}

// HistoryLength returns the number of entries currently stored in the history list.
// (See history_length http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX37)
func HistoryLength() int32 {
	return int32(C.history_length)
}

// HistoryBase returns the logical offset of the first entry in the history list.
// (See history_base http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX36)
func HistoryBase() int32 {
	return int32(C.history_base)
}

/*
// Return a nil terminated array of HIST_ENTRY * which is the current input history.
// Element 0 of this list is the beginning of time. If there is no history, return nil.
// (See history_list http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX17)
func HistoryList(offset int) string {
	C.history_list()
}
*/

// GetHistory returns the history entry at position index, starting from 0.
// If there is no entry there, or if index is greater than the history length, return an error.
// (See history_get http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX17)
func GetHistory(index int32) (string, error) {
	length := HistoryLength()
	if index < 0 {
		index += length
	}
	if index < 0 || index >= length {
		return "", fmt.Errorf("invalid index", index)
	}
	index += HistoryBase() // TODO
	entry := C.history_get(C.int(index))
	if entry == nil {
		return "", fmt.Errorf("invalid index", index)
	}
	return C.GoString(entry.line), nil
}
<commit_msg>Go vet<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package readline

/*
#include <stdlib.h>
//#include <readline/history.h>
#include <editline/readline.h>
*/
import "C"

import (
	"fmt"
	//	"os"
	"strings"
	"syscall"
	"unicode"
	"unsafe"
)

// UsingHistory begins a session in which the history functions might be used. This initializes the interactive variables.
// (See using_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX2)
func UsingHistory() {
	C.using_history()
}

// AddHistory places string at the end of the history list.
// Blank lines are discarded.
// (See add_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX5)
func AddHistory(line string) {
	if len(line) == 0 || len(strings.TrimSpace(line)) == 0 {
		return
	}
	if unicode.IsSpace(rune(line[0])) { // ignorespace
		return
	}
	if prev, err := GetHistory(-1); err == nil && prev == line { // ignore consecutive dups
		return
	}
	cline := C.CString(line)
	C.add_history(cline)
	C.free(unsafe.Pointer(cline))
}

// ReadHistory adds the content of filename to the history list, a line at a time.
// If filename is "", then read from '~/.history'.
// (See read_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX27)
func ReadHistory(filename string) (bool, error) {
	var cfilename *C.char
	if len(filename) != 0 {
		cfilename = C.CString(filename)
	}
	err := C.read_history(cfilename)
	if cfilename != nil {
		C.free(unsafe.Pointer(cfilename))
	}
	if err != 0 {
		e := syscall.Errno(err)
		if e == syscall.ENOENT { // ignored when the file doesn't exist.
			return false, nil
		}
		return false, e
	}
	return true, nil
}

// WriteHistory writes the current history to filename, overwriting filename if necessary.
// If filename is "", then write the history list to `~/.history'.
// (See write_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX29)
func WriteHistory(filename string) error {
	if HistoryLength() <= 0 {
		return nil
	}
	var cfilename *C.char
	if len(filename) != 0 {
		cfilename = C.CString(filename)
	}
	err := C.write_history(cfilename)
	if cfilename != nil {
		C.free(unsafe.Pointer(cfilename))
	}
	if err != 0 {
		return syscall.Errno(err)
	}
	return nil
}

// AppendHistory appends the last nelements of the history list to filename.
// If filename is "", then append to `~/.history'.
// (See append_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX30)
/* not supported by editline
func AppendHistory(nelements int, filename string) error {
	if HistoryLength() == 0 {
		return nil
	}
	// Checks if the file exists. If not, creates it.
	f, err := os.Open(filename)
	if os.IsNotExist(err) {
		f, err = os.Create(filename)
	}
	if err != nil {
		return err
	}
	if err = f.Close(); err != nil {
		return err
	}

	var cfilename *C.char
	if len(filename) != 0 {
		cfilename = C.CString(filename)
	}
	cerr := C.append_history(C.int(nelements), cfilename)
	if cfilename != nil {
		C.free(unsafe.Pointer(cfilename))
	}
	if cerr != 0 {
		return syscall.Errno(cerr)
	}
	return nil
}
*/

// TruncateHistoryFile truncates the history file filename, leaving only the last nlines lines.
// If filename is "", then `~/.history' is truncated.
// (See history_truncate_file http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX31)
func TruncateHistoryFile(filename string, nlines int32) error {
	var cfilename *C.char
	if len(filename) != 0 {
		cfilename = C.CString(filename)
	}
	err := C.history_truncate_file(cfilename, C.int(nlines))
	if cfilename != nil {
		C.free(unsafe.Pointer(cfilename))
	}
	if err != 0 {
		return syscall.Errno(err)
	}
	return nil
}

// ClearHistory clears the history list by deleting all the entries.
// (See clear_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX10)
func ClearHistory() {
	C.clear_history()
}

// StifleHistory cuts off the history list, remembering only the last max entries.
// (See stifle_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX11)
func StifleHistory(max int32) {
	C.stifle_history(C.int(max))
}

// UnstifleHistory stops stifling the history.
// This returns the previously-set maximum number of history entries (as set by StifleHistory()).
// The value is positive if the history was stifled, negative if it wasn't.
// (See unstifle_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX12)
func UnstifleHistory() int32 {
	return int32(C.unstifle_history())
}

// IsHistoryStifled says if the history is stifled.
// (See history_is_stifled http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX13)
func IsHistoryStifled() bool {
	return C.history_is_stifled() != 0
}

// HistoryLength returns the number of entries currently stored in the history list.
// (See history_length http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX37)
func HistoryLength() int32 {
	return int32(C.history_length)
}

// HistoryBase returns the logical offset of the first entry in the history list.
// (See history_base http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX36)
func HistoryBase() int32 {
	return int32(C.history_base)
}

/*
// Return a nil terminated array of HIST_ENTRY * which is the current input history.
// Element 0 of this list is the beginning of time. If there is no history, return nil.
// (See history_list http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX17)
func HistoryList(offset int) string {
	C.history_list()
}
*/

// GetHistory returns the history entry at position index, starting from 0.
// If there is no entry there, or if index is greater than the history length, return an error.
// (See history_get http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX17)
func GetHistory(index int32) (string, error) {
	length := HistoryLength()
	if index < 0 {
		index += length
	}
	if index < 0 || index >= length {
		return "", fmt.Errorf("invalid index %d", index)
	}
	index += HistoryBase() // TODO
	entry := C.history_get(C.int(index))
	if entry == nil {
		return "", fmt.Errorf("invalid index %d", index)
	}
	return C.GoString(entry.line), nil
}
<|endoftext|>


<commit_before>// Copyright 2018 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 zoekt

import (
	"encoding/binary"
	"fmt"
)

// hitIterator finds potential search matches, measured in offsets of
// the concatenation of all documents.
type hitIterator interface {
	// Return the first hit, or maxUInt32 if none.
	first() uint32

	// Skip until past limit. The argument maxUInt32 should be
	// treated specially.
	next(limit uint32)

	// Return how many bytes were read.
	updateStats(s *Stats)
}

// distanceHitIterator looks for hits at a fixed distance apart.
type distanceHitIterator struct {
	started  bool
	distance uint32
	i1       hitIterator
	i2       hitIterator
}

func (i *distanceHitIterator) String() string {
	return fmt.Sprintf("dist(%d, %v, %v)", i.distance, i.i1, i.i2)
}

func (i *distanceHitIterator) findNext() {
	for {
		var p1, p2 uint32
		p1 = i.i1.first()
		p2 = i.i2.first()
		if p1 == maxUInt32 || p2 == maxUInt32 {
			i.i1.next(maxUInt32)
			break
		}

		if p1+i.distance < p2 {
			i.i1.next(p2 - i.distance - 1)
		} else if p1+i.distance > p2 {
			i.i2.next(p1 + i.distance - 1)
		} else {
			break
		}
	}
}

func (i *distanceHitIterator) first() uint32 {
	if !i.started {
		i.findNext()
		i.started = true
	}
	return i.i1.first()
}

func (i *distanceHitIterator) updateStats(s *Stats) {
	i.i1.updateStats(s)
	i.i2.updateStats(s)
}

func (i *distanceHitIterator) next(limit uint32) {
	i.i1.next(limit)
	if l2 := limit + i.distance; l2 <= maxUInt32 {
		i.i2.next(l2)
	}
	i.findNext()
}

func (d *indexData) newDistanceTrigramIter(ng1, ng2 ngram, dist uint32, caseSensitive, fileName bool) (hitIterator, error) {
	if dist == 0 {
		return nil, fmt.Errorf("d == 0")
	}

	i1, err := d.trigramHitIterator(ng1, caseSensitive, fileName)
	if err != nil {
		return nil, err
	}
	i2, err := d.trigramHitIterator(ng2, caseSensitive, fileName)
	if err != nil {
		return nil, err
	}
	return &distanceHitIterator{
		i1:       i1,
		i2:       i2,
		distance: dist,
	}, nil
}

func (d *indexData) trigramHitIterator(ng ngram, caseSensitive, fileName bool) (hitIterator, error) {
	variants := []ngram{ng}
	if !caseSensitive {
		variants = generateCaseNgrams(ng)
	}

	iters := make([]hitIterator, 0, len(variants))
	for _, v := range variants {
		if fileName {
			blob := d.fileNameNgrams[v]
			if len(blob) > 0 {
				iters = append(iters, &inMemoryIterator{
					d.fileNameNgrams[v],
					v,
				})
			}
			continue
		}

		sec := d.ngrams[v]
		blob, err := d.readSectionBlob(sec)
		if err != nil {
			return nil, err
		}
		if len(blob) > 0 {
			iters = append(iters, newCompressedPostingIterator(blob, v))
		}
	}

	if len(iters) == 1 {
		return iters[0], nil
	}
	return &mergingIterator{
		iters: iters,
	}, nil
}

// inMemoryIterator is hitIterator that goes over an in-memory uint32 posting list.
type inMemoryIterator struct {
	postings []uint32
	what     ngram
}

func (i *inMemoryIterator) String() string {
	return fmt.Sprintf("mem(%s):%v", i.what, i.postings)
}

func (i *inMemoryIterator) first() uint32 {
	if len(i.postings) > 0 {
		return i.postings[0]
	}
	return maxUInt32
}

func (i *inMemoryIterator) updateStats(s *Stats) {
}

func (i *inMemoryIterator) next(limit uint32) {
	if limit == maxUInt32 {
		i.postings = nil
	}

	for len(i.postings) > 0 && i.postings[0] <= limit {
		i.postings = i.postings[1:]
	}
}

// compressedPostingIterator goes over a delta varint encoded posting
// list.
type compressedPostingIterator struct {
	blob, orig []byte
	_first     uint32
	what       ngram
}

func newCompressedPostingIterator(b []byte, w ngram) *compressedPostingIterator {
	d, sz := binary.Uvarint(b)
	return &compressedPostingIterator{
		_first: uint32(d),
		blob:   b[sz:],
		orig:   b,
		what:   w,
	}
}

func (i *compressedPostingIterator) String() string {
	return fmt.Sprintf("compressed(%s, %d, [%d bytes])", i.what, i._first, len(i.blob))
}

func (i *compressedPostingIterator) first() uint32 {
	return i._first
}

func (i *compressedPostingIterator) next(limit uint32) {
	if limit == maxUInt32 {
		i.blob = nil
		i._first = maxUInt32
		return
	}

	if i._first <= limit && len(i.blob) == 0 {
		i._first = maxUInt32
		return
	}

	for i._first <= limit && len(i.blob) > 0 {
		delta, sz := binary.Uvarint(i.blob)
		i._first += uint32(delta)
		i.blob = i.blob[sz:]
	}
}

func (i *compressedPostingIterator) updateStats(s *Stats) {
	s.IndexBytesLoaded += int64(len(i.orig) - len(i.blob))
}

// mergingIterator forms the merge of a set of hitIterators, to
// implement an OR operation at the hit level.
type mergingIterator struct {
	iters []hitIterator
}

func (i *mergingIterator) String() string {
	return fmt.Sprintf("merge:%v", i.iters)
}

func (i *mergingIterator) updateStats(s *Stats) {
	for _, j := range i.iters {
		j.updateStats(s)
	}
}

func (i *mergingIterator) first() uint32 {
	r := uint32(maxUInt32)
	for _, j := range i.iters {
		f := j.first()
		if f < r {
			r = f
		}
	}

	return r
}

func (i *mergingIterator) next(limit uint32) {
	for _, j := range i.iters {
		j.next(limit)
	}
}
<commit_msg>Handle the unlikely case of overflow for distanceHitIterator.next() <commit_after>// Copyright 2018 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 zoekt

import (
	"encoding/binary"
	"fmt"
)

// hitIterator finds potential search matches, measured in offsets of
// the concatenation of all documents.
type hitIterator interface {
	// Return the first hit, or maxUInt32 if none.
	first() uint32

	// Skip until past limit. The argument maxUInt32 should be
	// treated specially.
	next(limit uint32)

	// Return how many bytes were read.
	updateStats(s *Stats)
}

// distanceHitIterator looks for hits at a fixed distance apart.
type distanceHitIterator struct {
	started  bool
	distance uint32
	i1       hitIterator
	i2       hitIterator
}

func (i *distanceHitIterator) String() string {
	return fmt.Sprintf("dist(%d, %v, %v)", i.distance, i.i1, i.i2)
}

func (i *distanceHitIterator) findNext() {
	for {
		var p1, p2 uint32
		p1 = i.i1.first()
		p2 = i.i2.first()
		if p1 == maxUInt32 || p2 == maxUInt32 {
			i.i1.next(maxUInt32)
			break
		}

		if p1+i.distance < p2 {
			i.i1.next(p2 - i.distance - 1)
		} else if p1+i.distance > p2 {
			i.i2.next(p1 + i.distance - 1)
		} else {
			break
		}
	}
}

func (i *distanceHitIterator) first() uint32 {
	if !i.started {
		i.findNext()
		i.started = true
	}
	return i.i1.first()
}

func (i *distanceHitIterator) updateStats(s *Stats) {
	i.i1.updateStats(s)
	i.i2.updateStats(s)
}

func (i *distanceHitIterator) next(limit uint32) {
	i.i1.next(limit)
	l2 := limit + i.distance

	if l2 < limit { // overflow.
		l2 = maxUInt32
	}
	i.i2.next(l2)
	i.findNext()
}

func (d *indexData) newDistanceTrigramIter(ng1, ng2 ngram, dist uint32, caseSensitive, fileName bool) (hitIterator, error) {
	if dist == 0 {
		return nil, fmt.Errorf("d == 0")
	}

	i1, err := d.trigramHitIterator(ng1, caseSensitive, fileName)
	if err != nil {
		return nil, err
	}
	i2, err := d.trigramHitIterator(ng2, caseSensitive, fileName)
	if err != nil {
		return nil, err
	}
	return &distanceHitIterator{
		i1:       i1,
		i2:       i2,
		distance: dist,
	}, nil
}

func (d *indexData) trigramHitIterator(ng ngram, caseSensitive, fileName bool) (hitIterator, error) {
	variants := []ngram{ng}
	if !caseSensitive {
		variants = generateCaseNgrams(ng)
	}

	iters := make([]hitIterator, 0, len(variants))
	for _, v := range variants {
		if fileName {
			blob := d.fileNameNgrams[v]
			if len(blob) > 0 {
				iters = append(iters, &inMemoryIterator{
					d.fileNameNgrams[v],
					v,
				})
			}
			continue
		}

		sec := d.ngrams[v]
		blob, err := d.readSectionBlob(sec)
		if err != nil {
			return nil, err
		}
		if len(blob) > 0 {
			iters = append(iters, newCompressedPostingIterator(blob, v))
		}
	}

	if len(iters) == 1 {
		return iters[0], nil
	}
	return &mergingIterator{
		iters: iters,
	}, nil
}

// inMemoryIterator is hitIterator that goes over an in-memory uint32 posting list.
type inMemoryIterator struct {
	postings []uint32
	what     ngram
}

func (i *inMemoryIterator) String() string {
	return fmt.Sprintf("mem(%s):%v", i.what, i.postings)
}

func (i *inMemoryIterator) first() uint32 {
	if len(i.postings) > 0 {
		return i.postings[0]
	}
	return maxUInt32
}

func (i *inMemoryIterator) updateStats(s *Stats) {
}

func (i *inMemoryIterator) next(limit uint32) {
	if limit == maxUInt32 {
		i.postings = nil
	}

	for len(i.postings) > 0 && i.postings[0] <= limit {
		i.postings = i.postings[1:]
	}
}

// compressedPostingIterator goes over a delta varint encoded posting
// list.
type compressedPostingIterator struct {
	blob, orig []byte
	_first     uint32
	what       ngram
}

func newCompressedPostingIterator(b []byte, w ngram) *compressedPostingIterator {
	d, sz := binary.Uvarint(b)
	return &compressedPostingIterator{
		_first: uint32(d),
		blob:   b[sz:],
		orig:   b,
		what:   w,
	}
}

func (i *compressedPostingIterator) String() string {
	return fmt.Sprintf("compressed(%s, %d, [%d bytes])", i.what, i._first, len(i.blob))
}

func (i *compressedPostingIterator) first() uint32 {
	return i._first
}

func (i *compressedPostingIterator) next(limit uint32) {
	if limit == maxUInt32 {
		i.blob = nil
		i._first = maxUInt32
		return
	}

	if i._first <= limit && len(i.blob) == 0 {
		i._first = maxUInt32
		return
	}

	for i._first <= limit && len(i.blob) > 0 {
		delta, sz := binary.Uvarint(i.blob)
		i._first += uint32(delta)
		i.blob = i.blob[sz:]
	}
}

func (i *compressedPostingIterator) updateStats(s *Stats) {
	s.IndexBytesLoaded += int64(len(i.orig) - len(i.blob))
}

// mergingIterator forms the merge of a set of hitIterators, to
// implement an OR operation at the hit level.
type mergingIterator struct {
	iters []hitIterator
}

func (i *mergingIterator) String() string {
	return fmt.Sprintf("merge:%v", i.iters)
}

func (i *mergingIterator) updateStats(s *Stats) {
	for _, j := range i.iters {
		j.updateStats(s)
	}
}

func (i *mergingIterator) first() uint32 {
	r := uint32(maxUInt32)
	for _, j := range i.iters {
		f := j.first()
		if f < r {
			r = f
		}
	}

	return r
}

func (i *mergingIterator) next(limit uint32) {
	for _, j := range i.iters {
		j.next(limit)
	}
}
<|endoftext|>


<commit_before>package main

// Unpack a JPEG file one segment at a time and repackage into a new
// JPEG file.  It can process files which use the Multi-Picture Format
// extension to contain multiple images.

import (
	"fmt"
	jseg "github.com/garyhouston/jpegsegs"
	tiff "github.com/garyhouston/tiff66"
	"io"
	"log"
	"os"
)

// MPF processor that reads and repacks the index data.
type MPFIndexData struct {
	Tree         *tiff.IFDNode  // Unpacked MPF index TIFF tree.
	Index        *jseg.MPFIndex // MPF Index info.
	APP2WritePos uint32         // Position of the MPF APP2 marker in the output stream.
}

func (mpfData *MPFIndexData) ProcessAPP2(writer io.Seeker, reader io.Seeker, buf []byte) (bool, []byte, error) {
	done := false
	isMPF, next := jseg.GetMPFHeader(buf)
	if isMPF {
		savebuf := make([]byte, len(buf)-jseg.MPFHeaderSize)
		copy(savebuf, buf[next:])
		var err error
		mpfData.Tree, err = jseg.GetMPFTree(savebuf, tiff.MPFIndexSpace)
		if err != nil {
			return false, nil, err
		}
		mpfData.Tree.Fix()
		// MPF offsets are relative to the byte following the
		// MPF header, which is 4 bytes past the start of buf.
		// The current position of the reader is one byte past
		// the data read into buf.
		pos, err := reader.Seek(0, io.SeekCurrent)
		if err != nil {
			return false, nil, err
		}
		offset := uint32(pos) - uint32(len(buf)-4)
		if mpfData.Index, err = jseg.MPFIndexFromTIFF(mpfData.Tree, offset); err != nil {
			return false, nil, err
		}
		buf, err = jseg.MakeMPFSegment(mpfData.Tree)
		if err != nil {
			return false, nil, err
		}
		pos, err = writer.Seek(0, io.SeekCurrent)
		if err != nil {
			return false, nil, err
		}
		mpfData.APP2WritePos = uint32(pos)
		done = true
	}
	return done, buf, nil
}

// MPF processor that reads and repacks the attribute data.
type MPFAttributeData struct {
}

func (mpfData *MPFAttributeData) ProcessAPP2(writer io.Seeker, reader io.Seeker, buf []byte) (bool, []byte, error) {
	done := false
	isMPF, next := jseg.GetMPFHeader(buf)
	if isMPF {
		savebuf := make([]byte, len(buf)-jseg.MPFHeaderSize)
		copy(savebuf, buf[next:])
		tree, err := jseg.GetMPFTree(savebuf, tiff.MPFAttributeSpace)
		if err != nil {
			return false, nil, err
		}
		tree.Fix()
		buf, err = jseg.MakeMPFSegment(tree)
		if err != nil {
			return false, nil, err
		}
		done = true
	}
	return done, buf, nil
}

// MPF processor that does nothing.
type MPFDummyData struct {
}

func (mpfData *MPFDummyData) ProcessAPP2(writer io.Seeker, reader io.Seeker, buf []byte) (bool, []byte, error) {
	return false, buf, nil
}

type MPFProcessor interface {
	ProcessAPP2(writer io.Seeker, reader io.Seeker, buf []byte) (bool, []byte, error)
}

// Copy a single image, processing any MPF segment found.
func copyImage(writer io.WriteSeeker, reader io.ReadSeeker, mpfProcessor MPFProcessor) error {
	scanner, err := jseg.NewScanner(reader)
	if err != nil {
		return err
	}
	dumper, err := jseg.NewDumper(writer)
	if err != nil {
		return err
	}
	for {
		marker, buf, err := scanner.Scan()
		if err != nil {
			return err
		}
		if marker == jseg.APP0+2 {
			_, buf, err = mpfProcessor.ProcessAPP2(writer, reader, buf)
			if err != nil {
				return err
			}
		}
		if err := dumper.Dump(marker, buf); err != nil {
			return err
		}
		if marker == jseg.EOI {
			break
		}
	}
	return nil
}

// State for MPF image iterator.
type copyData struct {
	writer     io.WriteSeeker
	newOffsets []uint32
}

// Function to be applied to each MPF image: copies the image to the
// output stream.
func (copy *copyData) MPFApply(reader io.ReadSeeker, index uint32, length uint32) error {
	if index > 0 {
		pos, err := copy.writer.Seek(0, io.SeekCurrent)
		if err != nil {
			return err
		}
		copy.newOffsets[index] = uint32(pos)
		// Processing the MPF attribute data could be omitted,
		// by passing a MPFDummyData object.
		var mpfAttribute MPFAttributeData
		return copyImage(copy.writer, reader, &mpfAttribute)
	}
	return nil
}

// Copy additional images specified with MPF.
func copyMPFImages(writer io.WriteSeeker, reader io.ReadSeeker, index *jseg.MPFIndex) ([]uint32, error) {
	var copy copyData
	copy.writer = writer
	copy.newOffsets = make([]uint32, len(index.ImageOffsets))
	index.ImageIterate(reader, &copy)
	return copy.newOffsets, nil
}

// Modify a MPF Tiff tree with new image offsets and sizes, given the
// offsets and the end of file position.
func setMPFImagePositions(mpfTree *tiff.IFDNode, mpfOffset uint32, offsets []uint32, end uint32) {
	count := len(offsets)
	lengths := make([]uint32, count)
	for i := 0; i < count-1; i++ {
		lengths[i] = offsets[i+1] - offsets[i]
	}
	lengths[count-1] = end - offsets[count-1]
	indexWrite := jseg.MPFIndex{mpfOffset, offsets, lengths}
	indexWrite.PutToTiff(mpfTree)
}

// Modify a MPF TIFF tree with new image offsets and sizes, then overwrite the
// MPF data in the output stream.
func rewriteMPF(writer io.WriteSeeker, mpfTree *tiff.IFDNode, mpfWritePos uint32, offsets []uint32) error {
	end, err := writer.Seek(0, io.SeekCurrent)
	if err != nil {
		log.Fatal(err)
	}
	setMPFImagePositions(mpfTree, mpfWritePos+8, offsets, uint32(end))
	newbuf, err := jseg.MakeMPFSegment(mpfTree)
	if err != nil {
		return err
	}
	if _, err := writer.Seek(int64(mpfWritePos), io.SeekStart); err != nil {
		return err
	}
	if err := jseg.WriteMarker(writer, jseg.APP0+2); err != nil {
		return err
	}
	if err := jseg.WriteData(writer, newbuf); err != nil {
		return err
	}
	return nil
}

func main() {
	if len(os.Args) != 3 {
		fmt.Printf("Usage: %s infile outfile\n", os.Args[0])
		return
	}
	reader, err := os.Open(os.Args[1])
	if err != nil {
		log.Fatal(err)
	}
	defer reader.Close()
	writer, err := os.Create(os.Args[2])
	if err != nil {
		log.Fatal(err)
	}
	defer writer.Close()
	var mpfIndex MPFIndexData
	if err = copyImage(writer, reader, &mpfIndex); err != nil {
		log.Fatal(err)
	}
	if mpfIndex.Tree != nil {
		newOffsets, err := copyMPFImages(writer, reader, mpfIndex.Index)
		if err != nil {
			log.Fatal(err)
		}
		if err = rewriteMPF(writer, mpfIndex.Tree, mpfIndex.APP2WritePos, newOffsets); err != nil {
			log.Fatal(err)
		}
	}
}
<commit_msg>Don't need to copy buffer since it's doesn't escape the loop<commit_after>package main

// Unpack a JPEG file one segment at a time and repackage into a new
// JPEG file.  It can process files which use the Multi-Picture Format
// extension to contain multiple images.

import (
	"fmt"
	jseg "github.com/garyhouston/jpegsegs"
	tiff "github.com/garyhouston/tiff66"
	"io"
	"log"
	"os"
)

// MPF processor that reads and repacks the index data.
type MPFIndexData struct {
	Tree         *tiff.IFDNode  // Unpacked MPF index TIFF tree.
	Index        *jseg.MPFIndex // MPF Index info.
	APP2WritePos uint32         // Position of the MPF APP2 marker in the output stream.
}

func (mpfData *MPFIndexData) ProcessAPP2(writer io.Seeker, reader io.Seeker, buf []byte) (bool, []byte, error) {
	done := false
	isMPF, next := jseg.GetMPFHeader(buf)
	if isMPF {
		savebuf := make([]byte, len(buf)-jseg.MPFHeaderSize)
		copy(savebuf, buf[next:])
		var err error
		mpfData.Tree, err = jseg.GetMPFTree(savebuf, tiff.MPFIndexSpace)
		if err != nil {
			return false, nil, err
		}
		mpfData.Tree.Fix()
		// MPF offsets are relative to the byte following the
		// MPF header, which is 4 bytes past the start of buf.
		// The current position of the reader is one byte past
		// the data read into buf.
		pos, err := reader.Seek(0, io.SeekCurrent)
		if err != nil {
			return false, nil, err
		}
		offset := uint32(pos) - uint32(len(buf)-4)
		if mpfData.Index, err = jseg.MPFIndexFromTIFF(mpfData.Tree, offset); err != nil {
			return false, nil, err
		}
		buf, err = jseg.MakeMPFSegment(mpfData.Tree)
		if err != nil {
			return false, nil, err
		}
		pos, err = writer.Seek(0, io.SeekCurrent)
		if err != nil {
			return false, nil, err
		}
		mpfData.APP2WritePos = uint32(pos)
		done = true
	}
	return done, buf, nil
}

// MPF processor that reads and repacks the attribute data.
type MPFAttributeData struct {
}

func (mpfData *MPFAttributeData) ProcessAPP2(writer io.Seeker, reader io.Seeker, buf []byte) (bool, []byte, error) {
	done := false
	isMPF, next := jseg.GetMPFHeader(buf)
	if isMPF {
		tree, err := jseg.GetMPFTree(buf[next:], tiff.MPFAttributeSpace)
		if err != nil {
			return false, nil, err
		}
		tree.Fix()
		buf, err = jseg.MakeMPFSegment(tree)
		if err != nil {
			return false, nil, err
		}
		done = true
	}
	return done, buf, nil
}

// MPF processor that does nothing.
type MPFDummyData struct {
}

func (mpfData *MPFDummyData) ProcessAPP2(writer io.Seeker, reader io.Seeker, buf []byte) (bool, []byte, error) {
	return false, buf, nil
}

type MPFProcessor interface {
	ProcessAPP2(writer io.Seeker, reader io.Seeker, buf []byte) (bool, []byte, error)
}

// Copy a single image, processing any MPF segment found.
func copyImage(writer io.WriteSeeker, reader io.ReadSeeker, mpfProcessor MPFProcessor) error {
	scanner, err := jseg.NewScanner(reader)
	if err != nil {
		return err
	}
	dumper, err := jseg.NewDumper(writer)
	if err != nil {
		return err
	}
	for {
		marker, buf, err := scanner.Scan()
		if err != nil {
			return err
		}
		if marker == jseg.APP0+2 {
			_, buf, err = mpfProcessor.ProcessAPP2(writer, reader, buf)
			if err != nil {
				return err
			}
		}
		if err := dumper.Dump(marker, buf); err != nil {
			return err
		}
		if marker == jseg.EOI {
			break
		}
	}
	return nil
}

// State for MPF image iterator.
type copyData struct {
	writer     io.WriteSeeker
	newOffsets []uint32
}

// Function to be applied to each MPF image: copies the image to the
// output stream.
func (copy *copyData) MPFApply(reader io.ReadSeeker, index uint32, length uint32) error {
	if index > 0 {
		pos, err := copy.writer.Seek(0, io.SeekCurrent)
		if err != nil {
			return err
		}
		copy.newOffsets[index] = uint32(pos)
		// Processing the MPF attribute data could be omitted,
		// by passing a MPFDummyData object.
		var mpfAttribute MPFAttributeData
		return copyImage(copy.writer, reader, &mpfAttribute)
	}
	return nil
}

// Copy additional images specified with MPF.
func copyMPFImages(writer io.WriteSeeker, reader io.ReadSeeker, index *jseg.MPFIndex) ([]uint32, error) {
	var copy copyData
	copy.writer = writer
	copy.newOffsets = make([]uint32, len(index.ImageOffsets))
	index.ImageIterate(reader, &copy)
	return copy.newOffsets, nil
}

// Modify a MPF Tiff tree with new image offsets and sizes, given the
// offsets and the end of file position.
func setMPFImagePositions(mpfTree *tiff.IFDNode, mpfOffset uint32, offsets []uint32, end uint32) {
	count := len(offsets)
	lengths := make([]uint32, count)
	for i := 0; i < count-1; i++ {
		lengths[i] = offsets[i+1] - offsets[i]
	}
	lengths[count-1] = end - offsets[count-1]
	indexWrite := jseg.MPFIndex{mpfOffset, offsets, lengths}
	indexWrite.PutToTiff(mpfTree)
}

// Modify a MPF TIFF tree with new image offsets and sizes, then overwrite the
// MPF data in the output stream.
func rewriteMPF(writer io.WriteSeeker, mpfTree *tiff.IFDNode, mpfWritePos uint32, offsets []uint32) error {
	end, err := writer.Seek(0, io.SeekCurrent)
	if err != nil {
		log.Fatal(err)
	}
	setMPFImagePositions(mpfTree, mpfWritePos+8, offsets, uint32(end))
	newbuf, err := jseg.MakeMPFSegment(mpfTree)
	if err != nil {
		return err
	}
	if _, err := writer.Seek(int64(mpfWritePos), io.SeekStart); err != nil {
		return err
	}
	if err := jseg.WriteMarker(writer, jseg.APP0+2); err != nil {
		return err
	}
	if err := jseg.WriteData(writer, newbuf); err != nil {
		return err
	}
	return nil
}

func main() {
	if len(os.Args) != 3 {
		fmt.Printf("Usage: %s infile outfile\n", os.Args[0])
		return
	}
	reader, err := os.Open(os.Args[1])
	if err != nil {
		log.Fatal(err)
	}
	defer reader.Close()
	writer, err := os.Create(os.Args[2])
	if err != nil {
		log.Fatal(err)
	}
	defer writer.Close()
	var mpfIndex MPFIndexData
	if err = copyImage(writer, reader, &mpfIndex); err != nil {
		log.Fatal(err)
	}
	if mpfIndex.Tree != nil {
		newOffsets, err := copyMPFImages(writer, reader, mpfIndex.Index)
		if err != nil {
			log.Fatal(err)
		}
		if err = rewriteMPF(writer, mpfIndex.Tree, mpfIndex.APP2WritePos, newOffsets); err != nil {
			log.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net"
	"os"

	"github.com/lumanetworks/go-tcp-proxy"
)

// Configuration 配置类
type Configuration struct {
	// IsLoad 加载标记
	IsLoad bool
	// ListenAddress 本地监听地址
	ListenAddress string `json:"listen_address"`
	// Verbose 日志是否显示详情
	Verbose bool `json:"verbose"`
	// Verbose 日志是否显示更多详情
	VeryVerbose bool `json:"very_verbose"`
	// Nagles 关闭Nagles算法
	Nagles bool `json:"nagles"`
	// Hex 是否以Hex形式显示数据
	Hex bool `json:"hex"`
}

var (
	config Configuration
	connid = uint64(0)
)

func main() {
	config.IsLoad = false

	configFile, err := os.Open("config.json")
	if err != nil {
		log.Fatal("error:", err)
	}
	defer configFile.Close()

	decoder := json.NewDecoder(configFile)

	err = decoder.Decode(&config)

	if err != nil {
		log.Println("error:", err)
	}

	config.IsLoad = true

	logger := proxy.ColorLogger{
		Verbose: config.Verbose,
		Color:   true,
	}

	logger.Info("Proxying to api.mch.weixin.qq.com.")
	laddr, err := net.ResolveTCPAddr("tcp", config.ListenAddress)
	if err != nil {
		logger.Warn("Failed to resolve local address: %s", err)
		os.Exit(1)
	}
	raddr, err := net.ResolveTCPAddr("tcp", "api.mch.weixin.qq.com")
	if err != nil {
		logger.Warn("Failed to resolve remote address: %s", err)
		os.Exit(1)
	}
	listener, err := net.ListenTCP("tcp", laddr)
	if err != nil {
		logger.Warn("Failed to open local port to listen: %s", err)
		os.Exit(1)
	}

	for {
		conn, err := listener.AcceptTCP()
		if err != nil {
			logger.Warn("Failed to accept connection '%s'", err)
			continue
		}
		connid++

		var p *proxy.Proxy

		p = proxy.New(conn, laddr, raddr)

		p.Nagles = config.Nagles
		p.OutputHex = config.Hex
		p.Log = proxy.ColorLogger{
			Verbose:     config.Verbose,
			VeryVerbose: config.Verbose,
			Prefix:      fmt.Sprintf("Connection #%03d ", connid),
			Color:       true,
		}

		go p.Start()
	}
}

func init() {
}
<commit_msg>remove empty function<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net"
	"os"

	"github.com/lumanetworks/go-tcp-proxy"
)

// Configuration 配置类
type Configuration struct {
	// IsLoad 加载标记
	IsLoad bool
	// ListenAddress 本地监听地址
	ListenAddress string `json:"listen_address"`
	// Verbose 日志是否显示详情
	Verbose bool `json:"verbose"`
	// Verbose 日志是否显示更多详情
	VeryVerbose bool `json:"very_verbose"`
	// Nagles 关闭Nagles算法
	Nagles bool `json:"nagles"`
	// Hex 是否以Hex形式显示数据
	Hex bool `json:"hex"`
}

var (
	config Configuration
	connid = uint64(0)
)

func main() {
	config.IsLoad = false

	configFile, err := os.Open("config.json")
	if err != nil {
		log.Fatal("error:", err)
	}
	defer configFile.Close()

	decoder := json.NewDecoder(configFile)

	err = decoder.Decode(&config)

	if err != nil {
		log.Println("error:", err)
	}

	config.IsLoad = true

	logger := proxy.ColorLogger{
		Verbose: config.Verbose,
		Color:   true,
	}

	logger.Info("Proxying to api.mch.weixin.qq.com.")
	laddr, err := net.ResolveTCPAddr("tcp", config.ListenAddress)
	if err != nil {
		logger.Warn("Failed to resolve local address: %s", err)
		os.Exit(1)
	}
	raddr, err := net.ResolveTCPAddr("tcp", "api.mch.weixin.qq.com")
	if err != nil {
		logger.Warn("Failed to resolve remote address: %s", err)
		os.Exit(1)
	}
	listener, err := net.ListenTCP("tcp", laddr)
	if err != nil {
		logger.Warn("Failed to open local port to listen: %s", err)
		os.Exit(1)
	}

	for {
		conn, err := listener.AcceptTCP()
		if err != nil {
			logger.Warn("Failed to accept connection '%s'", err)
			continue
		}
		connid++

		var p *proxy.Proxy

		p = proxy.New(conn, laddr, raddr)

		p.Nagles = config.Nagles
		p.OutputHex = config.Hex
		p.Log = proxy.ColorLogger{
			Verbose:     config.Verbose,
			VeryVerbose: config.Verbose,
			Prefix:      fmt.Sprintf("Connection #%03d ", connid),
			Color:       true,
		}

		go p.Start()
	}
}
<|endoftext|>


<commit_before>package xmmsclient

import (
	"errors"
	"math"
	"strings"
)

var defaultSourcePrefs = []string{
	"server",
	"client/*",
	"plugin/playlist",
	"plugin/segment",
	"plugin/nibbler",
	"plugin/id3v2",
	"plugin/*",
	"*",
}

const (
	NoMatch int = math.MaxInt32
)

func match(sourcePrefs []string, source string) int {
	for index, pattern := range sourcePrefs {
		if strings.HasSuffix(pattern, "*") {
			if strings.HasPrefix(source, pattern[:len(pattern)-1]) {
				return index
			}
		} else if source == pattern {
			return index
		}
	}
	return NoMatch
}

func PropDictToDict(sourcePrefs []string, inputValue XmmsValue) (XmmsDict, error) {
	inputDict, ok := inputValue.(XmmsDict)
	if !ok {
		return nil, errors.New("Input not a XmmsDict->XmmsDict->XmmsValue")
	}

	result := XmmsDict{}
	for key, innerValue := range inputDict {
		innerDict, ok := innerValue.(XmmsDict)
		if !ok {
			return nil, errors.New("Input not a XmmsDict->XmmsDict->XmmsValue")
		}

		bestScore := NoMatch
		for source, value := range innerDict {
			score := match(sourcePrefs, source)
			if score < bestScore {
				result[key] = value
				bestScore = score
			}
		}
	}

	return result, nil
}

func PropDictToDictDefault(input XmmsValue) (XmmsDict, error) {
	return PropDictToDict(defaultSourcePrefs, input)
}
<commit_msg>Add documentation to PropDict functions.<commit_after>package xmmsclient

import (
	"errors"
	"math"
	"strings"
)

var defaultSourcePrefs = []string{
	"server",
	"client/*",
	"plugin/playlist",
	"plugin/segment",
	"plugin/nibbler",
	"plugin/id3v2",
	"plugin/*",
	"*",
}

const (
	NoMatch int = math.MaxInt32
)

func match(sourcePrefs []string, source string) int {
	for index, pattern := range sourcePrefs {
		if strings.HasSuffix(pattern, "*") {
			if strings.HasPrefix(source, pattern[:len(pattern)-1]) {
				return index
			}
		} else if source == pattern {
			return index
		}
	}
	return NoMatch
}

// Flatten a {key: {source: value}} to {key: value} based on source preferences.
// Source preferences are defined as a list of strings that may end with '*' to
// match any suffix.
func PropDictToDict(sourcePrefs []string, inputValue XmmsValue) (XmmsDict, error) {
	inputDict, ok := inputValue.(XmmsDict)
	if !ok {
		return nil, errors.New("Input not a XmmsDict->XmmsDict->XmmsValue")
	}

	result := XmmsDict{}
	for key, innerValue := range inputDict {
		innerDict, ok := innerValue.(XmmsDict)
		if !ok {
			return nil, errors.New("Input not a XmmsDict->XmmsDict->XmmsValue")
		}

		bestScore := NoMatch
		for source, value := range innerDict {
			score := match(sourcePrefs, source)
			if score < bestScore {
				result[key] = value
				bestScore = score
			}
		}
	}

	return result, nil
}

// Flatten a PropDict using default source preferences:
//  ["server", "client/*", "plugin/playlist", "plugin/segment",
//   "plugin/nibbler", "plugin/id3v2", "plugin/*", "*"]
func PropDictToDictDefault(input XmmsValue) (XmmsDict, error) {
	return PropDictToDict(defaultSourcePrefs, input)
}
<|endoftext|>