<commit_before>package citrixadc

import (
	"github.com/chiradeep/go-nitro/config/responder"

	"github.com/chiradeep/go-nitro/netscaler"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"

	"fmt"
	"log"
)

func resourceCitrixAdcResponderaction() *schema.Resource {
	return &schema.Resource{
		SchemaVersion: 1,
		Create:        createResponderactionFunc,
		Read:          readResponderactionFunc,
		Update:        updateResponderactionFunc,
		Delete:        deleteResponderactionFunc,
		CustomizeDiff: customizeResponderactionDiff,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},
		Schema: map[string]*schema.Schema{
			"bypasssafetycheck": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"comment": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"htmlpage": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"newname": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"reasonphrase": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"responsestatuscode": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
			},
			"target": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"type": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
		},
	}
}

func createResponderactionFunc(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG]  citrixadc-provider: In createResponderactionFunc")
	client := meta.(*NetScalerNitroClient).client
	var responderactionName string
	if v, ok := d.GetOk("name"); ok {
		responderactionName = v.(string)
	} else {
		responderactionName = resource.PrefixedUniqueId("tf-responderaction-")
		d.Set("name", responderactionName)
	}
	responderaction := responder.Responderaction{
		Bypasssafetycheck:  d.Get("bypasssafetycheck").(string),
		Comment:            d.Get("comment").(string),
		Htmlpage:           d.Get("htmlpage").(string),
		Name:               d.Get("name").(string),
		Newname:            d.Get("newname").(string),
		Reasonphrase:       d.Get("reasonphrase").(string),
		Responsestatuscode: d.Get("responsestatuscode").(int),
		Target:             d.Get("target").(string),
		Type:               d.Get("type").(string),
	}

	_, err := client.AddResource(netscaler.Responderaction.Type(), responderactionName, &responderaction)
	if err != nil {
		return err
	}

	d.SetId(responderactionName)

	err = readResponderactionFunc(d, meta)
	if err != nil {
		log.Printf("[ERROR] netscaler-provider: ?? we just created this responderaction but we can't read it ?? %s", responderactionName)
		return nil
	}
	return nil
}

func readResponderactionFunc(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG] citrixadc-provider:  In readResponderactionFunc")
	client := meta.(*NetScalerNitroClient).client
	responderactionName := d.Id()
	log.Printf("[DEBUG] citrixadc-provider: Reading responderaction state %s", responderactionName)
	data, err := client.FindResource(netscaler.Responderaction.Type(), responderactionName)
	if err != nil {
		log.Printf("[WARN] citrixadc-provider: Clearing responderaction state %s", responderactionName)
		d.SetId("")
		return nil
	}
	d.Set("name", data["name"])
	d.Set("bypasssafetycheck", data["bypasssafetycheck"])
	d.Set("comment", data["comment"])
	d.Set("htmlpage", data["htmlpage"])
	d.Set("name", data["name"])
	d.Set("newname", data["newname"])
	d.Set("reasonphrase", data["reasonphrase"])
	d.Set("responsestatuscode", data["responsestatuscode"])
	d.Set("target", data["target"])
	d.Set("type", data["type"])

	return nil

}

func updateResponderactionFunc(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG]  citrixadc-provider: In updateResponderactionFunc")
	client := meta.(*NetScalerNitroClient).client
	responderactionName := d.Get("name").(string)

	responderaction := responder.Responderaction{
		Name: d.Get("name").(string),
	}
	hasChange := false
	if d.HasChange("bypasssafetycheck") {
		log.Printf("[DEBUG]  citrixadc-provider: Bypasssafetycheck has changed for responderaction %s, starting update", responderactionName)
		responderaction.Bypasssafetycheck = d.Get("bypasssafetycheck").(string)
		hasChange = true
	}
	if d.HasChange("comment") {
		log.Printf("[DEBUG]  citrixadc-provider: Comment has changed for responderaction %s, starting update", responderactionName)
		responderaction.Comment = d.Get("comment").(string)
		hasChange = true
	}
	if d.HasChange("htmlpage") {
		log.Printf("[DEBUG]  citrixadc-provider: Htmlpage has changed for responderaction %s, starting update", responderactionName)
		responderaction.Htmlpage = d.Get("htmlpage").(string)
		hasChange = true
	}
	if d.HasChange("name") {
		log.Printf("[DEBUG]  citrixadc-provider: Name has changed for responderaction %s, starting update", responderactionName)
		responderaction.Name = d.Get("name").(string)
		hasChange = true
	}
	if d.HasChange("newname") {
		log.Printf("[DEBUG]  citrixadc-provider: Newname has changed for responderaction %s, starting update", responderactionName)
		responderaction.Newname = d.Get("newname").(string)
		hasChange = true
	}
	if d.HasChange("reasonphrase") {
		log.Printf("[DEBUG]  citrixadc-provider: Reasonphrase has changed for responderaction %s, starting update", responderactionName)
		responderaction.Reasonphrase = d.Get("reasonphrase").(string)
		hasChange = true
	}
	if d.HasChange("responsestatuscode") {
		log.Printf("[DEBUG]  citrixadc-provider: Responsestatuscode has changed for responderaction %s, starting update", responderactionName)
		responderaction.Responsestatuscode = d.Get("responsestatuscode").(int)
		hasChange = true
	}
	if d.HasChange("target") {
		log.Printf("[DEBUG]  citrixadc-provider: Target has changed for responderaction %s, starting update", responderactionName)
		responderaction.Target = d.Get("target").(string)
		hasChange = true
	}
	if d.HasChange("type") {
		log.Printf("[DEBUG]  citrixadc-provider: Type has changed for responderaction %s, starting update", responderactionName)
		responderaction.Type = d.Get("type").(string)
		hasChange = true
	}

	if hasChange {
		_, err := client.UpdateResource(netscaler.Responderaction.Type(), responderactionName, &responderaction)
		if err != nil {
			return fmt.Errorf("Error updating responderaction %s", responderactionName)
		}
	}
	return readResponderactionFunc(d, meta)
}

func deleteResponderactionFunc(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG]  citrixadc-provider: In deleteResponderactionFunc")
	client := meta.(*NetScalerNitroClient).client
	responderactionName := d.Id()
	err := client.DeleteResource(netscaler.Responderaction.Type(), responderactionName)
	if err != nil {
		return err
	}

	d.SetId("")

	return nil
}

func customizeResponderactionDiff(diff *schema.ResourceDiff, meta interface{}) error {
	log.Printf("[DEBUG] citrixadc-provider:  In customizeDiff")
	o := diff.GetChangedKeysPrefix("")

	// Check if target and bypasssafetycheck is in changed keys
	targetDefined := false
	bypasssafetycheckDefined := false

	for _, element := range o {

		if element == "target" {
			targetDefined = true
		}

		if element == "bypasssafetycheck" {
			bypasssafetycheckDefined = true
		}
	}

	// Clear bypasssafetycheck when present without target
	if bypasssafetycheckDefined && !targetDefined {
		diff.Clear("bypasssafetycheck")
	}

	return nil
}
<commit_msg>Remove newname from responderaction resource<commit_after>package citrixadc

import (
	"github.com/chiradeep/go-nitro/config/responder"

	"github.com/chiradeep/go-nitro/netscaler"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"

	"fmt"
	"log"
)

func resourceCitrixAdcResponderaction() *schema.Resource {
	return &schema.Resource{
		SchemaVersion: 1,
		Create:        createResponderactionFunc,
		Read:          readResponderactionFunc,
		Update:        updateResponderactionFunc,
		Delete:        deleteResponderactionFunc,
		CustomizeDiff: customizeResponderactionDiff,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},
		Schema: map[string]*schema.Schema{
			"bypasssafetycheck": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"comment": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"htmlpage": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"reasonphrase": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"responsestatuscode": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
			},
			"target": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"type": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
		},
	}
}

func createResponderactionFunc(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG]  citrixadc-provider: In createResponderactionFunc")
	client := meta.(*NetScalerNitroClient).client
	var responderactionName string
	if v, ok := d.GetOk("name"); ok {
		responderactionName = v.(string)
	} else {
		responderactionName = resource.PrefixedUniqueId("tf-responderaction-")
		d.Set("name", responderactionName)
	}
	responderaction := responder.Responderaction{
		Bypasssafetycheck:  d.Get("bypasssafetycheck").(string),
		Comment:            d.Get("comment").(string),
		Htmlpage:           d.Get("htmlpage").(string),
		Name:               d.Get("name").(string),
		Reasonphrase:       d.Get("reasonphrase").(string),
		Responsestatuscode: d.Get("responsestatuscode").(int),
		Target:             d.Get("target").(string),
		Type:               d.Get("type").(string),
	}

	_, err := client.AddResource(netscaler.Responderaction.Type(), responderactionName, &responderaction)
	if err != nil {
		return err
	}

	d.SetId(responderactionName)

	err = readResponderactionFunc(d, meta)
	if err != nil {
		log.Printf("[ERROR] netscaler-provider: ?? we just created this responderaction but we can't read it ?? %s", responderactionName)
		return nil
	}
	return nil
}

func readResponderactionFunc(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG] citrixadc-provider:  In readResponderactionFunc")
	client := meta.(*NetScalerNitroClient).client
	responderactionName := d.Id()
	log.Printf("[DEBUG] citrixadc-provider: Reading responderaction state %s", responderactionName)
	data, err := client.FindResource(netscaler.Responderaction.Type(), responderactionName)
	if err != nil {
		log.Printf("[WARN] citrixadc-provider: Clearing responderaction state %s", responderactionName)
		d.SetId("")
		return nil
	}
	d.Set("name", data["name"])
	d.Set("bypasssafetycheck", data["bypasssafetycheck"])
	d.Set("comment", data["comment"])
	d.Set("htmlpage", data["htmlpage"])
	d.Set("name", data["name"])
	d.Set("reasonphrase", data["reasonphrase"])
	d.Set("responsestatuscode", data["responsestatuscode"])
	d.Set("target", data["target"])
	d.Set("type", data["type"])

	return nil

}

