<commit_before>package broadcast

import (
	"sync"
	"time"
)

const (
	broadcastMainChanBufferSize = 64
	broadcastChanBufferSize     = 32
	broadcastSendTimeout        = time.Millisecond * 100
)

type BroadcastMessage string

type GroupBroadcast struct {
	chStop chan struct{}
	chMain chan BroadcastMessage
	chs    []chan BroadcastMessage
	chsMux *sync.RWMutex

	flagStarted bool
}

func NewGroupBroadcast() *GroupBroadcast {
	return &GroupBroadcast{
		chStop: make(chan struct{}),
		chMain: make(chan BroadcastMessage, broadcastMainChanBufferSize),
		chs:    make([]chan BroadcastMessage, 0),
		chsMux: &sync.RWMutex{},
	}
}

func (gb *GroupBroadcast) BroadcastMessageTimeout(message BroadcastMessage, timeout time.Duration) bool {
	var timer = time.NewTimer(timeout)
	defer timer.Stop()

	select {
	case gb.chMain <- message:
		return true
	case <-gb.chStop:
	case <-timer.C:
	}

	return false
}

func (gb *GroupBroadcast) BroadcastMessage(message BroadcastMessage) {
	select {
	case gb.chMain <- message:
	case <-gb.chStop:
	}
}

func (gb *GroupBroadcast) Start(stop <-chan struct{}) {
	if gb.flagStarted {
		return
	}
	gb.flagStarted = true

	go func() {
		select {
		case <-stop:
		}
		gb.stop()
	}()

	go func() {
		for {
			select {
			case message, ok := <-gb.chMain:
				if !ok {
					return
				}
				gb.broadcast(message)
			case <-gb.chStop:
				return
			}
		}
	}()
}

func (gb *GroupBroadcast) broadcast(message BroadcastMessage) {
	gb.chsMux.RLock()
	defer gb.chsMux.RUnlock()

	for _, ch := range gb.chs {
		select {
		case ch <- message:
		case <-gb.chStop:
		}
	}
}

func (gb *GroupBroadcast) createChan() chan BroadcastMessage {
	ch := make(chan BroadcastMessage, broadcastChanBufferSize)

	gb.chsMux.Lock()
	gb.chs = append(gb.chs, ch)
	gb.chsMux.Unlock()

	return ch
}

func (gb *GroupBroadcast) deleteChan(ch chan BroadcastMessage) {
	go func() {
		for range ch {
		}
	}()

	gb.chsMux.Lock()
	for i := range gb.chs {
		if gb.chs[i] == ch {
			gb.chs = append(gb.chs[:i], gb.chs[i+1:]...)
			close(ch)
			break
		}
	}
	gb.chsMux.Unlock()
}

func (gb *GroupBroadcast) ListenMessages(stop <-chan struct{}, buffer uint) <-chan BroadcastMessage {
	ch := gb.createChan()
	chOut := make(chan BroadcastMessage, buffer)

	go func() {
		defer close(chOut)
		defer gb.deleteChan(ch)

		for {
			select {
			case <-stop:
				return
			case <-gb.chStop:
				return
			case message, ok := <-ch:
				if !ok {
					return
				}
				gb.send(chOut, message, stop, broadcastSendTimeout)
			}
		}
	}()

	return chOut
}

func (gb *GroupBroadcast) send(ch chan BroadcastMessage, message BroadcastMessage, stop <-chan struct{}, timeout time.Duration) {
	const tickSize = 5

	var timer = time.NewTimer(timeout)
	defer timer.Stop()

	var ticker = time.NewTicker(timeout / tickSize)
	defer ticker.Stop()

	if cap(ch) == 0 {
		select {
		case ch <- message:
		case <-gb.chStop:
		case <-stop:
		case <-timer.C:
		}
	} else {
		for {
			select {
			case ch <- message:
				return
			case <-gb.chStop:
				return
			case <-stop:
				return
			case <-timer.C:
				return
			case <-ticker.C:
				if len(ch) == cap(ch) {
					select {
					case <-ch:
					case ch <- message:
						return
					case <-stop:
						return
					case <-gb.chStop:
						return
					case <-timer.C:
						return
					}
				}
			}
		}
	}
}

func (gb *GroupBroadcast) stop() {
	close(gb.chStop)
	close(gb.chMain)

	gb.chsMux.Lock()
	defer gb.chsMux.Unlock()

	for _, ch := range gb.chs {
		close(ch)
	}

	gb.chs = gb.chs[:0]
}
<commit_msg>Invrease broadcast chan buffer size<commit_after>package broadcast

import (
	"sync"
	"time"
)

const (
	broadcastMainChanBufferSize = 64
	broadcastChanBufferSize     = 64
	broadcastSendTimeout        = time.Millisecond * 100
)

type BroadcastMessage string

type GroupBroadcast struct {
	chStop chan struct{}
	chMain chan BroadcastMessage
	chs    []chan BroadcastMessage
	chsMux *sync.RWMutex

	flagStarted bool
}

func NewGroupBroadcast() *GroupBroadcast {
	return &GroupBroadcast{
		chStop: make(chan struct{}),
		chMain: make(chan BroadcastMessage, broadcastMainChanBufferSize),
		chs:    make([]chan BroadcastMessage, 0),
		chsMux: &sync.RWMutex{},
	}
}

func (gb *GroupBroadcast) BroadcastMessageTimeout(message BroadcastMessage, timeout time.Duration) bool {
	var timer = time.NewTimer(timeout)
	defer timer.Stop()

	select {
	case gb.chMain <- message:
		return true
	case <-gb.chStop:
	case <-timer.C:
	}

	return false
}

func (gb *GroupBroadcast) BroadcastMessage(message BroadcastMessage) {
	select {
	case gb.chMain <- message:
	case <-gb.chStop:
	}
}

func (gb *GroupBroadcast) Start(stop <-chan struct{}) {
	if gb.flagStarted {
		return
	}
	gb.flagStarted = true

	go func() {
		select {
		case <-stop:
		}
		gb.stop()
	}()

	go func() {
		for {
			select {
			case message, ok := <-gb.chMain:
				if !ok {
					return
				}
				gb.broadcast(message)
			case <-gb.chStop:
				return
			}
		}
	}()
}

func (gb *GroupBroadcast) broadcast(message BroadcastMessage) {
	gb.chsMux.RLock()
	defer gb.chsMux.RUnlock()

	for _, ch := range gb.chs {
		select {
		case ch <- message:
		case <-gb.chStop:
		}
	}
}

func (gb *GroupBroadcast) createChan() chan BroadcastMessage {
	ch := make(chan BroadcastMessage, broadcastChanBufferSize)

	gb.chsMux.Lock()
	gb.chs = append(gb.chs, ch)
	gb.chsMux.Unlock()

	return ch
}

func (gb *GroupBroadcast) deleteChan(ch chan BroadcastMessage) {
	go func() {
		for range ch {
		}
	}()

	gb.chsMux.Lock()
	for i := range gb.chs {
		if gb.chs[i] == ch {
			gb.chs = append(gb.chs[:i], gb.chs[i+1:]...)
			close(ch)
			break
		}
	}
	gb.chsMux.Unlock()
}

func (gb *GroupBroadcast) ListenMessages(stop <-chan struct{}, buffer uint) <-chan BroadcastMessage {
	ch := gb.createChan()
	chOut := make(chan BroadcastMessage, buffer)

	go func() {
		defer close(chOut)
		defer gb.deleteChan(ch)

		for {
			select {
			case <-stop:
				return
			case <-gb.chStop:
				return
			case message, ok := <-ch:
				if !ok {
					return
				}
				gb.send(chOut, message, stop, broadcastSendTimeout)
			}
		}
	}()

	return chOut
}

func (gb *GroupBroadcast) send(ch chan BroadcastMessage, message BroadcastMessage, stop <-chan struct{}, timeout time.Duration) {
	const tickSize = 5

	var timer = time.NewTimer(timeout)
	defer timer.Stop()

	var ticker = time.NewTicker(timeout / tickSize)
	defer ticker.Stop()

	if cap(ch) == 0 {
		select {
		case ch <- message:
		case <-gb.chStop:
		case <-stop:
		case <-timer.C:
		}
	} else {
		for {
			select {
			case ch <- message:
				return
			case <-gb.chStop:
				return
			case <-stop:
				return
			case <-timer.C:
				return
			case <-ticker.C:
				if len(ch) == cap(ch) {
					select {
					case <-ch:
					case ch <- message:
						return
					case <-stop:
						return
					case <-gb.chStop:
						return
					case <-timer.C:
						return
					}
				}
			}
		}
	}
}

func (gb *GroupBroadcast) stop() {
	close(gb.chStop)
	close(gb.chMain)

	gb.chsMux.Lock()
	defer gb.chsMux.Unlock()

	for _, ch := range gb.chs {
		close(ch)
	}

	gb.chs = gb.chs[:0]
}
<|endoftext|>


<commit_before>package activity

import (
	"reflect"
	"time"

	"github.com/tolexo/aero/activity/model"
	"github.com/tolexo/aero/db/tmongo"
	mgo "gopkg.in/mgo.v2"
)

const (
	DB_CONTAINER = "database.omni"
)

//Log User activity
func LogActivity(url string, body interface{},
	resp reflect.Value, respCode int, respTime float64) {
	apiDetail := model.APIDetail{
		Url:      url,
		Body:     body,
		Resp:     resp.Interface(),
		RespCode: respCode,
		RespTime: respTime,
		Time:     time.Now(),
	}
	go func() {
		if sess, mdb, err := tmongo.GetMongoConn(DB_CONTAINER); err == nil {
			defer sess.Close()
			sess.SetSafe(&mgo.Safe{W: 0})
			sess.DB(mdb).C("activity").Insert(apiDetail)
		}
	}()
}
<commit_msg>PRA-410: worker removed<commit_after>package activity

import (
	"reflect"
	"time"

	"github.com/tolexo/aero/activity/model"
	"github.com/tolexo/aero/db/tmongo"
	mgo "gopkg.in/mgo.v2"
)

const (
	DB_CONTAINER = "database.omni"
)

//Log User activity
func LogActivity(url string, body interface{},
	resp reflect.Value, respCode int, respTime float64) {
	apiDetail := model.APIDetail{
		Url:      url,
		Body:     body,
		Resp:     resp.Interface(),
		RespCode: respCode,
		RespTime: respTime,
		Time:     time.Now(),
	}
	if sess, mdb, err := tmongo.GetMongoConn(DB_CONTAINER); err == nil {
		defer sess.Close()
		sess.SetSafe(&mgo.Safe{W: 0})
		sess.DB(mdb).C("activity").Insert(apiDetail)
	}
}
<|endoftext|>


<commit_before>package builder

// nginx
const (
	NginxVersion           = "1.13.10"
	NginxDownloadURLPrefix = "https://nginx.org/download"
)

// pcre
const (
	PcreVersion           = "8.41"
	PcreDownloadURLPrefix = "https://ftp.pcre.org/pub/pcre"
)

// openssl
const (
	OpenSSLVersion           = "1.0.2n"
	OpenSSLDownloadURLPrefix = "https://www.openssl.org/source"
)

// libressl
const (
	LibreSSLVersion           = "2.6.4"
	LibreSSLDownloadURLPrefix = "https://ftp.openbsd.org/pub/OpenBSD/LibreSSL"
)

// zlib
const (
	ZlibVersion           = "1.2.11"
	ZlibDownloadURLPrefix = "https://zlib.net/fossils"
)

// openResty
const (
	OpenRestyVersion           = "1.13.6.1"
	OpenRestyDownloadURLPrefix = "https://openresty.org/download"
)

// tengine
const (
	TengineVersion           = "2.2.2"
	TengineDownloadURLPrefix = "http://tengine.taobao.org/download"
)

// component enumerations
const (
	ComponentNginx = iota
	ComponentOpenResty
	ComponentTengine
	ComponentPcre
	ComponentOpenSSL
	ComponentLibreSSL
	ComponentZlib
	ComponentMax
)
<commit_msg>bumped default openssl version to 1.0.2o.<commit_after>package builder

// nginx
const (
	NginxVersion           = "1.13.10"
	NginxDownloadURLPrefix = "https://nginx.org/download"
)

// pcre
const (
	PcreVersion           = "8.41"
	PcreDownloadURLPrefix = "https://ftp.pcre.org/pub/pcre"
)

// openssl
const (
	OpenSSLVersion           = "1.0.2o"
	OpenSSLDownloadURLPrefix = "https://www.openssl.org/source"
)

// libressl
const (
	LibreSSLVersion           = "2.6.4"
	LibreSSLDownloadURLPrefix = "https://ftp.openbsd.org/pub/OpenBSD/LibreSSL"
)

// zlib
const (
	ZlibVersion           = "1.2.11"
	ZlibDownloadURLPrefix = "https://zlib.net/fossils"
)

// openResty
const (
	OpenRestyVersion           = "1.13.6.1"
	OpenRestyDownloadURLPrefix = "https://openresty.org/download"
)

// tengine
const (
	TengineVersion           = "2.2.2"
	TengineDownloadURLPrefix = "http://tengine.taobao.org/download"
)

// component enumerations
const (
	ComponentNginx = iota
	ComponentOpenResty
	ComponentTengine
	ComponentPcre
	ComponentOpenSSL
	ComponentLibreSSL
	ComponentZlib
	ComponentMax
)
<|endoftext|>


<commit_before>package build

import (
	"archive/zip"
	"encoding/json"
	"github.com/lonnc/golang-nw"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"
	"text/template"
)

type Package struct {
	Name   string `json:"name"`
	Main   string `json:"main"`
	Window Window `json:"window"`
	Bin    string `json:"-"`
	EnvVar string `json:"-"`
}

