<commit_before>package directEmail

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"mime/quotedprintable"
	"net/http"
	"path/filepath"
	"strings"
	"time"
)

// SetRawMessageBytes
func (self *Email) SetRawMessageBytes(data []byte) error {
	self.raw.Reset()
	_, err := self.raw.Write(data)
	return err
}

// SetRawMessageString
func (self *Email) SetRawMessageString(data string) error {
	self.raw.Reset()
	_, err := self.raw.WriteString(data)
	return err
}

// GetRawMessageBytes
func (self *Email) GetRawMessageBytes() []byte {
	return self.raw.Bytes()
}

// GetRawMessageString
func (self *Email) GetRawMessageString() string {
	return self.raw.String()
}

// Header add extra headers to email
func (self *Email) Header(headers ...string) {
	for i := range headers {
		self.headers = append(self.headers, headers[i])
	}
}

// TextPlain add text/plain content to email
func (self *Email) TextPlain(content string) (err error) {
	var part bytes.Buffer
	defer part.Reset()
	_, err = part.WriteString("Content-Type: text/plain;\r\n\t charset=\"utf-8\"\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n")
	if err != nil {
		return err
	}
	w := quotedprintable.NewWriter(&part)
	w.Write([]byte(strings.TrimLeft(content, "\r\n")))
	w.Close()
	self.textPlain = part.Bytes()
	return nil
}

// TextHtml add text/html content to email
func (self *Email) TextHtml(content string) (err error) {
	var part bytes.Buffer
	defer part.Reset()
	_, err = part.WriteString("Content-Type: text/html;\r\n\t charset=\"utf-8\"\r\nContent-Transfer-Encoding: base64\r\n\r\n")
	if err != nil {
		return err
	}
	err = self.line76(&part, base64.StdEncoding.EncodeToString([]byte(content)))
	if err != nil {
		return err
	}
	self.textHtml = part.Bytes()
	return nil
}

// TextHtmlWithRelated add text/html content with related file.
//
// Example use file in html
//  email.TextHtmlWithRelated(
//  	`... <img src="cid:myImage.jpg" width="500px" height="250px" border="1px" alt="My image"/> ...`,
//  	"/path/to/attach/myImage.jpg",
//  )
func (self *Email) TextHtmlWithRelated(content string, files ...string) (err error) {
	var (
		part bytes.Buffer
		data []byte
	)
	defer part.Reset()

	marker := self.makeMarker()
	_, err = part.WriteString("Content-Type: multipart/related;\r\n\tboundary=\"" + marker + "\"\r\n")
	if err != nil {
		return err
	}

	_, err = part.WriteString("\r\n--" + marker + "\r\n")
	if err != nil {
		return err
	}
	_, err = part.WriteString("Content-Type: text/html;\r\n\t charset=\"utf-8\"\r\nContent-Transfer-Encoding: base64\r\n\r\n")
	if err != nil {
		return err
	}
	err = self.line76(&part, base64.StdEncoding.EncodeToString([]byte(content)))
	if err != nil {
		return err
	}

	for i := range files {
		_, err = part.WriteString("\r\n--" + marker + "\r\n")
		if err != nil {
			return err
		}
		data, err = ioutil.ReadFile(files[i])
		if err != nil {
			return err
		}
		_, err = part.WriteString(fmt.Sprintf("Content-Type: %s;\r\n\tname=\"%s\"\r\nContent-Transfer-Encoding: base64\r\nContent-ID: <%s>\r\nContent-Disposition: inline;\r\n\tfilename=\"%s\"; size=%d;\r\n\r\n", http.DetectContentType(data), filepath.Base(files[i]), filepath.Base(files[i]), filepath.Base(files[i]), len(data)))
		if err != nil {
			return err
		}
		err = self.line76(&part, base64.StdEncoding.EncodeToString(data))
		if err != nil {
			return err
		}
	}
	_, err = part.WriteString("\r\n--" + marker + "--\r\n")

	self.textHtml = part.Bytes()
	return nil
}

// Attachment attach files to email message
func (self *Email) Attachment(files ...string) (err error) {
	var (
		part bytes.Buffer
		data []byte
	)

	for i := range files {
		data, err = ioutil.ReadFile(files[i])
		if err != nil {
			return err
		}
		_, err = part.WriteString(fmt.Sprintf("Content-Type: %s;\r\n\tname=\"%s\"\r\nContent-Transfer-Encoding: base64\r\nContent-Disposition: attachment;\r\n\tfilename=\"%s\"; size=%d;\r\n\r\n", http.DetectContentType(data), filepath.Base(files[i]), filepath.Base(files[i]), len(data)))
		if err != nil {
			return err
		}
		err = self.line76(&part, base64.StdEncoding.EncodeToString(data))
		if err != nil {
			return err
		}
		self.attachments = append(self.attachments, part.Bytes())
		part.Reset()
	}

	return nil
}

// Render added text/html, text/plain, attachments part to raw view
func (self *Email) Render() (err error) {
	return self.RenderWithDkim("", []byte{})
}

// Render added text/html, text/plain, attachments part to raw view
// If dkim selector not blank add DKIM signature email
// Generate private key:
//  openssl genrsa -out /path/to/key/example.com.key 2048
// Generate public key:
//  openssl rsa -in /path/to/key/example.com.key -pubout
// Add public key to DNS myselector._domainkey.example.com TXT record
//  k=rsa; p=MIGfMA0GC...
func (self *Email) RenderWithDkim(dkimSelector string, dkimPrivateKey []byte) (err error) {
	var (
		marker string
	)

	// -------------- head ----------------------------------------------------------
	_, err = self.raw.WriteString("Return-path: <" + self.FromEmail + ">\r\n")
	if err != nil {
		return err
	}

	_, err = self.raw.WriteString("From: ")
	if err != nil {
		return err
	}
	if self.FromName != "" {
		_, err = self.raw.WriteString(self.encodeRFC2045(self.FromName) + " ")
		if err != nil {
			return err
		}
	}
	_, err = self.raw.WriteString("<" + self.FromEmail + ">\r\n")
	if err != nil {
		return err
	}
	_, err = self.raw.WriteString("To: ")
	if err != nil {
		return err
	}
	if self.ToName != "" {
		_, err = self.raw.WriteString(self.encodeRFC2045(self.ToName) + " ")
		if err != nil {
			return err
		}
	}
	_, err = self.raw.WriteString("<" + self.ToEmail + ">\r\n")
	if err != nil {
		return err
	}

	_, err = self.raw.WriteString("Subject: " + self.encodeRFC2045(self.Subject) + "\r\n")
	if err != nil {
		return err
	}
	_, err = self.raw.WriteString("MIME-Version: 1.0\r\n")
	if err != nil {
		return err
	}
	_, err = self.raw.WriteString("Date: " + time.Now().Format(time.RFC1123Z) + "\r\n")
	if err != nil {
		return err
	}

	// Email has attachment?
	if len(self.attachments) > 0 {
		marker = self.makeMarker()
		_, err = self.raw.WriteString("Content-Type: multipart/mixed;\r\n\tboundary=\"" + marker + "\"\r\n")
		if err != nil {
			return err
		}
	}

	// add extra headers
	_, err = self.raw.WriteString(strings.Join(self.headers, "\r\n"))
	if err != nil {
		return err
	}
	if len(self.headers) > 0 {
		_, err = self.raw.WriteString("\r\n")
	}

	startBody := self.raw.Len()
	// ------------- /head ---------------------------------------------------------

	if len(self.textPlain) > 0 || len(self.textHtml) > 0 {
		if marker != "" {
			_, err = self.raw.WriteString("\r\n--" + marker + "\r\n")
		}
		err = self.renderText()
		if err != nil {
			return err
		}
	}

	// ------------- attachments ----------------------------------------------------------
	for i := range self.attachments {
		_, err = self.raw.WriteString("\r\n--" + marker + "\r\n")
		if err != nil {
			return err
		}
		_, err = self.raw.Write(self.attachments[i])
		if err != nil {
			return err
		}
		if err != nil {
			return err
		}
	}
	// ------------- /attachments ----------------------------------------------------------

	if marker != "" {
		_, err = self.raw.WriteString("\r\n--" + marker + "--\r\n")
		if err != nil {
			return err
		}
	}

	// ------------ blank email ------------------------------------------------------------
	if len(self.textPlain) == 0 && len(self.textHtml) == 0 && len(self.attachments) == 0 {
		_, err = self.raw.WriteString("Content-Type: text/plain;\r\n\t charset=\"utf-8\"\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nBlank email")
		if err != nil {
			return err
		}
	}
	// ------------ /blank email -----------------------------------------------------------

	// ------------ DKIM -------------------------------------------------------------------
	self.bodyLenght = self.raw.Len() - startBody

	if dkimSelector != "" {
		err = self.dkimSign(dkimSelector, dkimPrivateKey)
		if err != nil {
			return err
		}
	}
	// ------------ /DKIM ------------------------------------------------------------------

	return nil
}

func (self *Email) renderText() error {
	var (
		marker string
		err    error
	)
	if len(self.textPlain) > 0 && len(self.textHtml) > 0 {
		marker = self.makeMarker()
		_, err = self.raw.WriteString("Content-Type: multipart/alternative;\r\n\tboundary=\"" + marker + "\"\r\n")
		if err != nil {
			return err
		}
	}

	if marker != "" {
		_, err = self.raw.WriteString("\r\n--" + marker + "\r\n")
	}

	if len(self.textPlain) > 0 {
		_, err = self.raw.Write(self.textPlain)
		if err != nil {
			return err
		}
	}

	if marker != "" {
		_, err = self.raw.WriteString("\r\n--" + marker + "\r\n")
	}

	if len(self.textHtml) > 0 {
		_, err = self.raw.Write(self.textHtml)
		if err != nil {
			return err
		}
	}

	if marker != "" {
		_, err = self.raw.WriteString("\r\n--" + marker + "--\r\n")
	}

	return nil
}
<commit_msg>clean unused code<commit_after>package directEmail

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"mime/quotedprintable"
	"net/http"
	"path/filepath"
	"strings"
	"time"
)

// SetRawMessageBytes
func (self *Email) SetRawMessageBytes(data []byte) error {
	self.raw.Reset()
	_, err := self.raw.Write(data)
	return err
}

// SetRawMessageString
func (self *Email) SetRawMessageString(data string) error {
	self.raw.Reset()
	_, err := self.raw.WriteString(data)
	return err
}

// GetRawMessageBytes
func (self *Email) GetRawMessageBytes() []byte {
	return self.raw.Bytes()
}

// GetRawMessageString
func (self *Email) GetRawMessageString() string {
	return self.raw.String()
}

// Header add extra headers to email
func (self *Email) Header(headers ...string) {
	for i := range headers {
		self.headers = append(self.headers, headers[i])
	}
}