func updateResponderactionFunc(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG]  citrixadc-provider: In updateResponderactionFunc")
	client := meta.(*NetScalerNitroClient).client
	responderactionName := d.Get("name").(string)

	responderaction := responder.Responderaction{
		Name: d.Get("name").(string),
	}
	hasChange := false
	if d.HasChange("bypasssafetycheck") {
		log.Printf("[DEBUG]  citrixadc-provider: Bypasssafetycheck has changed for responderaction %s, starting update", responderactionName)
		responderaction.Bypasssafetycheck = d.Get("bypasssafetycheck").(string)
		hasChange = true
	}
	if d.HasChange("comment") {
		log.Printf("[DEBUG]  citrixadc-provider: Comment has changed for responderaction %s, starting update", responderactionName)
		responderaction.Comment = d.Get("comment").(string)
		hasChange = true
	}
	if d.HasChange("htmlpage") {
		log.Printf("[DEBUG]  citrixadc-provider: Htmlpage has changed for responderaction %s, starting update", responderactionName)
		responderaction.Htmlpage = d.Get("htmlpage").(string)
		hasChange = true
	}
	if d.HasChange("name") {
		log.Printf("[DEBUG]  citrixadc-provider: Name has changed for responderaction %s, starting update", responderactionName)
		responderaction.Name = d.Get("name").(string)
		hasChange = true
	}
	if d.HasChange("reasonphrase") {
		log.Printf("[DEBUG]  citrixadc-provider: Reasonphrase has changed for responderaction %s, starting update", responderactionName)
		responderaction.Reasonphrase = d.Get("reasonphrase").(string)
		hasChange = true
	}
	if d.HasChange("responsestatuscode") {
		log.Printf("[DEBUG]  citrixadc-provider: Responsestatuscode has changed for responderaction %s, starting update", responderactionName)
		responderaction.Responsestatuscode = d.Get("responsestatuscode").(int)
		hasChange = true
	}
	if d.HasChange("target") {
		log.Printf("[DEBUG]  citrixadc-provider: Target has changed for responderaction %s, starting update", responderactionName)
		responderaction.Target = d.Get("target").(string)
		hasChange = true
	}
	if d.HasChange("type") {
		log.Printf("[DEBUG]  citrixadc-provider: Type has changed for responderaction %s, starting update", responderactionName)
		responderaction.Type = d.Get("type").(string)
		hasChange = true
	}

	if hasChange {
		_, err := client.UpdateResource(netscaler.Responderaction.Type(), responderactionName, &responderaction)
		if err != nil {
			return fmt.Errorf("Error updating responderaction %s", responderactionName)
		}
	}
	return readResponderactionFunc(d, meta)
}

func deleteResponderactionFunc(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG]  citrixadc-provider: In deleteResponderactionFunc")
	client := meta.(*NetScalerNitroClient).client
	responderactionName := d.Id()
	err := client.DeleteResource(netscaler.Responderaction.Type(), responderactionName)
	if err != nil {
		return err
	}

	d.SetId("")

	return nil
}

func customizeResponderactionDiff(diff *schema.ResourceDiff, meta interface{}) error {
	log.Printf("[DEBUG] citrixadc-provider:  In customizeDiff")
	o := diff.GetChangedKeysPrefix("")

	// Check if target and bypasssafetycheck is in changed keys
	targetDefined := false
	bypasssafetycheckDefined := false

	for _, element := range o {

		if element == "target" {
			targetDefined = true
		}

		if element == "bypasssafetycheck" {
			bypasssafetycheckDefined = true
		}
	}

	// Clear bypasssafetycheck when present without target
	if bypasssafetycheckDefined && !targetDefined {
		diff.Clear("bypasssafetycheck")
	}

	return nil
}
<|endoftext|>


<commit_before>package pipe

import (
	"errors"
	"io"
	"sync"
	"time"

	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/signal"
)

type state byte

const (
	open state = iota
	closed
	errord
)

type pipe struct {
	sync.Mutex
	data        buf.MultiBuffer
	readSignal  *signal.Notifier
	writeSignal *signal.Notifier
	limit       int32
	state       state
}

var errBufferFull = errors.New("buffer full")

func (p *pipe) getState(forRead bool) error {
	switch p.state {
	case open:
		if !forRead && p.limit >= 0 && p.data.Len() > p.limit {
			return errBufferFull
		}
		return nil
	case closed:
		if forRead {
			if !p.data.IsEmpty() {
				return nil
			}
			return io.EOF
		}
		return io.ErrClosedPipe
	case errord:
		return io.ErrClosedPipe
	default:
		panic("impossible case")
	}
}

func (p *pipe) readMultiBufferInternal() (buf.MultiBuffer, error) {
	p.Lock()
	defer p.Unlock()

	if err := p.getState(true); err != nil {
		return nil, err
	}

	data := p.data
	p.data = nil
	return data, nil
}

func (p *pipe) ReadMultiBuffer() (buf.MultiBuffer, error) {
	for {
		data, err := p.readMultiBufferInternal()
		if data != nil || err != nil {
			p.writeSignal.Signal()
			return data, err
		}

		<-p.readSignal.Wait()
	}
}

func (p *pipe) ReadMultiBufferWithTimeout(d time.Duration) (buf.MultiBuffer, error) {
	timer := time.After(d)
	for {
		data, err := p.readMultiBufferInternal()
		if data != nil || err != nil {
			p.writeSignal.Signal()
			return data, err
		}

		select {
		case <-p.readSignal.Wait():
		case <-timer:
			return nil, buf.ErrReadTimeout
		}
	}
}

func (p *pipe) writeMultiBufferInternal(mb buf.MultiBuffer) error {
	p.Lock()
	defer p.Unlock()

	if err := p.getState(false); err != nil {
		return err
	}

	p.data.AppendMulti(mb)
	return nil
}

func (p *pipe) WriteMultiBuffer(mb buf.MultiBuffer) error {
	if mb.IsEmpty() {
		return nil
	}

	for {
		err := p.writeMultiBufferInternal(mb)
		if err == nil || err != errBufferFull {
			p.readSignal.Signal()
			return err
		}

		<-p.writeSignal.Wait()
	}
}

func (p *pipe) Close() error {
	p.Lock()
	defer p.Unlock()

	if p.state == closed || p.state == errord {
		return nil
	}

	p.state = closed
	p.readSignal.Signal()
	p.writeSignal.Signal()
	return nil
}

func (p *pipe) CloseError() {
	p.Lock()
	defer p.Unlock()

	p.state = errord

	if !p.data.IsEmpty() {
		p.data.Release()
		p.data = nil
	}

	p.readSignal.Signal()
	p.writeSignal.Signal()
}
<commit_msg>don't error if pipe is already closed.<commit_after>package pipe

import (
	"errors"
	"io"
	"sync"
	"time"

	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/signal"
)

type state byte

const (
	open state = iota
	closed
	errord
)

type pipe struct {
	sync.Mutex
	data        buf.MultiBuffer
	readSignal  *signal.Notifier
	writeSignal *signal.Notifier
	limit       int32
	state       state
}

var errBufferFull = errors.New("buffer full")

func (p *pipe) getState(forRead bool) error {
	switch p.state {
	case open:
		if !forRead && p.limit >= 0 && p.data.Len() > p.limit {
			return errBufferFull
		}
		return nil
	case closed:
		if !forRead {
			return io.ErrClosedPipe
		}
		if !p.data.IsEmpty() {
			return nil
		}
		return io.EOF
	case errord:
		return io.ErrClosedPipe
	default:
		panic("impossible case")
	}
}

func (p *pipe) readMultiBufferInternal() (buf.MultiBuffer, error) {
	p.Lock()
	defer p.Unlock()

	if err := p.getState(true); err != nil {
		return nil, err
	}

	data := p.data
	p.data = nil
	return data, nil
}

func (p *pipe) ReadMultiBuffer() (buf.MultiBuffer, error) {
	for {
		data, err := p.readMultiBufferInternal()
		if data != nil || err != nil {
			p.writeSignal.Signal()
			return data, err
		}

		<-p.readSignal.Wait()
	}
}

func (p *pipe) ReadMultiBufferWithTimeout(d time.Duration) (buf.MultiBuffer, error) {
	timer := time.After(d)
	for {
		data, err := p.readMultiBufferInternal()
		if data != nil || err != nil {
			p.writeSignal.Signal()
			return data, err
		}

		select {
		case <-p.readSignal.Wait():
		case <-timer:
			return nil, buf.ErrReadTimeout
		}
	}
}

func (p *pipe) writeMultiBufferInternal(mb buf.MultiBuffer) error {
	p.Lock()
	defer p.Unlock()

	if err := p.getState(false); err != nil {
		return err
	}

	p.data.AppendMulti(mb)
	return nil
}

func (p *pipe) WriteMultiBuffer(mb buf.MultiBuffer) error {
	if mb.IsEmpty() {
		return nil
	}

	for {
		err := p.writeMultiBufferInternal(mb)
		if err == nil || err != errBufferFull {
			p.readSignal.Signal()
			return err
		}

		<-p.writeSignal.Wait()
	}
}

func (p *pipe) Close() error {
	p.Lock()
	defer p.Unlock()

	if p.state == closed || p.state == errord {
		return nil
	}

	p.state = closed
	p.readSignal.Signal()
	p.writeSignal.Signal()
	return nil
}

func (p *pipe) CloseError() {
	p.Lock()
	defer p.Unlock()

	if p.state == closed || p.state == errord {
		return
	}

	if !p.data.IsEmpty() {
		p.data.Release()
		p.data = nil
	}

	p.readSignal.Signal()
	p.writeSignal.Signal()
}
<|endoftext|>


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

// Package mutator defines the operations to transform mutations into changes in
// the map as well as operations to write and read mutations to and from the
// database.
package mutator

import (
	"errors"

	"github.com/golang/protobuf/proto"

	"github.com/google/keytransparency/core/transaction"

	tpb "github.com/google/keytransparency/core/proto/keytransparency_v1_proto"
)

var (
	// MaxMutationSize represent the maximum allowed mutation size in bytes.
	MaxMutationSize = 16 * 1024
	// ErrReplay occurs when two mutations acting on the same entry & epoch
	// occur.
	ErrReplay = errors.New("mutation replay")
	// ErrSize occurs when the mutation size is larger than the allowed upper
	// bound.
	ErrSize = errors.New("mutation: too large")
	// ErrPreviousHash occurs when the mutation the hash of the previous
	// entry provided in the mutation does not match the previous entry
	// itself.
	ErrPreviousHash = errors.New("mutation: previous entry hash does not match the hash provided in the mutation")
	// ErrMissingKey occurs when a mutation does not have authorized keys.
	ErrMissingKey = errors.New("mutation: missing authorized key(s)")
	// ErrInvalidSig occurs when either the current or previous update entry
	// signature verification fails.
	ErrInvalidSig = errors.New("mutation: invalid signature")
	// ErrUnauthorized occurs when the mutation has not been signed by a key in the
	// previous entry.
	ErrUnauthorized = errors.New("mutation: unauthorized")
)

// Mutator verifies mutations and transforms values in the map.
type Mutator interface {
	// Mutate verifies that this is a valid mutation for this item and
	// applies mutation to value.
	Mutate(value, mutation proto.Message) (proto.Message, error)
}

// Mutation reads and writes mutations to the database.
// TODO: Add mapID to this interface to support multiple maps per server.
type Mutation interface {
	// ReadRange reads all mutations for a specific given mapID and sequence
	// range. The range is identified by a starting sequence number and a
	// count. Note that startSequence is not included in the result.
	// ReadRange stops when endSequence or count is reached, whichever comes
	// first. ReadRange also returns the maximum sequence number read.
	ReadRange(txn transaction.Txn, startSequence, endSequence uint64, count int32) (uint64, []*tpb.Entry, error)
	// ReadAll reads all mutations starting from the given sequence number.
	// Note that startSequence is not included in the result. ReadAll also
	// returns the maximum sequence number read.
	ReadAll(txn transaction.Txn, startSequence uint64) (uint64, []*tpb.Entry, error)
	// Write saves the mutation in the database. Write returns the sequence
	// number that is written.
	Write(txn transaction.Txn, mutation *tpb.Entry) (uint64, error)
}
<commit_msg>Add mapID to mutation interface<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package mutator defines the operations to transform mutations into changes in
// the map as well as operations to write and read mutations to and from the
// database.
package mutator