type Window struct {
	Title    string `json:"title,omitempty"`
	Toolbar  bool   `json:"toolbar"`
	Show     bool   `json:"show,omitempty"`
	Position string `json:"position,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
}

type Templates struct {
	IndexHtml string
	ClientJs  string
	ScriptJs  string
}

var DefaultTemplates = Templates{IndexHtml: index, ClientJs: client, ScriptJs: script}

// CreateNW creates a node-webkit .nw file
func (p Package) CreateNW(zw *zip.Writer, templates Templates, myapp io.Reader, includes string) error {
	// Add in a couple of package defaults
	p.Main = "index.html"
	p.EnvVar = nw.EnvVar

	if w, err := zw.Create("package.json"); err != nil {
		return err
	} else {
		if _, err := p.writeJsonTo(w); err != nil {
			return err
		}
	}

	filenameTemplates := map[string]string{
		"index.html": templates.IndexHtml,
		"client.js":  templates.ClientJs,
		"script.js":  templates.ScriptJs}
	for filename, str := range filenameTemplates {
		if w, err := zw.Create(filename); err != nil {
			return err
		} else {
			if t, err := template.New(filename).Parse(str); err != nil {
				return err
			} else {
				if err := t.Execute(w, p); err != nil {
					return err
				}
			}
		}
	}

	if includes != "" {
		if err := copyIncludes(zw, includes); err != nil {
			return err
		}
	}

	binHeader := zip.FileHeader{Name: p.Bin}
	binHeader.SetMode(0755) // Make it executable
	if w, err := zw.CreateHeader(&binHeader); err != nil {
		return err
	} else {
		if _, err := io.Copy(w, myapp); err != nil {
			return err
		}
	}

	return nil
}

func (p Package) writeJsonTo(w io.Writer) (int64, error) {
	b, err := json.Marshal(p)
	if err != nil {
		return 0, err
	}
	n, err := w.Write(b)
	return int64(n), err
}

// Copy any files from the includes directory
func copyIncludes(zw *zip.Writer, includes string) error {
	includes = path.Clean(includes)
	if !strings.HasSuffix(includes, "/") {
		includes += "/"
	}
	return filepath.Walk(includes, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		if w, err := zw.Create(strings.TrimPrefix(path, includes)); err != nil {
			return err
		} else {
			b, err := ioutil.ReadFile(path)
			if err != nil {
				return err
			} else {
				_, err := w.Write(b)
				if err != nil {
					return err
				}
			}
		}
		return nil
	})
}
<commit_msg>Fix for issue #8 - handling paths in windows.<commit_after>package build

import (
	"archive/zip"
	"encoding/json"
	"github.com/lonnc/golang-nw"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"
	"text/template"
)

type Package struct {
	Name   string `json:"name"`
	Main   string `json:"main"`
	Window Window `json:"window"`
	Bin    string `json:"-"`
	EnvVar string `json:"-"`
}

type Window struct {
	Title    string `json:"title,omitempty"`
	Toolbar  bool   `json:"toolbar"`
	Show     bool   `json:"show,omitempty"`
	Position string `json:"position,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
}

type Templates struct {
	IndexHtml string
	ClientJs  string
	ScriptJs  string
}

var DefaultTemplates = Templates{IndexHtml: index, ClientJs: client, ScriptJs: script}

// CreateNW creates a node-webkit .nw file
func (p Package) CreateNW(zw *zip.Writer, templates Templates, myapp io.Reader, includes string) error {
	// Add in a couple of package defaults
	p.Main = "index.html"
	p.EnvVar = nw.EnvVar

	if w, err := zw.Create("package.json"); err != nil {
		return err
	} else {
		if _, err := p.writeJsonTo(w); err != nil {
			return err
		}
	}

	filenameTemplates := map[string]string{
		"index.html": templates.IndexHtml,
		"client.js":  templates.ClientJs,
		"script.js":  templates.ScriptJs}
	for filename, str := range filenameTemplates {
		if w, err := zw.Create(filename); err != nil {
			return err
		} else {
			if t, err := template.New(filename).Parse(str); err != nil {
				return err
			} else {
				if err := t.Execute(w, p); err != nil {
					return err
				}
			}
		}
	}

	if includes != "" {
		if err := copyIncludes(zw, includes); err != nil {
			return err
		}
	}

	binHeader := zip.FileHeader{Name: p.Bin}
	binHeader.SetMode(0755) // Make it executable
	if w, err := zw.CreateHeader(&binHeader); err != nil {
		return err
	} else {
		if _, err := io.Copy(w, myapp); err != nil {
			return err
		}
	}

	return nil
}

func (p Package) writeJsonTo(w io.Writer) (int64, error) {
	b, err := json.Marshal(p)
	if err != nil {
		return 0, err
	}
	n, err := w.Write(b)
	return int64(n), err
}

// Copy any files from the includes directory
func copyIncludes(zw *zip.Writer, includes string) error {
	includes = path.Clean(includes)
	if !strings.HasSuffix(includes, "/") {
		includes += "/"
	}
	return filepath.Walk(includes, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		path = filepath.ToSlash(path)
		if w, err := zw.Create(strings.TrimPrefix(path, includes)); err != nil {
			return err
		} else {
			b, err := ioutil.ReadFile(path)
			if err != nil {
				return err
			} else {
				_, err := w.Write(b)
				if err != nil {
					return err
				}
			}
		}
		return nil
	})
}
<|endoftext|>


<commit_before>package octokit

// Organization is a representation of an organization on GitHub, containing
// all identifying information related to the specific organization.

import (
	"time"
)

var (
	OrganizationURL      = Hyperlink("/orgs/{org}")
	OrganizationReposURL = Hyperlink("/orgs/{org}/repos{?type,page,per_page,sort}")
	YourOrganizationsURL = Hyperlink("/user/orgs")
	UserOrganizationsURL = Hyperlink("/users/{username}/orgs")
)

func (c *Client) Organization() (organization *OrganizationService) {
	organization = &OrganizationService{client: c}
	return
}

// A service for getting as well as updating organization information
type OrganizationService struct {
	client *Client
}

// Get the specified organization's information
func (g *OrganizationService) OrganizationGet(uri *Hyperlink, params M) (
	organization Organization, result *Result) {
	if uri == nil {
		uri = &OrganizationURL
	}
	url, err := uri.Expand(params)
	if err != nil {
		return Organization{}, &Result{Err: err}
	}
	result = g.client.get(url, &organization)
	return
}

// Update specified organization's information
func (g *OrganizationService) OrganizationUpdate(uri *Hyperlink,
	input OrganizationParams, URLParams M) (organization Organization,
	result *Result) {
	if uri == nil {
		uri = &OrganizationURL
	}
	url, err := uri.Expand(URLParams)
	if err != nil {
		return Organization{}, &Result{Err: err}
	}
	result = g.client.patch(url, input, &organization)
	return
}

// Get the list of repository information of an organization
func (g *OrganizationService) OrganizationRepos(uri *Hyperlink, params M) (
	repos []Repository, result *Result) {
	if uri == nil {
		uri = &OrganizationReposURL
	}
	url, err := uri.Expand(params)
	if err != nil {
		return nil, &Result{Err: err}
	}
	result = g.client.get(url, &repos)
	return
}

// Get information for the list of organizations the current user belongs to
func (g *OrganizationService) YourOrganizations(uri *Hyperlink, params M) (
	organizations []Organization, result *Result) {
	if uri == nil {
		uri = &YourOrganizationsURL
	}
	url, err := uri.Expand(params)
	if err != nil {
		return nil, &Result{Err: err}
	}
	result = g.client.get(url, &organizations)
	return
}

// Get the information for the list of organizations the specified user belongs to
func (g *OrganizationService) UserOrganizations(uri *Hyperlink, params M) (
	organizations []Organization, result *Result) {
	if uri == nil {
		uri = &UserOrganizationsURL
	}
	url, err := uri.Expand(params)
	if err != nil {
		return nil, &Result{Err: err}
	}
	result = g.client.get(url, &organizations)
	return
}

type Organization struct {
	Description      string     `json:"description, omitempty"`
	AvatarURL        string     `json:"avatar_url,omitempty"`
	PublicMembersURL Hyperlink  `json:"public_member_url,omitempty"`
	MembersURL       Hyperlink  `json:"members_url,omitempty"`
	EventsURL        Hyperlink  `json:"events_url,omitempty"`
	ReposURL         Hyperlink  `json:"repos_url,omitempty"`
	URL              string     `json:"url,omitempty"`
	ID               int        `json:"id,omitempty"`
	Login            string     `json:"login,omitempty"`
	Name             string     `json:"name, omitempty"`
	Company          string     `json:"company, omitempty"`
	Blog             string     `json:"blog, omitempty"`
	Location         string     `json:"location, omitempty"`
	Email            string     `json:"email, omitempty"`
	PublicRepos      int        `json:"public_repos,omitempty"`
	PublicGists      int        `json:"public_gists,omitempty"`
	Followers        int        `json:"followers,omitempty"`
	Followering      int        `json:"following,omitempty"`
	HTMLURL          string     `json:"html_url,omitempty"`
	CreatedAt        *time.Time `json:"created_at,omitempty"`
	UpdatedAt        *time.Time `json:"updated_at,omitempty"`
	Type             string     `json:"type,omitempty"`

	//Limited Access Fields
	Total_Private_Repos int    `json:"total_private_repos,omitempty"`
	Owned_Private_Repos int    `json:"owned_private_repos,omitempty"`
	Private_Gists       int    `json:"private_gists,omitempty"`
	Disk_Usage          int    `json:"disk_usage,omitempty"`
	Collaborators       int    `json:"collaborators,omitempty"`
	BillingEmail        string `json:"billing_email,omitempty"`
	Plan                Plan   `json:"plan,omitempty"`
}

type Plan struct {
	Name         string `json:"name,omitempty"`
	Space        int    `json:"space,omitempty"`
	PrivateRepos int    `json:"private_repos,omitempty"`
}

// OrganizationParams represents the struture used to create or update an Organization
type OrganizationParams struct {
	BillingEmail string `json:"billing_email,omitempty"`
	Blog         string `json:"blog,omitempty"`
	Company      string `json:"company,omitempty"`
	Email        string `json:"email,omitempty"`
	Location     string `json:"location,omitempty"`
	Name         string `json:"name,omitempty"`
	Description  string `json:"description,omitempty"`
}
<commit_msg>Doc urls orgs<commit_after>package octokit

// Organization is a representation of an organization on GitHub, containing
// all identifying information related to the specific organization.

import (
	"time"
)

var (
	OrganizationURL      = Hyperlink("/orgs/{org}")
	OrganizationReposURL = Hyperlink("/orgs/{org}/repos{?type,page,per_page,sort}")
	YourOrganizationsURL = Hyperlink("/user/orgs")
	UserOrganizationsURL = Hyperlink("/users/{username}/orgs")
)

func (c *Client) Organization() (organization *OrganizationService) {
	organization = &OrganizationService{client: c}
	return
}

// A service for getting as well as updating organization information
type OrganizationService struct {
	client *Client
}

// Get the specified organization's information
//
// https://developer.github.com/v3/orgs/#get-an-organization
func (g *OrganizationService) OrganizationGet(uri *Hyperlink, params M) (
	organization Organization, result *Result) {
	if uri == nil {
		uri = &OrganizationURL
	}
	url, err := uri.Expand(params)
	if err != nil {
		return Organization{}, &Result{Err: err}
	}
	result = g.client.get(url, &organization)
	return
}

// Update specified organization's information
//
// https://developer.github.com/v3/orgs/#edit-an-organization
func (g *OrganizationService) OrganizationUpdate(uri *Hyperlink,
	input OrganizationParams, URLParams M) (organization Organization,
	result *Result) {
	if uri == nil {
		uri = &OrganizationURL
	}
	url, err := uri.Expand(URLParams)
	if err != nil {
		return Organization{}, &Result{Err: err}
	}
	result = g.client.patch(url, input, &organization)
	return
}

// Get the list of repository information of an organization
//
// https://developer.github.com/v3/repos/#list-organization-repositories
func (g *OrganizationService) OrganizationRepos(uri *Hyperlink, params M) (
	repos []Repository, result *Result) {
	if uri == nil {
		uri = &OrganizationReposURL
	}
	url, err := uri.Expand(params)
	if err != nil {
		return nil, &Result{Err: err}
	}
	result = g.client.get(url, &repos)
	return
}

// Get information for the list of organizations the current user belongs to
//
// https://developer.github.com/v3/orgs/#list-your-organizations
func (g *OrganizationService) YourOrganizations(uri *Hyperlink, params M) (
	organizations []Organization, result *Result) {
	if uri == nil {
		uri = &YourOrganizationsURL
	}
	url, err := uri.Expand(params)
	if err != nil {
		return nil, &Result{Err: err}
	}
	result = g.client.get(url, &organizations)
	return
}

// Get the information for the list of organizations the specified user belongs to
//
// https://developer.github.com/v3/orgs/#list-user-organizations
func (g *OrganizationService) UserOrganizations(uri *Hyperlink, params M) (
	organizations []Organization, result *Result) {
	if uri == nil {
		uri = &UserOrganizationsURL
	}
	url, err := uri.Expand(params)
	if err != nil {
		return nil, &Result{Err: err}
	}
	result = g.client.get(url, &organizations)
	return
}