// TextPlain add text/plain content to email
func (self *Email) TextPlain(content string) (err error) {
	var part bytes.Buffer
	defer part.Reset()
	_, err = part.WriteString("Content-Type: text/plain;\r\n\t charset=\"utf-8\"\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n")
	if err != nil {
		return err
	}
	w := quotedprintable.NewWriter(&part)
	w.Write([]byte(strings.TrimLeft(content, "\r\n")))
	w.Close()
	self.textPlain = part.Bytes()
	return nil
}

// TextHtml add text/html content to email
func (self *Email) TextHtml(content string) (err error) {
	var part bytes.Buffer
	defer part.Reset()
	_, err = part.WriteString("Content-Type: text/html;\r\n\t charset=\"utf-8\"\r\nContent-Transfer-Encoding: base64\r\n\r\n")
	if err != nil {
		return err
	}
	err = self.line76(&part, base64.StdEncoding.EncodeToString([]byte(content)))
	if err != nil {
		return err
	}
	self.textHtml = part.Bytes()
	return nil
}

// TextHtmlWithRelated add text/html content with related file.
//
// Example use file in html
//  email.TextHtmlWithRelated(
//  	`... <img src="cid:myImage.jpg" width="500px" height="250px" border="1px" alt="My image"/> ...`,
//  	"/path/to/attach/myImage.jpg",
//  )
func (self *Email) TextHtmlWithRelated(content string, files ...string) (err error) {
	var (
		part bytes.Buffer
		data []byte
	)
	defer part.Reset()

	marker := self.makeMarker()
	_, err = part.WriteString("Content-Type: multipart/related;\r\n\tboundary=\"" + marker + "\"\r\n")
	if err != nil {
		return err
	}

	_, err = part.WriteString("\r\n--" + marker + "\r\n")
	if err != nil {
		return err
	}
	_, err = part.WriteString("Content-Type: text/html;\r\n\t charset=\"utf-8\"\r\nContent-Transfer-Encoding: base64\r\n\r\n")
	if err != nil {
		return err
	}
	err = self.line76(&part, base64.StdEncoding.EncodeToString([]byte(content)))
	if err != nil {
		return err
	}

	for i := range files {
		_, err = part.WriteString("\r\n--" + marker + "\r\n")
		if err != nil {
			return err
		}
		data, err = ioutil.ReadFile(files[i])
		if err != nil {
			return err
		}
		_, err = part.WriteString(fmt.Sprintf("Content-Type: %s;\r\n\tname=\"%s\"\r\nContent-Transfer-Encoding: base64\r\nContent-ID: <%s>\r\nContent-Disposition: inline;\r\n\tfilename=\"%s\"; size=%d;\r\n\r\n", http.DetectContentType(data), filepath.Base(files[i]), filepath.Base(files[i]), filepath.Base(files[i]), len(data)))
		if err != nil {
			return err
		}
		err = self.line76(&part, base64.StdEncoding.EncodeToString(data))
		if err != nil {
			return err
		}
	}
	_, err = part.WriteString("\r\n--" + marker + "--\r\n")

	self.textHtml = part.Bytes()
	return nil
}

// Attachment attach files to email message
func (self *Email) Attachment(files ...string) (err error) {
	var (
		part bytes.Buffer
		data []byte
	)

	for i := range files {
		data, err = ioutil.ReadFile(files[i])
		if err != nil {
			return err
		}
		_, err = part.WriteString(fmt.Sprintf("Content-Type: %s;\r\n\tname=\"%s\"\r\nContent-Transfer-Encoding: base64\r\nContent-Disposition: attachment;\r\n\tfilename=\"%s\"; size=%d;\r\n\r\n", http.DetectContentType(data), filepath.Base(files[i]), filepath.Base(files[i]), len(data)))
		if err != nil {
			return err
		}
		err = self.line76(&part, base64.StdEncoding.EncodeToString(data))
		if err != nil {
			return err
		}
		self.attachments = append(self.attachments, part.Bytes())
		part.Reset()
	}

	return nil
}

// Render added text/html, text/plain, attachments part to raw view
func (self *Email) Render() (err error) {
	return self.RenderWithDkim("", []byte{})
}

// Render added text/html, text/plain, attachments part to raw view
// If dkim selector not blank add DKIM signature email
// Generate private key:
//  openssl genrsa -out /path/to/key/example.com.key 2048
// Generate public key:
//  openssl rsa -in /path/to/key/example.com.key -pubout
// Add public key to DNS myselector._domainkey.example.com TXT record
//  k=rsa; p=MIGfMA0GC...
func (self *Email) RenderWithDkim(dkimSelector string, dkimPrivateKey []byte) (err error) {
	var (
		marker string
	)

	// -------------- head ----------------------------------------------------------
	_, err = self.raw.WriteString("Return-path: <" + self.FromEmail + ">\r\n")
	if err != nil {
		return err
	}

	_, err = self.raw.WriteString("From: ")
	if err != nil {
		return err
	}
	if self.FromName != "" {
		_, err = self.raw.WriteString(self.encodeRFC2045(self.FromName) + " ")
		if err != nil {
			return err
		}
	}
	_, err = self.raw.WriteString("<" + self.FromEmail + ">\r\n")
	if err != nil {
		return err
	}
	_, err = self.raw.WriteString("To: ")
	if err != nil {
		return err
	}
	if self.ToName != "" {
		_, err = self.raw.WriteString(self.encodeRFC2045(self.ToName) + " ")
		if err != nil {
			return err
		}
	}
	_, err = self.raw.WriteString("<" + self.ToEmail + ">\r\n")
	if err != nil {
		return err
	}

	_, err = self.raw.WriteString("Subject: " + self.encodeRFC2045(self.Subject) + "\r\n")
	if err != nil {
		return err
	}
	_, err = self.raw.WriteString("MIME-Version: 1.0\r\n")
	if err != nil {
		return err
	}
	_, err = self.raw.WriteString("Date: " + time.Now().Format(time.RFC1123Z) + "\r\n")
	if err != nil {
		return err
	}

	// Email has attachment?
	if len(self.attachments) > 0 {
		marker = self.makeMarker()
		_, err = self.raw.WriteString("Content-Type: multipart/mixed;\r\n\tboundary=\"" + marker + "\"\r\n")
		if err != nil {
			return err
		}
	}

	// add extra headers
	_, err = self.raw.WriteString(strings.Join(self.headers, "\r\n"))
	if err != nil {
		return err
	}
	if len(self.headers) > 0 {
		_, err = self.raw.WriteString("\r\n")
	}

	startBody := self.raw.Len()
	// ------------- /head ---------------------------------------------------------

	if len(self.textPlain) > 0 || len(self.textHtml) > 0 {
		if marker != "" {
			_, err = self.raw.WriteString("\r\n--" + marker + "\r\n")
		}
		err = self.renderText()
		if err != nil {
			return err
		}
	}

	// ------------- attachments ----------------------------------------------------------
	for i := range self.attachments {
		_, err = self.raw.WriteString("\r\n--" + marker + "\r\n")
		if err != nil {
			return err
		}
		_, err = self.raw.Write(self.attachments[i])
		if err != nil {
			return err
		}
		if err != nil {
			return err
		}
	}
	// ------------- /attachments ----------------------------------------------------------

	if marker != "" {
		_, err = self.raw.WriteString("\r\n--" + marker + "--\r\n")
		if err != nil {
			return err
		}
	}

	// ------------ blank email ------------------------------------------------------------
	if len(self.textPlain) == 0 && len(self.textHtml) == 0 && len(self.attachments) == 0 {
		_, err = self.raw.WriteString("Content-Type: text/plain;\r\n\t charset=\"utf-8\"\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nBlank email")
		if err != nil {
			return err
		}
	}
	// ------------ /blank email -----------------------------------------------------------

	// ------------ DKIM -------------------------------------------------------------------
	self.bodyLenght = self.raw.Len() - startBody

	if dkimSelector != "" {
		err = self.dkimSign(dkimSelector, dkimPrivateKey)
		if err != nil {
			return err
		}
	}
	// ------------ /DKIM ------------------------------------------------------------------

	return nil
}

func (self *Email) renderText() error {
	var (
		marker string
		err    error
	)
	if len(self.textPlain) > 0 && len(self.textHtml) > 0 {
		marker = self.makeMarker()
		_, err = self.raw.WriteString("Content-Type: multipart/alternative;\r\n\tboundary=\"" + marker + "\"\r\n")
		if err != nil {
			return err
		}
	}

	if marker != "" {
		_, err = self.raw.WriteString("\r\n--" + marker + "\r\n")
	}

	if len(self.textPlain) > 0 {
		_, err = self.raw.Write(self.textPlain)
		if err != nil {
			return err
		}
	}

	if marker != "" {
		_, err = self.raw.WriteString("\r\n--" + marker + "\r\n")
	}

	if len(self.textHtml) > 0 {
		_, err = self.raw.Write(self.textHtml)
		if err != nil {
			return err
		}
	}

	if marker != "" {
		_, err = self.raw.WriteString("\r\n--" + marker + "--\r\n")
	}

	return nil
}
<|endoftext|>


<commit_before>// Package metrics provides minimalist instrumentation for your applications in
// the form of counters and gauges.
//
// Counters
//
// A counter is a monotonically-increasing, unsigned, 64-bit integer used to
// represent the number of times an event has occurred. By tracking the deltas
// between measurements of a counter over intervals of time, an aggregation
// layer can derive rates, acceleration, etc.
//
// Gauges
//
// A gauge returns instantaneous measurements of something using signed, 64-bit
// integers. This value does not need to be monotonic.
//
// Histograms
//
// A histogram tracks the distribution of a stream of values (e.g. the number of
// milliseconds it takes to handle requests), adding gauges for the values at
// meaningful quantiles: 50th, 75th, 90th, 95th, 99th, 99.9th.
//
// Reporting
//
// Measurements from counters and gauges are available as expvars. Your service
// should return its expvars from an HTTP endpoint (i.e., /debug/vars) as a JSON
// object.
package metrics

import (
	"expvar"
	"sync"
	"time"

	"github.com/codahale/hdrhistogram"
)

// A Counter is a monotonically increasing unsigned integer.
//
// Use a counter to derive rates (e.g., record total number of requests, derive
// requests per second).
type Counter string

// Add increments the counter by one.
func (c Counter) Add() {
	c.AddN(1)
}

// AddN increments the counter by N.
func (c Counter) AddN(delta uint64) {
	cm.Lock()
	counters[string(c)] += delta
	cm.Unlock()
}

// SetFunc sets the counter's value to the lazily-called return value of the
// given function.
func (c Counter) SetFunc(f func() uint64) {
	cm.Lock()
	defer cm.Unlock()

	counterFuncs[string(c)] = f
}