import (
	"errors"

	"github.com/golang/protobuf/proto"

	"github.com/google/keytransparency/core/transaction"

	tpb "github.com/google/keytransparency/core/proto/keytransparency_v1_proto"
)

var (
	// MaxMutationSize represent the maximum allowed mutation size in bytes.
	MaxMutationSize = 16 * 1024
	// ErrReplay occurs when two mutations acting on the same entry & epoch
	// occur.
	ErrReplay = errors.New("mutation replay")
	// ErrSize occurs when the mutation size is larger than the allowed upper
	// bound.
	ErrSize = errors.New("mutation: too large")
	// ErrPreviousHash occurs when the mutation the hash of the previous
	// entry provided in the mutation does not match the previous entry
	// itself.
	ErrPreviousHash = errors.New("mutation: previous entry hash does not match the hash provided in the mutation")
	// ErrMissingKey occurs when a mutation does not have authorized keys.
	ErrMissingKey = errors.New("mutation: missing authorized key(s)")
	// ErrInvalidSig occurs when either the current or previous update entry
	// signature verification fails.
	ErrInvalidSig = errors.New("mutation: invalid signature")
	// ErrUnauthorized occurs when the mutation has not been signed by a key in the
	// previous entry.
	ErrUnauthorized = errors.New("mutation: unauthorized")
)

// Mutator verifies mutations and transforms values in the map.
type Mutator interface {
	// Mutate verifies that this is a valid mutation for this item and
	// applies mutation to value.
	Mutate(value, mutation proto.Message) (proto.Message, error)
}

// Mutation reads and writes mutations to the database.
type Mutation interface {
	// ReadRange reads all mutations for a specific given mapID and sequence
	// range. The range is identified by a starting sequence number and a
	// count. Note that startSequence is not included in the result.
	// ReadRange stops when endSequence or count is reached, whichever comes
	// first. ReadRange also returns the maximum sequence number read.
	ReadRange(txn transaction.Txn, mapID int64, startSequence, endSequence uint64, count int32) (uint64, []*tpb.Entry, error)
	// ReadAll reads all mutations starting from the given sequence number.
	// Note that startSequence is not included in the result. ReadAll also
	// returns the maximum sequence number read.
	ReadAll(txn transaction.Txn, mapID int64, startSequence uint64) (uint64, []*tpb.Entry, error)
	// Write saves the mutation in the database. Write returns the sequence
	// number that is written.
	Write(txn transaction.Txn, mapID int64, mutation *tpb.Entry) (uint64, error)
}
<|endoftext|>


<commit_before>package lsof

import (
	"errors"

	vnet "v2ray.com/core/common/net"
)

func GetCommandNameBySocket(network string, addr vnet.Address, port vnet.Port) (string, error) {
	return "", errors.New("not implemented")
}
<commit_msg>fix build<commit_after>package lsof

import (
	"errors"
)

func GetCommandNameBySocket(network string, addr string, port uint16) (string, error) {
	return "", errors.New("not implemented")
}
<|endoftext|>


<commit_before>package event

import (
	"fmt"
	"github.com/Cepave/alarm/logger"
	coommonModel "github.com/Cepave/common/model"
	"github.com/Cepave/common/utils"
	"github.com/astaxie/beego/orm"
	"time"
)

func insertEvent(q orm.Ormer, eve *coommonModel.Event) (res interface{}, err error) {
	var status int
	if status = 0; eve.Status == "OK" {
		status = 1
	}
	sqltemplete := `INSERT INTO events (
		event_caseId,
		step,
		cond,
		status,
		timestamp
	) VALUES(?,?,?,?,?)`
	res, err = q.Raw(
		sqltemplete,
		eve.Id,
		eve.CurrentStep,
		fmt.Sprintf("%v %v %v", eve.LeftValue, eve.Operator(), eve.RightValue()),
		status,
		time.Unix(eve.EventTime, 0),
	).Exec()
	return
}

func InsertEvent(eve *coommonModel.Event) {
	log := logger.Logger()
	q := orm.NewOrm()
	q.Using("falcon_portal")
	var event []EventCases
	q.Raw("select * from event_cases where id = ?", eve.Id).QueryRows(&event)
	if len(event) == 0 {
		//create cases
		sqltemplete := `INSERT INTO event_cases (
					id,
					endpoint,
					metric,
					func,
					cond,
					note,
					max_step,
					current_step,
					priority,
					status,
					timestamp,
					update_at,
					tpl_creator,
					expression_id,
					strategy_id,
					template_id
					) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`
		res1, err := q.Raw(
			sqltemplete,
			eve.Id,
			eve.Endpoint,
			counterGen(eve.Metric(), utils.SortedTags(eve.PushedTags)),
			eve.Func(),
			//cond
			fmt.Sprintf("%v %v %v", eve.LeftValue, eve.Operator(), eve.RightValue()),
			eve.Strategy.Note,
			eve.MaxStep(),
			eve.CurrentStep,
			eve.Priority(),
			eve.Status,
			//start_at
			time.Unix(eve.EventTime, 0),
			//update_at
			time.Unix(eve.EventTime, 0),
			eve.Strategy.Tpl.Creator,
			eve.ExpressionId(),
			eve.StrategyId(),
			//template_id
			eve.TplId()).Exec()
		log.Debug(fmt.Sprintf("%v, %v", res1, err))

		//insert case
		res2, err := insertEvent(q, eve)
		log.Debug(fmt.Sprintf("%v, %v", res2, err))

	} else {
		//update cases
		res1, err := q.Raw(
			`UPDATE event_cases SET
					update_at = ?,
					max_step = ?,
					current_step = ?,
					note = ?,
					cond = ?,
					status = ?
					WHERE id = ?`,
			time.Unix(eve.EventTime, 0),
			eve.MaxStep(),
			eve.CurrentStep,
			eve.Strategy.Note,
			fmt.Sprintf("%v %v %v", eve.LeftValue, eve.Operator(), eve.RightValue()),
			eve.Status,
			eve.Id).Exec()
		log.Debug(fmt.Sprintf("%v, %v", res1, err))
		//insert case
		res2, err := insertEvent(q, eve)
		log.Debug(fmt.Sprintf("%v, %v", res2, err))
	}
}

func counterGen(metric string, tags string) (mycounter string) {
	mycounter = metric
	if tags != "" {
		mycounter = fmt.Sprintf("%s/%s", metric, tags)
	}
	return
}
<commit_msg>update the start time of cases in every step 1<commit_after>package event

import (
	"fmt"
	"github.com/Cepave/alarm/logger"
	coommonModel "github.com/Cepave/common/model"
	"github.com/Cepave/common/utils"
	"github.com/astaxie/beego/orm"
	"time"
)

func insertEvent(q orm.Ormer, eve *coommonModel.Event) (res interface{}, err error) {
	var status int
	if status = 0; eve.Status == "OK" {
		status = 1
	}
	sqltemplete := `INSERT INTO events (
		event_caseId,
		step,
		cond,
		status,
		timestamp
	) VALUES(?,?,?,?,?)`
	res, err = q.Raw(
		sqltemplete,
		eve.Id,
		eve.CurrentStep,
		fmt.Sprintf("%v %v %v", eve.LeftValue, eve.Operator(), eve.RightValue()),
		status,
		time.Unix(eve.EventTime, 0),
	).Exec()
	return
}

func InsertEvent(eve *coommonModel.Event) {
	log := logger.Logger()
	q := orm.NewOrm()
	q.Using("falcon_portal")
	var event []EventCases
	q.Raw("select * from event_cases where id = ?", eve.Id).QueryRows(&event)
	if len(event) == 0 {
		//create cases
		sqltemplete := `INSERT INTO event_cases (
					id,
					endpoint,
					metric,
					func,
					cond,
					note,
					max_step,
					current_step,
					priority,
					status,
					timestamp,
					update_at,
					tpl_creator,
					expression_id,
					strategy_id,
					template_id
					) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`
		res1, err := q.Raw(
			sqltemplete,
			eve.Id,
			eve.Endpoint,
			counterGen(eve.Metric(), utils.SortedTags(eve.PushedTags)),
			eve.Func(),
			//cond
			fmt.Sprintf("%v %v %v", eve.LeftValue, eve.Operator(), eve.RightValue()),
			eve.Strategy.Note,
			eve.MaxStep(),
			eve.CurrentStep,
			eve.Priority(),
			eve.Status,
			//start_at
			time.Unix(eve.EventTime, 0),
			//update_at
			time.Unix(eve.EventTime, 0),
			eve.Strategy.Tpl.Creator,
			eve.ExpressionId(),
			eve.StrategyId(),
			//template_id
			eve.TplId()).Exec()
		log.Debug(fmt.Sprintf("%v, %v", res1, err))

		//insert case
		res2, err := insertEvent(q, eve)
		log.Debug(fmt.Sprintf("%v, %v", res2, err))

	} else {

		if eve.CurrentStep == 1 {
			//update start time of cases
			res1, err := q.Raw(
				`UPDATE event_cases SET
						timestamp = ?,
						update_at = ?,
						max_step = ?,
						current_step = ?,
						note = ?,
						cond = ?,
						status = ?
						WHERE id = ?`,
				time.Unix(eve.EventTime, 0),
				time.Unix(eve.EventTime, 0),
				eve.MaxStep(),
				eve.CurrentStep,
				eve.Strategy.Note,
				fmt.Sprintf("%v %v %v", eve.LeftValue, eve.Operator(), eve.RightValue()),
				eve.Status,
				eve.Id).Exec()
			log.Debug(fmt.Sprintf("%v, %v", res1, err))
			//insert case
			res2, err := insertEvent(q, eve)
			log.Debug(fmt.Sprintf("%v, %v", res2, err))
		} else {
			res1, err := q.Raw(
				`UPDATE event_cases SET
						update_at = ?,
						max_step = ?,
						current_step = ?,
						note = ?,
						cond = ?,
						status = ?
						WHERE id = ?`,
				time.Unix(eve.EventTime, 0),
				eve.MaxStep(),
				eve.CurrentStep,
				eve.Strategy.Note,
				fmt.Sprintf("%v %v %v", eve.LeftValue, eve.Operator(), eve.RightValue()),
				eve.Status,
				eve.Id).Exec()
			log.Debug(fmt.Sprintf("%v, %v", res1, err))
			//insert case
			res2, err := insertEvent(q, eve)
			log.Debug(fmt.Sprintf("%v, %v", res2, err))
		}
	}
}

func counterGen(metric string, tags string) (mycounter string) {
	mycounter = metric
	if tags != "" {
		mycounter = fmt.Sprintf("%s/%s", metric, tags)
	}
	return
}
<|endoftext|>


<commit_before>package thumbs

import (
	"crypto/md5"
	"database/sql"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"sync"

	"github.com/cheggaaa/pb"
	_ "github.com/mattn/go-sqlite3"
)

const (
	thumbsDir = "public/thumbs"
	workers   = 4 // should be at least 1
)

var thumbsPath string