type Organization struct {
	Description      string     `json:"description, omitempty"`
	AvatarURL        string     `json:"avatar_url,omitempty"`
	PublicMembersURL Hyperlink  `json:"public_member_url,omitempty"`
	MembersURL       Hyperlink  `json:"members_url,omitempty"`
	EventsURL        Hyperlink  `json:"events_url,omitempty"`
	ReposURL         Hyperlink  `json:"repos_url,omitempty"`
	URL              string     `json:"url,omitempty"`
	ID               int        `json:"id,omitempty"`
	Login            string     `json:"login,omitempty"`
	Name             string     `json:"name, omitempty"`
	Company          string     `json:"company, omitempty"`
	Blog             string     `json:"blog, omitempty"`
	Location         string     `json:"location, omitempty"`
	Email            string     `json:"email, omitempty"`
	PublicRepos      int        `json:"public_repos,omitempty"`
	PublicGists      int        `json:"public_gists,omitempty"`
	Followers        int        `json:"followers,omitempty"`
	Followering      int        `json:"following,omitempty"`
	HTMLURL          string     `json:"html_url,omitempty"`
	CreatedAt        *time.Time `json:"created_at,omitempty"`
	UpdatedAt        *time.Time `json:"updated_at,omitempty"`
	Type             string     `json:"type,omitempty"`

	//Limited Access Fields
	Total_Private_Repos int    `json:"total_private_repos,omitempty"`
	Owned_Private_Repos int    `json:"owned_private_repos,omitempty"`
	Private_Gists       int    `json:"private_gists,omitempty"`
	Disk_Usage          int    `json:"disk_usage,omitempty"`
	Collaborators       int    `json:"collaborators,omitempty"`
	BillingEmail        string `json:"billing_email,omitempty"`
	Plan                Plan   `json:"plan,omitempty"`
}

type Plan struct {
	Name         string `json:"name,omitempty"`
	Space        int    `json:"space,omitempty"`
	PrivateRepos int    `json:"private_repos,omitempty"`
}

// OrganizationParams represents the struture used to create or update an Organization
type OrganizationParams struct {
	BillingEmail string `json:"billing_email,omitempty"`
	Blog         string `json:"blog,omitempty"`
	Company      string `json:"company,omitempty"`
	Email        string `json:"email,omitempty"`
	Location     string `json:"location,omitempty"`
	Name         string `json:"name,omitempty"`
	Description  string `json:"description,omitempty"`
}
<|endoftext|>


<commit_before>package intgeom

import (
	"math"

	"github.com/oakmound/oak/v2/alg"
)

// Point2 represents a 2D point in space.
type Point2 [2]int

// Point3 represents a 3D point in space.
type Point3 [3]int

// Dim returns the value of p in the ith dimension.
// Panics if i > 1. No check is made for efficiency's sake, pending benchmarks,
// but adding an error here would significantly worsen the API.
func (p Point2) Dim(i int) int {
	return p[i]
}

// Dim returns the value of p in the ith dimension.
// Panics if i > 2. No check is made for efficiency's sake, pending benchmarks,
// but adding an error here would significantly worsen the API.
func (p Point3) Dim(i int) int {
	return p[i]
}

// X returns p's value on the X axis.
func (p Point2) X() int {
	return p.Dim(0)
}

// Y returns p's value on the Y axis.
func (p Point2) Y() int {
	return p.Dim(1)
}

// X returns p's value on the X axis.
func (p Point3) X() int {
	return p.Dim(0)
}

// Y returns p's value on the Y axis.
func (p Point3) Y() int {
	return p.Dim(1)
}

// Z returns p's value on the Z axis.
func (p Point3) Z() int {
	return p.Dim(2)
}

// Distance calculates the distance between this Point2 and another.
func (p Point2) Distance(p2 Point2) float64 {
	return Distance2(p.X(), p.Y(), p2.X(), p2.Y())
}

// Distance calculates the distance between this Point3 and another.
func (p Point3) Distance(p2 Point3) float64 {
	return Distance3(p.X(), p.Y(), p.Z(), p2.X(), p2.Y(), p2.Z())
}

// Distance2 calculates the euclidean distance between two points, as two (x,y) pairs
func Distance2(x1, y1, x2, y2 int) float64 {
	return math.Sqrt(
		math.Pow(float64(x1-x2), 2) +
			math.Pow(float64(y1-y2), 2))
}

// Distance3 calculates the euclidean distance between two points, as two (x,y,z) triplets
func Distance3(x1, y1, z1, x2, y2, z2 int) float64 {
	return math.Sqrt(
		math.Pow(float64(x1-x2), 2) +
			math.Pow(float64(y1-y2), 2) +
			math.Pow(float64(z1-z2), 2))
}

// LesserOf returns the lowest values on each axis of the input points as a point.
func (p Point2) LesserOf(ps ...Point2) Point2 {
	for _, p2 := range ps {
		if p2[0] < p[0] {
			p[0] = p2[0]
		}
		if p2[1] < p[1] {
			p[1] = p2[1]
		}
	}
	return p
}

// LesserOf returns the lowest values on each axis of the input points as a point.
func (p Point3) LesserOf(ps ...Point3) Point3 {
	for _, p2 := range ps {
		if p2[0] < p[0] {
			p[0] = p2[0]
		}
		if p2[1] < p[1] {
			p[1] = p2[1]
		}
		if p2[2] < p[2] {
			p[2] = p2[2]
		}
	}
	return p
}

// GreaterOf returns the highest values on each axis of the input points as a point.
func (p Point2) GreaterOf(ps ...Point2) Point2 {
	for _, p2 := range ps {
		if p2[0] > p[0] {
			p[0] = p2[0]
		}
		if p2[1] > p[1] {
			p[1] = p2[1]
		}
	}
	return p
}

// GreaterOf returns the highest values on each axis of the input points as a point.
func (p Point3) GreaterOf(ps ...Point3) Point3 {
	for _, p2 := range ps {
		if p2[0] > p[0] {
			p[0] = p2[0]
		}
		if p2[1] > p[1] {
			p[1] = p2[1]
		}
		if p2[2] > p[2] {
			p[2] = p2[2]
		}
	}
	return p
}

// Add combines the input points via addition.
func (p Point2) Add(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] += p2[0]
		p[1] += p2[1]
	}
	return p
}

// Sub combines the input points via subtraction.
func (p Point2) Sub(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] -= p2[0]
		p[1] -= p2[1]
	}
	return p
}

// Mul combines in the input points via multiplication.
func (p Point2) Mul(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] *= p2[0]
		p[1] *= p2[1]
	}
	return p
}

// MulConst multiplies all elements of a point by the input floats
func (p Point2) MulConst(fs ...int) Point2 {
	for _, f := range fs {
		p[0] *= f
		p[1] *= f
	}
	return p
}

// Div combines the input points via division.
// Div does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point2) Div(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] /= p2[0]
		p[1] /= p2[1]
	}
	return p
}

// DivConst divides all elements of a point by the input floats
// DivConst does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point2) DivConst(fs ...int) Point2 {
	for _, f := range fs {
		p[0] /= f
		p[1] /= f
	}
	return p
}

// Add combines the input points via addition.
func (p Point3) Add(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] += p2[0]
		p[1] += p2[1]
		p[2] += p2[2]
	}
	return p
}

// Sub combines the input points via subtraction.
func (p Point3) Sub(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] -= p2[0]
		p[1] -= p2[1]
		p[2] -= p2[2]
	}
	return p
}

// Mul combines in the input points via multiplication.
func (p Point3) Mul(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] *= p2[0]
		p[1] *= p2[1]
		p[2] *= p2[2]
	}
	return p
}

// MulConst multiplies all elements of a point by the input floats
func (p Point3) MulConst(fs ...int) Point3 {
	for _, f := range fs {
		p[0] *= f
		p[1] *= f
		p[2] *= f
	}
	return p
}

// Div combines the input points via division.
// Div does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point3) Div(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] /= p2[0]
		p[1] /= p2[1]
		p[2] /= p2[2]
	}
	return p
}

// DivConst divides all elements of a point by the input floats
// DivConst does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point3) DivConst(fs ...int) Point3 {
	for _, f := range fs {
		p[0] /= f
		p[1] /= f
		p[2] /= f
	}
	return p
}

// Dot returns the dot product of the input points
func (p Point2) Dot(p2 Point2) int {
	return p[0]*p2[0] + p[1]*p2[1]
}

// Dot returns the dot product of the input points
func (p Point3) Dot(p2 Point3) int {
	return p[0]*p2[0] + p[1]*p2[1] + p[2]*p2[2]
}

// Magnitude returns the magnitude of the combined components of a Point
func (p Point2) Magnitude() float64 {
	return math.Sqrt(float64(p.Dot(p)))
}

// Magnitude returns the magnitude of the combined components of a Point
func (p Point3) Magnitude() float64 {
	return math.Sqrt(float64(p.Dot(p)))
}

// ToRect converts this point into a rectangle spanning span distance
// in each axis.
func (p Point2) ToRect(span int) Rect2 {
	return NewRect2WH(p[0], p[1], span, span)
}

// ToRect converts this point into a rectangle spanning span distance
// in each axis.
func (p Point3) ToRect(span int) Rect3 {
	return NewRect3WH(p[0], p[1], p[2], span, span, span)
}

// ProjectX projects the Point3 onto the x axis, removing it's
// x component and returning a Point2
// todo: I'm not sure about this (these) function name
func (p Point3) ProjectX() Point2 {
	return Point2{p[1], p[2]}
}

// ProjectY projects the Point3 onto the y axis, removing it's
// y component and returning a Point2
func (p Point3) ProjectY() Point2 {
	return Point2{p[0], p[2]}
}

// ProjectZ projects the Point3 onto the z axis, removing it's
// z component and returning a Point2
func (p Point3) ProjectZ() Point2 {
	return Point2{p[0], p[1]}
}

// ToAngle returns this point as an angle in degrees.
func (p Point2) ToAngle() float64 {
	return p.ToRadians() * alg.RadToDeg
}

// ToRadians returns this point as an angle in radians.
func (p Point2) ToRadians() float64 {
	return math.Atan2(float64(p[1]), float64(p[0]))
}

// AngleTo returns the angle from p to p2 in degrees.
func (p Point2) AngleTo(p2 Point2) float64 {
	return p.Sub(p2).ToAngle()
}

// RadiansTo returns the angle from p to p2 in radians.
func (p Point2) RadiansTo(p2 Point2) float64 {
	return p.Sub(p2).ToRadians()
}
<commit_msg>Update integom accesor docs<commit_after>package intgeom

import (
	"math"

	"github.com/oakmound/oak/v2/alg"
)

// Point2 represents a 2D point in space.
type Point2 [2]int

// Point3 represents a 3D point in space.
type Point3 [3]int

// Dim returns the value of p in the ith dimension.
// Panics if i > 1. No check is made for efficiency's sake, pending benchmarks,
// but adding an error here would significantly worsen the API.
func (p Point2) Dim(i int) int {
	return p[i]
}

// Dim returns the value of p in the ith dimension.
// Panics if i > 2. No check is made for efficiency's sake, pending benchmarks,
// but adding an error here would significantly worsen the API.
func (p Point3) Dim(i int) int {
	return p[i]
}

// X returns the point's value on the X axis.
func (p Point2) X() int {
	return p.Dim(0)
}

// Y returns the point's value on the Y axis.
func (p Point2) Y() int {
	return p.Dim(1)
}

// X returns the point's value on the X axis.
func (p Point3) X() int {
	return p.Dim(0)
}

// Y returns the point's value on the Y axis.
func (p Point3) Y() int {
	return p.Dim(1)
}

// Z returns the point's value on the Z axis.
func (p Point3) Z() int {
	return p.Dim(2)
}

// Distance calculates the distance between this Point2 and another.
func (p Point2) Distance(p2 Point2) float64 {
	return Distance2(p.X(), p.Y(), p2.X(), p2.Y())
}

// Distance calculates the distance between this Point3 and another.
func (p Point3) Distance(p2 Point3) float64 {
	return Distance3(p.X(), p.Y(), p.Z(), p2.X(), p2.Y(), p2.Z())
}

// Distance2 calculates the euclidean distance between two points, as two (x,y) pairs
func Distance2(x1, y1, x2, y2 int) float64 {
	return math.Sqrt(
		math.Pow(float64(x1-x2), 2) +
			math.Pow(float64(y1-y2), 2))
}

// Distance3 calculates the euclidean distance between two points, as two (x,y,z) triplets
func Distance3(x1, y1, z1, x2, y2, z2 int) float64 {
	return math.Sqrt(
		math.Pow(float64(x1-x2), 2) +
			math.Pow(float64(y1-y2), 2) +
			math.Pow(float64(z1-z2), 2))
}

// LesserOf returns the lowest values on each axis of the input points as a point.
func (p Point2) LesserOf(ps ...Point2) Point2 {
	for _, p2 := range ps {
		if p2[0] < p[0] {
			p[0] = p2[0]
		}
		if p2[1] < p[1] {
			p[1] = p2[1]
		}
	}
	return p
}

// LesserOf returns the lowest values on each axis of the input points as a point.
func (p Point3) LesserOf(ps ...Point3) Point3 {
	for _, p2 := range ps {
		if p2[0] < p[0] {
			p[0] = p2[0]
		}
		if p2[1] < p[1] {
			p[1] = p2[1]
		}
		if p2[2] < p[2] {
			p[2] = p2[2]
		}
	}
	return p
}

// GreaterOf returns the highest values on each axis of the input points as a point.
func (p Point2) GreaterOf(ps ...Point2) Point2 {
	for _, p2 := range ps {
		if p2[0] > p[0] {
			p[0] = p2[0]
		}
		if p2[1] > p[1] {
			p[1] = p2[1]
		}
	}
	return p
}

// GreaterOf returns the highest values on each axis of the input points as a point.
func (p Point3) GreaterOf(ps ...Point3) Point3 {
	for _, p2 := range ps {
		if p2[0] > p[0] {
			p[0] = p2[0]
		}
		if p2[1] > p[1] {
			p[1] = p2[1]
		}
		if p2[2] > p[2] {
			p[2] = p2[2]
		}
	}
	return p
}

// Add combines the input points via addition.
func (p Point2) Add(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] += p2[0]
		p[1] += p2[1]
	}
	return p
}