// SetBatchFunc sets the counter's value to the lazily-called return value of
// the given function, with an additional initializer function for a related
// batch of counters, all of which are keyed by an arbitrary value.
func (c Counter) SetBatchFunc(key interface{}, init func(), f func() uint64) {
	cm.Lock()
	defer cm.Unlock()

	gm.Lock()
	defer gm.Unlock()

	counterFuncs[string(c)] = f
	if _, ok := inits[key]; !ok {
		inits[key] = init
	}
}

// Remove removes the given counter.
func (c Counter) Remove() {
	cm.Lock()
	defer cm.Unlock()

	gm.Lock()
	defer gm.Unlock()

	delete(counters, string(c))
	delete(counterFuncs, string(c))
	delete(inits, string(c))
}

// A Gauge is an instantaneous measurement of a value.
//
// Use a gauge to track metrics which increase and decrease (e.g., amount of
// free memory).
type Gauge string

// Set the gauge's value to the given value.
func (g Gauge) Set(value int64) {
	gm.Lock()
	defer gm.Unlock()

	gauges[string(g)] = func() int64 {
		return value
	}
}

// SetFunc sets the gauge's value to the lazily-called return value of the given
// function.
func (g Gauge) SetFunc(f func() int64) {
	gm.Lock()
	defer gm.Unlock()

	gauges[string(g)] = f
}

// SetBatchFunc sets the gauge's value to the lazily-called return value of the
// given function, with an additional initializer function for a related batch
// of gauges, all of which are keyed by an arbitrary value.
func (g Gauge) SetBatchFunc(key interface{}, init func(), f func() int64) {
	gm.Lock()
	defer gm.Unlock()

	gauges[string(g)] = f
	if _, ok := inits[key]; !ok {
		inits[key] = init
	}
}

// Remove removes the given counter.
func (g Gauge) Remove() {
	gm.Lock()
	defer gm.Unlock()

	delete(gauges, string(g))
	delete(inits, string(g))
}

// Reset removes all existing counters and gauges.
func Reset() {
	cm.Lock()
	defer cm.Unlock()

	gm.Lock()
	defer gm.Unlock()

	hm.Lock()
	defer hm.Unlock()

	counters = make(map[string]uint64)
	counterFuncs = make(map[string]func() uint64)
	gauges = make(map[string]func() int64)
	histograms = make(map[string]*Histogram)
	inits = make(map[interface{}]func())
}

// Snapshot returns a copy of the values of all registered counters and gauges.
func Snapshot() (c map[string]uint64, g map[string]int64) {
	cm.Lock()
	defer cm.Unlock()

	gm.Lock()
	defer gm.Unlock()

	hm.Lock()
	defer hm.Unlock()

	for _, init := range inits {
		init()
	}

	c = make(map[string]uint64, len(counters)+len(counterFuncs))
	for n, v := range counters {
		c[n] = v
	}

	for n, f := range counterFuncs {
		c[n] = f()
	}

	g = make(map[string]int64, len(gauges))
	for n, f := range gauges {
		g[n] = f()
	}

	return
}

// NewHistogram returns a windowed HDR histogram which drops data older than
// five minutes. The returned histogram is safe to use from multiple goroutines.
//
// Use a histogram to track the distribution of a stream of values (e.g., the
// latency associated with HTTP requests).
func NewHistogram(name string, minValue, maxValue int64, sigfigs int) *Histogram {
	hm.Lock()
	defer hm.Unlock()

	if _, ok := histograms[name]; ok {
		panic(name + " already exists")
	}

	hist := &Histogram{
		name: name,
		hist: hdrhistogram.NewWindowed(5, minValue, maxValue, sigfigs),
	}
	histograms[name] = hist

	Gauge(name+".P50").SetBatchFunc(hname(name), hist.merge, hist.valueAt(50))
	Gauge(name+".P75").SetBatchFunc(hname(name), hist.merge, hist.valueAt(75))
	Gauge(name+".P90").SetBatchFunc(hname(name), hist.merge, hist.valueAt(90))
	Gauge(name+".P95").SetBatchFunc(hname(name), hist.merge, hist.valueAt(95))
	Gauge(name+".P99").SetBatchFunc(hname(name), hist.merge, hist.valueAt(99))
	Gauge(name+".P999").SetBatchFunc(hname(name), hist.merge, hist.valueAt(99.9))

	return hist
}

// Remove removes the given histogram.
func (h *Histogram) Remove() {

	hm.Lock()
	defer hm.Unlock()

	Gauge(h.name + ".P50").Remove()
	Gauge(h.name + ".P75").Remove()
	Gauge(h.name + ".P90").Remove()
	Gauge(h.name + ".P95").Remove()
	Gauge(h.name + ".P99").Remove()
	Gauge(h.name + ".P999").Remove()

	delete(histograms, h.name)
}

type hname string // unexported to prevent collisions

// A Histogram measures the distribution of a stream of values.
type Histogram struct {
	name string
	hist *hdrhistogram.WindowedHistogram
	m    *hdrhistogram.Histogram
	rw   sync.RWMutex
}

// RecordValue records the given value, or returns an error if the value is out
// of range.
// Returned error values are of type Error.
func (h *Histogram) RecordValue(v int64) error {
	h.rw.Lock()
	defer h.rw.Unlock()

	err := h.hist.Current.RecordValue(v)
	if err != nil {
		return Error{h.name, err}
	}
	return nil
}

func (h *Histogram) rotate() {
	h.rw.Lock()
	defer h.rw.Unlock()

	h.hist.Rotate()
}

func (h *Histogram) merge() {
	h.rw.Lock()
	defer h.rw.Unlock()

	h.m = h.hist.Merge()
}

func (h *Histogram) valueAt(q float64) func() int64 {
	return func() int64 {
		h.rw.RLock()
		defer h.rw.RUnlock()

		if h.m == nil {
			return 0
		}

		return h.m.ValueAtQuantile(q)
	}
}

// Error describes an error and the name of the metric where it occurred.
type Error struct {
	Metric string
	Err    error
}

func (e Error) Error() string {
	return e.Metric + ": " + e.Err.Error()
}

var (
	counters     = make(map[string]uint64)
	counterFuncs = make(map[string]func() uint64)
	gauges       = make(map[string]func() int64)
	inits        = make(map[interface{}]func())
	histograms   = make(map[string]*Histogram)

	cm, gm, hm sync.Mutex
)

func init() {
	expvar.Publish("metrics", expvar.Func(func() interface{} {
		counters, gauges := Snapshot()
		return map[string]interface{}{
			"Counters": counters,
			"Gauges":   gauges,
		}
	}))

	go func() {
		for _ = range time.NewTicker(1 * time.Minute).C {
			hm.Lock()
			for _, h := range histograms {
				h.rotate()
			}
			hm.Unlock()
		}
	}()
}
<commit_msg>Access name of histogram<commit_after>// Package metrics provides minimalist instrumentation for your applications in
// the form of counters and gauges.
//
// Counters
//
// A counter is a monotonically-increasing, unsigned, 64-bit integer used to
// represent the number of times an event has occurred. By tracking the deltas
// between measurements of a counter over intervals of time, an aggregation
// layer can derive rates, acceleration, etc.
//
// Gauges
//
// A gauge returns instantaneous measurements of something using signed, 64-bit
// integers. This value does not need to be monotonic.
//
// Histograms
//
// A histogram tracks the distribution of a stream of values (e.g. the number of
// milliseconds it takes to handle requests), adding gauges for the values at
// meaningful quantiles: 50th, 75th, 90th, 95th, 99th, 99.9th.
//
// Reporting
//
// Measurements from counters and gauges are available as expvars. Your service
// should return its expvars from an HTTP endpoint (i.e., /debug/vars) as a JSON
// object.
package metrics

import (
	"expvar"
	"sync"
	"time"

	"github.com/codahale/hdrhistogram"
)

// A Counter is a monotonically increasing unsigned integer.
//
// Use a counter to derive rates (e.g., record total number of requests, derive
// requests per second).
type Counter string

// Add increments the counter by one.
func (c Counter) Add() {
	c.AddN(1)
}

// AddN increments the counter by N.
func (c Counter) AddN(delta uint64) {
	cm.Lock()
	counters[string(c)] += delta
	cm.Unlock()
}

// SetFunc sets the counter's value to the lazily-called return value of the
// given function.
func (c Counter) SetFunc(f func() uint64) {
	cm.Lock()
	defer cm.Unlock()

	counterFuncs[string(c)] = f
}

// SetBatchFunc sets the counter's value to the lazily-called return value of
// the given function, with an additional initializer function for a related
// batch of counters, all of which are keyed by an arbitrary value.
func (c Counter) SetBatchFunc(key interface{}, init func(), f func() uint64) {
	cm.Lock()
	defer cm.Unlock()

	gm.Lock()
	defer gm.Unlock()

	counterFuncs[string(c)] = f
	if _, ok := inits[key]; !ok {
		inits[key] = init
	}
}

// Remove removes the given counter.
func (c Counter) Remove() {
	cm.Lock()
	defer cm.Unlock()

	gm.Lock()
	defer gm.Unlock()

	delete(counters, string(c))
	delete(counterFuncs, string(c))
	delete(inits, string(c))
}

// A Gauge is an instantaneous measurement of a value.
//
// Use a gauge to track metrics which increase and decrease (e.g., amount of
// free memory).
type Gauge string

// Set the gauge's value to the given value.
func (g Gauge) Set(value int64) {
	gm.Lock()
	defer gm.Unlock()

	gauges[string(g)] = func() int64 {
		return value
	}
}

// SetFunc sets the gauge's value to the lazily-called return value of the given
// function.
func (g Gauge) SetFunc(f func() int64) {
	gm.Lock()
	defer gm.Unlock()

	gauges[string(g)] = f
}

// SetBatchFunc sets the gauge's value to the lazily-called return value of the
// given function, with an additional initializer function for a related batch
// of gauges, all of which are keyed by an arbitrary value.
func (g Gauge) SetBatchFunc(key interface{}, init func(), f func() int64) {
	gm.Lock()
	defer gm.Unlock()

	gauges[string(g)] = f
	if _, ok := inits[key]; !ok {
		inits[key] = init
	}
}

// Remove removes the given counter.
func (g Gauge) Remove() {
	gm.Lock()
	defer gm.Unlock()

	delete(gauges, string(g))
	delete(inits, string(g))
}

// Reset removes all existing counters and gauges.
func Reset() {
	cm.Lock()
	defer cm.Unlock()

	gm.Lock()
	defer gm.Unlock()

	hm.Lock()
	defer hm.Unlock()

	counters = make(map[string]uint64)
	counterFuncs = make(map[string]func() uint64)
	gauges = make(map[string]func() int64)
	histograms = make(map[string]*Histogram)
	inits = make(map[interface{}]func())
}