func generateThumb(photoPath, thumbPath, thumbSize string, crop bool) error {
	if _, err := os.Stat(thumbPath); err == nil { // file exists
		return err
	}

	vipsOpts := []string{
		"--rotate",
		"--size", thumbSize,
		"--interpolator", "bicubic",
		"--output", thumbPath + "[Q=97,no_subsample,strip]",
	}

	if crop {
		vipsOpts = append(vipsOpts, "--crop")
	}

	cmdArgs := append([]string{photoPath}, vipsOpts...)
	return exec.Command("vipsthumbnail", cmdArgs...).Run()
}

func generateThumbs(photoPath string) (err error) {
	smallThumbPhotoPath := photoPath

	identifier := fmt.Sprintf("%x", md5.Sum([]byte(photoPath)))
	thumbPathFmt := path.Join(thumbsPath, fmt.Sprintf("%s_%%s.jpg", identifier))
	bigThumbPath := fmt.Sprintf(thumbPathFmt, "big")
	smallThumbPath := fmt.Sprintf(thumbPathFmt, "small")

	err = generateThumb(photoPath, bigThumbPath, "1000", false)
	if err == nil {
		smallThumbPhotoPath = bigThumbPath // create small thumb from big for speed
	} else {
		log.Println("Failed to create", bigThumbPath, "for", photoPath, "with error:", err)
	}

	err = generateThumb(smallThumbPhotoPath, smallThumbPath, "200", true)
	if err != nil {
		log.Println("Failed to create", smallThumbPath, "for", photoPath, "with error:", err)
	}

	return
}

func GenerateThumbs(thymePath string) {
	var photosCount int

	logFile, err := os.Create("thyme-generate-thumbs.log")
	if err == nil {
		log.SetOutput(logFile)
	}
	defer logFile.Close()

	dbPath := path.Join(os.Getenv("HOME"), ".thyme.db")
	db, err := sql.Open("sqlite3", dbPath)
	if err != nil {
		log.Fatalln("Failed to open database:", err)
	}
	defer db.Close()

	rows, err := db.Query(`
	SELECT path FROM photos
	JOIN sets ON photos.set_id = sets.id
	ORDER BY sets.taken_at DESC, photos.taken_at ASC
	`)
	if err != nil {
		log.Fatalln("Failed to access table:", err)
	}
	defer rows.Close()

	err = db.QueryRow("SELECT COUNT(*) FROM photos").Scan(&photosCount)
	if err != nil {
		log.Fatalln("Failed to get photos count:", err)
	}

	thumbsPath, err = filepath.Abs(path.Join(thymePath, thumbsDir))
	if err != nil {
		log.Fatalln("Failed to resolve absolute path:", err)
	}

	err = os.MkdirAll(thumbsPath, os.ModeDir|0755)
	if err != nil {
		log.Fatalln("Failed to create thumbs path:", err)
	}

	ch := make(chan string)
	wg := sync.WaitGroup{}
	bar := pb.StartNew(photosCount)

	for i := 0; i < workers; i++ {
		wg.Add(1)
		go func() {
			for photoPath := range ch {
				generateThumbs(photoPath)
				bar.Increment()
			}

			wg.Done()
		}()
	}

	for rows.Next() {
		var photoPath string
		if err := rows.Scan(&photoPath); err != nil {
			log.Fatalln("Failed to get photo path:", err)
		}
		ch <- photoPath
	}

	close(ch)
	wg.Wait()

	if err := rows.Err(); err != nil {
		log.Fatalln(err)
	}

	// Remove empty log file
	logFileInfo, err := logFile.Stat()
	if err == nil && logFileInfo.Size() == 0 {
		os.Remove(logFileInfo.Name())
	}
}
<commit_msg>Log to file right before showing progress bar<commit_after>package thumbs

import (
	"crypto/md5"
	"database/sql"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"sync"

	"github.com/cheggaaa/pb"
	_ "github.com/mattn/go-sqlite3"
)

const (
	thumbsDir = "public/thumbs"
	workers   = 4 // should be at least 1
)

var thumbsPath string

func generateThumb(photoPath, thumbPath, thumbSize string, crop bool) error {
	if _, err := os.Stat(thumbPath); err == nil { // file exists
		return err
	}

	vipsOpts := []string{
		"--rotate",
		"--size", thumbSize,
		"--interpolator", "bicubic",
		"--output", thumbPath + "[Q=97,no_subsample,strip]",
	}

	if crop {
		vipsOpts = append(vipsOpts, "--crop")
	}

	cmdArgs := append([]string{photoPath}, vipsOpts...)
	return exec.Command("vipsthumbnail", cmdArgs...).Run()
}

func generateThumbs(photoPath string) (err error) {
	smallThumbPhotoPath := photoPath

	identifier := fmt.Sprintf("%x", md5.Sum([]byte(photoPath)))
	thumbPathFmt := path.Join(thumbsPath, fmt.Sprintf("%s_%%s.jpg", identifier))
	bigThumbPath := fmt.Sprintf(thumbPathFmt, "big")
	smallThumbPath := fmt.Sprintf(thumbPathFmt, "small")

	err = generateThumb(photoPath, bigThumbPath, "1000", false)
	if err == nil {
		smallThumbPhotoPath = bigThumbPath // create small thumb from big for speed
	} else {
		log.Println("Failed to create", bigThumbPath, "for", photoPath, "with error:", err)
	}

	err = generateThumb(smallThumbPhotoPath, smallThumbPath, "200", true)
	if err != nil {
		log.Println("Failed to create", smallThumbPath, "for", photoPath, "with error:", err)
	}

	return
}

func GenerateThumbs(thymePath string) {
	var photosCount int

	dbPath := path.Join(os.Getenv("HOME"), ".thyme.db")
	db, err := sql.Open("sqlite3", dbPath)
	if err != nil {
		log.Fatalln("Failed to open database:", err)
	}
	defer db.Close()

	rows, err := db.Query(`
	SELECT path FROM photos
	JOIN sets ON photos.set_id = sets.id
	ORDER BY sets.taken_at DESC, photos.taken_at ASC
	`)
	if err != nil {
		log.Fatalln("Failed to access table:", err)
	}
	defer rows.Close()

	err = db.QueryRow("SELECT COUNT(*) FROM photos").Scan(&photosCount)
	if err != nil {
		log.Fatalln("Failed to get photos count:", err)
	}

	thumbsPath, err = filepath.Abs(path.Join(thymePath, thumbsDir))
	if err != nil {
		log.Fatalln("Failed to resolve absolute path:", err)
	}

	err = os.MkdirAll(thumbsPath, os.ModeDir|0755)
	if err != nil {
		log.Fatalln("Failed to create thumbs path:", err)
	}

	// log to file because a progress bar is going to be rendered
	logFile, err := os.Create("thyme-generate-thumbs.log")
	if err == nil {
		log.SetOutput(logFile)
	}
	defer logFile.Close()

	ch := make(chan string)
	wg := sync.WaitGroup{}
	bar := pb.StartNew(photosCount)

	for i := 0; i < workers; i++ {
		wg.Add(1)
		go func() {
			for photoPath := range ch {
				generateThumbs(photoPath)
				bar.Increment()
			}

			wg.Done()
		}()
	}

	for rows.Next() {
		var photoPath string
		if err := rows.Scan(&photoPath); err != nil {
			log.Fatalln("Failed to get photo path:", err)
		}
		ch <- photoPath
	}

	close(ch)
	wg.Wait()

	if err := rows.Err(); err != nil {
		log.Fatalln(err)
	}

	// Remove empty log file
	logFileInfo, err := logFile.Stat()
	if err == nil && logFileInfo.Size() == 0 {
		os.Remove(logFileInfo.Name())
	}
}
<|endoftext|>


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

package oto

import (
	"errors"
	"io"
	"reflect"
	"runtime"
	"sync"
	"syscall/js"
	"unsafe"
)

type context struct {
	audioContext js.Value
	ready        bool
	callbacks    map[string]js.Func

	sampleRate      int
	channelNum      int
	bitDepthInBytes int
}

func newContext(sampleRate int, channelNum int, bitDepthInBytes int) (*context, chan struct{}, error) {
	ready := make(chan struct{})

	class := js.Global().Get("AudioContext")
	if !class.Truthy() {
		class = js.Global().Get("webkitAudioContext")
	}
	if !class.Truthy() {
		return nil, nil, errors.New("oto: AudioContext or webkitAudioContext was not found")
	}
	options := js.Global().Get("Object").New()
	options.Set("sampleRate", sampleRate)

	d := &context{
		audioContext:    class.New(options),
		sampleRate:      sampleRate,
		channelNum:      channelNum,
		bitDepthInBytes: bitDepthInBytes,
	}

	setCallback := func(event string) js.Func {
		var f js.Func
		f = js.FuncOf(func(this js.Value, arguments []js.Value) interface{} {
			if !d.ready {
				d.audioContext.Call("resume")
				d.ready = true
				close(ready)
			}
			js.Global().Get("document").Call("removeEventListener", event, f)
			return nil
		})
		js.Global().Get("document").Call("addEventListener", event, f)
		d.callbacks[event] = f
		return f
	}

	// Browsers require user interaction to start the audio.
	// https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#webaudio
	d.callbacks = map[string]js.Func{}
	setCallback("touchend")
	setCallback("keyup")
	setCallback("mouseup")

	return d, ready, nil
}

type player struct {
	context *context
	src     io.Reader
	eof     bool
	state   playerState
	gain    js.Value
	err     error
	buf     []byte

	nextPos           float64
	bufferSourceNodes []js.Value
	appendBufferFunc  js.Func

	cond *sync.Cond
}

func (c *context) NewPlayer(src io.Reader) Player {
	p := &player{
		context: c,
		src:     src,
		gain:    c.audioContext.Call("createGain"),
		cond:    sync.NewCond(&sync.Mutex{}),
	}
	p.appendBufferFunc = js.FuncOf(p.appendBuffer)
	p.gain.Call("connect", c.audioContext.Get("destination"))
	runtime.SetFinalizer(p, (*player).Close)
	return p
}

func (c *context) Suspend() error {
	c.audioContext.Call("suspend")
	return nil
}

func (c *context) Resume() error {
	c.audioContext.Call("resume")
	return nil
}

func (c *context) Err() error {
	return nil
}

func (p *player) Play() {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.err != nil {
		return
	}
	if p.state != playerPaused {
		return
	}

	buf := make([]byte, p.context.maxBufferSize())
	for len(p.buf) < p.context.maxBufferSize() {
		n, err := p.src.Read(buf)
		if err != nil && err != io.EOF {
			p.setErrorImpl(err)
			return
		}
		p.buf = append(p.buf, buf[:n]...)
		if err == io.EOF {
			p.eof = true
			break
		}
	}

	p.state = playerPlay
	p.appendBufferImpl(js.Undefined())
	p.appendBufferImpl(js.Undefined())

	go p.loop()
}

func (p *player) Pause() {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	p.pauseImpl()
}

func (p *player) pauseImpl() {
	if p.err != nil {
		return
	}
	if p.state != playerPlay {
		return
	}

	// Change the state first. appendBuffer is called as an 'ended' callback.
	var data [2][]float32
	for _, n := range p.bufferSourceNodes {
		for ch := 0; ch < 2; ch++ {
			t := n.Get("buffer").Call("getChannelData", ch)
			data[ch] = append(data[ch], float32ArrayToFloat32Slice(t)...)
		}
		n.Set("onended", nil)
		n.Call("stop")
		n.Call("disconnect")
	}
	p.buf = append(fromLR(data[0], data[1]), p.buf...)
	p.state = playerPaused
	p.bufferSourceNodes = p.bufferSourceNodes[:0]
	p.nextPos = 0
	p.cond.Signal()
}