// Sub combines the input points via subtraction.
func (p Point2) Sub(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] -= p2[0]
		p[1] -= p2[1]
	}
	return p
}

// Mul combines in the input points via multiplication.
func (p Point2) Mul(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] *= p2[0]
		p[1] *= p2[1]
	}
	return p
}

// MulConst multiplies all elements of a point by the input floats
func (p Point2) MulConst(fs ...int) Point2 {
	for _, f := range fs {
		p[0] *= f
		p[1] *= f
	}
	return p
}

// Div combines the input points via division.
// Div does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point2) Div(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] /= p2[0]
		p[1] /= p2[1]
	}
	return p
}

// DivConst divides all elements of a point by the input floats
// DivConst does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point2) DivConst(fs ...int) Point2 {
	for _, f := range fs {
		p[0] /= f
		p[1] /= f
	}
	return p
}

// Add combines the input points via addition.
func (p Point3) Add(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] += p2[0]
		p[1] += p2[1]
		p[2] += p2[2]
	}
	return p
}

// Sub combines the input points via subtraction.
func (p Point3) Sub(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] -= p2[0]
		p[1] -= p2[1]
		p[2] -= p2[2]
	}
	return p
}

// Mul combines in the input points via multiplication.
func (p Point3) Mul(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] *= p2[0]
		p[1] *= p2[1]
		p[2] *= p2[2]
	}
	return p
}

// MulConst multiplies all elements of a point by the input floats
func (p Point3) MulConst(fs ...int) Point3 {
	for _, f := range fs {
		p[0] *= f
		p[1] *= f
		p[2] *= f
	}
	return p
}

// Div combines the input points via division.
// Div does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point3) Div(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] /= p2[0]
		p[1] /= p2[1]
		p[2] /= p2[2]
	}
	return p
}

// DivConst divides all elements of a point by the input floats
// DivConst does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point3) DivConst(fs ...int) Point3 {
	for _, f := range fs {
		p[0] /= f
		p[1] /= f
		p[2] /= f
	}
	return p
}

// Dot returns the dot product of the input points
func (p Point2) Dot(p2 Point2) int {
	return p[0]*p2[0] + p[1]*p2[1]
}

// Dot returns the dot product of the input points
func (p Point3) Dot(p2 Point3) int {
	return p[0]*p2[0] + p[1]*p2[1] + p[2]*p2[2]
}

// Magnitude returns the magnitude of the combined components of a Point
func (p Point2) Magnitude() float64 {
	return math.Sqrt(float64(p.Dot(p)))
}

// Magnitude returns the magnitude of the combined components of a Point
func (p Point3) Magnitude() float64 {
	return math.Sqrt(float64(p.Dot(p)))
}

// ToRect converts this point into a rectangle spanning span distance
// in each axis.
func (p Point2) ToRect(span int) Rect2 {
	return NewRect2WH(p[0], p[1], span, span)
}

// ToRect converts this point into a rectangle spanning span distance
// in each axis.
func (p Point3) ToRect(span int) Rect3 {
	return NewRect3WH(p[0], p[1], p[2], span, span, span)
}

// ProjectX projects the Point3 onto the x axis, removing it's
// x component and returning a Point2
// todo: I'm not sure about this (these) function name
func (p Point3) ProjectX() Point2 {
	return Point2{p[1], p[2]}
}

// ProjectY projects the Point3 onto the y axis, removing it's
// y component and returning a Point2
func (p Point3) ProjectY() Point2 {
	return Point2{p[0], p[2]}
}

// ProjectZ projects the Point3 onto the z axis, removing it's
// z component and returning a Point2
func (p Point3) ProjectZ() Point2 {
	return Point2{p[0], p[1]}
}

// ToAngle returns this point as an angle in degrees.
func (p Point2) ToAngle() float64 {
	return p.ToRadians() * alg.RadToDeg
}

// ToRadians returns this point as an angle in radians.
func (p Point2) ToRadians() float64 {
	return math.Atan2(float64(p[1]), float64(p[0]))
}

// AngleTo returns the angle from p to p2 in degrees.
func (p Point2) AngleTo(p2 Point2) float64 {
	return p.Sub(p2).ToAngle()
}

// RadiansTo returns the angle from p to p2 in radians.
func (p Point2) RadiansTo(p2 Point2) float64 {
	return p.Sub(p2).ToRadians()
}
<|endoftext|>


<commit_before>package echo

import (
	"html/template"
	"sync"
)

var (
	mutex         sync.RWMutex
	emptyHTML     = template.HTML(``)
	emptyJS       = template.JS(``)
	emptyCSS      = template.CSS(``)
	emptyHTMLAttr = template.HTMLAttr(``)
)

type store map[string]interface{}

func (s store) Set(key string, value interface{}) store {
	mutex.Lock()
	s[key] = value
	mutex.Unlock()
	return s
}

func (s store) Get(key string) interface{} {
	mutex.RLock()
	defer mutex.RUnlock()
	if v, y := s[key]; y {
		return v
	}
	return nil
}

func (s store) String(key string) string {
	if v, y := s.Get(key).(string); y {
		return v
	}
	return ``
}

func (s store) HTML(key string) template.HTML {
	val := s.Get(key)
	if v, y := val.(template.HTML); y {
		return v
	}
	if v, y := val.(string); y {
		return template.HTML(v)
	}
	return emptyHTML
}

func (s store) HTMLAttr(key string) template.HTMLAttr {
	val := s.Get(key)
	if v, y := val.(template.HTMLAttr); y {
		return v
	}
	if v, y := val.(string); y {
		return template.HTMLAttr(v)
	}
	return emptyHTMLAttr
}

func (s store) JS(key string) template.JS {
	val := s.Get(key)
	if v, y := val.(template.JS); y {
		return v
	}
	if v, y := val.(string); y {
		return template.JS(v)
	}
	return emptyJS
}

func (s store) CSS(key string) template.CSS {
	val := s.Get(key)
	if v, y := val.(template.CSS); y {
		return v
	}
	if v, y := val.(string); y {
		return template.CSS(v)
	}
	return emptyCSS
}

func (s store) Bool(key string) bool {
	if v, y := s.Get(key).(bool); y {
		return v
	}
	return false
}

func (s store) Float64(key string) float64 {
	if v, y := s.Get(key).(float64); y {
		return v
	}
	return 0
}

func (s store) Float32(key string) float32 {
	if v, y := s.Get(key).(float32); y {
		return v
	}
	return 0
}

func (s store) Int8(key string) int8 {
	if v, y := s.Get(key).(int8); y {
		return v
	}
	return 0
}

func (s store) Int16(key string) int16 {
	if v, y := s.Get(key).(int16); y {
		return v
	}
	return 0
}

func (s store) Int(key string) int {
	if v, y := s.Get(key).(int); y {
		return v
	}
	return 0
}

func (s store) Int32(key string) int32 {
	if v, y := s.Get(key).(int32); y {
		return v
	}
	return 0
}

func (s store) Int64(key string) int64 {
	if v, y := s.Get(key).(int64); y {
		return v
	}
	return 0
}

func (s store) Decr(key string, n int64) int64 {
	v, _ := s.Get(key).(int64)
	v -= n
	s.Set(key, v)
	return v
}

func (s store) Incr(key string, n int64) int64 {
	v, _ := s.Get(key).(int64)
	v += n
	s.Set(key, v)
	return v
}

func (s store) Uint8(key string) uint8 {
	if v, y := s.Get(key).(uint8); y {
		return v
	}
	return 0
}

func (s store) Uint16(key string) uint16 {
	if v, y := s.Get(key).(uint16); y {
		return v
	}
	return 0
}

func (s store) Uint(key string) uint {
	if v, y := s.Get(key).(uint); y {
		return v
	}
	return 0
}

func (s store) Uint32(key string) uint32 {
	if v, y := s.Get(key).(uint32); y {
		return v
	}
	return 0
}

func (s store) Uint64(key string) uint64 {
	if v, y := s.Get(key).(uint64); y {
		return v
	}
	return 0
}

func (s store) Delete(keys ...string) {
	mutex.Lock()
	for _, key := range keys {
		if _, y := s[key]; y {
			delete(s, key)
		}
	}
	mutex.Unlock()
}
<commit_msg>update<commit_after>package echo

import (
	"html/template"
	"strconv"
	"sync"
)

var (
	mutex         sync.RWMutex
	emptyHTML     = template.HTML(``)
	emptyJS       = template.JS(``)
	emptyCSS      = template.CSS(``)
	emptyHTMLAttr = template.HTMLAttr(``)
)

type store map[string]interface{}

func (s store) Set(key string, value interface{}) store {
	mutex.Lock()
	s[key] = value
	mutex.Unlock()
	return s
}

func (s store) Get(key string) interface{} {
	mutex.RLock()
	defer mutex.RUnlock()
	if v, y := s[key]; y {
		return v
	}
	return nil
}

func (s store) String(key string) string {
	if v, y := s.Get(key).(string); y {
		return v
	}
	return ``
}

func (s store) HTML(key string) template.HTML {
	val := s.Get(key)
	if v, y := val.(template.HTML); y {
		return v
	}
	if v, y := val.(string); y {
		return template.HTML(v)
	}
	return emptyHTML
}

func (s store) HTMLAttr(key string) template.HTMLAttr {
	val := s.Get(key)
	if v, y := val.(template.HTMLAttr); y {
		return v
	}
	if v, y := val.(string); y {
		return template.HTMLAttr(v)
	}
	return emptyHTMLAttr
}

func (s store) JS(key string) template.JS {
	val := s.Get(key)
	if v, y := val.(template.JS); y {
		return v
	}
	if v, y := val.(string); y {
		return template.JS(v)
	}
	return emptyJS
}

func (s store) CSS(key string) template.CSS {
	val := s.Get(key)
	if v, y := val.(template.CSS); y {
		return v
	}
	if v, y := val.(string); y {
		return template.CSS(v)
	}
	return emptyCSS
}

func (s store) Bool(key string) bool {
	if v, y := s.Get(key).(bool); y {
		return v
	}
	return false
}

func (s store) Float64(key string) float64 {
	val := s.Get(key)
	if v, y := val.(float64); y {
		return v
	}
	if v, y := val.(int64); y {
		return float64(v)
	}
	if v, y := val.(uint64); y {
		return float64(v)
	}
	if v, y := val.(float32); y {
		return float64(v)
	}
	if v, y := val.(int32); y {
		return float64(v)
	}
	if v, y := val.(uint32); y {
		return float64(v)
	}
	if v, y := val.(int); y {
		return float64(v)
	}
	if v, y := val.(uint); y {
		return float64(v)
	}
	if v, y := val.(string); y {
		v, _ := strconv.ParseFloat(v, 64)
		return v
	}
	return 0
}

func (s store) Float32(key string) float32 {
	val := s.Get(key)
	if v, y := val.(float32); y {
		return v
	}
	if v, y := val.(int32); y {
		return float32(v)
	}
	if v, y := val.(uint32); y {
		return float32(v)
	}
	if v, y := val.(string); y {
		v, _ := strconv.ParseFloat(v, 32)
		return float32(v)
	}
	return 0
}

func (s store) Int8(key string) int8 {
	val := s.Get(key)
	if v, y := val.(int8); y {
		return v
	}
	if v, y := val.(string); y {
		v, _ := strconv.ParseInt(v, 10, 8)
		return int8(v)
	}
	return 0
}

func (s store) Int16(key string) int16 {
	val := s.Get(key)
	if v, y := val.(int16); y {
		return v
	}
	if v, y := val.(string); y {
		v, _ := strconv.ParseInt(v, 10, 16)
		return int16(v)
	}
	return 0
}

func (s store) Int(key string) int {
	val := s.Get(key)
	if v, y := val.(int); y {
		return v
	}
	if v, y := val.(string); y {
		v, _ := strconv.Atoi(v)
		return v
	}
	return 0
}

func (s store) Int32(key string) int32 {
	val := s.Get(key)
	if v, y := val.(int32); y {
		return v
	}
	if v, y := val.(string); y {
		v, _ := strconv.ParseInt(v, 10, 32)
		return int32(v)
	}
	return 0
}

func (s store) Int64(key string) int64 {
	val := s.Get(key)
	if v, y := val.(int64); y {
		return v
	}
	if v, y := val.(string); y {
		v, _ := strconv.ParseInt(v, 10, 64)
		return v
	}
	return 0
}

func (s store) Decr(key string, n int64) int64 {
	v, _ := s.Get(key).(int64)
	v -= n
	s.Set(key, v)
	return v
}

func (s store) Incr(key string, n int64) int64 {
	v, _ := s.Get(key).(int64)
	v += n
	s.Set(key, v)
	return v
}

func (s store) Uint8(key string) uint8 {
	val := s.Get(key)
	if v, y := val.(uint8); y {
		return v
	}
	if v, y := val.(string); y {
		v, _ := strconv.ParseUint(v, 10, 8)
		return uint8(v)
	}
	return 0
}

func (s store) Uint16(key string) uint16 {
	val := s.Get(key)
	if v, y := val.(uint16); y {
		return v
	}
	if v, y := val.(string); y {
		v, _ := strconv.ParseUint(v, 10, 16)
		return uint16(v)
	}
	return 0
}

func (s store) Uint(key string) uint {
	val := s.Get(key)
	if v, y := val.(uint); y {
		return v
	}
	if v, y := val.(string); y {
		v, _ := strconv.ParseUint(v, 10, 32)
		return uint(v)
	}
	return 0
}

func (s store) Uint32(key string) uint32 {
	val := s.Get(key)
	if v, y := val.(uint32); y {
		return v
	}
	if v, y := val.(string); y {
		v, _ := strconv.ParseUint(v, 10, 32)
		return uint32(v)
	}
	return 0
}