// Snapshot returns a copy of the values of all registered counters and gauges.
func Snapshot() (c map[string]uint64, g map[string]int64) {
	cm.Lock()
	defer cm.Unlock()

	gm.Lock()
	defer gm.Unlock()

	hm.Lock()
	defer hm.Unlock()

	for _, init := range inits {
		init()
	}

	c = make(map[string]uint64, len(counters)+len(counterFuncs))
	for n, v := range counters {
		c[n] = v
	}

	for n, f := range counterFuncs {
		c[n] = f()
	}

	g = make(map[string]int64, len(gauges))
	for n, f := range gauges {
		g[n] = f()
	}

	return
}

// NewHistogram returns a windowed HDR histogram which drops data older than
// five minutes. The returned histogram is safe to use from multiple goroutines.
//
// Use a histogram to track the distribution of a stream of values (e.g., the
// latency associated with HTTP requests).
func NewHistogram(name string, minValue, maxValue int64, sigfigs int) *Histogram {
	hm.Lock()
	defer hm.Unlock()

	if _, ok := histograms[name]; ok {
		panic(name + " already exists")
	}

	hist := &Histogram{
		name: name,
		hist: hdrhistogram.NewWindowed(5, minValue, maxValue, sigfigs),
	}
	histograms[name] = hist

	Gauge(name+".P50").SetBatchFunc(hname(name), hist.merge, hist.valueAt(50))
	Gauge(name+".P75").SetBatchFunc(hname(name), hist.merge, hist.valueAt(75))
	Gauge(name+".P90").SetBatchFunc(hname(name), hist.merge, hist.valueAt(90))
	Gauge(name+".P95").SetBatchFunc(hname(name), hist.merge, hist.valueAt(95))
	Gauge(name+".P99").SetBatchFunc(hname(name), hist.merge, hist.valueAt(99))
	Gauge(name+".P999").SetBatchFunc(hname(name), hist.merge, hist.valueAt(99.9))

	return hist
}

// Remove removes the given histogram.
func (h *Histogram) Remove() {

	hm.Lock()
	defer hm.Unlock()

	Gauge(h.name + ".P50").Remove()
	Gauge(h.name + ".P75").Remove()
	Gauge(h.name + ".P90").Remove()
	Gauge(h.name + ".P95").Remove()
	Gauge(h.name + ".P99").Remove()
	Gauge(h.name + ".P999").Remove()

	delete(histograms, h.name)
}

type hname string // unexported to prevent collisions

// A Histogram measures the distribution of a stream of values.
type Histogram struct {
	name string
	hist *hdrhistogram.WindowedHistogram
	m    *hdrhistogram.Histogram
	rw   sync.RWMutex
}

// Name returns the name of the histogram
func (h *Histogram) Name() string {
	return h.name
}

// RecordValue records the given value, or returns an error if the value is out
// of range.
// Returned error values are of type Error.
func (h *Histogram) RecordValue(v int64) error {
	h.rw.Lock()
	defer h.rw.Unlock()

	err := h.hist.Current.RecordValue(v)
	if err != nil {
		return Error{h.name, err}
	}
	return nil
}

func (h *Histogram) rotate() {
	h.rw.Lock()
	defer h.rw.Unlock()

	h.hist.Rotate()
}

func (h *Histogram) merge() {
	h.rw.Lock()
	defer h.rw.Unlock()

	h.m = h.hist.Merge()
}

func (h *Histogram) valueAt(q float64) func() int64 {
	return func() int64 {
		h.rw.RLock()
		defer h.rw.RUnlock()

		if h.m == nil {
			return 0
		}

		return h.m.ValueAtQuantile(q)
	}
}

// Error describes an error and the name of the metric where it occurred.
type Error struct {
	Metric string
	Err    error
}

func (e Error) Error() string {
	return e.Metric + ": " + e.Err.Error()
}

var (
	counters     = make(map[string]uint64)
	counterFuncs = make(map[string]func() uint64)
	gauges       = make(map[string]func() int64)
	inits        = make(map[interface{}]func())
	histograms   = make(map[string]*Histogram)

	cm, gm, hm sync.Mutex
)

func init() {
	expvar.Publish("metrics", expvar.Func(func() interface{} {
		counters, gauges := Snapshot()
		return map[string]interface{}{
			"Counters": counters,
			"Gauges":   gauges,
		}
	}))

	go func() {
		for _ = range time.NewTicker(1 * time.Minute).C {
			hm.Lock()
			for _, h := range histograms {
				h.rotate()
			}
			hm.Unlock()
		}
	}()
}
<|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 bytes

//go:noescape

// IndexByte returns the index of the first instance of c in s, or -1 if c is not present in s.
func IndexByte(s []byte, c byte) int // ../runtime/asm_$GOARCH.s

//go:noescape

// Equal returns a boolean reporting whether a == b.
// A nil argument is equivalent to an empty slice.
func Equal(a, b []byte) bool // ../runtime/asm_$GOARCH.s

//go:noescape

// Compare returns an integer comparing two byte slices lexicographically.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
// A nil argument is equivalent to an empty slice.
func Compare(a, b []byte) int // ../runtime/noasm_arm.goc or ../runtime/asm_{386,amd64}.s
<commit_msg>bytes: clarify Equal docs<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 bytes

//go:noescape

// IndexByte returns the index of the first instance of c in s, or -1 if c is not present in s.
func IndexByte(s []byte, c byte) int // ../runtime/asm_$GOARCH.s

//go:noescape

// Equal returns a boolean reporting whether a and b
// are the same length and contain the same bytes.
// A nil argument is equivalent to an empty slice.
func Equal(a, b []byte) bool // ../runtime/asm_$GOARCH.s

//go:noescape

// Compare returns an integer comparing two byte slices lexicographically.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
// A nil argument is equivalent to an empty slice.
func Compare(a, b []byte) int // ../runtime/noasm_arm.goc or ../runtime/asm_{386,amd64}.s
<|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.

// This package parses OCSP responses as specified in RFC 2560. OCSP responses
// are signed messages attesting to the validity of a certificate for a small
// period of time. This is used to manage revocation for X.509 certificates.
package ocsp

import (
	"asn1"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/x509"
	"os"
	"time"
)

var idPKIXOCSPBasic = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 5, 5, 7, 48, 1, 1})
var idSHA1WithRSA = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 1, 5})

// These are internal structures that reflect the ASN.1 structure of an OCSP
// response. See RFC 2560, section 4.2.

const (
	ocspSuccess       = 0
	ocspMalformed     = 1
	ocspInternalError = 2
	ocspTryLater      = 3
	ocspSigRequired   = 4
	ocspUnauthorized  = 5
)

type rdnSequence []relativeDistinguishedNameSET

type relativeDistinguishedNameSET []attributeTypeAndValue

type attributeTypeAndValue struct {
	Type  asn1.ObjectIdentifier
	Value interface{}
}

type algorithmIdentifier struct {
	Algorithm asn1.ObjectIdentifier
}

type certID struct {
	HashAlgorithm algorithmIdentifier
	NameHash      []byte
	IssuerKeyHash []byte
	SerialNumber  asn1.RawValue
}

type responseASN1 struct {
	Status   asn1.Enumerated
	Response responseBytes "explicit,tag:0"
}

type responseBytes struct {
	ResponseType asn1.ObjectIdentifier
	Response     []byte
}

type basicResponse struct {
	TBSResponseData    responseData
	SignatureAlgorithm algorithmIdentifier
	Signature          asn1.BitString
	Certificates       []asn1.RawValue "explicit,tag:0,optional"
}

type responseData struct {
	Raw           asn1.RawContent
	Version       int         "optional,default:1,explicit,tag:0"
	RequestorName rdnSequence "optional,explicit,tag:1"
	KeyHash       []byte      "optional,explicit,tag:2"
	ProducedAt    *time.Time
	Responses     []singleResponse
}

type singleResponse struct {
	CertID     certID
	Good       asn1.Flag   "explicit,tag:0,optional"
	Revoked    revokedInfo "explicit,tag:1,optional"
	Unknown    asn1.Flag   "explicit,tag:2,optional"
	ThisUpdate *time.Time
	NextUpdate *time.Time "explicit,tag:0,optional"
}

type revokedInfo struct {
	RevocationTime *time.Time
	Reason         int "explicit,tag:0,optional"
}

// This is the exposed reflection of the internal OCSP structures.

const (
	// Good means that the certificate is valid.
	Good = iota
	// Revoked means that the certificate has been deliberately revoked.
	Revoked = iota
	// Unknown means that the OCSP responder doesn't know about the certificate.
	Unknown = iota
	// ServerFailed means that the OCSP responder failed to process the request.
	ServerFailed = iota
)

// Response represents an OCSP response. See RFC 2560.
type Response struct {
	// Status is one of {Good, Revoked, Unknown, ServerFailed}
	Status                                        int
	SerialNumber                                  []byte
	ProducedAt, ThisUpdate, NextUpdate, RevokedAt *time.Time
	RevocationReason                              int
	Certificate                                   *x509.Certificate
}

// ParseError results from an invalid OCSP response.
type ParseError string

func (p ParseError) String() string {
	return string(p)
}

// ParseResponse parses an OCSP response in DER form. It only supports
// responses for a single certificate and only those using RSA signatures.
// Non-RSA responses will result in an x509.UnsupportedAlgorithmError.
// Signature errors or parse failures will result in a ParseError.
func ParseResponse(bytes []byte) (*Response, os.Error) {
	var resp responseASN1
	rest, err := asn1.Unmarshal(&resp, bytes)
	if err != nil {
		return nil, err
	}
	if len(rest) > 0 {
		return nil, ParseError("trailing data in OCSP response")
	}

	ret := new(Response)
	if resp.Status != ocspSuccess {
		ret.Status = ServerFailed
		return ret, nil
	}

	if !resp.Response.ResponseType.Equal(idPKIXOCSPBasic) {
		return nil, ParseError("bad OCSP response type")
	}

	var basicResp basicResponse
	rest, err = asn1.Unmarshal(&basicResp, resp.Response.Response)
	if err != nil {
		return nil, err
	}

	if len(basicResp.Certificates) != 1 {
		return nil, ParseError("OCSP response contains bad number of certificates")
	}

	if len(basicResp.TBSResponseData.Responses) != 1 {
		return nil, ParseError("OCSP response contains bad number of responses")
	}

	ret.Certificate, err = x509.ParseCertificate(basicResp.Certificates[0].FullBytes)
	if err != nil {
		return nil, err
	}

	if ret.Certificate.PublicKeyAlgorithm != x509.RSA || !basicResp.SignatureAlgorithm.Algorithm.Equal(idSHA1WithRSA) {
		return nil, x509.UnsupportedAlgorithmError{}
	}

	h := sha1.New()
	hashType := rsa.HashSHA1

	pub := ret.Certificate.PublicKey.(*rsa.PublicKey)
	h.Write(basicResp.TBSResponseData.Raw)
	digest := h.Sum()
	signature := basicResp.Signature.RightAlign()

	if rsa.VerifyPKCS1v15(pub, hashType, digest, signature) != nil {
		return nil, ParseError("bad OCSP signature")
	}

	r := basicResp.TBSResponseData.Responses[0]

	ret.SerialNumber = r.CertID.SerialNumber.Bytes

	switch {
	case bool(r.Good):
		ret.Status = Good
	case bool(r.Unknown):
		ret.Status = Unknown
	default:
		ret.Status = Revoked
		ret.RevokedAt = r.Revoked.RevocationTime
		ret.RevocationReason = r.Revoked.Reason
	}

	ret.ProducedAt = basicResp.TBSResponseData.ProducedAt
	ret.ThisUpdate = r.ThisUpdate
	ret.NextUpdate = r.NextUpdate

	return ret, nil
}
<commit_msg>crypto/ocsp: update for asn1 change (fix build)<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.