func (p *player) appendBuffer(this js.Value, args []js.Value) interface{} {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	p.appendBufferImpl(this)
	return nil
}

func (p *player) appendBufferImpl(audioBuffer js.Value) {
	// appendBuffer is called as the 'ended' callback of a buffer.
	// 'this' is an AudioBufferSourceNode that already finishes its playing.
	for i, n := range p.bufferSourceNodes {
		if n.Equal(audioBuffer) {
			p.bufferSourceNodes = append(p.bufferSourceNodes[:i], p.bufferSourceNodes[i+1:]...)
			break
		}
	}

	if p.state != playerPlay {
		return
	}

	if p.eof && len(p.buf) == 0 {
		if len(p.bufferSourceNodes) == 0 {
			p.pauseImpl()
		}
		return
	}

	c := p.context.audioContext.Get("currentTime").Float()
	if p.nextPos < c {
		// The exact current time might be too early. Add some delay on purpose to avoid buffer overlapping.
		p.nextPos = c + 1.0/60.0
	}

	bs := make([]byte, p.context.oneBufferSize())
	n := copy(bs, p.buf)
	copy(p.buf, p.buf[n:])
	p.buf = p.buf[:len(p.buf)-n]
	if len(p.buf) < p.context.maxBufferSize() {
		p.cond.Signal()
	}

	if len(bs) == 0 {
		// createBuffer fails with 0 bytes. Add some zeros instead.
		bs = make([]byte, 4096)
	}

	l, r := toLR(bs)
	tl, tr := float32SliceToTypedArray(l), float32SliceToTypedArray(r)

	buf := p.context.audioContext.Call("createBuffer", p.context.channelNum, len(bs)/p.context.channelNum/p.context.bitDepthInBytes, p.context.sampleRate)
	if buf.Get("copyToChannel").Truthy() {
		buf.Call("copyToChannel", tl, 0, 0)
		buf.Call("copyToChannel", tr, 1, 0)
	} else {
		// copyToChannel is not defined on Safari 11.
		buf.Call("getChannelData", 0).Call("set", tl)
		buf.Call("getChannelData", 1).Call("set", tr)
	}

	s := p.context.audioContext.Call("createBufferSource")
	s.Set("buffer", buf)
	s.Set("onended", p.appendBufferFunc)
	s.Call("connect", p.gain)
	s.Call("start", p.nextPos)
	p.nextPos += buf.Get("duration").Float()
	p.bufferSourceNodes = append(p.bufferSourceNodes, s)

	return
}

func (p *player) IsPlaying() bool {
	return p.state == playerPlay
}

func (p *player) Reset() {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	p.resetImpl()
}

func (p *player) resetImpl() {
	if p.err != nil {
		return
	}
	if p.state == playerClosed {
		return
	}

	p.pauseImpl()
	p.eof = false
	p.buf = p.buf[:0]
}

func (p *player) Volume() float64 {
	return p.gain.Get("gain").Get("value").Float()
}

func (p *player) SetVolume(volume float64) {
	p.gain.Get("gain").Set("value", volume)
}

func (p *player) UnplayedBufferSize() int {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	// This is not an accurate buffer size as part of the buffers might already be consumed.
	var sec float64
	for _, n := range p.bufferSourceNodes {
		sec += n.Get("buffer").Get("duration").Float()
	}
	return len(p.buf) + int(sec*float64(p.context.sampleRate*p.context.channelNum*p.context.bitDepthInBytes))
}

func (p *player) Err() error {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	return p.err
}

func (p *player) Close() error {
	runtime.SetFinalizer(p, nil)
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	return p.closeImpl()
}

func (p *player) closeImpl() error {
	p.resetImpl()
	p.state = playerClosed
	p.appendBufferFunc.Release()
	p.cond.Signal()
	return p.err
}

func (p *player) setError(err error) {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	p.setErrorImpl(err)
}

func (p *player) setErrorImpl(err error) {
	p.err = err
	p.closeImpl()
}

func (p *player) shouldWait() bool {
	switch p.state {
	case playerPaused:
		// Even when the player is paused, the loop immediately ends.
		// WebAudio doesn't have a notion of pause.
		return false
	case playerPlay:
		return len(p.buf) >= p.context.maxBufferSize()
	case playerClosed:
		return false
	default:
		panic("not reached")
	}
}

func (p *player) wait() bool {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	for p.shouldWait() {
		p.cond.Wait()
	}
	return p.state == playerPlay && !p.eof
}

func (p *player) loop() {
	buf := make([]byte, 4096)
	for {
		if !p.wait() {
			return
		}

		n, err := p.src.Read(buf)
		if err != nil && err != io.EOF {
			p.setError(err)
			return
		}

		p.cond.L.Lock()
		p.buf = append(p.buf, buf[:n]...)
		if err == io.EOF {
			// p.eof can be true even if the buffer is not consumed yet.
			// This might be different from the other drivers.
			p.eof = true
			p.cond.L.Unlock()
			return
		}
		p.cond.L.Unlock()
	}
}

func toLR(data []byte) ([]float32, []float32) {
	const max = 1 << 15

	l := make([]float32, len(data)/4)
	r := make([]float32, len(data)/4)
	for i := 0; i < len(data)/4; i++ {
		l[i] = float32(int16(data[4*i])|int16(data[4*i+1])<<8) / max
		r[i] = float32(int16(data[4*i+2])|int16(data[4*i+3])<<8) / max
	}
	return l, r
}

func fromLR(l, r []float32) []byte {
	const max = 1 << 15

	if len(l) != len(r) {
		panic("oto: len(l) must equal to len(r) at fromLR")
	}
	bs := make([]byte, len(l)*4)
	for i := range l {
		lv := int16(l[i] * max)
		bs[4*i] = byte(lv)
		bs[4*i+1] = byte(lv >> 8)
		rv := int16(r[i] * max)
		bs[4*i+2] = byte(rv)
		bs[4*i+3] = byte(rv >> 8)
	}
	return bs
}

func float32SliceToTypedArray(s []float32) js.Value {
	h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
	h.Len *= 4
	h.Cap *= 4
	bs := *(*[]byte)(unsafe.Pointer(h))

	a := js.Global().Get("Uint8Array").New(len(bs))
	js.CopyBytesToJS(a, bs)
	runtime.KeepAlive(s)
	buf := a.Get("buffer")
	return js.Global().Get("Float32Array").New(buf, a.Get("byteOffset"), a.Get("byteLength").Int()/4)
}