func (s store) Uint64(key string) uint64 {
	val := s.Get(key)
	if v, y := val.(uint64); y {
		return v
	}
	if v, y := val.(string); y {
		v, _ := strconv.ParseUint(v, 10, 64)
		return v
	}
	return 0
}

func (s store) Delete(keys ...string) {
	mutex.Lock()
	for _, key := range keys {
		if _, y := s[key]; y {
			delete(s, key)
		}
	}
	mutex.Unlock()
}
<|endoftext|>


<commit_before>package channel

import (
	"bytes"
	"errors"
	"io"
	"regexp"
	"sync"
	"time"

	"github.com/scrapli/scrapligo/logging"
	"github.com/scrapli/scrapligo/transport"
	"github.com/scrapli/scrapligo/util"
)

const (
	// DefaultTimeoutOpsSeconds is the default time value for operations -- 60 seconds.
	DefaultTimeoutOpsSeconds = 60
	// DefaultReadDelayMilliSeconds is the default value for the delay between reads of the
	// transport -- 5 milliseconds.
	DefaultReadDelayMilliSeconds = 5
	// DefaultReturnChar is the character used to send an "enter" key to the device, "\n".
	DefaultReturnChar = "\n"

	redacted = "redacted"
)

var (
	promptPattern     *regexp.Regexp //nolint:gochecknoglobals
	promptPatternOnce sync.Once      //nolint:gochecknoglobals
)

func getPromptPattern() *regexp.Regexp {
	promptPatternOnce.Do(func() {
		promptPattern = regexp.MustCompile(`(?im)^[a-z\d.\-@()/:]{1,48}[#>$]\s*$`)
	})

	return promptPattern
}

// NewChannel returns a scrapligo Channel object.
func NewChannel(
	l *logging.Instance,
	t *transport.Transport,
	options ...util.Option,
) (*Channel, error) {
	patterns := getAuthPatterns()

	c := &Channel{
		l: l,
		t: t,

		TimeoutOps: DefaultTimeoutOpsSeconds * time.Second,
		ReadDelay:  DefaultReadDelayMilliSeconds * time.Millisecond,

		UsernamePattern:   patterns.username,
		PasswordPattern:   patterns.password,
		PassphrasePattern: patterns.passphrase,

		PromptPattern: getPromptPattern(),
		ReturnChar:    []byte(DefaultReturnChar),

		done: make(chan bool),

		Q:    util.NewQueue(),
		Errs: make(chan error),

		ChannelLog: nil,
	}

	for _, option := range options {
		err := option(c)
		if err != nil {
			if !errors.Is(err, util.ErrIgnoredOption) {
				return nil, err
			}
		}
	}

	return c, nil
}

// Channel is an object that sits "on top" of a scrapligo Transport object, its purpose in life is
// to read data from the transport into its Q, and provide methods to read "until" an input or an
// expected prompt is seen.
type Channel struct {
	l *logging.Instance
	t *transport.Transport

	TimeoutOps time.Duration
	ReadDelay  time.Duration

	AuthBypass bool

	UsernamePattern   *regexp.Regexp
	PasswordPattern   *regexp.Regexp
	PassphrasePattern *regexp.Regexp

	PromptPattern *regexp.Regexp
	ReturnChar    []byte

	done chan bool

	Q    *util.Queue
	Errs chan error

	ChannelLog io.Writer
}

// Open opens the underlying Transport and begins the `read` goroutine, this also kicks off any
// in channel authentication (if necessary).
func (c *Channel) Open() error {
	err := c.t.Open()
	if err != nil {
		c.l.Criticalf("error opening channel, error: %s", err)

		return err
	}

	c.l.Debug("starting channel read loop")

	go c.read()

	if !c.AuthBypass {
		var b []byte

		switch tt := c.t.Impl.(type) {
		case *transport.System:
			c.l.Debug("transport type is 'system', begin in channel ssh authentication")

			b, err = c.AuthenticateSSH([]byte(c.t.Args.Password), []byte(tt.SSHArgs.PrivateKeyPassPhrase))
			if err != nil {
				return err
			}
		case *transport.Telnet:
			c.l.Debug("transport type is 'telnet', begin in channel telnet authentication")

			b, err = c.AuthenticateTelnet([]byte(c.t.Args.User), []byte(c.t.Args.Password))
			if err != nil {
				return err
			}
		}

		if len(b) > 0 {
			// requeue any buffer data we get during in channel authentication back onto the
			// read buffer. mostly this should only be relevant for netconf where we need to
			// read the server capabilities.
			c.Q.Requeue(b)
		}
	} else {
		c.l.Debug("auth bypass is enabled, skipping in channel auth check")
	}

	return nil
}

// Close signals to stop the channel read loop and closes the underlying Transport object.
func (c *Channel) Close() error {
	c.done <- true

	return c.t.Close(false)
}

type result struct {
	b   []byte
	err error
}

func (c *Channel) processOut(b []byte, strip bool) []byte {
	lines := bytes.Split(b, []byte("\n"))

	cleanLines := make([][]byte, len(lines))
	for i, l := range lines {
		cleanLines[i] = bytes.TrimRight(l, " ")
	}

	b = bytes.Join(cleanLines, []byte("\n"))

	if strip {
		b = c.PromptPattern.ReplaceAll(b, nil)
	}

	b = bytes.Trim(b, string(c.ReturnChar))
	b = bytes.Trim(b, "\n")

	return b
}

// GetTimeout returns the target timeout for an operation based on the TimeoutOps attribute of the
// Channel and the value t.
func (c *Channel) GetTimeout(t time.Duration) time.Duration {
	if t == -1 {
		return c.TimeoutOps
	}

	if t == 0 {
		return util.MaxTimeout * time.Second
	}

	return t
}
<commit_msg>decrease channel read delay default<commit_after>package channel

import (
	"bytes"
	"errors"
	"io"
	"regexp"
	"sync"
	"time"

	"github.com/scrapli/scrapligo/logging"
	"github.com/scrapli/scrapligo/transport"
	"github.com/scrapli/scrapligo/util"
)

const (
	// DefaultTimeoutOpsSeconds is the default time value for operations -- 60 seconds.
	DefaultTimeoutOpsSeconds = 60
	// DefaultReadDelayMicroSeconds is the default value for the delay between reads of the
	// transport -- 5 microseconds.
	DefaultReadDelayMicroSeconds = 5
	// DefaultReturnChar is the character used to send an "enter" key to the device, "\n".
	DefaultReturnChar = "\n"

	redacted = "redacted"
)

var (
	promptPattern     *regexp.Regexp //nolint:gochecknoglobals
	promptPatternOnce sync.Once      //nolint:gochecknoglobals
)

func getPromptPattern() *regexp.Regexp {
	promptPatternOnce.Do(func() {
		promptPattern = regexp.MustCompile(`(?im)^[a-z\d.\-@()/:]{1,48}[#>$]\s*$`)
	})

	return promptPattern
}

// NewChannel returns a scrapligo Channel object.
func NewChannel(
	l *logging.Instance,
	t *transport.Transport,
	options ...util.Option,
) (*Channel, error) {
	patterns := getAuthPatterns()

	c := &Channel{
		l: l,
		t: t,

		TimeoutOps: DefaultTimeoutOpsSeconds * time.Second,
		ReadDelay:  DefaultReadDelayMicroSeconds * time.Microsecond,

		UsernamePattern:   patterns.username,
		PasswordPattern:   patterns.password,
		PassphrasePattern: patterns.passphrase,

		PromptPattern: getPromptPattern(),
		ReturnChar:    []byte(DefaultReturnChar),

		done: make(chan bool),

		Q:    util.NewQueue(),
		Errs: make(chan error),

		ChannelLog: nil,
	}

	for _, option := range options {
		err := option(c)
		if err != nil {
			if !errors.Is(err, util.ErrIgnoredOption) {
				return nil, err
			}
		}
	}

	return c, nil
}

// Channel is an object that sits "on top" of a scrapligo Transport object, its purpose in life is
// to read data from the transport into its Q, and provide methods to read "until" an input or an
// expected prompt is seen.
type Channel struct {
	l *logging.Instance
	t *transport.Transport

	TimeoutOps time.Duration
	ReadDelay  time.Duration

	AuthBypass bool

	UsernamePattern   *regexp.Regexp
	PasswordPattern   *regexp.Regexp
	PassphrasePattern *regexp.Regexp

	PromptPattern *regexp.Regexp
	ReturnChar    []byte

	done chan bool

	Q    *util.Queue
	Errs chan error

	ChannelLog io.Writer
}

// Open opens the underlying Transport and begins the `read` goroutine, this also kicks off any
// in channel authentication (if necessary).
func (c *Channel) Open() error {
	err := c.t.Open()
	if err != nil {
		c.l.Criticalf("error opening channel, error: %s", err)

		return err
	}

	c.l.Debug("starting channel read loop")

	go c.read()

	if !c.AuthBypass {
		var b []byte

		switch tt := c.t.Impl.(type) {
		case *transport.System:
			c.l.Debug("transport type is 'system', begin in channel ssh authentication")

			b, err = c.AuthenticateSSH([]byte(c.t.Args.Password), []byte(tt.SSHArgs.PrivateKeyPassPhrase))
			if err != nil {
				return err
			}
		case *transport.Telnet:
			c.l.Debug("transport type is 'telnet', begin in channel telnet authentication")

			b, err = c.AuthenticateTelnet([]byte(c.t.Args.User), []byte(c.t.Args.Password))
			if err != nil {
				return err
			}
		}

		if len(b) > 0 {
			// requeue any buffer data we get during in channel authentication back onto the
			// read buffer. mostly this should only be relevant for netconf where we need to
			// read the server capabilities.
			c.Q.Requeue(b)
		}
	} else {
		c.l.Debug("auth bypass is enabled, skipping in channel auth check")
	}

	return nil
}

// Close signals to stop the channel read loop and closes the underlying Transport object.
func (c *Channel) Close() error {
	c.done <- true

	return c.t.Close(false)
}

type result struct {
	b   []byte
	err error
}

func (c *Channel) processOut(b []byte, strip bool) []byte {
	lines := bytes.Split(b, []byte("\n"))

	cleanLines := make([][]byte, len(lines))
	for i, l := range lines {
		cleanLines[i] = bytes.TrimRight(l, " ")
	}

	b = bytes.Join(cleanLines, []byte("\n"))

	if strip {
		b = c.PromptPattern.ReplaceAll(b, nil)
	}

	b = bytes.Trim(b, string(c.ReturnChar))
	b = bytes.Trim(b, "\n")

	return b
}

// GetTimeout returns the target timeout for an operation based on the TimeoutOps attribute of the
// Channel and the value t.
func (c *Channel) GetTimeout(t time.Duration) time.Duration {
	if t == -1 {
		return c.TimeoutOps
	}

	if t == 0 {
		return util.MaxTimeout * time.Second
	}

	return t
}
<|endoftext|>


<commit_before>package marvel_test