// This package parses OCSP responses as specified in RFC 2560. OCSP responses
// are signed messages attesting to the validity of a certificate for a small
// period of time. This is used to manage revocation for X.509 certificates.
package ocsp

import (
	"asn1"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/x509"
	"os"
	"time"
)

var idPKIXOCSPBasic = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 5, 5, 7, 48, 1, 1})
var idSHA1WithRSA = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 1, 5})

// These are internal structures that reflect the ASN.1 structure of an OCSP
// response. See RFC 2560, section 4.2.

const (
	ocspSuccess       = 0
	ocspMalformed     = 1
	ocspInternalError = 2
	ocspTryLater      = 3
	ocspSigRequired   = 4
	ocspUnauthorized  = 5
)

type rdnSequence []relativeDistinguishedNameSET

type relativeDistinguishedNameSET []attributeTypeAndValue

type attributeTypeAndValue struct {
	Type  asn1.ObjectIdentifier
	Value interface{}
}

type algorithmIdentifier struct {
	Algorithm asn1.ObjectIdentifier
}

type certID struct {
	HashAlgorithm algorithmIdentifier
	NameHash      []byte
	IssuerKeyHash []byte
	SerialNumber  asn1.RawValue
}

type responseASN1 struct {
	Status   asn1.Enumerated
	Response responseBytes "explicit,tag:0"
}

type responseBytes struct {
	ResponseType asn1.ObjectIdentifier
	Response     []byte
}

type basicResponse struct {
	TBSResponseData    responseData
	SignatureAlgorithm algorithmIdentifier
	Signature          asn1.BitString
	Certificates       []asn1.RawValue "explicit,tag:0,optional"
}

type responseData struct {
	Raw           asn1.RawContent
	Version       int         "optional,default:1,explicit,tag:0"
	RequestorName rdnSequence "optional,explicit,tag:1"
	KeyHash       []byte      "optional,explicit,tag:2"
	ProducedAt    *time.Time
	Responses     []singleResponse
}

type singleResponse struct {
	CertID     certID
	Good       asn1.Flag   "explicit,tag:0,optional"
	Revoked    revokedInfo "explicit,tag:1,optional"
	Unknown    asn1.Flag   "explicit,tag:2,optional"
	ThisUpdate *time.Time
	NextUpdate *time.Time "explicit,tag:0,optional"
}

type revokedInfo struct {
	RevocationTime *time.Time
	Reason         int "explicit,tag:0,optional"
}

// This is the exposed reflection of the internal OCSP structures.

const (
	// Good means that the certificate is valid.
	Good = iota
	// Revoked means that the certificate has been deliberately revoked.
	Revoked = iota
	// Unknown means that the OCSP responder doesn't know about the certificate.
	Unknown = iota
	// ServerFailed means that the OCSP responder failed to process the request.
	ServerFailed = iota
)

// Response represents an OCSP response. See RFC 2560.
type Response struct {
	// Status is one of {Good, Revoked, Unknown, ServerFailed}
	Status                                        int
	SerialNumber                                  []byte
	ProducedAt, ThisUpdate, NextUpdate, RevokedAt *time.Time
	RevocationReason                              int
	Certificate                                   *x509.Certificate
}

// ParseError results from an invalid OCSP response.
type ParseError string

func (p ParseError) String() string {
	return string(p)
}

// ParseResponse parses an OCSP response in DER form. It only supports
// responses for a single certificate and only those using RSA signatures.
// Non-RSA responses will result in an x509.UnsupportedAlgorithmError.
// Signature errors or parse failures will result in a ParseError.
func ParseResponse(bytes []byte) (*Response, os.Error) {
	var resp responseASN1
	rest, err := asn1.Unmarshal(bytes, &resp)
	if err != nil {
		return nil, err
	}
	if len(rest) > 0 {
		return nil, ParseError("trailing data in OCSP response")
	}

	ret := new(Response)
	if resp.Status != ocspSuccess {
		ret.Status = ServerFailed
		return ret, nil
	}

	if !resp.Response.ResponseType.Equal(idPKIXOCSPBasic) {
		return nil, ParseError("bad OCSP response type")
	}

	var basicResp basicResponse
	rest, err = asn1.Unmarshal(resp.Response.Response, &basicResp)
	if err != nil {
		return nil, err
	}

	if len(basicResp.Certificates) != 1 {
		return nil, ParseError("OCSP response contains bad number of certificates")
	}

	if len(basicResp.TBSResponseData.Responses) != 1 {
		return nil, ParseError("OCSP response contains bad number of responses")
	}

	ret.Certificate, err = x509.ParseCertificate(basicResp.Certificates[0].FullBytes)
	if err != nil {
		return nil, err
	}

	if ret.Certificate.PublicKeyAlgorithm != x509.RSA || !basicResp.SignatureAlgorithm.Algorithm.Equal(idSHA1WithRSA) {
		return nil, x509.UnsupportedAlgorithmError{}
	}

	h := sha1.New()
	hashType := rsa.HashSHA1

	pub := ret.Certificate.PublicKey.(*rsa.PublicKey)
	h.Write(basicResp.TBSResponseData.Raw)
	digest := h.Sum()
	signature := basicResp.Signature.RightAlign()

	if rsa.VerifyPKCS1v15(pub, hashType, digest, signature) != nil {
		return nil, ParseError("bad OCSP signature")
	}

	r := basicResp.TBSResponseData.Responses[0]

	ret.SerialNumber = r.CertID.SerialNumber.Bytes

	switch {
	case bool(r.Good):
		ret.Status = Good
	case bool(r.Unknown):
		ret.Status = Unknown
	default:
		ret.Status = Revoked
		ret.RevokedAt = r.Revoked.RevocationTime
		ret.RevocationReason = r.Revoked.Reason
	}

	ret.ProducedAt = basicResp.TBSResponseData.ProducedAt
	ret.ThisUpdate = r.ThisUpdate
	ret.NextUpdate = r.NextUpdate

	return ret, nil
}
<|endoftext|>


<commit_before>// Copyright 2016 Olivier Mengué. All rights reserved.
// Use of this source code is governed by the Apache 2.0 license that
// can be found in the LICENSE file.

// Package jsonptr implements JSON Pointer (RFC 6901) lookup
package jsonptr

import (
	"bytes"
	"errors"
	"fmt"
	"strconv"
)

var (
	ErrSyntax   = errors.New("invalid JSON pointer")
	ErrIndex    = errors.New("invalid array index")
	ErrProperty = errors.New("property not found")
)

// PtrError is the structured error for JSON Pointer parsing or navigation
// errors
type PtrError struct {
	// Ptr is the substring of the original pointer where the error occurred
	Ptr string
	// Err is one of ErrSyntax, ErrIndex, ErrProperty
	Err error
}

// Error implement the 'error' interface
func (e *PtrError) Error() string {
	return strconv.Quote(e.Ptr) + ": " + e.Err.Error()
}

func syntaxError(ptr string) *PtrError {
	return &PtrError{ptr, ErrSyntax}
}

func indexError(ptr string) *PtrError {
	return &PtrError{ptr, ErrIndex}
}

func propertyError(ptr string) *PtrError {
	return &PtrError{ptr, ErrProperty}
}

func docError(ptr string, doc interface{}) *PtrError {
	return &PtrError{ptr, fmt.Errorf("not an object or array but %T", doc)}
}

func arrayIndex(b []byte) (int, error) {
	if len(b) == 0 {
		return -1, ErrSyntax
	}
	if len(b) == 1 {
		if b[0] == '0' {
			return 0, nil
		}
		if b[0] == '-' {
			return -1, nil
		}
	}
	if b[0] < '1' {
		return -1, ErrSyntax
	}
	var n int
	const maxInt = (1 << (strconv.IntSize - 1)) - 1
	const cutoff = maxInt/10 + 1
	for i := 0; i < len(b); i++ {
		c := b[i]
		if c < '0' || c > '9' {
			return -1, ErrSyntax
		}
		if n >= cutoff {
			// Overflow
			return -1, ErrSyntax
		}
		n *= 10
		n1 := n + int(c-'0')
		if n1 < n || n1 > maxInt {
			// Overflow
			return -1, ErrSyntax
		}
		n = n1
	}
	return n, nil
}

func propertyName(b []byte) (string, error) {
	// FIXME reject '~' followed by something else than '0', '1'
	return string(
		bytes.Replace(
			bytes.Replace(b,
				[]byte(`~1`), []byte(`/`), -1),
			[]byte(`~0`), []byte(`~`), -1),
	), nil
}

// Get extracts a value from a JSON-like data tree
//
// In case of error a PtrError is returned
func Get(doc interface{}, ptr string) (interface{}, error) {
	if len(ptr) == 0 {
		return doc, nil
	}
	if ptr[0] != '/' {
		return nil, syntaxError(ptr)
	}
	bptr := []byte(ptr)
	cur := bptr[1:]
	p := int(1)
	for {
		q := bytes.IndexByte(cur, `/`[0])
		if q == -1 {
			q = len(cur)
		}
		p += q

		switch here := (doc).(type) {
		case map[string]interface{}:
			key, err := propertyName(cur[:q])
			if err != nil {
				return nil, &PtrError{string(bptr[:p]), err}
			}
			var ok bool
			if doc, ok = here[key]; !ok {
				return nil, propertyError(string(bptr[:p]))
			}
		case []interface{}:
			n, err := arrayIndex(cur[:q])
			if err != nil {
				return nil, &PtrError{string(bptr[:p]), err}
			}
			if n < 0 || n >= len(here) {
				return nil, indexError(string(bptr[:p]))
			}
			doc = here[n]
		default:
			return nil, docError(string(bptr[:p]), doc)
		}
		if p >= len(bptr) {
			break
		}
		p++
		cur = bptr[p:]
	}

	return doc, nil
}