func float32ArrayToFloat32Slice(v js.Value) []float32 {
	bs := make([]byte, v.Get("byteLength").Int())
	js.CopyBytesToGo(bs, js.Global().Get("Uint8Array").New(v.Get("buffer"), v.Get("byteOffset"), v.Get("byteLength")))

	h := (*reflect.SliceHeader)(unsafe.Pointer(&bs))
	h.Len /= 4
	h.Cap /= 4
	f32s := *(*[]float32)(unsafe.Pointer(h))
	runtime.KeepAlive(bs)

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

package oto

import (
	"errors"
	"io"
	"reflect"
	"runtime"
	"sync"
	"syscall/js"
	"unsafe"
)

type context struct {
	audioContext js.Value
	ready        bool
	callbacks    map[string]js.Func

	sampleRate      int
	channelNum      int
	bitDepthInBytes int
}

func newContext(sampleRate int, channelNum int, bitDepthInBytes int) (*context, chan struct{}, error) {
	ready := make(chan struct{})

	class := js.Global().Get("AudioContext")
	if !class.Truthy() {
		class = js.Global().Get("webkitAudioContext")
	}
	if !class.Truthy() {
		return nil, nil, errors.New("oto: AudioContext or webkitAudioContext was not found")
	}
	options := js.Global().Get("Object").New()
	options.Set("sampleRate", sampleRate)

	d := &context{
		audioContext:    class.New(options),
		sampleRate:      sampleRate,
		channelNum:      channelNum,
		bitDepthInBytes: bitDepthInBytes,
	}

	setCallback := func(event string) js.Func {
		var f js.Func
		f = js.FuncOf(func(this js.Value, arguments []js.Value) interface{} {
			if !d.ready {
				d.audioContext.Call("resume")
				d.ready = true
				close(ready)
			}
			js.Global().Get("document").Call("removeEventListener", event, f)
			return nil
		})
		js.Global().Get("document").Call("addEventListener", event, f)
		d.callbacks[event] = f
		return f
	}

	// Browsers require user interaction to start the audio.
	// https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#webaudio
	d.callbacks = map[string]js.Func{}
	setCallback("touchend")
	setCallback("keyup")
	setCallback("mouseup")

	return d, ready, nil
}

type player struct {
	context *context
	src     io.Reader
	eof     bool
	state   playerState
	gain    js.Value
	err     error
	buf     []byte

	f32L []float32
	f32R []float32

	nextPos           float64
	bufferSourceNodes []js.Value
	appendBufferFunc  js.Func

	cond *sync.Cond
}

func (c *context) NewPlayer(src io.Reader) Player {
	p := &player{
		context: c,
		src:     src,
		gain:    c.audioContext.Call("createGain"),
		cond:    sync.NewCond(&sync.Mutex{}),
	}
	p.appendBufferFunc = js.FuncOf(p.appendBuffer)
	p.gain.Call("connect", c.audioContext.Get("destination"))
	runtime.SetFinalizer(p, (*player).Close)
	return p
}

func (c *context) Suspend() error {
	c.audioContext.Call("suspend")
	return nil
}

func (c *context) Resume() error {
	c.audioContext.Call("resume")
	return nil
}

func (c *context) Err() error {
	return nil
}

func (p *player) Play() {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.err != nil {
		return
	}
	if p.state != playerPaused {
		return
	}

	buf := make([]byte, p.context.maxBufferSize())
	for len(p.buf) < p.context.maxBufferSize() {
		n, err := p.src.Read(buf)
		if err != nil && err != io.EOF {
			p.setErrorImpl(err)
			return
		}
		p.buf = append(p.buf, buf[:n]...)
		if err == io.EOF {
			p.eof = true
			break
		}
	}

	p.state = playerPlay
	p.appendBufferImpl(js.Undefined())
	p.appendBufferImpl(js.Undefined())

	go p.loop()
}

func (p *player) Pause() {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	p.pauseImpl()
}

func (p *player) pauseImpl() {
	if p.err != nil {
		return
	}
	if p.state != playerPlay {
		return
	}

	// Change the state first. appendBuffer is called as an 'ended' callback.
	var data [2][]float32
	for _, n := range p.bufferSourceNodes {
		for ch := 0; ch < 2; ch++ {
			t := n.Get("buffer").Call("getChannelData", ch)
			data[ch] = append(data[ch], float32ArrayToFloat32Slice(t)...)
		}
		n.Set("onended", nil)
		n.Call("stop")
		n.Call("disconnect")
	}

	bs := make([]byte, len(data[0])*4)
	fromLR(bs, data[0], data[1])
	p.buf = append(p.buf, bs...)
	p.state = playerPaused
	p.bufferSourceNodes = p.bufferSourceNodes[:0]
	p.nextPos = 0
	p.cond.Signal()
}

func (p *player) appendBuffer(this js.Value, args []js.Value) interface{} {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	p.appendBufferImpl(this)
	return nil
}

func (p *player) appendBufferImpl(audioBuffer js.Value) {
	// appendBuffer is called as the 'ended' callback of a buffer.
	// 'this' is an AudioBufferSourceNode that already finishes its playing.
	for i, n := range p.bufferSourceNodes {
		if n.Equal(audioBuffer) {
			p.bufferSourceNodes = append(p.bufferSourceNodes[:i], p.bufferSourceNodes[i+1:]...)
			break
		}
	}

	if p.state != playerPlay {
		return
	}

	if p.eof && len(p.buf) == 0 {
		if len(p.bufferSourceNodes) == 0 {
			p.pauseImpl()
		}
		return
	}

	c := p.context.audioContext.Get("currentTime").Float()
	if p.nextPos < c {
		// The exact current time might be too early. Add some delay on purpose to avoid buffer overlapping.
		p.nextPos = c + 1.0/60.0
	}

	bs := make([]byte, p.context.oneBufferSize())
	n := copy(bs, p.buf)
	copy(p.buf, p.buf[n:])
	p.buf = p.buf[:len(p.buf)-n]
	if len(p.buf) < p.context.maxBufferSize() {
		p.cond.Signal()
	}

	if len(bs) == 0 {
		// createBuffer fails with 0 bytes. Add some zeros instead.
		bs = make([]byte, 4096)
	}

	if cap(p.f32L) < len(bs)/4 {
		p.f32L = make([]float32, len(bs)/4)
	} else {
		p.f32L = p.f32L[:len(bs)/4]
	}
	if cap(p.f32R) < len(bs)/4 {
		p.f32R = make([]float32, len(bs)/4)
	} else {
		p.f32R = p.f32R[:len(bs)/4]
	}
	toLR(p.f32L, p.f32R, bs)
	tl, tr := float32SliceToTypedArray(p.f32L), float32SliceToTypedArray(p.f32R)

	buf := p.context.audioContext.Call("createBuffer", p.context.channelNum, len(bs)/p.context.channelNum/p.context.bitDepthInBytes, p.context.sampleRate)
	if buf.Get("copyToChannel").Truthy() {
		buf.Call("copyToChannel", tl, 0, 0)
		buf.Call("copyToChannel", tr, 1, 0)
	} else {
		// copyToChannel is not defined on Safari 11.
		buf.Call("getChannelData", 0).Call("set", tl)
		buf.Call("getChannelData", 1).Call("set", tr)
	}

	s := p.context.audioContext.Call("createBufferSource")
	s.Set("buffer", buf)
	s.Set("onended", p.appendBufferFunc)
	s.Call("connect", p.gain)
	s.Call("start", p.nextPos)
	p.nextPos += buf.Get("duration").Float()
	p.bufferSourceNodes = append(p.bufferSourceNodes, s)

	return
}

func (p *player) IsPlaying() bool {
	return p.state == playerPlay
}

func (p *player) Reset() {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	p.resetImpl()
}

func (p *player) resetImpl() {
	if p.err != nil {
		return
	}
	if p.state == playerClosed {
		return
	}

	p.pauseImpl()
	p.eof = false
	p.buf = p.buf[:0]
}

func (p *player) Volume() float64 {
	return p.gain.Get("gain").Get("value").Float()
}

func (p *player) SetVolume(volume float64) {
	p.gain.Get("gain").Set("value", volume)
}

func (p *player) UnplayedBufferSize() int {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	// This is not an accurate buffer size as part of the buffers might already be consumed.
	var sec float64
	for _, n := range p.bufferSourceNodes {
		sec += n.Get("buffer").Get("duration").Float()
	}
	return len(p.buf) + int(sec*float64(p.context.sampleRate*p.context.channelNum*p.context.bitDepthInBytes))
}

func (p *player) Err() error {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	return p.err
}

func (p *player) Close() error {
	runtime.SetFinalizer(p, nil)
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	return p.closeImpl()
}

func (p *player) closeImpl() error {
	p.resetImpl()
	p.state = playerClosed
	p.appendBufferFunc.Release()
	p.cond.Signal()
	return p.err
}

func (p *player) setError(err error) {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()
	p.setErrorImpl(err)
}

func (p *player) setErrorImpl(err error) {
	p.err = err
	p.closeImpl()
}

func (p *player) shouldWait() bool {
	switch p.state {
	case playerPaused:
		// Even when the player is paused, the loop immediately ends.
		// WebAudio doesn't have a notion of pause.
		return false
	case playerPlay:
		return len(p.buf) >= p.context.maxBufferSize()
	case playerClosed:
		return false
	default:
		panic("not reached")
	}
}

func (p *player) wait() bool {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	for p.shouldWait() {
		p.cond.Wait()
	}
	return p.state == playerPlay && !p.eof
}

func (p *player) loop() {
	buf := make([]byte, 4096)
	for {
		if !p.wait() {
			return
		}

		n, err := p.src.Read(buf)
		if err != nil && err != io.EOF {
			p.setError(err)
			return
		}

		p.cond.L.Lock()
		p.buf = append(p.buf, buf[:n]...)
		if err == io.EOF {
			// p.eof can be true even if the buffer is not consumed yet.
			// This might be different from the other drivers.
			p.eof = true
			p.cond.L.Unlock()
			return
		}
		p.cond.L.Unlock()
	}
}

func toLR(l, r []float32, data []byte) {
	const max = 1 << 15

	for i := 0; i < len(data)/4; i++ {
		l[i] = float32(int16(data[4*i])|int16(data[4*i+1])<<8) / max
		r[i] = float32(int16(data[4*i+2])|int16(data[4*i+3])<<8) / max
	}
}

func fromLR(bs []byte, l, r []float32) {
	const max = 1 << 15

	if len(l) != len(r) {
		panic("oto: len(l) must equal to len(r) at fromLR")
	}

	for i := range l {
		lv := int16(l[i] * max)
		bs[4*i] = byte(lv)
		bs[4*i+1] = byte(lv >> 8)
		rv := int16(r[i] * max)
		bs[4*i+2] = byte(rv)
		bs[4*i+3] = byte(rv >> 8)
	}
}

func float32SliceToTypedArray(s []float32) js.Value {
	h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
	h.Len *= 4
	h.Cap *= 4
	bs := *(*[]byte)(unsafe.Pointer(h))

	a := js.Global().Get("Uint8Array").New(len(bs))
	js.CopyBytesToJS(a, bs)
	runtime.KeepAlive(s)
	buf := a.Get("buffer")
	return js.Global().Get("Float32Array").New(buf, a.Get("byteOffset"), a.Get("byteLength").Int()/4)
}

func float32ArrayToFloat32Slice(v js.Value) []float32 {
	bs := make([]byte, v.Get("byteLength").Int())
	js.CopyBytesToGo(bs, js.Global().Get("Uint8Array").New(v.Get("buffer"), v.Get("byteOffset"), v.Get("byteLength")))

	h := (*reflect.SliceHeader)(unsafe.Pointer(&bs))
	h.Len /= 4
	h.Cap /= 4
	f32s := *(*[]float32)(unsafe.Pointer(h))
	runtime.KeepAlive(bs)

	return f32s
}
<|endoftext|>


<commit_before>// dsrt.go -- directoy sort in reverse date order.  IE, newest is first.

package main

import (
	"bufio"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/user"
	"path/filepath"
	"runtime"
	"sort"
	"strconv"
	"strings"
)

const lastCompiled = "21 May 17"

/*
Revision History
----------------
20 Apr 17 -- Started writing dsize rtn, based on dirlist.go
21 Apr 17 -- Now tweaking the output format.  And used flag package.  One as a pointer and one as a value, just to learn them.
22 Apr 17 -- Coded the use of the first non flag commandline param,  which is all I need.  Note that the flag must appear before the non-flag param, else the flag is ignored.
22 Apr 17 -- Now writing dsrt, to function similarly to dsort.
24 Apr 17 -- Now adding file matching, like "dir" or "ls" does.
25 Apr 17 -- Now adding sort by size as an option, like -s, and commas
26 Apr 17 -- Noticed that the match routine is case sensitive.  I don't like that.
27 Apr 17 -- commandline now allows a file spec.  I intend this for Windows.  I'll see how it goes.
19 May 19 -- Will now show the uid:gid for linux.
20 May 19 -- Turns out that (*syscall.Stat_t) only compiles on linux. Time for platform specific code.
*/

// FIS is a FileInfo slice, as in os.FileInfo
type FISlice []os.FileInfo
type FISliceDate []os.FileInfo
type FISliceSize []os.FileInfo

func (f FISliceDate) Less(i, j int) bool {
	return f[i].ModTime().UnixNano() > f[j].ModTime().UnixNano() // I want a reverse sort, newest first
}

func (f FISliceDate) Swap(i, j int) {
	f[i], f[j] = f[j], f[i]
}

func (f FISliceDate) Len() int {
	return len(f)
}

func (f FISliceSize) Less(i, j int) bool {
	return f[i].Size() > f[j].Size() // I want a reverse sort, largest first
}

func (f FISliceSize) Swap(i, j int) {
	f[i], f[j] = f[j], f[i]
}

func (f FISliceSize) Len() int {
	return len(f)
}

func main() {
	const numlines = 50
	var userptr *user.User
	var files FISlice
	var filesDate FISliceDate
	var filesSize FISliceSize
	var err error
	var count int

	var revflag = flag.Bool("r", false, "reverse the sort, ie, oldest or smallest is first") // Ptr

	var RevFlag bool
	flag.BoolVar(&RevFlag, "R", false, "Reverse the sort, ie, oldest or smallest is first") // Value

	var nlines = flag.Int("n", numlines, "number of lines to display") // Ptr

	var NLines int
	flag.IntVar(&NLines, "N", numlines, "number of lines to display") // Value

	var helpflag = flag.Bool("h", false, "print help message") // pointer
	var HelpFlag bool
	flag.BoolVar(&HelpFlag, "H", false, "print help message")

	var sizeflag = flag.Bool("s", false, "sort by size instead of by date") // pointer
	var SizeFlag bool
	flag.BoolVar(&SizeFlag, "S", false, "sort by size instead of by date")
	flag.Parse()

	fmt.Println(" dsrt will display sorted by date or size.  Written in Go.  LastCompiled ", lastCompiled)
	fmt.Println()

	uid := os.Getuid() // int
	gid := os.Getgid() // int
	systemStr := ""
	linuxflag := runtime.GOOS == "linux"
	if linuxflag {
		systemStr = "Linux"
	} else if runtime.GOOS == "windows" {
		systemStr = "Windows"
	} else {
		systemStr = "Mac, maybe"
	}

	userptr, err = user.Current()
	if err != nil {
		fmt.Println(" user.Current error is ", err, "Exiting.")
		os.Exit(1)
	}

	if *helpflag || HelpFlag {
		flag.PrintDefaults()
		fmt.Printf("uid=%d, gid=%d, on a computer running %s for %s:%s Username %s, Name %s, HomeDir %s \n",
			uid, gid, systemStr, userptr.Uid, userptr.Gid, userptr.Username, userptr.Name, userptr.HomeDir)

	}

	Reverse := *revflag || RevFlag
	SizeSort := *sizeflag || SizeFlag

	NumLines := numlines
	if *nlines != numlines {
		NumLines = *nlines
	} else if NLines != numlines {
		NumLines = NLines
	}
	askforinput := true

	CleanDirName := "." + string(filepath.Separator)
	CleanFileName := ""
	commandline := flag.Arg(0) // this only gets the first non flag argument.  That's all I want
	if len(commandline) > 0 {
		//		CleanDirName = filepath.Clean(commandline)
		CleanDirName, CleanFileName = filepath.Split(commandline)
		CleanFileName = strings.ToUpper(CleanFileName)
		askforinput = false
	}

	if askforinput {
		// Asking for input so don't have to worry about command line globbing
		fmt.Print(" Enter input for globbing: ")
		scanner := bufio.NewScanner(os.Stdin)
		scanner.Scan()
		newtext := scanner.Text()
		if err = scanner.Err(); err != nil {
			fmt.Fprintln(os.Stderr, " reading std input: ", err)
			os.Exit(1)
		}
		if len(newtext) > 0 {
			// time to do the stuff I'm writing this pgm for
			CleanDirName, CleanFileName = filepath.Split(newtext)
			CleanFileName = strings.ToUpper(CleanFileName)
		}

	}

	if len(CleanDirName) == 0 {
		CleanDirName = "." + string(filepath.Separator)
	}

	if len(CleanFileName) == 0 {
		CleanFileName = "*"
	}

	if SizeSort {
		filesSize, err = ioutil.ReadDir(CleanDirName)
		if err != nil {
			log.Fatal(err)
		}
		if Reverse {
			sort.Sort(sort.Reverse(filesSize))
		} else {
			sort.Sort(filesSize)
		}
		files = FISlice(filesSize)
	} else {
		filesDate, err = ioutil.ReadDir(CleanDirName)
		if err != nil {
			log.Fatal(err)
		}
		if Reverse {
			sort.Sort(sort.Reverse(filesDate))
		} else {
			sort.Sort(filesDate)
		}
		files = FISlice(filesDate)
	}

	fmt.Println(" Dirname is", CleanDirName)

	for _, f := range files {
		NAME := strings.ToUpper(f.Name())
		if BOOL, _ := filepath.Match(CleanFileName, NAME); BOOL {
			s := f.ModTime().Format("Jan-02-2006 15:04:05")
			sizeint := int(f.Size())
			sizestr := strconv.Itoa(sizeint)
			if sizeint > 100000 {
				sizestr = AddCommas(sizestr)
			}

			usernameStr, groupnameStr := GetUserGroupStr(f)
			if linuxflag {
				if f.IsDir() {
					fmt.Printf("%10v %s:%s %15s %s <%s>\n", f.Mode(), usernameStr, groupnameStr, sizestr, s, f.Name())
				} else if f.Mode().IsRegular() {
					fmt.Printf("%10v %s:%s %15s %s %s\n", f.Mode(), usernameStr, groupnameStr, sizestr, s, f.Name())
				} else { // it's a symlink
					fmt.Printf("%10v %s:%s %15s %s (%s)\n", f.Mode(), usernameStr, groupnameStr, sizestr, s, f.Name())
				}
			} else { // must be windows because this won't compile on Mac.  And I'm ignoring symlinks
				if f.IsDir() {
					fmt.Printf("%15s %s <%s>\n", sizestr, s, f.Name())
				} else {
					fmt.Printf("%15s %s %s\n", sizestr, s, f.Name())
				}
			}
			count++
			if count > NumLines {
				break
			}
		}
	}

} // end main dsrt

//-------------------------------------------------------------------- InsertByteSlice
func InsertIntoByteSlice(slice, insertion []byte, index int) []byte {
	return append(slice[:index], append(insertion, slice[index:]...)...)
}

//---------------------------------------------------------------------- AddCommas
func AddCommas(instr string) string {
	var Comma []byte = []byte{','}

	BS := make([]byte, 0, 15)
	BS = append(BS, instr...)

	i := len(BS)

	for NumberOfCommas := i / 3; (NumberOfCommas > 0) && (i > 3); NumberOfCommas-- {
		i -= 3
		BS = InsertIntoByteSlice(BS, Comma, i)
	}
	return string(BS)
} // AddCommas
//---------------------------------------------------------------------------------------------------

// ---------------------------- GetIDname -----------------------------------------------------------
func GetIDname(uidStr string) string {

	ptrToUser, err := user.LookupId(uidStr)
	if err != nil {
		panic("uid not found")
	}

	idname := ptrToUser.Username
	return idname

} // GetIDname

/*
package path
func Match

func Match(pattern, name string) (matched bool, err error)

Match reports whether name matches the shell file name pattern.  The pattern syntax is:

pattern:
	{ term }
term:
	'*'         matches any sequence of non-/ characters
	'?'         matches any single non-/ character
	'[' [ '^' ] { character-range } ']'
	            character class (must be non-empty)
	c           matches character c (c != '*', '?', '\\', '[')
	'\\' c      matches character c

character-range:
	c           matches character c (c != '\\', '-', ']')
	'\\' c      matches character c
	lo '-' hi   matches character c for lo <= c <= hi

Match requires pattern to match all of name, not just a substring.  The only possible returned error is ErrBadPattern, when pattern is malformed.

package os
type FileInfo

type FileInfo interface {
        Name() string       // base name of the file
        Size() int64        // length in bytes for regular files; system-dependent for others
        Mode() FileMode     // file mode bits
        ModTime() time.Time // modification time
        IsDir() bool        // abbreviation for Mode().IsDir()
        Sys() interface{}   // underlying data source (can return nil)
}

A FileInfo describes a file and is returned by Stat and Lstat.

func Lstat

func Lstat(name string) (FileInfo, error)

Lstat returns a FileInfo describing the named file.  If the file is a symbolic link, the returned FileInfo describes the symbolic link.  Lstat makes no attempt to follow the link.
If there is an error, it will be of type *PathError.

func Stat

func Stat(name string) (FileInfo, error)

Stat returns a FileInfo describing the named file.  If there is an error, it will be of type *PathError.

The insight I had with my append troubles that the 1 slice entries were empty, is that when I used append, it would do just that to the end of the slice, and ignore the empty slices.
I needed to make the slice as empty for this to work.  So I am directly assigning the DirEntries slice, and appending the FileNames slice, to make sure that these both are doing what I want.
This code is now doing exactly what I want.  I guess there is no substitute for playing with myself.  Wait, that didn't come out right.  Or did it.

package os/user
type User struct {
  Uid string
  Gid string
  Username string // login name
  Name string     // full or display name.  It may be blank.
  HomeDir string
}
*/
<commit_msg>modified:   dsrt/dsrt.go -- User call fails on GOARCH=386<commit_after>// dsrt.go -- directoy sort in reverse date order.  IE, newest is first.

package main

import (
	"bufio"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/user"
	"path/filepath"
	"runtime"
	"sort"
	"strconv"
	"strings"
)

const lastCompiled = "21 May 17"

/*
Revision History
----------------
20 Apr 17 -- Started writing dsize rtn, based on dirlist.go
21 Apr 17 -- Now tweaking the output format.  And used flag package.  One as a pointer and one as a value, just to learn them.
22 Apr 17 -- Coded the use of the first non flag commandline param,  which is all I need.  Note that the flag must appear before the non-flag param, else the flag is ignored.
22 Apr 17 -- Now writing dsrt, to function similarly to dsort.
24 Apr 17 -- Now adding file matching, like "dir" or "ls" does.
25 Apr 17 -- Now adding sort by size as an option, like -s, and commas
26 Apr 17 -- Noticed that the match routine is case sensitive.  I don't like that.
27 Apr 17 -- commandline now allows a file spec.  I intend this for Windows.  I'll see how it goes.
19 May 19 -- Will now show the uid:gid for linux.
20 May 19 -- Turns out that (*syscall.Stat_t) only compiles on linux. Time for platform specific code.
*/

// FIS is a FileInfo slice, as in os.FileInfo
type FISlice []os.FileInfo
type FISliceDate []os.FileInfo
type FISliceSize []os.FileInfo

func (f FISliceDate) Less(i, j int) bool {
	return f[i].ModTime().UnixNano() > f[j].ModTime().UnixNano() // I want a reverse sort, newest first
}

func (f FISliceDate) Swap(i, j int) {
	f[i], f[j] = f[j], f[i]
}

func (f FISliceDate) Len() int {
	return len(f)
}

func (f FISliceSize) Less(i, j int) bool {
	return f[i].Size() > f[j].Size() // I want a reverse sort, largest first
}

func (f FISliceSize) Swap(i, j int) {
	f[i], f[j] = f[j], f[i]
}

func (f FISliceSize) Len() int {
	return len(f)
}

func main() {
	const numlines = 50
	var userptr *user.User
	var files FISlice
	var filesDate FISliceDate
	var filesSize FISliceSize
	var err error
	var count int

	var revflag = flag.Bool("r", false, "reverse the sort, ie, oldest or smallest is first") // Ptr

	var RevFlag bool
	flag.BoolVar(&RevFlag, "R", false, "Reverse the sort, ie, oldest or smallest is first") // Value

	var nlines = flag.Int("n", numlines, "number of lines to display") // Ptr

	var NLines int
	flag.IntVar(&NLines, "N", numlines, "number of lines to display") // Value

	var helpflag = flag.Bool("h", false, "print help message") // pointer
	var HelpFlag bool
	flag.BoolVar(&HelpFlag, "H", false, "print help message")

	var sizeflag = flag.Bool("s", false, "sort by size instead of by date") // pointer
	var SizeFlag bool
	flag.BoolVar(&SizeFlag, "S", false, "sort by size instead of by date")
	flag.Parse()

	fmt.Println(" dsrt will display sorted by date or size.  Written in Go.  LastCompiled ", lastCompiled)
	fmt.Println()

	uid := os.Getuid() // int
	gid := os.Getgid() // int
	systemStr := ""
	linuxflag := runtime.GOOS == "linux"
	if linuxflag {
		systemStr = "Linux"
	} else if runtime.GOOS == "windows" {
		systemStr = "Windows"
	} else {
		systemStr = "Mac, maybe"
	}

	if runtime.GOARCH == "amd64" {
		userptr, err = user.Current()
		if err != nil {
			fmt.Println(" user.Current error is ", err, "Exiting.")
			os.Exit(1)
		}
	}

	if *helpflag || HelpFlag {
		flag.PrintDefaults()
		fmt.Printf("uid=%d, gid=%d, on a computer running %s for %s:%s Username %s, Name %s, HomeDir %s \n",
			uid, gid, systemStr, userptr.Uid, userptr.Gid, userptr.Username, userptr.Name, userptr.HomeDir)

	}

	Reverse := *revflag || RevFlag
	SizeSort := *sizeflag || SizeFlag

	NumLines := numlines
	if *nlines != numlines {
		NumLines = *nlines
	} else if NLines != numlines {
		NumLines = NLines
	}
	askforinput := true

	CleanDirName := "." + string(filepath.Separator)
	CleanFileName := ""
	commandline := flag.Arg(0) // this only gets the first non flag argument.  That's all I want
	if len(commandline) > 0 {
		//		CleanDirName = filepath.Clean(commandline)
		CleanDirName, CleanFileName = filepath.Split(commandline)
		CleanFileName = strings.ToUpper(CleanFileName)
		askforinput = false
	}

	if askforinput {
		// Asking for input so don't have to worry about command line globbing
		fmt.Print(" Enter input for globbing: ")
		scanner := bufio.NewScanner(os.Stdin)
		scanner.Scan()
		newtext := scanner.Text()
		if err = scanner.Err(); err != nil {
			fmt.Fprintln(os.Stderr, " reading std input: ", err)
			os.Exit(1)
		}
		if len(newtext) > 0 {
			// time to do the stuff I'm writing this pgm for
			CleanDirName, CleanFileName = filepath.Split(newtext)
			CleanFileName = strings.ToUpper(CleanFileName)
		}

	}

	if len(CleanDirName) == 0 {
		CleanDirName = "." + string(filepath.Separator)
	}

	if len(CleanFileName) == 0 {
		CleanFileName = "*"
	}

	if SizeSort {
		filesSize, err = ioutil.ReadDir(CleanDirName)
		if err != nil {
			log.Fatal(err)
		}
		if Reverse {
			sort.Sort(sort.Reverse(filesSize))
		} else {
			sort.Sort(filesSize)
		}
		files = FISlice(filesSize)
	} else {
		filesDate, err = ioutil.ReadDir(CleanDirName)
		if err != nil {
			log.Fatal(err)
		}
		if Reverse {
			sort.Sort(sort.Reverse(filesDate))
		} else {
			sort.Sort(filesDate)
		}
		files = FISlice(filesDate)
	}

	fmt.Println(" Dirname is", CleanDirName)

	for _, f := range files {
		NAME := strings.ToUpper(f.Name())
		if BOOL, _ := filepath.Match(CleanFileName, NAME); BOOL {
			s := f.ModTime().Format("Jan-02-2006 15:04:05")
			sizeint := int(f.Size())
			sizestr := strconv.Itoa(sizeint)
			if sizeint > 100000 {
				sizestr = AddCommas(sizestr)
			}

			usernameStr, groupnameStr := GetUserGroupStr(f)
			if linuxflag {
				if f.IsDir() {
					fmt.Printf("%10v %s:%s %15s %s <%s>\n", f.Mode(), usernameStr, groupnameStr, sizestr, s, f.Name())
				} else if f.Mode().IsRegular() {
					fmt.Printf("%10v %s:%s %15s %s %s\n", f.Mode(), usernameStr, groupnameStr, sizestr, s, f.Name())
				} else { // it's a symlink
					fmt.Printf("%10v %s:%s %15s %s (%s)\n", f.Mode(), usernameStr, groupnameStr, sizestr, s, f.Name())
				}
			} else { // must be windows because this won't compile on Mac.  And I'm ignoring symlinks
				if f.IsDir() {
					fmt.Printf("%15s %s <%s>\n", sizestr, s, f.Name())
				} else {
					fmt.Printf("%15s %s %s\n", sizestr, s, f.Name())
				}
			}
			count++
			if count > NumLines {
				break
			}
		}
	}

} // end main dsrt

//-------------------------------------------------------------------- InsertByteSlice
func InsertIntoByteSlice(slice, insertion []byte, index int) []byte {
	return append(slice[:index], append(insertion, slice[index:]...)...)
}

//---------------------------------------------------------------------- AddCommas
func AddCommas(instr string) string {
	var Comma []byte = []byte{','}

	BS := make([]byte, 0, 15)
	BS = append(BS, instr...)

	i := len(BS)

	for NumberOfCommas := i / 3; (NumberOfCommas > 0) && (i > 3); NumberOfCommas-- {
		i -= 3
		BS = InsertIntoByteSlice(BS, Comma, i)
	}
	return string(BS)
} // AddCommas
//---------------------------------------------------------------------------------------------------

// ---------------------------- GetIDname -----------------------------------------------------------
func GetIDname(uidStr string) string {

	ptrToUser, err := user.LookupId(uidStr)
	if err != nil {
		panic("uid not found")
	}

	idname := ptrToUser.Username
	return idname

} // GetIDname

/*
package path
func Match

func Match(pattern, name string) (matched bool, err error)

Match reports whether name matches the shell file name pattern.  The pattern syntax is:

pattern:
	{ term }
term:
	'*'         matches any sequence of non-/ characters
	'?'         matches any single non-/ character
	'[' [ '^' ] { character-range } ']'
	            character class (must be non-empty)
	c           matches character c (c != '*', '?', '\\', '[')
	'\\' c      matches character c

character-range:
	c           matches character c (c != '\\', '-', ']')
	'\\' c      matches character c
	lo '-' hi   matches character c for lo <= c <= hi

Match requires pattern to match all of name, not just a substring.  The only possible returned error is ErrBadPattern, when pattern is malformed.

package os
type FileInfo

type FileInfo interface {
        Name() string       // base name of the file
        Size() int64        // length in bytes for regular files; system-dependent for others
        Mode() FileMode     // file mode bits
        ModTime() time.Time // modification time
        IsDir() bool        // abbreviation for Mode().IsDir()
        Sys() interface{}   // underlying data source (can return nil)
}

A FileInfo describes a file and is returned by Stat and Lstat.

func Lstat

func Lstat(name string) (FileInfo, error)

Lstat returns a FileInfo describing the named file.  If the file is a symbolic link, the returned FileInfo describes the symbolic link.  Lstat makes no attempt to follow the link.
If there is an error, it will be of type *PathError.

func Stat

func Stat(name string) (FileInfo, error)

Stat returns a FileInfo describing the named file.  If there is an error, it will be of type *PathError.

The insight I had with my append troubles that the 1 slice entries were empty, is that when I used append, it would do just that to the end of the slice, and ignore the empty slices.
I needed to make the slice as empty for this to work.  So I am directly assigning the DirEntries slice, and appending the FileNames slice, to make sure that these both are doing what I want.
This code is now doing exactly what I want.  I guess there is no substitute for playing with myself.  Wait, that didn't come out right.  Or did it.

package os/user
type User struct {
  Uid string
  Gid string
  Username string // login name
  Name string     // full or display name.  It may be blank.
  HomeDir string
}
*/
<|endoftext|>


<commit_before>/*
Copyright 2020 The Knative Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"encoding/json"
	"fmt"
	gb "go/build"
	"path/filepath"
	"strings"

	"knative.dev/pkg/test/cmd"
)

// https://golang.org/pkg/cmd/go/internal/modinfo/#ModulePublic
type modInfo struct {
	Path string
	Dir  string
}

type gobuild struct {
	mod *modInfo
}

// moduleInfo returns the module path and module root directory for a project
// using go modules, otherwise returns nil.
// If there is something wrong in getting the module info, it will return an error.
//
// Related: https://github.com/golang/go/issues/26504
func moduleInfo() (*modInfo, error) {
	// If `go list -m` returns an error, the project is not using Go modules.
	_, err := cmd.RunCommands("go list -m")
	if err != nil {
		return nil, nil
	}

	output, err := cmd.RunCommand("go list -mod=readonly -m -json")
	if err != nil {
		return nil, fmt.Errorf("failed getting module info: %v", err)
	}
	var info modInfo
	if err := json.Unmarshal([]byte(output), &info); err != nil {
		return nil, fmt.Errorf("failed parsing module info %q: %v", output, err)
	}
	return &info, nil
}

// importPackage wraps go/build.Import to handle go modules.
//
// Note that we will fall back to GOPATH if the project isn't using go modules.
func (g *gobuild) importPackage(s string) (*gb.Package, error) {
	if g.mod == nil {
		return gb.Import(s, WorkingDir, gb.ImportComment)
	}

	// If we're inside a go modules project, try to use the module's directory
	// as our source root to import:
	// * paths that match module path prefix (they should be in this project)
	// * relative paths (they should also be in this project)
	gp, err := gb.Import(s, g.mod.Dir, gb.ImportComment)
	return gp, err
}

func (g *gobuild) qualifyLocalImport(ip string) (string, error) {
	if g.mod == nil {
		gopathsrc := filepath.Join(gb.Default.GOPATH, "src")
		if !strings.HasPrefix(WorkingDir, gopathsrc) {
			return "", fmt.Errorf("working directory must be on ${GOPATH}/src = %s", gopathsrc)
		}
		return filepath.Join(strings.TrimPrefix(WorkingDir, gopathsrc+string(filepath.Separator)), ip), nil
	}
	return filepath.Join(g.mod.Path, ip), nil
}
<commit_msg>fix dep collector by not using pkg (#1897)<commit_after>/*
Copyright 2020 The Knative Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"encoding/json"
	"fmt"
	gb "go/build"
	"os/exec"
	"path/filepath"
	"strings"
)

// https://golang.org/pkg/cmd/go/internal/modinfo/#ModulePublic
type modInfo struct {
	Path string
	Dir  string
}

type gobuild struct {
	mod *modInfo
}

// moduleInfo returns the module path and module root directory for a project
// using go modules, otherwise returns nil.
// If there is something wrong in getting the module info, it will return an error.
//
// Related: https://github.com/golang/go/issues/26504
func moduleInfo() (*modInfo, error) {
	// If `go list -m` returns an error, the project is not using Go modules.
	c := exec.Command("go", "list", "-m")
	_, err := c.Output()
	if err != nil {
		return nil, nil
	}

	lc := exec.Command("go", "list", "-mod=readonly", "-m", "-json")
	output, err := lc.Output()
	if err != nil {
		return nil, fmt.Errorf("failed getting module info: %v", err)
	}
	var info modInfo
	if err := json.Unmarshal(output, &info); err != nil {
		return nil, fmt.Errorf("failed parsing module info %q: %v", output, err)
	}
	return &info, nil
}

// importPackage wraps go/build.Import to handle go modules.
//
// Note that we will fall back to GOPATH if the project isn't using go modules.
func (g *gobuild) importPackage(s string) (*gb.Package, error) {
	if g.mod == nil {
		return gb.Import(s, WorkingDir, gb.ImportComment)
	}

	// If we're inside a go modules project, try to use the module's directory
	// as our source root to import:
	// * paths that match module path prefix (they should be in this project)
	// * relative paths (they should also be in this project)
	gp, err := gb.Import(s, g.mod.Dir, gb.ImportComment)
	return gp, err
}

func (g *gobuild) qualifyLocalImport(ip string) (string, error) {
	if g.mod == nil {
		gopathsrc := filepath.Join(gb.Default.GOPATH, "src")
		if !strings.HasPrefix(WorkingDir, gopathsrc) {
			return "", fmt.Errorf("working directory must be on ${GOPATH}/src = %s", gopathsrc)
		}
		return filepath.Join(strings.TrimPrefix(WorkingDir, gopathsrc+string(filepath.Separator)), ip), nil
	}
	return filepath.Join(g.mod.Path, ip), nil
}
<|endoftext|>