import (
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestCharactersAll(t *testing.T) {
	c := newTestClient(t, "characters_all")
	defer c.stopRecorder()

	chars, err := c.Characters.All()
	assert.NoError(t, err, "Characters.All() returned an error")
	assert.NotEmpty(t, chars, "Characters.All() returned empty character list")
}

func TestCharactersGetWrapped(t *testing.T) {
	c := newTestClient(t, "characters_get")
	defer c.stopRecorder()

	wrap, resp, err := c.Characters.GetWrapped(1017575)
	assert.NoError(t, err, "Characters.GetWrapped() returned an error")
	assert.NotNil(t, resp)

	t.Run("CharacterDataWrapper is correct", func(t *testing.T) {
		assert.Equal(t, 200, wrap.Code, "Incorrect Code")
		assert.Equal(t, "ok", strings.ToLower(wrap.Status), "Incorrect Status")
		assert.Contains(t, strings.ToLower(wrap.Copyright), "marvel", "Incorrect Copyright")
		assert.Contains(t, strings.ToLower(wrap.AttributionText), "marvel", "Incorrect AttributionText")
		assert.Contains(t, strings.ToLower(wrap.AttributionHTML), "marvel", "Incorrect AttributionHTML")
		assert.NotEmpty(t, wrap.ETag, "Empty ETag")
	})
	t.Run("CharacterDataContainer is correct", func(t *testing.T) {
		assert.Equal(t, 0, wrap.Data.Offset)
		assert.Equal(t, 20, wrap.Data.Limit)
		assert.Equal(t, 1, wrap.Data.Total)
		assert.Equal(t, 1, wrap.Data.Count)
	})
}

func TestCharactersGet(t *testing.T) {
	c := newTestClient(t, "characters_get")
	defer c.stopRecorder()

	char, err := c.Characters.Get(1017575)
	assert.NoError(t, err, "Characters.Get() returned an error for 1017575")

	assert.Equal(t, 1017575, char.ID, "Incorrect ID")
	assert.Contains(t, strings.ToLower(char.Name), "wilson", "Incorrect Name")
	assert.Contains(t, strings.ToLower(char.Description), "falcon", "Incorrect Description")
	assert.True(t, time.Now().After(char.Modified.Time), "Incorrect Modified time")
	assert.NotEmpty(t, char.Thumbnail, "Incorrect Thumbnail")
	assert.True(t, strings.HasSuffix(strings.ToLower(char.ResourceURI), "characters/1017575"), "Incorrect ResourceURI")
	assert.Equal(t, 25, char.Comics.Available)
	assert.True(t, strings.HasSuffix(strings.ToLower(char.Comics.CollectionURI), "characters/1017575/comics"), "Incorrect comics CollectionURI")
	assert.Equal(t, 9, char.Series.Available)
	assert.True(t, strings.HasSuffix(strings.ToLower(char.Series.CollectionURI), "characters/1017575/series"), "Incorrect series CollectionURI")
	assert.Equal(t, 25, char.Stories.Available)
	assert.True(t, strings.HasSuffix(strings.ToLower(char.Stories.CollectionURI), "characters/1017575/stories"), "Incorrect stories CollectionURI")
	assert.Equal(t, 0, char.Events.Available)
	assert.True(t, strings.HasSuffix(strings.ToLower(char.Events.CollectionURI), "characters/1017575/events"), "Incorrect events CollectionURI")
	assert.NotEmpty(t, char.URLs, "Incorrect URLs")
}

func TestCharacterGetBadID(t *testing.T) {
	c := newTestClient(t, "characters_get_bad_id")
	defer c.stopRecorder()

	char, err := c.Characters.Get(-1)
	assert.Error(t, err)
	assert.Nil(t, char, "Character should have been nil")
}
<commit_msg>Update test to match live API<commit_after>package marvel_test

import (
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestCharactersAll(t *testing.T) {
	c := newTestClient(t, "characters_all")
	defer c.stopRecorder()

	chars, err := c.Characters.All()
	assert.NoError(t, err, "Characters.All() returned an error")
	assert.NotEmpty(t, chars, "Characters.All() returned empty character list")
}

func TestCharactersGetWrapped(t *testing.T) {
	c := newTestClient(t, "characters_get")
	defer c.stopRecorder()

	wrap, resp, err := c.Characters.GetWrapped(1017575)
	assert.NoError(t, err, "Characters.GetWrapped() returned an error")
	assert.NotNil(t, resp)

	t.Run("CharacterDataWrapper is correct", func(t *testing.T) {
		assert.Equal(t, 200, wrap.Code, "Incorrect Code")
		assert.Equal(t, "ok", strings.ToLower(wrap.Status), "Incorrect Status")
		assert.Contains(t, strings.ToLower(wrap.Copyright), "marvel", "Incorrect Copyright")
		assert.Contains(t, strings.ToLower(wrap.AttributionText), "marvel", "Incorrect AttributionText")
		assert.Contains(t, strings.ToLower(wrap.AttributionHTML), "marvel", "Incorrect AttributionHTML")
		assert.NotEmpty(t, wrap.ETag, "Empty ETag")
	})
	t.Run("CharacterDataContainer is correct", func(t *testing.T) {
		assert.Equal(t, 0, wrap.Data.Offset)
		assert.Equal(t, 20, wrap.Data.Limit)
		assert.Equal(t, 1, wrap.Data.Total)
		assert.Equal(t, 1, wrap.Data.Count)
	})
}

func TestCharactersGet(t *testing.T) {
	c := newTestClient(t, "characters_get")
	defer c.stopRecorder()

	char, err := c.Characters.Get(1017575)
	assert.NoError(t, err, "Characters.Get() returned an error for 1017575")

	assert.Equal(t, 1017575, char.ID, "Incorrect ID")
	assert.Contains(t, strings.ToLower(char.Name), "wilson", "Incorrect Name")
	assert.Contains(t, strings.ToLower(char.Description), "falcon", "Incorrect Description")
	assert.True(t, time.Now().After(char.Modified.Time), "Incorrect Modified time")
	assert.NotEmpty(t, char.Thumbnail, "Incorrect Thumbnail")
	assert.True(t, strings.HasSuffix(strings.ToLower(char.ResourceURI), "characters/1017575"), "Incorrect ResourceURI")
	assert.Equal(t, 25, char.Comics.Available)
	assert.True(t, strings.HasSuffix(strings.ToLower(char.Comics.CollectionURI), "characters/1017575/comics"), "Incorrect comics CollectionURI")
	assert.Equal(t, 9, char.Series.Available)
	assert.True(t, strings.HasSuffix(strings.ToLower(char.Series.CollectionURI), "characters/1017575/series"), "Incorrect series CollectionURI")
	assert.Equal(t, 25, char.Stories.Available)
	assert.True(t, strings.HasSuffix(strings.ToLower(char.Stories.CollectionURI), "characters/1017575/stories"), "Incorrect stories CollectionURI")
	assert.Equal(t, 1, char.Events.Available)
	assert.True(t, strings.HasSuffix(strings.ToLower(char.Events.CollectionURI), "characters/1017575/events"), "Incorrect events CollectionURI")
	assert.NotEmpty(t, char.URLs, "Incorrect URLs")
}

func TestCharacterGetBadID(t *testing.T) {
	c := newTestClient(t, "characters_get_bad_id")
	defer c.stopRecorder()

	char, err := c.Characters.Get(-1)
	assert.Error(t, err)
	assert.Nil(t, char, "Character should have been nil")
}
<|endoftext|>


<commit_before>package cli

import (
	"bytes"
	"errors"
	"fmt"
	"os"
)

type Command interface {
	Definition() string
	Exec() error
}

type Module struct {
	Children   map[string]*Module
	Command    Command
	Definition string
}

func NewModule(name string, definition string) *Module {
	return &Module{Children: make(map[string]*Module, 0), Definition: definition}
}

func NewCommandModule(command Command) *Module {
	return &Module{Command: command}
}

func (m *Module) AddCommand(name string, command Command) *Module {
	child := NewCommandModule(command)
	m.Children[name] = child
	return child
}

func (m *Module) AddModule(name string, definition string) *Module {
	child := NewModule(name, definition)
	m.Children[name] = child
	return child
}

func (m *Module) FindModule(args []string) (*Module, error) {
	moduleWalker := m
	var errStr bytes.Buffer
	for i := 0; i < len(args); i, moduleWalker = i+1, moduleWalker.Children[args[i]] {
		module := moduleWalker.Children[args[i]]
		if module == nil {
			errStr.WriteString(fmt.Sprintf("Command %s not found\n\n", args[i]))
			break
		}
		if module.Command == nil {
			continue
		}
		// command behaves like a subprocess, it will parse arguments again
		// so we re discarding parsed arguments
		temp := os.Args
		os.Args = []string{temp[0]}
		os.Args = append(os.Args, temp[i+2:]...)
		return module, nil
	}
	errStr.WriteString(moduleWalker.printPossibleCommands())
	return nil, errors.New(errStr.String())
}

func (m *Module) printPossibleCommands() string {
	var buffer bytes.Buffer
	buffer.WriteString("Possible commands: \n")
	for n, module := range m.Children {
		buffer.WriteString(fmt.Sprintf("  %-10s  ", n))
		var definition string
		if module.Command != nil {
			definition = module.Command.Definition()
		} else {
			definition = module.Definition
		}
		buffer.WriteString(fmt.Sprintf("%s\n", definition))
	}
	return buffer.String()
}
<commit_msg>added doc for command<commit_after>package cli

import (
	"bytes"
	"errors"
	"fmt"
	"os"
)

// To add a module, implement this interface
// Definition is the command definition
// Exec is the behaviour that you want to implement as a command
type Command interface {
	Definition() string
	Exec() error
}

type Module struct {
	Children   map[string]*Module
	Command    Command
	Definition string
}

func NewModule(name string, definition string) *Module {
	return &Module{Children: make(map[string]*Module, 0), Definition: definition}
}

func NewCommandModule(command Command) *Module {
	return &Module{Command: command}
}

func (m *Module) AddCommand(name string, command Command) *Module {
	child := NewCommandModule(command)
	m.Children[name] = child
	return child
}

func (m *Module) AddModule(name string, definition string) *Module {
	child := NewModule(name, definition)
	m.Children[name] = child
	return child
}

func (m *Module) FindModule(args []string) (*Module, error) {
	moduleWalker := m
	var errStr bytes.Buffer
	for i := 0; i < len(args); i, moduleWalker = i+1, moduleWalker.Children[args[i]] {
		module := moduleWalker.Children[args[i]]
		if module == nil {
			errStr.WriteString(fmt.Sprintf("Command %s not found\n\n", args[i]))
			break
		}
		if module.Command == nil {
			continue
		}
		// command behaves like a subprocess, it will parse arguments again
		// so we re discarding parsed arguments
		temp := os.Args
		os.Args = []string{temp[0]}
		os.Args = append(os.Args, temp[i+2:]...)
		return module, nil
	}
	errStr.WriteString(moduleWalker.printPossibleCommands())
	return nil, errors.New(errStr.String())
}

func (m *Module) printPossibleCommands() string {
	var buffer bytes.Buffer
	buffer.WriteString("Possible commands: \n")
	for n, module := range m.Children {
		buffer.WriteString(fmt.Sprintf("  %-10s  ", n))
		var definition string
		if module.Command != nil {
			definition = module.Command.Definition()
		} else {
			definition = module.Definition
		}
		buffer.WriteString(fmt.Sprintf("%s\n", definition))
	}
	return buffer.String()
}
<|endoftext|>


<commit_before>/* Copyright 2019 The Subscribe with Google Authors. 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 encryption

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"github.com/golang/protobuf/proto"
	"github.com/google/tink/go/aead"
	"github.com/google/tink/go/core/registry"
	"github.com/google/tink/go/hybrid"
	"github.com/google/tink/go/insecurecleartextkeyset"
	"github.com/google/tink/go/keyset"
	gcmpb "github.com/google/tink/proto/aes_gcm_go_proto"
	tinkpb "github.com/google/tink/proto/tink_go_proto"
	"golang.org/x/net/html"
	"golang.org/x/net/html/atom"
	"net/http"
	"strings"
	"unicode/utf8"
)

// Helper functions for the SwG Encryption Script.

const aesGCMKeyURL string = "type.googleapis.com/google.crypto.tink.AesGcmKey"
const aesGCMKeySize uint32 = 16

// Public function to generate an encrypted HTML document given the original.
func GenerateEncryptedDocument(htmlStr, accessRequirement string, pubKeys map[string]tinkpb.Keyset) (string, error) {
	km, err := registry.GetKeyManager(aesGCMKeyURL)
	if err != nil {
		return "", err
	}
	key, err := generateNewAesGcmKey(km)
	if err != nil {
		return "", err
	}
	keyBuf, err := proto.Marshal(key)
	if err != nil {
		return "", err
	}
	ks := createAesGcmKeyset(keyBuf)
	kh, err := insecurecleartextkeyset.Read(&keyset.MemReaderWriter{Keyset: &ks})
	if err != nil {
		return "", err
	}
	parsedHTML, err := html.Parse(strings.NewReader(htmlStr))
	if err != nil {
		return "", err
	}
	encryptedSections := getAllEncryptedSections(parsedHTML)
	if len(encryptedSections) == 0 {
		return "", errors.New("No encrypted sections found.")
	}
	if err = encryptAllSections(parsedHTML, encryptedSections, kh); err != nil {
		return "", err
	}
	encryptedKeys, err := encryptDocumentKey(base64.StdEncoding.EncodeToString(key.KeyValue), accessRequirement, pubKeys)
	if err != nil {
		return "", err
	}
	if err = addEncryptedDocumentKeyToHead(encryptedKeys, parsedHTML); err != nil {
		return "", err
	}
	return renderNode(parsedHTML), nil
}

// Retrieves a Tink public key from the given URL.
func RetrieveTinkPublicKey(publicKeyURL string) (tinkpb.Keyset, error) {
	resp, err := http.Get(publicKeyURL)
	if err != nil {
		return tinkpb.Keyset{}, err
	}
	r := keyset.NewJSONReader(resp.Body)
	ks, err := r.Read()
	if err != nil {
		return tinkpb.Keyset{}, err
	}
	return *ks, nil
}

// Generates a new AES-GCM key.
func generateNewAesGcmKey(km registry.KeyManager) (*gcmpb.AesGcmKey, error) {
	p, err := proto.Marshal(&gcmpb.AesGcmKeyFormat{KeySize: aesGCMKeySize})
	if err != nil {
		return nil, err
	}
	m, err := km.NewKey(p)
	if err != nil {
		return nil, err
	}
	return m.(*gcmpb.AesGcmKey), nil
}

// Creates an AES-GCM Keyset using the input key.
// Example output proto:
// 		primary_key_id: 1
// 		key: <
// 			key_data: <
//   			type_url: "type.googleapis.com/google.crypto.tink.AesGcmKey"
//   			value: "\032\020\355\323'\277\341\241u\020w\322\177\207\357\374\301/"
//   			key_material_type: SYMMETRIC
// 			>
// 			status: ENABLED
// 			key_id: 1
// 			output_prefix_type: TINK
// 		>
func createAesGcmKeyset(key []byte) tinkpb.Keyset {
	keyData := tinkpb.KeyData{
		KeyMaterialType: tinkpb.KeyData_SYMMETRIC,
		TypeUrl:         aesGCMKeyURL,
		Value:           key,
	}
	keys := []*tinkpb.Keyset_Key{
		&tinkpb.Keyset_Key{
			KeyData:          &keyData,
			Status:           tinkpb.KeyStatusType_ENABLED,
			KeyId:            1,
			OutputPrefixType: tinkpb.OutputPrefixType_RAW,
		},
	}
	return tinkpb.Keyset{
		PrimaryKeyId: 1,
		Key:          keys,
	}
}

// Retrieves all encrypted content sections from the parsed HTML tree.
func getAllEncryptedSections(parsedHTML *html.Node) []*html.Node {
	for n := parsedHTML.FirstChild; n != nil; n = n.NextSibling {
		if (n.DataAtom == atom.Html) && (len(n.Attr) != 0) {
			for bn := n.FirstChild; bn != nil; bn = bn.NextSibling {
				if bn.DataAtom == atom.Body {
					return getEncryptedSectionsDFS(bn)
				}
			}
		}
	}
	return nil
}

// Searches for all
 nodes and returns them.
func getEncryptedSectionsDFS(bodyNode *html.Node) []*html.Node {
	var encryptedSections []*html.Node
	var queue []*html.Node
	var n *html.Node
	queue = append(queue, bodyNode)
	for {
		if len(queue) == 0 {
			break
		}
		n, queue = queue[len(queue)-1], queue[:len(queue)-1]
		if n.Type == html.ElementNode && n.DataAtom == atom.Section {
			var contentSubSection bool = false
			var encrypted bool = false
			for _, a := range n.Attr {
				if a.Key == "subscriptions-section" && a.Val == "content" {
					contentSubSection = true
				} else if a.Key == "encrypted" {
					encrypted = true
				}
			}
			if contentSubSection && encrypted {
				encryptedSections = append(encryptedSections, n)
			}
		}
		for cn := n.FirstChild; cn != nil; cn = cn.NextSibling {
			queue = append(queue, cn)
		}
	}
	return encryptedSections
}

// Encrypts the content inside of the input "encryptedSections" nodes.
func encryptAllSections(parsedHTML *html.Node, encryptedSections []*html.Node, kh *keyset.Handle) error {
	cipher, err := aead.New(kh)
	if err != nil {
		return err
	}
	for _, node := range encryptedSections {
		var content []string
		for c := node.FirstChild; c != nil; c = c.NextSibling {
			content = append(content, renderNode(c))
			node.RemoveChild(c)
		}
		b := []byte(strings.Join(content, ""))
		if !utf8.Valid(b) {
			return errors.New("Content contains invalid UTF-8.")
		}
		encContent, err := cipher.Encrypt(b, nil)
		if err != nil {
			return err
		}
		textNode := &html.Node{Type: html.TextNode, Data: base64.StdEncoding.EncodeToString(encContent)}
		attrs := []html.Attribute{
			html.Attribute{Key: "type", Val: "application/octet-stream"},
			html.Attribute{Key: "ciphertext", Val: ""},
		}
		scriptNode := &html.Node{
			Type:     html.ElementNode,
			Data:     "script",
			DataAtom: atom.Script,
			Attr:     attrs,
		}
		node.AppendChild(scriptNode)
		scriptNode.AppendChild(textNode)
	}
	return nil
}

type swgEncryptionKey struct {
	AccessRequirement []string
	Key               string
}

// Encrypts the document's symmetric key using the input Keyset.
func encryptDocumentKey(docKeyset, accessRequirement string, pubKeys map[string]tinkpb.Keyset) (map[string]string, error) {
	outMap := make(map[string]string)
	for domain, ks := range pubKeys {
		handle, err := keyset.NewHandleWithNoSecrets(&ks)
		if err != nil {
			return nil, err
		}
		he, err := hybrid.NewHybridEncrypt(handle)
		if err != nil {
			return nil, err
		}
		swgKey := swgEncryptionKey{
			AccessRequirement: []string{accessRequirement},
			Key:               docKeyset,
		}
		log.Println("swgkey: ", fmt.Sprintf("%v", swgKey))
		jsonData, err := json.Marshal(swgKey)
		if err != nil {
			return nil, err
		}
		log.Println("jsondata: ", base64.StdEncoding.EncodeToString(jsonData))
		enc, err := he.Encrypt(jsonData, nil)
		if err != nil {
			return nil, err
		}
		log.Println("out: ", base64.StdEncoding.EncodeToString(enc))
		outMap[domain] = base64.StdEncoding.EncodeToString(enc)
	}
	return outMap, nil
}

// Adds the encrypted document keys to the output document's head.
func addEncryptedDocumentKeyToHead(encryptedKeys map[string]string, parsedHTML *html.Node) error {
	for n := parsedHTML.FirstChild; n != nil; n = n.NextSibling {
		if (n.DataAtom == atom.Html) && (len(n.Attr) != 0) {
			for cn := n.FirstChild; cn != nil; cn = cn.NextSibling {
				if cn.DataAtom == atom.Head {
					attrs := []html.Attribute{
						html.Attribute{Key: "type", Val: "application/json"},
						html.Attribute{Key: "cryptokeys", Val: ""},
					}
					cryptoKeys := &html.Node{
						Type:     html.ElementNode,
						Data:     "script",
						DataAtom: atom.Script,
						Attr:     attrs,
					}
					jsonEncKeys, err := json.Marshal(encryptedKeys)
					if err != nil {
						return err
					}
					textNode := &html.Node{Type: html.TextNode, Data: string(jsonEncKeys)}
					cryptoKeys.AppendChild(textNode)
					cn.AppendChild(cryptoKeys)
					return nil
				}
			}
		}
	}
	return errors.New("Could not add cryptokeys to head.")
}

// Renders the input Node to a string.
func renderNode(n *html.Node) string {
	b := new(bytes.Buffer)
	html.Render(b, n)
	return b.String()
}
<commit_msg>Cleaning imports and logging.<commit_after>/* Copyright 2019 The Subscribe with Google Authors. 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 encryption

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"github.com/golang/protobuf/proto"
	"github.com/google/tink/go/aead"
	"github.com/google/tink/go/core/registry"
	"github.com/google/tink/go/hybrid"
	"github.com/google/tink/go/insecurecleartextkeyset"
	"github.com/google/tink/go/keyset"
	gcmpb "github.com/google/tink/proto/aes_gcm_go_proto"
	tinkpb "github.com/google/tink/proto/tink_go_proto"
	"golang.org/x/net/html"
	"golang.org/x/net/html/atom"
	"net/http"
	"strings"
	"unicode/utf8"
)

// Helper functions for the SwG Encryption Script.

const aesGCMKeyURL string = "type.googleapis.com/google.crypto.tink.AesGcmKey"
const aesGCMKeySize uint32 = 16

// Public function to generate an encrypted HTML document given the original.
func GenerateEncryptedDocument(htmlStr, accessRequirement string, pubKeys map[string]tinkpb.Keyset) (string, error) {
	km, err := registry.GetKeyManager(aesGCMKeyURL)
	if err != nil {
		return "", err
	}
	key, err := generateNewAesGcmKey(km)
	if err != nil {
		return "", err
	}
	keyBuf, err := proto.Marshal(key)
	if err != nil {
		return "", err
	}
	ks := createAesGcmKeyset(keyBuf)
	kh, err := insecurecleartextkeyset.Read(&keyset.MemReaderWriter{Keyset: &ks})
	if err != nil {
		return "", err
	}
	parsedHTML, err := html.Parse(strings.NewReader(htmlStr))
	if err != nil {
		return "", err
	}
	encryptedSections := getAllEncryptedSections(parsedHTML)
	if len(encryptedSections) == 0 {
		return "", errors.New("No encrypted sections found.")
	}
	if err = encryptAllSections(parsedHTML, encryptedSections, kh); err != nil {
		return "", err
	}
	encryptedKeys, err := encryptDocumentKey(base64.StdEncoding.EncodeToString(key.KeyValue), accessRequirement, pubKeys)
	if err != nil {
		return "", err
	}
	if err = addEncryptedDocumentKeyToHead(encryptedKeys, parsedHTML); err != nil {
		return "", err
	}
	return renderNode(parsedHTML), nil
}

// Retrieves a Tink public key from the given URL.
func RetrieveTinkPublicKey(publicKeyURL string) (tinkpb.Keyset, error) {
	resp, err := http.Get(publicKeyURL)
	if err != nil {
		return tinkpb.Keyset{}, err
	}
	r := keyset.NewJSONReader(resp.Body)
	ks, err := r.Read()
	if err != nil {
		return tinkpb.Keyset{}, err
	}
	return *ks, nil
}

// Generates a new AES-GCM key.
func generateNewAesGcmKey(km registry.KeyManager) (*gcmpb.AesGcmKey, error) {
	p, err := proto.Marshal(&gcmpb.AesGcmKeyFormat{KeySize: aesGCMKeySize})
	if err != nil {
		return nil, err
	}
	m, err := km.NewKey(p)
	if err != nil {
		return nil, err
	}
	return m.(*gcmpb.AesGcmKey), nil
}

// Creates an AES-GCM Keyset using the input key.
// Example output proto:
// 		primary_key_id: 1
// 		key: <
// 			key_data: <
//   			type_url: "type.googleapis.com/google.crypto.tink.AesGcmKey"
//   			value: "\032\020\355\323'\277\341\241u\020w\322\177\207\357\374\301/"
//   			key_material_type: SYMMETRIC
// 			>
// 			status: ENABLED
// 			key_id: 1
// 			output_prefix_type: TINK
// 		>
func createAesGcmKeyset(key []byte) tinkpb.Keyset {
	keyData := tinkpb.KeyData{
		KeyMaterialType: tinkpb.KeyData_SYMMETRIC,
		TypeUrl:         aesGCMKeyURL,
		Value:           key,
	}
	keys := []*tinkpb.Keyset_Key{
		&tinkpb.Keyset_Key{
			KeyData:          &keyData,
			Status:           tinkpb.KeyStatusType_ENABLED,
			KeyId:            1,
			OutputPrefixType: tinkpb.OutputPrefixType_RAW,
		},
	}
	return tinkpb.Keyset{
		PrimaryKeyId: 1,
		Key:          keys,
	}
}

// Retrieves all encrypted content sections from the parsed HTML tree.
func getAllEncryptedSections(parsedHTML *html.Node) []*html.Node {
	for n := parsedHTML.FirstChild; n != nil; n = n.NextSibling {
		if (n.DataAtom == atom.Html) && (len(n.Attr) != 0) {
			for bn := n.FirstChild; bn != nil; bn = bn.NextSibling {
				if bn.DataAtom == atom.Body {
					return getEncryptedSectionsDFS(bn)
				}
			}
		}
	}
	return nil
}

// Searches for all
 nodes and returns them.
func getEncryptedSectionsDFS(bodyNode *html.Node) []*html.Node {
	var encryptedSections []*html.Node
	var queue []*html.Node
	var n *html.Node
	queue = append(queue, bodyNode)
	for {
		if len(queue) == 0 {
			break
		}
		n, queue = queue[len(queue)-1], queue[:len(queue)-1]
		if n.Type == html.ElementNode && n.DataAtom == atom.Section {
			var contentSubSection bool = false
			var encrypted bool = false
			for _, a := range n.Attr {
				if a.Key == "subscriptions-section" && a.Val == "content" {
					contentSubSection = true
				} else if a.Key == "encrypted" {
					encrypted = true
				}
			}
			if contentSubSection && encrypted {
				encryptedSections = append(encryptedSections, n)
			}
		}
		for cn := n.FirstChild; cn != nil; cn = cn.NextSibling {
			queue = append(queue, cn)
		}
	}
	return encryptedSections
}

// Encrypts the content inside of the input "encryptedSections" nodes.
func encryptAllSections(parsedHTML *html.Node, encryptedSections []*html.Node, kh *keyset.Handle) error {
	cipher, err := aead.New(kh)
	if err != nil {
		return err
	}
	for _, node := range encryptedSections {
		var content []string
		for c := node.FirstChild; c != nil; c = c.NextSibling {
			content = append(content, renderNode(c))
			node.RemoveChild(c)
		}
		b := []byte(strings.Join(content, ""))
		if !utf8.Valid(b) {
			return errors.New("Content contains invalid UTF-8.")
		}
		encContent, err := cipher.Encrypt(b, nil)
		if err != nil {
			return err
		}
		textNode := &html.Node{Type: html.TextNode, Data: base64.StdEncoding.EncodeToString(encContent)}
		attrs := []html.Attribute{
			html.Attribute{Key: "type", Val: "application/octet-stream"},
			html.Attribute{Key: "ciphertext", Val: ""},
		}
		scriptNode := &html.Node{
			Type:     html.ElementNode,
			Data:     "script",
			DataAtom: atom.Script,
			Attr:     attrs,
		}
		node.AppendChild(scriptNode)
		scriptNode.AppendChild(textNode)
	}
	return nil
}

type swgEncryptionKey struct {
	AccessRequirement []string
	Key               string
}

// Encrypts the document's symmetric key using the input Keyset.
func encryptDocumentKey(docKey, accessRequirement string, pubKeys map[string]tinkpb.Keyset) (map[string]string, error) {
	outMap := make(map[string]string)
	for domain, ks := range pubKeys {
		handle, err := keyset.NewHandleWithNoSecrets(&ks)
		if err != nil {
			return nil, err
		}
		he, err := hybrid.NewHybridEncrypt(handle)
		if err != nil {
			return nil, err
		}
		swgKey := swgEncryptionKey{
			AccessRequirement: []string{accessRequirement},
			Key:               docKey,
		}
		jsonData, err := json.Marshal(swgKey)
		if err != nil {
			return nil, err
		}
		enc, err := he.Encrypt(jsonData, nil)
		if err != nil {
			return nil, err
		}
		outMap[domain] = base64.StdEncoding.EncodeToString(enc)
	}
	return outMap, nil
}

// Adds the encrypted document keys to the output document's head.
func addEncryptedDocumentKeyToHead(encryptedKeys map[string]string, parsedHTML *html.Node) error {
	for n := parsedHTML.FirstChild; n != nil; n = n.NextSibling {
		if (n.DataAtom == atom.Html) && (len(n.Attr) != 0) {
			for cn := n.FirstChild; cn != nil; cn = cn.NextSibling {
				if cn.DataAtom == atom.Head {
					attrs := []html.Attribute{
						html.Attribute{Key: "type", Val: "application/json"},
						html.Attribute{Key: "cryptokeys", Val: ""},
					}
					cryptoKeys := &html.Node{
						Type:     html.ElementNode,
						Data:     "script",
						DataAtom: atom.Script,
						Attr:     attrs,
					}
					jsonEncKeys, err := json.Marshal(encryptedKeys)
					if err != nil {
						return err
					}
					textNode := &html.Node{Type: html.TextNode, Data: string(jsonEncKeys)}
					cryptoKeys.AppendChild(textNode)
					cn.AppendChild(cryptoKeys)
					return nil
				}
			}
		}
	}
	return errors.New("Could not add cryptokeys to head.")
}

// Renders the input Node to a string.
func renderNode(n *html.Node) string {
	b := new(bytes.Buffer)
	html.Render(b, n)
	return b.String()
}
<|endoftext|>


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

//go.build go.1.16
// +build go.1.16

// Running this program in the tools directory will produce a coverage file /tmp/cover.out
// and a coverage report for all the packages under internal/lsp, accumulated by all the tests
// under gopls.
//
// -o controls where the coverage file is written, defaulting to /tmp/cover.out
// -i coverage-file will generate the report from an existing coverage file
// -v controls verbosity (0: only report coverage, 1: report as each directory is finished,
//      2: report on each test, 3: more details, 4: too much)
// -t tests only tests packages in the given comma-separated list of directories in gopls.
//      The names should start with ., as in ./internal/regtest/bench
// -run tests. If set, -run tests is passed on to the go test command.
//
// Despite gopls' use of goroutines, the counts are almost deterministic.
package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"sort"
	"strings"
	"time"

	"golang.org/x/tools/cover"
)

var (
	proFile = flag.String("i", "", "existing profile file")
	outFile = flag.String("o", "/tmp/cover.out", "where to write the coverage file")
	verbose = flag.Int("v", 0, "how much detail to print as tests are running")
	tests   = flag.String("t", "", "list of tests to run")
	run     = flag.String("run", "", "value of -run to pass to go test")
)

func main() {
	log.SetFlags(log.Lshortfile)
	flag.Parse()

	if *proFile != "" {
		report(*proFile)
		return
	}

	checkCwd()
	// find the packages under gopls containing tests
	tests := listDirs("gopls")
	tests = onlyTests(tests)
	tests = realTestName(tests)

	// report coverage for packages under internal/lsp
	parg := "golang.org/x/tools/internal/lsp/..."

	accum := []string{}
	seen := make(map[string]bool)
	now := time.Now()
	for _, toRun := range tests {
		if excluded(toRun) {
			continue
		}
		x := runTest(toRun, parg)
		if *verbose > 0 {
			fmt.Printf("finished %s %.1fs\n", toRun, time.Since(now).Seconds())
		}
		lines := bytes.Split(x, []byte{'\n'})
		for _, l := range lines {
			if len(l) == 0 {
				continue
			}
			if !seen[string(l)] {
				// not accumulating counts, so only works for mode:set
				seen[string(l)] = true
				accum = append(accum, string(l))
			}
		}
	}
	sort.Strings(accum[1:])
	if err := os.WriteFile(*outFile, []byte(strings.Join(accum, "\n")), 0644); err != nil {
		log.Print(err)
	}
	report(*outFile)
}

type result struct {
	Time    time.Time
	Test    string
	Action  string
	Package string
	Output  string
	Elapsed float64
}

func runTest(tName, parg string) []byte {
	args := []string{"test", "-short", "-coverpkg", parg, "-coverprofile", *outFile,
		"-json"}
	if *run != "" {
		args = append(args, fmt.Sprintf("-run=%s", *run))
	}
	args = append(args, tName)
	cmd := exec.Command("go", args...)
	cmd.Dir = "./gopls"
	ans, err := cmd.Output()
	if *verbose > 1 {
		got := strings.Split(string(ans), "\n")
		for _, g := range got {
			if g == "" {
				continue
			}
			var m result
			if err := json.Unmarshal([]byte(g), &m); err != nil {
				log.Printf("%T/%v", err, err) // shouldn't happen
				continue
			}
			maybePrint(m)
		}
	}
	if err != nil {
		log.Printf("%s: %q, cmd=%s", tName, ans, cmd.String())
	}
	buf, err := os.ReadFile(*outFile)
	if err != nil {
		log.Fatal(err)
	}
	return buf
}

func report(fn string) {
	profs, err := cover.ParseProfiles(fn)
	if err != nil {
		log.Fatal(err)
	}
	for _, p := range profs {
		statements, counts := 0, 0
		for _, x := range p.Blocks {
			statements += x.NumStmt
			if x.Count != 0 {
				counts += x.NumStmt // sic: if any were executed, all were
			}
		}
		pc := 100 * float64(counts) / float64(statements)
		fmt.Printf("%3.0f%% %3d/%3d %s\n", pc, counts, statements, p.FileName)
	}
}

var todo []string // tests to run

func excluded(tname string) bool {
	if *tests == "" { // run all tests
		return false
	}
	if todo == nil {
		todo = strings.Split(*tests, ",")
	}
	for _, nm := range todo {
		if tname == nm { // run this test
			return false
		}
	}
	// not in list, skip it
	return true
}

// should m.Package be printed sometime?
func maybePrint(m result) {
	switch m.Action {
	case "pass", "fail", "skip":
		fmt.Printf("%s %s %.3f\n", m.Action, m.Test, m.Elapsed)
	case "run":
		if *verbose > 2 {
			fmt.Printf("%s %s %.3f\n", m.Action, m.Test, m.Elapsed)
		}
	case "output":
		if *verbose > 3 {
			fmt.Printf("%s %s %q %.3f\n", m.Action, m.Test, m.Output, m.Elapsed)
		}
	default:
		log.Fatalf("unknown action %s\n", m.Action)
	}
}

// return only the directories that contain tests
func onlyTests(s []string) []string {
	ans := []string{}
outer:
	for _, d := range s {
		files, err := os.ReadDir(d)
		if err != nil {
			log.Fatalf("%s: %v", d, err)
		}
		for _, de := range files {
			if strings.Contains(de.Name(), "_test.go") {
				ans = append(ans, d)
				continue outer
			}
		}
	}
	return ans
}

// replace the prefix gopls/ with ./ as the tests are run in the gopls directory
func realTestName(p []string) []string {
	ans := []string{}
	for _, x := range p {
		x = x[len("gopls/"):]
		ans = append(ans, "./"+x)
	}
	return ans
}

// make sure we start in a tools directory
func checkCwd() {
	dir, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}
	// we expect to be a the root of golang.org/x/tools
	cmd := exec.Command("go", "list", "-m", "-f", "{{.Dir}}", "golang.org/x/tools")
	buf, err := cmd.Output()
	buf = bytes.Trim(buf, "\n \t") // remove \n at end
	if err != nil {
		log.Fatal(err)
	}
	if string(buf) != dir {
		log.Fatalf("wrong directory: in %q, should be in %q", dir, string(buf))
	}
	// and we expect gopls and internal/lsp as subdirectories
	_, err = os.Stat("gopls")
	if err != nil {
		log.Fatalf("expected a gopls directory, %v", err)
	}
	_, err = os.Stat("internal/lsp")
	if err != nil {
		log.Fatalf("expected to see internal/lsp, %v", err)
	}
}

func listDirs(dir string) []string {
	ans := []string{}
	f := func(path string, dirEntry os.DirEntry, err error) error {
		if strings.HasSuffix(path, "/testdata") || strings.HasSuffix(path, "/typescript") {
			return filepath.SkipDir
		}
		if dirEntry.IsDir() {
			ans = append(ans, path)
		}
		return nil
	}
	filepath.WalkDir(dir, f)
	return ans
}
<commit_msg>gopls/internal/coverage: apply gofmt to the build tag syntax<commit_after>// Copyright 2021 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.

//go:build go.1.16
// +build go.1.16

// Running this program in the tools directory will produce a coverage file /tmp/cover.out
// and a coverage report for all the packages under internal/lsp, accumulated by all the tests
// under gopls.
//
// -o controls where the coverage file is written, defaulting to /tmp/cover.out
// -i coverage-file will generate the report from an existing coverage file
// -v controls verbosity (0: only report coverage, 1: report as each directory is finished,
//      2: report on each test, 3: more details, 4: too much)
// -t tests only tests packages in the given comma-separated list of directories in gopls.
//      The names should start with ., as in ./internal/regtest/bench
// -run tests. If set, -run tests is passed on to the go test command.
//
// Despite gopls' use of goroutines, the counts are almost deterministic.
package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"sort"
	"strings"
	"time"

	"golang.org/x/tools/cover"
)

var (
	proFile = flag.String("i", "", "existing profile file")
	outFile = flag.String("o", "/tmp/cover.out", "where to write the coverage file")
	verbose = flag.Int("v", 0, "how much detail to print as tests are running")
	tests   = flag.String("t", "", "list of tests to run")
	run     = flag.String("run", "", "value of -run to pass to go test")
)

func main() {
	log.SetFlags(log.Lshortfile)
	flag.Parse()

	if *proFile != "" {
		report(*proFile)
		return
	}

	checkCwd()
	// find the packages under gopls containing tests
	tests := listDirs("gopls")
	tests = onlyTests(tests)
	tests = realTestName(tests)

	// report coverage for packages under internal/lsp
	parg := "golang.org/x/tools/internal/lsp/..."

	accum := []string{}
	seen := make(map[string]bool)
	now := time.Now()
	for _, toRun := range tests {
		if excluded(toRun) {
			continue
		}
		x := runTest(toRun, parg)
		if *verbose > 0 {
			fmt.Printf("finished %s %.1fs\n", toRun, time.Since(now).Seconds())
		}
		lines := bytes.Split(x, []byte{'\n'})
		for _, l := range lines {
			if len(l) == 0 {
				continue
			}
			if !seen[string(l)] {
				// not accumulating counts, so only works for mode:set
				seen[string(l)] = true
				accum = append(accum, string(l))
			}
		}
	}
	sort.Strings(accum[1:])
	if err := os.WriteFile(*outFile, []byte(strings.Join(accum, "\n")), 0644); err != nil {
		log.Print(err)
	}
	report(*outFile)
}

type result struct {
	Time    time.Time
	Test    string
	Action  string
	Package string
	Output  string
	Elapsed float64
}

func runTest(tName, parg string) []byte {
	args := []string{"test", "-short", "-coverpkg", parg, "-coverprofile", *outFile,
		"-json"}
	if *run != "" {
		args = append(args, fmt.Sprintf("-run=%s", *run))
	}
	args = append(args, tName)
	cmd := exec.Command("go", args...)
	cmd.Dir = "./gopls"
	ans, err := cmd.Output()
	if *verbose > 1 {
		got := strings.Split(string(ans), "\n")
		for _, g := range got {
			if g == "" {
				continue
			}
			var m result
			if err := json.Unmarshal([]byte(g), &m); err != nil {
				log.Printf("%T/%v", err, err) // shouldn't happen
				continue
			}
			maybePrint(m)
		}
	}
	if err != nil {
		log.Printf("%s: %q, cmd=%s", tName, ans, cmd.String())
	}
	buf, err := os.ReadFile(*outFile)
	if err != nil {
		log.Fatal(err)
	}
	return buf
}

func report(fn string) {
	profs, err := cover.ParseProfiles(fn)
	if err != nil {
		log.Fatal(err)
	}
	for _, p := range profs {
		statements, counts := 0, 0
		for _, x := range p.Blocks {
			statements += x.NumStmt
			if x.Count != 0 {
				counts += x.NumStmt // sic: if any were executed, all were
			}
		}
		pc := 100 * float64(counts) / float64(statements)
		fmt.Printf("%3.0f%% %3d/%3d %s\n", pc, counts, statements, p.FileName)
	}
}

var todo []string // tests to run

func excluded(tname string) bool {
	if *tests == "" { // run all tests
		return false
	}
	if todo == nil {
		todo = strings.Split(*tests, ",")
	}
	for _, nm := range todo {
		if tname == nm { // run this test
			return false
		}
	}
	// not in list, skip it
	return true
}

// should m.Package be printed sometime?
func maybePrint(m result) {
	switch m.Action {
	case "pass", "fail", "skip":
		fmt.Printf("%s %s %.3f\n", m.Action, m.Test, m.Elapsed)
	case "run":
		if *verbose > 2 {
			fmt.Printf("%s %s %.3f\n", m.Action, m.Test, m.Elapsed)
		}
	case "output":
		if *verbose > 3 {
			fmt.Printf("%s %s %q %.3f\n", m.Action, m.Test, m.Output, m.Elapsed)
		}
	default:
		log.Fatalf("unknown action %s\n", m.Action)
	}
}

// return only the directories that contain tests
func onlyTests(s []string) []string {
	ans := []string{}
outer:
	for _, d := range s {
		files, err := os.ReadDir(d)
		if err != nil {
			log.Fatalf("%s: %v", d, err)
		}
		for _, de := range files {
			if strings.Contains(de.Name(), "_test.go") {
				ans = append(ans, d)
				continue outer
			}
		}
	}
	return ans
}

// replace the prefix gopls/ with ./ as the tests are run in the gopls directory
func realTestName(p []string) []string {
	ans := []string{}
	for _, x := range p {
		x = x[len("gopls/"):]
		ans = append(ans, "./"+x)
	}
	return ans
}

// make sure we start in a tools directory
func checkCwd() {
	dir, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}
	// we expect to be a the root of golang.org/x/tools
	cmd := exec.Command("go", "list", "-m", "-f", "{{.Dir}}", "golang.org/x/tools")
	buf, err := cmd.Output()
	buf = bytes.Trim(buf, "\n \t") // remove \n at end
	if err != nil {
		log.Fatal(err)
	}
	if string(buf) != dir {
		log.Fatalf("wrong directory: in %q, should be in %q", dir, string(buf))
	}
	// and we expect gopls and internal/lsp as subdirectories
	_, err = os.Stat("gopls")
	if err != nil {
		log.Fatalf("expected a gopls directory, %v", err)
	}
	_, err = os.Stat("internal/lsp")
	if err != nil {
		log.Fatalf("expected to see internal/lsp, %v", err)
	}
}

func listDirs(dir string) []string {
	ans := []string{}
	f := func(path string, dirEntry os.DirEntry, err error) error {
		if strings.HasSuffix(path, "/testdata") || strings.HasSuffix(path, "/typescript") {
			return filepath.SkipDir
		}
		if dirEntry.IsDir() {
			ans = append(ans, path)
		}
		return nil
	}
	filepath.WalkDir(dir, f)
	return ans
}
<|endoftext|>