// Set modifies a JSON-like data tree
//
// In case of error a PtrError is returned
func Set(doc *interface{}, ptr string, value interface{}) error {
	if len(ptr) == 0 {
		*doc = value
		return nil
	}
	bptr := []byte(ptr)
	p := bytes.LastIndexByte(bptr, '/')
	if p < 0 {
		return syntaxError(ptr)
	}
	prop := bptr[p+1:]
	parentPtr := string(bptr[:p])

	parent, err := Get(*doc, parentPtr)
	if err != nil {
		return err
	}

	switch parent := (parent).(type) {
	case map[string]interface{}:
		key, err := propertyName(prop)
		if err != nil {
			return &PtrError{ptr, err}
		}
		parent[key] = value
	case []interface{}:
		n, err := arrayIndex(prop)
		if err != nil {
			return &PtrError{ptr, err}

		}
		if n == -1 {
			n = len(parent)
		} else if n < len(parent) {
			parent[n] = value
			return nil
		}

		// if n > len(parent) {
		//	return &PtrError{ptr, ErrIndex}
		//}

		// TODO make+copy
		for i := n - len(parent) - 1; i > 0; i-- {
			parent = append(parent, nil)
		}
		parent = append(parent, value)
		// We appended beyond original len, so the slice changed so we have to
		// store the new one at the old place
		// No error can happen as we already parsed the pointer
		_ = Set(doc, parentPtr, parent)
	default:
		return docError(parentPtr, parent)
	}

	return nil
}
<commit_msg>Use string instead of []byte internally<commit_after>// Copyright 2016 Olivier Mengué. All rights reserved.
// Use of this source code is governed by the Apache 2.0 license that
// can be found in the LICENSE file.

// Package jsonptr implements JSON Pointer (RFC 6901) lookup
package jsonptr

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

var (
	ErrSyntax   = errors.New("invalid JSON pointer")
	ErrIndex    = errors.New("invalid array index")
	ErrProperty = errors.New("property not found")
)

// PtrError is the structured error for JSON Pointer parsing or navigation
// errors
type PtrError struct {
	// Ptr is the substring of the original pointer where the error occurred
	Ptr string
	// Err is one of ErrSyntax, ErrIndex, ErrProperty
	Err error
}

// Error implement the 'error' interface
func (e *PtrError) Error() string {
	return strconv.Quote(e.Ptr) + ": " + e.Err.Error()
}

func syntaxError(ptr string) *PtrError {
	return &PtrError{ptr, ErrSyntax}
}

func indexError(ptr string) *PtrError {
	return &PtrError{ptr, ErrIndex}
}

func propertyError(ptr string) *PtrError {
	return &PtrError{ptr, ErrProperty}
}

func docError(ptr string, doc interface{}) *PtrError {
	return &PtrError{ptr, fmt.Errorf("not an object or array but %T", doc)}
}

func arrayIndex(token string) (int, error) {
	if len(token) == 0 {
		return -1, ErrSyntax
	}
	if len(token) == 1 {
		if token[0] == '0' {
			return 0, nil
		}
		if token[0] == '-' {
			return -1, nil
		}
	}
	if token[0] < '1' {
		return -1, ErrSyntax
	}
	var n int
	const maxInt = (1 << (strconv.IntSize - 1)) - 1
	const cutoff = maxInt/10 + 1
	for i := 0; i < len(token); i++ {
		c := token[i]
		if c < '0' || c > '9' {
			return -1, ErrSyntax
		}
		if n >= cutoff {
			// Overflow
			return -1, ErrSyntax
		}
		n *= 10
		n1 := n + int(c-'0')
		if n1 < n || n1 > maxInt {
			// Overflow
			return -1, ErrSyntax
		}
		n = n1
	}
	return n, nil
}

func propertyName(token string) (string, error) {
	// FIXME reject '~' followed by something else than '0', '1'
	return strings.Replace(
			strings.Replace(token,
				`~1`, `/`, -1),
			`~0`, `~`, -1),
		nil
}

// Get extracts a value from a JSON-like data tree
//
// In case of error a PtrError is returned
func Get(doc interface{}, ptr string) (interface{}, error) {
	if len(ptr) == 0 {
		return doc, nil
	}
	if ptr[0] != '/' {
		return nil, syntaxError(ptr)
	}
	cur := ptr[1:]
	p := int(1)
	for {
		q := strings.IndexByte(cur, '/')
		if q == -1 {
			q = len(cur)
		}
		p += q

		switch here := (doc).(type) {
		case map[string]interface{}:
			key, err := propertyName(cur[:q])
			if err != nil {
				return nil, &PtrError{ptr[:p], err}
			}
			var ok bool
			if doc, ok = here[key]; !ok {
				return nil, propertyError(ptr[:p])
			}
		case []interface{}:
			n, err := arrayIndex(cur[:q])
			if err != nil {
				return nil, &PtrError{ptr[:p], err}
			}
			if n < 0 || n >= len(here) {
				return nil, indexError(ptr[:p])
			}
			doc = here[n]
		default:
			return nil, docError(ptr[:p], doc)
		}
		if p >= len(ptr) {
			break
		}
		p++
		cur = ptr[p:]
	}

	return doc, nil
}

// Set modifies a JSON-like data tree
//
// In case of error a PtrError is returned
func Set(doc *interface{}, ptr string, value interface{}) error {
	if len(ptr) == 0 {
		*doc = value
		return nil
	}
	p := strings.LastIndexByte(ptr, '/')
	if p < 0 {
		return syntaxError(ptr)
	}
	prop := ptr[p+1:]
	parentPtr := ptr[:p]

	parent, err := Get(*doc, parentPtr)
	if err != nil {
		return err
	}

	switch parent := (parent).(type) {
	case map[string]interface{}:
		key, err := propertyName(prop)
		if err != nil {
			return &PtrError{ptr, err}
		}
		parent[key] = value
	case []interface{}:
		n, err := arrayIndex(prop)
		if err != nil {
			return &PtrError{ptr, err}

		}
		if n == -1 {
			n = len(parent)
		} else if n < len(parent) {
			parent[n] = value
			return nil
		}

		// if n > len(parent) {
		//	return &PtrError{ptr, ErrIndex}
		//}

		// TODO make+copy
		for i := n - len(parent) - 1; i > 0; i-- {
			parent = append(parent, nil)
		}
		parent = append(parent, value)
		// We appended beyond original len, so the slice changed so we have to
		// store the new one at the old place
		// No error can happen as we already parsed the pointer
		_ = Set(doc, parentPtr, parent)
	default:
		return docError(parentPtr, parent)
	}

	return nil
}
<|endoftext|>


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

// Package dwarf provides access to DWARF debugging information loaded from
// executable files, as defined in the DWARF 2.0 Standard at
// http://dwarfstd.org/doc/dwarf-2.0.0.pdf
package dwarf

import "encoding/binary"

// Data represents the DWARF debugging information
// loaded from an executable file (for example, an ELF or Mach-O executable).
type Data struct {
	// raw data
	abbrev   []byte
	aranges  []byte
	frame    []byte
	info     []byte
	line     []byte
	pubnames []byte
	ranges   []byte
	str      []byte

	// parsed data
	abbrevCache map[uint32]abbrevTable
	addrsize    int
	order       binary.ByteOrder
	typeCache   map[Offset]Type
	unit        []unit
}

// New returns a new Data object initialized from the given parameters.
// Clients should typically use [TODO(rsc): method to be named later] instead of calling
// New directly.
//
// The []byte arguments are the data from the corresponding debug section
// in the object file; for example, for an ELF object, abbrev is the contents of
// the ".debug_abbrev" section.
func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Data, error) {
	d := &Data{
		abbrev:      abbrev,
		aranges:     aranges,
		frame:       frame,
		info:        info,
		line:        line,
		pubnames:    pubnames,
		ranges:      ranges,
		str:         str,
		abbrevCache: make(map[uint32]abbrevTable),
		typeCache:   make(map[Offset]Type),
	}

	// Sniff .debug_info to figure out byte order.
	// bytes 4:6 are the version, a tiny 16-bit number (1, 2, 3).
	if len(d.info) < 6 {
		return nil, DecodeError{"info", Offset(len(d.info)), "too short"}
	}
	x, y := d.info[4], d.info[5]
	switch {
	case x == 0 && y == 0:
		return nil, DecodeError{"info", 4, "unsupported version 0"}
	case x == 0:
		d.order = binary.BigEndian
	case y == 0:
		d.order = binary.LittleEndian
	default:
		return nil, DecodeError{"info", 4, "cannot determine byte order"}
	}

	u, err := d.parseUnits()
	if err != nil {
		return nil, err
	}
	d.unit = u
	return d, nil
}
<commit_msg>debug/dwarf: address TODO in doc comment for New<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package dwarf provides access to DWARF debugging information loaded from
// executable files, as defined in the DWARF 2.0 Standard at
// http://dwarfstd.org/doc/dwarf-2.0.0.pdf
package dwarf

import "encoding/binary"

// Data represents the DWARF debugging information
// loaded from an executable file (for example, an ELF or Mach-O executable).
type Data struct {
	// raw data
	abbrev   []byte
	aranges  []byte
	frame    []byte
	info     []byte
	line     []byte
	pubnames []byte
	ranges   []byte
	str      []byte

	// parsed data
	abbrevCache map[uint32]abbrevTable
	addrsize    int
	order       binary.ByteOrder
	typeCache   map[Offset]Type
	unit        []unit
}

// New returns a new Data object initialized from the given parameters.
// Rather than calling this function directly, clients should typically use
// the DWARF method of the File type of the appropriate package debug/elf,
// debug/macho, or debug/pe.
//
// The []byte arguments are the data from the corresponding debug section
// in the object file; for example, for an ELF object, abbrev is the contents of
// the ".debug_abbrev" section.
func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Data, error) {
	d := &Data{
		abbrev:      abbrev,
		aranges:     aranges,
		frame:       frame,
		info:        info,
		line:        line,
		pubnames:    pubnames,
		ranges:      ranges,
		str:         str,
		abbrevCache: make(map[uint32]abbrevTable),
		typeCache:   make(map[Offset]Type),
	}

	// Sniff .debug_info to figure out byte order.
	// bytes 4:6 are the version, a tiny 16-bit number (1, 2, 3).
	if len(d.info) < 6 {
		return nil, DecodeError{"info", Offset(len(d.info)), "too short"}
	}
	x, y := d.info[4], d.info[5]
	switch {
	case x == 0 && y == 0:
		return nil, DecodeError{"info", 4, "unsupported version 0"}
	case x == 0:
		d.order = binary.BigEndian
	case y == 0:
		d.order = binary.LittleEndian
	default:
		return nil, DecodeError{"info", 4, "cannot determine byte order"}
	}

	u, err := d.parseUnits()
	if err != nil {
		return nil, err
	}
	d.unit = u
	return d, nil
}
<|endoftext|>


<commit_before>// Copyright 2011 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.

// Sockets for Windows

package net

import (
	"syscall"
)

func setKernelSpecificSockopt(s syscall.Handle, f int) {
	// Allow reuse of recently-used addresses and ports.
	syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)

	// Allow broadcast.
	syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)

	if f == syscall.AF_INET6 {
		// using ip, tcp, udp, etc.
		// allow both protocols even if the OS default is otherwise.
		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
	}
}
<commit_msg>net: do not set SO_REUSEADDR for windows<commit_after>// Copyright 2011 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.

// Sockets for Windows

package net

import (
	"syscall"
)

func setKernelSpecificSockopt(s syscall.Handle, f int) {
	// Allow broadcast.
	syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)

	if f == syscall.AF_INET6 {
		// using ip, tcp, udp, etc.
		// allow both protocols even if the OS default is otherwise.
		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
	}
}
<|endoftext|>


<commit_before>package jsx

import (
	"fmt"
	"strings"

	"github.com/russross/blackfriday"

	"golang.org/x/net/html"
	"golang.org/x/net/html/atom"
	r "myitcv.io/react"
)

// each of the parse* functions does zero validation
// this is intentional because everything is expected to
// go via the generic parse function

// TODO code generate these parse functions

func parseP(n *html.Node) *r.PElem {
	var kids []r.Element

	// TODO attributes

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return r.P(nil, kids...)
}

func parseHr(n *html.Node) *r.HrElem {
	// TODO attributes

	return r.Hr(nil)
}

func parseBr(n *html.Node) *r.BrElem {
	// TODO attributes

	return r.Br(nil)
}

func parseH1(n *html.Node) *r.H1Elem {
	var kids []r.Element

	// TODO attributes

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return r.H1(nil, kids...)
}

func parseSpan(n *html.Node) *r.SpanElem {
	var kids []r.Element

	var vp *r.SpanProps

	if len(n.Attr) > 0 {
		vp = new(r.SpanProps)

		for _, a := range n.Attr {
			switch a.Key {
			case "classname":
				vp.ClassName = a.Val
			case "style":
				vp.Style = parseCSS(a.Val)
			default:
				panic(fmt.Errorf("don't know how to handle <span> attribute %q", a.Key))
			}
		}
	}

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return r.Span(vp, kids...)
}

func parseI(n *html.Node) *r.IElem {
	var kids []r.Element

	var vp *r.IProps

	if len(n.Attr) > 0 {
		vp = new(r.IProps)

		for _, a := range n.Attr {
			switch a.Key {
			case "id":
				vp.ID = a.Val
			case "classname":
				vp.ClassName = a.Val
			default:
				panic(fmt.Errorf("don't know how to handle <i> attribute %q", a.Key))
			}
		}
	}

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return r.I(vp, kids...)
}

func parseFooter(n *html.Node) *r.FooterElem {
	var kids []r.Element

	var vp *r.FooterProps

	if len(n.Attr) > 0 {
		vp = new(r.FooterProps)

		for _, a := range n.Attr {
			switch a.Key {
			case "id":
				vp.ID = a.Val
			case "classname":
				vp.ClassName = a.Val
			default:
				panic(fmt.Errorf("don't know how to handle <footer> attribute %q", a.Key))
			}
		}
	}

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return r.Footer(vp, kids...)
}

func parseDiv(n *html.Node) *r.DivElem {
	var kids []r.Element

	var vp *r.DivProps

	if len(n.Attr) > 0 {
		vp = new(r.DivProps)

		for _, a := range n.Attr {
			switch a.Key {
			case "id":
				vp.ID = a.Val
			case "classname":
				vp.ClassName = a.Val
			case "style":
				vp.Style = parseCSS(a.Val)
			default:
				panic(fmt.Errorf("don't know how to handle <div> attribute %q", a.Key))
			}
		}
	}

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return r.Div(vp, kids...)
}

func parseButton(n *html.Node) *r.ButtonElem {
	var kids []r.Element

	var vp *r.ButtonProps

	if len(n.Attr) > 0 {
		vp = new(r.ButtonProps)

		for _, a := range n.Attr {
			switch a.Key {
			case "id":
				vp.ID = a.Val
			case "classname":
				vp.ClassName = a.Val
			default:
				panic(fmt.Errorf("don't know how to handle <div> attribute %q", a.Key))
			}
		}
	}

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return r.Button(vp, kids...)
}

func parseCode(n *html.Node) *r.CodeElem {
	var kids []r.Element

	// TODO attributes

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return r.Code(nil, kids...)
}

func parseH3(n *html.Node) *r.H3Elem {
	var kids []r.Element

	// TODO attributes

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return r.H3(nil, kids...)
}

func parseImg(n *html.Node) *r.ImgElem {
	var kids []r.Element

	var vp *r.ImgProps

	if len(n.Attr) > 0 {
		vp = new(r.ImgProps)

		for _, a := range n.Attr {
			switch a.Key {
			case "src":
				vp.Src = a.Val
			case "style":
				vp.Style = parseCSS(a.Val)
			default:
				panic(fmt.Errorf("don't know how to handle <img> attribute %q", a.Key))
			}
		}
	}

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return r.Img(vp, kids...)
}

func parseA(n *html.Node) *r.AElem {
	var kids []r.Element

	var vp *r.AProps

	if len(n.Attr) > 0 {
		vp = new(r.AProps)

		for _, a := range n.Attr {
			switch a.Key {
			case "href":
				vp.Href = a.Val
			case "target":
				vp.Target = a.Val
			default:
				panic(fmt.Errorf("don't know how to handle <a> attribute %q", a.Key))
			}
		}
	}

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return r.A(vp, kids...)
}

// TODO replace with proper parser
func parseCSS(s string) *r.CSS {
	res := new(r.CSS)

	parts := strings.Split(s, ";")

	for _, p := range parts {
		kv := strings.Split(p, ":")
		if len(kv) != 2 {
			panic(fmt.Errorf("invalid key-val %q in %q", p, s))
		}

		k, v := kv[0], kv[1]

		k = strings.TrimSpace(k)
		v = strings.TrimSpace(v)
		v = strings.Trim(v, "\"")

		switch k {
		case "overflow-y":
			res.OverflowY = v
		case "margin-top":
			res.MarginTop = v
		case "font-size":
			res.FontSize = v
		case "font-style":
			res.FontStyle = v
		default:
			panic(fmt.Errorf("unknown CSS key %q in %q", k, s))
		}
	}

	return res
}

func parse(n *html.Node) r.Element {
	switch n.Type {
	case html.TextNode:
		return r.S(n.Data)
	case html.ElementNode:
		// we will fall out from here...
	default:
		panic(fmt.Errorf("cannot handle NodeType %v", n.Type))
	}

	switch n.Data {
	case "p":
		return parseP(n)
	case "h1":
		return parseH1(n)
	case "code":
		return parseCode(n)
	case "h3":
		return parseH3(n)
	case "img":
		return parseImg(n)
	case "a":
		return parseA(n)
	case "footer":
		return parseFooter(n)
	case "div":
		return parseDiv(n)
	case "span":
		return parseSpan(n)
	case "hr":
		return parseHr(n)
	case "br":
		return parseBr(n)
	case "button":
		return parseButton(n)
	case "i":
		return parseI(n)
	default:
		panic(fmt.Errorf("cannot handle Element %v", n.Data))
	}
}

var htmlCache = make(map[string][]r.Element)

// HTML is a runtime JSX-like parser. It parses the supplied HTML string into
// myitcv.io/react element values. It exists as a stop-gap runtime solution to
// full JSX-like support within the GopherJS compiler. It should only be used
// where the argument is a compile-time constant string (TODO enforce this
// within reactVet). HTML will panic in case s cannot be parsed as a valid HTML
// fragment
//
func HTML(s string) []r.Element {
	s = strings.TrimSpace(s)

	if v, ok := htmlCache[s]; ok {
		return v
	}

	// a dummy div for parsing the fragment
	div := &html.Node{
		Type:     html.ElementNode,
		Data:     "div",
		DataAtom: atom.Div,
	}

	elems, err := html.ParseFragment(strings.NewReader(s), div)
	if err != nil {
		panic(fmt.Errorf("failed to parse HTML %q: %v", s, err))
	}

	res := make([]r.Element, len(elems))

	for i, v := range elems {
		res[i] = parse(v)
	}

	htmlCache[s] = res

	return res
}

// HTMLElem is a convenience wrapper around HTML where only a single root
// element is expected. HTMLElem will panic if more than one HTML element
// results
//
func HTMLElem(s string) r.Element {
	res := HTML(s)

	if v := len(res); v != 1 {
		panic(fmt.Errorf("expected single element result from %q; got %v", s, v))
	}

	return res[0]
}

// Markdown is a runtime JSX-like parser for markdown. It parses the supplied
// markdown string into an HTML string and then hands off to the HTML function.
// Like the HTML function, it exists as a stop-gap runtime solution to full
// JSX-like support within the GopherJS compiler. It should only be used where
// the argument is a compile-time constant string (TODO enforce this within
// reactVet). Markdown will panic in case the markdown string s results in an
// invalid HTML string
//
func Markdown(s string) []r.Element {

	h := blackfriday.MarkdownCommon([]byte(s))

	return HTML(string(h))
}
<commit_msg>Use react package name in jsx for clearer docs<commit_after>/*

Package jsx allows you to render blocks of HTML as myitcv.io/react elements.
It is a temporary runtime solution for what will become a compile-time
transpilation, much like JSX's relationship with Javascript.

For more information see https://github.com/myitcv/react/wiki

*/
package jsx

import (
	"fmt"
	"strings"

	"myitcv.io/react"

	"github.com/russross/blackfriday"

	"golang.org/x/net/html"
	"golang.org/x/net/html/atom"
)

// each of the parse* functions does zero validation
// this is intentional because everything is expected to
// go via the generic parse function

// TODO code generate these parse functions

func parseP(n *html.Node) *react.PElem {
	var kids []react.Element

	// TODO attributes

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return react.P(nil, kids...)
}

func parseHr(n *html.Node) *react.HrElem {
	// TODO attributes

	return react.Hr(nil)
}

func parseBr(n *html.Node) *react.BrElem {
	// TODO attributes

	return react.Br(nil)
}

func parseH1(n *html.Node) *react.H1Elem {
	var kids []react.Element

	// TODO attributes

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return react.H1(nil, kids...)
}

func parseSpan(n *html.Node) *react.SpanElem {
	var kids []react.Element

	var vp *react.SpanProps

	if len(n.Attr) > 0 {
		vp = new(react.SpanProps)

		for _, a := range n.Attr {
			switch a.Key {
			case "classname":
				vp.ClassName = a.Val
			case "style":
				vp.Style = parseCSS(a.Val)
			default:
				panic(fmt.Errorf("don't know how to handle <span> attribute %q", a.Key))
			}
		}
	}

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return react.Span(vp, kids...)
}

func parseI(n *html.Node) *react.IElem {
	var kids []react.Element

	var vp *react.IProps

	if len(n.Attr) > 0 {
		vp = new(react.IProps)

		for _, a := range n.Attr {
			switch a.Key {
			case "id":
				vp.ID = a.Val
			case "classname":
				vp.ClassName = a.Val
			default:
				panic(fmt.Errorf("don't know how to handle <i> attribute %q", a.Key))
			}
		}
	}

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return react.I(vp, kids...)
}

func parseFooter(n *html.Node) *react.FooterElem {
	var kids []react.Element

	var vp *react.FooterProps

	if len(n.Attr) > 0 {
		vp = new(react.FooterProps)

		for _, a := range n.Attr {
			switch a.Key {
			case "id":
				vp.ID = a.Val
			case "classname":
				vp.ClassName = a.Val
			default:
				panic(fmt.Errorf("don't know how to handle <footer> attribute %q", a.Key))
			}
		}
	}

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return react.Footer(vp, kids...)
}

func parseDiv(n *html.Node) *react.DivElem {
	var kids []react.Element

	var vp *react.DivProps

	if len(n.Attr) > 0 {
		vp = new(react.DivProps)

		for _, a := range n.Attr {
			switch a.Key {
			case "id":
				vp.ID = a.Val
			case "classname":
				vp.ClassName = a.Val
			case "style":
				vp.Style = parseCSS(a.Val)
			default:
				panic(fmt.Errorf("don't know how to handle <div> attribute %q", a.Key))
			}
		}
	}

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return react.Div(vp, kids...)
}

func parseButton(n *html.Node) *react.ButtonElem {
	var kids []react.Element

	var vp *react.ButtonProps

	if len(n.Attr) > 0 {
		vp = new(react.ButtonProps)

		for _, a := range n.Attr {
			switch a.Key {
			case "id":
				vp.ID = a.Val
			case "classname":
				vp.ClassName = a.Val
			default:
				panic(fmt.Errorf("don't know how to handle <div> attribute %q", a.Key))
			}
		}
	}

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return react.Button(vp, kids...)
}

func parseCode(n *html.Node) *react.CodeElem {
	var kids []react.Element

	// TODO attributes

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return react.Code(nil, kids...)
}

func parseH3(n *html.Node) *react.H3Elem {
	var kids []react.Element

	// TODO attributes

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return react.H3(nil, kids...)
}

func parseImg(n *html.Node) *react.ImgElem {
	var kids []react.Element

	var vp *react.ImgProps

	if len(n.Attr) > 0 {
		vp = new(react.ImgProps)

		for _, a := range n.Attr {
			switch a.Key {
			case "src":
				vp.Src = a.Val
			case "style":
				vp.Style = parseCSS(a.Val)
			default:
				panic(fmt.Errorf("don't know how to handle <img> attribute %q", a.Key))
			}
		}
	}

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return react.Img(vp, kids...)
}

func parseA(n *html.Node) *react.AElem {
	var kids []react.Element

	var vp *react.AProps

	if len(n.Attr) > 0 {
		vp = new(react.AProps)

		for _, a := range n.Attr {
			switch a.Key {
			case "href":
				vp.Href = a.Val
			case "target":
				vp.Target = a.Val
			default:
				panic(fmt.Errorf("don't know how to handle <a> attribute %q", a.Key))
			}
		}
	}

	for c := n.FirstChild; c != nil; c = c.NextSibling {
		kids = append(kids, parse(c))
	}

	return react.A(vp, kids...)
}

// TODO replace with proper parser
func parseCSS(s string) *react.CSS {
	res := new(react.CSS)

	parts := strings.Split(s, ";")

	for _, p := range parts {
		kv := strings.Split(p, ":")
		if len(kv) != 2 {
			panic(fmt.Errorf("invalid key-val %q in %q", p, s))
		}

		k, v := kv[0], kv[1]

		k = strings.TrimSpace(k)
		v = strings.TrimSpace(v)
		v = strings.Trim(v, "\"")

		switch k {
		case "overflow-y":
			res.OverflowY = v
		case "margin-top":
			res.MarginTop = v
		case "font-size":
			res.FontSize = v
		case "font-style":
			res.FontStyle = v
		default:
			panic(fmt.Errorf("unknown CSS key %q in %q", k, s))
		}
	}

	return res
}

func parse(n *html.Node) react.Element {
	switch n.Type {
	case html.TextNode:
		return react.S(n.Data)
	case html.ElementNode:
		// we will fall out from here...
	default:
		panic(fmt.Errorf("cannot handle NodeType %v", n.Type))
	}

	switch n.Data {
	case "p":
		return parseP(n)
	case "h1":
		return parseH1(n)
	case "code":
		return parseCode(n)
	case "h3":
		return parseH3(n)
	case "img":
		return parseImg(n)
	case "a":
		return parseA(n)
	case "footer":
		return parseFooter(n)
	case "div":
		return parseDiv(n)
	case "span":
		return parseSpan(n)
	case "hr":
		return parseHr(n)
	case "br":
		return parseBr(n)
	case "button":
		return parseButton(n)
	case "i":
		return parseI(n)
	default:
		panic(fmt.Errorf("cannot handle Element %v", n.Data))
	}
}

var htmlCache = make(map[string][]react.Element)

// HTML is a runtime JSX-like parsereact. It parses the supplied HTML string into
// myitcv.io/react element values. It exists as a stop-gap runtime solution to
// full JSX-like support within the GopherJS compilereact. It should only be used
// where the argument is a compile-time constant string (TODO enforce this
// within reactVet). HTML will panic in case s cannot be parsed as a valid HTML
// fragment
//
func HTML(s string) []react.Element {
	s = strings.TrimSpace(s)

	if v, ok := htmlCache[s]; ok {
		return v
	}

	// a dummy div for parsing the fragment
	div := &html.Node{
		Type:     html.ElementNode,
		Data:     "div",
		DataAtom: atom.Div,
	}

	elems, err := html.ParseFragment(strings.NewReader(s), div)
	if err != nil {
		panic(fmt.Errorf("failed to parse HTML %q: %v", s, err))
	}

	res := make([]react.Element, len(elems))

	for i, v := range elems {
		res[i] = parse(v)
	}

	htmlCache[s] = res

	return res
}

// HTMLElem is a convenience wrapper around HTML where only a single root
// element is expected. HTMLElem will panic if more than one HTML element
// results
//
func HTMLElem(s string) react.Element {
	res := HTML(s)

	if v := len(res); v != 1 {
		panic(fmt.Errorf("expected single element result from %q; got %v", s, v))
	}

	return res[0]
}

// Markdown is a runtime JSX-like parser for markdown. It parses the supplied
// markdown string into an HTML string and then hands off to the HTML function.
// Like the HTML function, it exists as a stop-gap runtime solution to full
// JSX-like support within the GopherJS compilereact. It should only be used where
// the argument is a compile-time constant string (TODO enforce this within
// reactVet). Markdown will panic in case the markdown string s results in an
// invalid HTML string
//
func Markdown(s string) []react.Element {

	h := blackfriday.MarkdownCommon([]byte(s))

	return HTML(string(h))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"sync"

	"github.com/Kutabe/vk"
	"github.com/antonholmquist/jason"
	"github.com/kennygrant/sanitize"
)

func getMusicAsync(wg *sync.WaitGroup, responseURL string, responseArtist string, responseTitle string) {
	fmt.Printf("URL GET:%s\n", responseURL)
	defer wg.Done()
	response, err := http.Get(responseURL)
	if err != nil {
		log.Print(err)
		return
	}
	defer response.Body.Close()
	audio, err := ioutil.ReadAll(response.Body)
	if err != nil {
		log.Print(err)
		return
	}
	filename := sanitize.BaseName(responseArtist+" - "+responseTitle) + ".mp3"
	err = ioutil.WriteFile(filename, audio, 0777)
	if err != nil {
		log.Print(err)
		return
	}
	fmt.Printf("FILE DONE:%s\n", filename)
}
func main() {
	var wg sync.WaitGroup
	var login, password string
	const maxConnectionCount int = 10
	fmt.Print("Automatic VK.com music downloader\n")
	fmt.Print("Login(Email or Phone): ")
	fmt.Scanf("%s\n", &login)
	fmt.Print("Password: ")
	fmt.Scanf("%s\n", &password)
	user, err := vk.Auth(login, password)
	if err != nil {
		log.Fatal(err)
	}
	responseJSON, _ := vk.Request("audio.get", nil, user)
	responseObject, _ := jason.NewObjectFromBytes(responseJSON)
	responseArray, _ := responseObject.GetObjectArray("response")
	conCounter := 0
	for _, responseElement := range responseArray {
		responseURL, _ := responseElement.GetString("url")
		responseArtist, _ := responseElement.GetString("artist")
		responseTitle, _ := responseElement.GetString("title")

		conCounter += 1
		wg.Add(1)
		go getMusicAsync(&wg, responseURL, responseArtist, responseTitle)
		if conCounter > maxConnectionCount {
			wg.Wait()
			conCounter = 0
		}
	}
	wg.Wait()
}
<commit_msg>Error messages should be newline<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"sync"

	"github.com/Kutabe/vk"
	"github.com/antonholmquist/jason"
	"github.com/kennygrant/sanitize"
)

func getMusicAsync(wg *sync.WaitGroup, responseURL string, responseArtist string, responseTitle string) {
	fmt.Printf("URL GET:%s\n", responseURL)
	defer wg.Done()
	response, err := http.Get(responseURL)
	if err != nil {
		log.Println(err)
		return
	}
	defer response.Body.Close()
	audio, err := ioutil.ReadAll(response.Body)
	if err != nil {
		log.Println(err)
		return
	}
	filename := sanitize.BaseName(responseArtist+" - "+responseTitle) + ".mp3"
	err = ioutil.WriteFile(filename, audio, 0777)
	if err != nil {
		log.Println(err)
		return
	}
	fmt.Printf("FILE DONE:%s\n", filename)
}
func main() {
	var wg sync.WaitGroup
	var login, password string
	const maxConnectionCount int = 10
	fmt.Print("Automatic VK.com music downloader\n")
	fmt.Print("Login(Email or Phone): ")
	fmt.Scanf("%s\n", &login)
	fmt.Print("Password: ")
	fmt.Scanf("%s\n", &password)
	user, err := vk.Auth(login, password)
	if err != nil {
		log.Fatal(err)
	}
	responseJSON, _ := vk.Request("audio.get", nil, user)
	responseObject, _ := jason.NewObjectFromBytes(responseJSON)
	responseArray, _ := responseObject.GetObjectArray("response")
	conCounter := 0
	for _, responseElement := range responseArray {
		responseURL, _ := responseElement.GetString("url")
		responseArtist, _ := responseElement.GetString("artist")
		responseTitle, _ := responseElement.GetString("title")

		conCounter += 1
		wg.Add(1)
		go getMusicAsync(&wg, responseURL, responseArtist, responseTitle)
		if conCounter > maxConnectionCount {
			wg.Wait()
			conCounter = 0
		}
	}
	wg.Wait()
}
<|endoftext|>