<commit_before>// Copyright (c) 2013-2017 The btcsuite developers
// Copyright (c) 2017 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/Roasbeef/btcd/netsync"
	"github.com/roasbeef/btcd/addrmgr"
	"github.com/roasbeef/btcd/blockchain"
	"github.com/roasbeef/btcd/blockchain/indexers"
	"github.com/roasbeef/btcd/connmgr"
	"github.com/roasbeef/btcd/database"
	"github.com/roasbeef/btcd/mempool"
	"github.com/roasbeef/btcd/mining"
	"github.com/roasbeef/btcd/mining/cpuminer"
	"github.com/roasbeef/btcd/peer"
	"github.com/roasbeef/btcd/txscript"

	"github.com/btcsuite/btclog"
	"github.com/jrick/logrotate/rotator"
)

// logWriter implements an io.Writer that outputs to both standard output and
// the write-end pipe of an initialized log rotator.
type logWriter struct{}

func (logWriter) Write(p []byte) (n int, err error) {
	os.Stdout.Write(p)
	logRotator.Write(p)
	return len(p), nil
}

// Loggers per subsystem.  A single backend logger is created and all subsytem
// loggers created from it will write to the backend.  When adding new
// subsystems, add the subsystem logger variable here and to the
// subsystemLoggers map.
//
// Loggers can not be used before the log rotator has been initialized with a
// log file.  This must be performed early during application startup by calling
// initLogRotator.
var (
	// backendLog is the logging backend used to create all subsystem loggers.
	// The backend must not be used before the log rotator has been initialized,
	// or data races and/or nil pointer dereferences will occur.
	backendLog = btclog.NewBackend(logWriter{})

	// logRotator is one of the logging outputs.  It should be closed on
	// application shutdown.
	logRotator *rotator.Rotator

	adxrLog = backendLog.Logger("ADXR")
	amgrLog = backendLog.Logger("AMGR")
	cmgrLog = backendLog.Logger("CMGR")
	bcdbLog = backendLog.Logger("BCDB")
	btcdLog = backendLog.Logger("BTCD")
	chanLog = backendLog.Logger("CHAN")
	discLog = backendLog.Logger("DISC")
	indxLog = backendLog.Logger("INDX")
	minrLog = backendLog.Logger("MINR")
	peerLog = backendLog.Logger("PEER")
	rpcsLog = backendLog.Logger("RPCS")
	scrpLog = backendLog.Logger("SCRP")
	srvrLog = backendLog.Logger("SRVR")
	syncLog = backendLog.Logger("SYNC")
	txmpLog = backendLog.Logger("TXMP")
)

// Initialize package-global logger variables.
func init() {
	addrmgr.UseLogger(amgrLog)
	connmgr.UseLogger(cmgrLog)
	database.UseLogger(bcdbLog)
	blockchain.UseLogger(chanLog)
	indexers.UseLogger(indxLog)
	mining.UseLogger(minrLog)
	cpuminer.UseLogger(minrLog)
	peer.UseLogger(peerLog)
	txscript.UseLogger(scrpLog)
	netsync.UseLogger(syncLog)
	mempool.UseLogger(txmpLog)
}

// subsystemLoggers maps each subsystem identifier to its associated logger.
var subsystemLoggers = map[string]btclog.Logger{
	"ADXR": adxrLog,
	"AMGR": amgrLog,
	"CMGR": cmgrLog,
	"BCDB": bcdbLog,
	"BTCD": btcdLog,
	"CHAN": chanLog,
	"DISC": discLog,
	"INDX": indxLog,
	"MINR": minrLog,
	"PEER": peerLog,
	"RPCS": rpcsLog,
	"SCRP": scrpLog,
	"SRVR": srvrLog,
	"SYNC": syncLog,
	"TXMP": txmpLog,
}

// initLogRotator initializes the logging rotater to write logs to logFile and
// create roll files in the same directory.  It must be called before the
// package-global log rotater variables are used.
func initLogRotator(logFile string) {
	logDir, _ := filepath.Split(logFile)
	err := os.MkdirAll(logDir, 0700)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create log directory: %v\n", err)
		os.Exit(1)
	}
	r, err := rotator.New(logFile, 10*1024, false, 3)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create file rotator: %v\n", err)
		os.Exit(1)
	}

	logRotator = r
}

// setLogLevel sets the logging level for provided subsystem.  Invalid
// subsystems are ignored.  Uninitialized subsystems are dynamically created as
// needed.
func setLogLevel(subsystemID string, logLevel string) {
	// Ignore invalid subsystems.
	logger, ok := subsystemLoggers[subsystemID]
	if !ok {
		return
	}

	// Defaults to info if the log level is invalid.
	level, _ := btclog.LevelFromString(logLevel)
	logger.SetLevel(level)
}

// setLogLevels sets the log level for all subsystem loggers to the passed
// level.  It also dynamically creates the subsystem loggers as needed, so it
// can be used to initialize the logging system.
func setLogLevels(logLevel string) {
	// Configure all sub-systems with the new logging level.  Dynamically
	// create loggers as needed.
	for subsystemID := range subsystemLoggers {
		setLogLevel(subsystemID, logLevel)
	}
}

// directionString is a helper function that returns a string that represents
// the direction of a connection (inbound or outbound).
func directionString(inbound bool) string {
	if inbound {
		return "inbound"
	}
	return "outbound"
}

// pickNoun returns the singular or plural form of a noun depending
// on the count n.
func pickNoun(n uint64, singular, plural string) string {
	if n == 1 {
		return singular
	}
	return plural
}
<commit_msg>log: update to latest log rotator API<commit_after>// Copyright (c) 2013-2017 The btcsuite developers
// Copyright (c) 2017 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/roasbeef/btcd/netsync"

	"github.com/roasbeef/btcd/addrmgr"
	"github.com/roasbeef/btcd/blockchain"
	"github.com/roasbeef/btcd/blockchain/indexers"
	"github.com/roasbeef/btcd/connmgr"
	"github.com/roasbeef/btcd/database"
	"github.com/roasbeef/btcd/mempool"
	"github.com/roasbeef/btcd/mining"
	"github.com/roasbeef/btcd/mining/cpuminer"
	"github.com/roasbeef/btcd/peer"
	"github.com/roasbeef/btcd/txscript"

	"github.com/btcsuite/btclog"
	"github.com/jrick/logrotate/rotator"
)

// logWriter implements an io.Writer that outputs to both standard output and
// the write-end pipe of an initialized log rotator.
type logWriter struct{}

func (logWriter) Write(p []byte) (n int, err error) {
	os.Stdout.Write(p)
	logRotator.Write(p)
	return len(p), nil
}

// Loggers per subsystem.  A single backend logger is created and all subsytem
// loggers created from it will write to the backend.  When adding new
// subsystems, add the subsystem logger variable here and to the
// subsystemLoggers map.
//
// Loggers can not be used before the log rotator has been initialized with a
// log file.  This must be performed early during application startup by calling
// initLogRotator.
var (
	// backendLog is the logging backend used to create all subsystem loggers.
	// The backend must not be used before the log rotator has been initialized,
	// or data races and/or nil pointer dereferences will occur.
	backendLog = btclog.NewBackend(logWriter{})

	// logRotator is one of the logging outputs.  It should be closed on
	// application shutdown.
	logRotator *rotator.Rotator

	adxrLog = backendLog.Logger("ADXR")
	amgrLog = backendLog.Logger("AMGR")
	cmgrLog = backendLog.Logger("CMGR")
	bcdbLog = backendLog.Logger("BCDB")
	btcdLog = backendLog.Logger("BTCD")
	chanLog = backendLog.Logger("CHAN")
	discLog = backendLog.Logger("DISC")
	indxLog = backendLog.Logger("INDX")
	minrLog = backendLog.Logger("MINR")
	peerLog = backendLog.Logger("PEER")
	rpcsLog = backendLog.Logger("RPCS")
	scrpLog = backendLog.Logger("SCRP")
	srvrLog = backendLog.Logger("SRVR")
	syncLog = backendLog.Logger("SYNC")
	txmpLog = backendLog.Logger("TXMP")
)

// Initialize package-global logger variables.
func init() {
	addrmgr.UseLogger(amgrLog)
	connmgr.UseLogger(cmgrLog)
	database.UseLogger(bcdbLog)
	blockchain.UseLogger(chanLog)
	indexers.UseLogger(indxLog)
	mining.UseLogger(minrLog)
	cpuminer.UseLogger(minrLog)
	peer.UseLogger(peerLog)
	txscript.UseLogger(scrpLog)
	netsync.UseLogger(syncLog)
	mempool.UseLogger(txmpLog)
}

// subsystemLoggers maps each subsystem identifier to its associated logger.
var subsystemLoggers = map[string]btclog.Logger{
	"ADXR": adxrLog,
	"AMGR": amgrLog,
	"CMGR": cmgrLog,
	"BCDB": bcdbLog,
	"BTCD": btcdLog,
	"CHAN": chanLog,
	"DISC": discLog,
	"INDX": indxLog,
	"MINR": minrLog,
	"PEER": peerLog,
	"RPCS": rpcsLog,
	"SCRP": scrpLog,
	"SRVR": srvrLog,
	"SYNC": syncLog,
	"TXMP": txmpLog,
}

// initLogRotator initializes the logging rotater to write logs to logFile and
// create roll files in the same directory.  It must be called before the
// package-global log rotater variables are used.
func initLogRotator(logFile string) {
	logDir, _ := filepath.Split(logFile)
	err := os.MkdirAll(logDir, 0700)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create log directory: %v\n", err)
		os.Exit(1)
	}
	r, err := rotator.New(logFile, 10*1024, false, 3)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create file rotator: %v\n", err)
		os.Exit(1)
	}

	logRotator = r
}

// setLogLevel sets the logging level for provided subsystem.  Invalid
// subsystems are ignored.  Uninitialized subsystems are dynamically created as
// needed.
func setLogLevel(subsystemID string, logLevel string) {
	// Ignore invalid subsystems.
	logger, ok := subsystemLoggers[subsystemID]
	if !ok {
		return
	}

	// Defaults to info if the log level is invalid.
	level, _ := btclog.LevelFromString(logLevel)
	logger.SetLevel(level)
}

// setLogLevels sets the log level for all subsystem loggers to the passed
// level.  It also dynamically creates the subsystem loggers as needed, so it
// can be used to initialize the logging system.
func setLogLevels(logLevel string) {
	// Configure all sub-systems with the new logging level.  Dynamically
	// create loggers as needed.
	for subsystemID := range subsystemLoggers {
		setLogLevel(subsystemID, logLevel)
	}
}

// directionString is a helper function that returns a string that represents
// the direction of a connection (inbound or outbound).
func directionString(inbound bool) string {
	if inbound {
		return "inbound"
	}
	return "outbound"
}

// pickNoun returns the singular or plural form of a noun depending
// on the count n.
func pickNoun(n uint64, singular, plural string) string {
	if n == 1 {
		return singular
	}
	return plural
}
<|endoftext|>


<commit_before>package artifactory

import (
	"log"
	"net/http"
)

type http500 struct {
	httpEntity []byte
}

type Config struct {
	Username string
	Password string
	APIKey   string
	BaseURL  string
	Doer     Doer
	Log      log.Logger
}

type Doer interface {
	Do(*http.Request) (*http.Response, error)
}

type DefaultClient struct {
	config Config
}

type Client interface {
	CreateSnapshotRepository(string) (*HTTPStatus, error)
	RemoveRepository(string) (*HTTPStatus, error)
	LocalRepositoryExists(string) (bool, error)
	GetVirtualRepositoryConfiguration(string) (VirtualRepositoryConfiguration, error)
	AddLocalRepositoryToGroup(string, string) (*HTTPStatus, error)
	RemoveLocalRepositoryFromGroup(string, string) (*HTTPStatus, error)
	RemoveItemFromRepository(string, string) (*HTTPStatus, error)
}

type HTTPStatus struct {
	StatusCode int
	Entity     []byte
}

type LocalRepositoryConfiguration struct {
	Key                     string      `json:"key"`
	RClass                  string      `json:"rclass"`
	Notes                   string      `json:"notes"`
	PackageType             string      `json:"packageType"`
	Description             string      `json:"description"`
	RepoLayoutRef           string      `json:"repoLayoutRef"`
	HandleSnapshots         bool        `json:"handleSnapshots"`
	HandleReleases          bool        `json:"handleReleases"`
	MaxUniqueSnapshots      int         `json:"maxUniqueSnapshots"`
	SnapshotVersionBehavior string      `json:"snapshotVersionBehavior"`
	HTTPStatus              *HTTPStatus `json:"-"`
}

type VirtualRepositoryConfiguration struct {
	Key           string      `json:"key"`
	RClass        string      `json:"rclass"`
	Repositories  []string    `json:"repositories"`
	PackageType   string      `json:"packageType"`
	RepoLayoutRef string      `json:"repoLayoutRef"`
	HTTPStatus    *HTTPStatus `json:"-"`
}

type BooleanResponse struct {
	Result     bool
	HTTPStatus *HTTPStatus
}
<commit_msg>Config.Log should be pointer to Logger<commit_after>package artifactory

import (
	"log"
	"net/http"
)

type http500 struct {
	httpEntity []byte
}

type Config struct {
	Username string
	Password string
	APIKey   string
	BaseURL  string
	Doer     Doer
	Log      *log.Logger
}

type Doer interface {
	Do(*http.Request) (*http.Response, error)
}

type DefaultClient struct {
	config Config
}

type Client interface {
	CreateSnapshotRepository(string) (*HTTPStatus, error)
	RemoveRepository(string) (*HTTPStatus, error)
	LocalRepositoryExists(string) (bool, error)
	GetVirtualRepositoryConfiguration(string) (VirtualRepositoryConfiguration, error)
	AddLocalRepositoryToGroup(string, string) (*HTTPStatus, error)
	RemoveLocalRepositoryFromGroup(string, string) (*HTTPStatus, error)
	RemoveItemFromRepository(string, string) (*HTTPStatus, error)
}

type HTTPStatus struct {
	StatusCode int
	Entity     []byte
}

type LocalRepositoryConfiguration struct {
	Key                     string      `json:"key"`
	RClass                  string      `json:"rclass"`
	Notes                   string      `json:"notes"`
	PackageType             string      `json:"packageType"`
	Description             string      `json:"description"`
	RepoLayoutRef           string      `json:"repoLayoutRef"`
	HandleSnapshots         bool        `json:"handleSnapshots"`
	HandleReleases          bool        `json:"handleReleases"`
	MaxUniqueSnapshots      int         `json:"maxUniqueSnapshots"`
	SnapshotVersionBehavior string      `json:"snapshotVersionBehavior"`
	HTTPStatus              *HTTPStatus `json:"-"`
}

type VirtualRepositoryConfiguration struct {
	Key           string      `json:"key"`
	RClass        string      `json:"rclass"`
	Repositories  []string    `json:"repositories"`
	PackageType   string      `json:"packageType"`
	RepoLayoutRef string      `json:"repoLayoutRef"`
	HTTPStatus    *HTTPStatus `json:"-"`
}

type BooleanResponse struct {
	Result     bool
	HTTPStatus *HTTPStatus
}
<|endoftext|>


<commit_before>package log

import (
	"io"
	"os"
	"time"

	"github.com/go-kit/kit/log"
)

var logger = newLog(os.Stderr)

type Log struct{ ctx *log.Context }

func newLog(w io.Writer) *Log {
	return &Log{ctx: log.NewContext(log.NewJSONLogger(w))}
}

func (l *Log) KV(k string, v interface{}) *Log { return &Log{ctx: l.ctx.With(k, v)} }
func (l *Log) Err(err error) *Log              { return l.KV("err", err) }
func (l *Log) Error(msg string)                { l.log("error", msg) }
func (l *Log) Info(msg string)                 { l.log("info", msg) }
func (l *Log) Fatal(msg string)                { l.log("fatal", msg); os.Exit(1) }

func (l *Log) log(lvl, msg string) {
	err := l.ctx.Log(
		"level", lvl,
		"msg", msg,
		"src", log.DefaultCaller(),
		"time", time.Now().UTC().Format(time.RFC3339Nano),
	)
	if err != nil {
		panic(err)
	}
}

func KV(k string, v interface{}) *Log { return logger.KV(k, v) }
func Err(err error) *Log              { return logger.Err(err) }
func Error(msg string)                { logger.log("error", msg) }
func Info(msg string)                 { logger.log("info", msg) }
func Fatal(msg string)                { logger.log("fatal", msg); os.Exit(1) }
<commit_msg>smarter interface handling, expose package lvl KV func<commit_after>package log

import (
	"io"
	"os"
	"time"

	"github.com/go-kit/kit/log"
)

var logger = newLog(os.Stderr)

type Log struct{ ctx *log.Context }

func newLog(w io.Writer) *Log {
	return &Log{ctx: log.NewContext(log.NewJSONLogger(w))}
}

func (l *Log) KV(k string, v interface{}) *Log {
	switch s := v.(type) {
	case interface {
		String() string
	}:
		v = s.String()
	case interface {
		GoString() string
	}:
		v = s.GoString()
	}
	return &Log{ctx: l.ctx.With(k, v)}
}

func (l *Log) Err(err error) *Log { return l.KV("err", err) }
func (l *Log) Error(msg string)   { l.log("error", msg) }
func (l *Log) Info(msg string)    { l.log("info", msg) }
func (l *Log) Fatal(msg string)   { l.log("fatal", msg); os.Exit(1) }

func (l *Log) log(lvl, msg string) {
	err := l.ctx.Log(
		"level", lvl,
		"msg", msg,
		"src", log.DefaultCaller(),
		"time", time.Now().UTC().Format(time.RFC3339Nano),
	)
	if err != nil {
		panic(err)
	}
}

func Err(err error) *Log              { return logger.Err(err) }
func Error(msg string)                { logger.log("error", msg) }
func Info(msg string)                 { logger.log("info", msg) }
func Fatal(msg string)                { logger.log("fatal", msg); os.Exit(1) }
func KV(k string, v interface{}) *Log { return logger.KV(k, v) }
<|endoftext|>


<commit_before>// types.go

// This file contains the various types used by the API

package atlas

// APIError is for errors returned by the RIPE API.
type APIError struct {
	Error struct {
		Status int    `json:"status"`
		Code   int    `json:"code"`
		Detail string `json:"detail"`
		Title  string `json:"title"`
	} `json:"error"`
}

// Key is holding the API key parameters
type Key struct {
	UUID      string `json:"uuid"`
	ValidFrom string `json:"valid_from"`
	ValidTo   string `json:"valid_to"`
	Enabled   bool
	IsActive  bool    `json:"is_active"`
	CreatedAt string  `json:"created_at"`
	Label     string  `json:"label"`
	Grants    []Grant `json:"grants"`
	Type      string  `json:"type"`
}

// Grant is the permission(s) associated with a key
type Grant struct {
	Permission string `json:"permission"`
	Target     struct {
		Type string `json:"type"`
		ID   string `json:"id"`
	} `json:"target"`
}

// Probe is holding probe's data
type Probe struct {
	AddressV4      string `json:"address_v4"`
	AddressV6      string `json:"address_v6"`
	AsnV4          int    `json:"asn_v4"`
	AsnV6          int    `json:"asn_v6"`
	CountryCode    string `json:"country_code"`
	Description    string `json:"description"`
	FirstConnected int    `json:"first_connected"`
	Geometry       struct {
		Type        string    `json:"type"`
		Coordinates []float64 `json:"coordinates"`
	} `json:"geometry"`
	ID            int    `json:"id"`
	IsAnchor      bool   `json:"is_anchor"`
	IsPublic      bool   `json:"is_public"`
	LastConnected int    `json:"last_connected"`
	PrefixV4      string `json:"prefix_v4"`
	PrefixV6      string `json:"prefix_v6"`
	Status        struct {
		Since string `json:"since"`
		ID    int    `json:"id"`
		Name  string `json:"name"`
	} `json:"status"`
	StatusSince int `json:"status_since"`
	Tags        []struct {
		Name string `json:"name"`
		Slug string `json:"slug"`
	} `json:"tags"`
	Type string `json:"type"`
}

// Measurement is what we are working with
type Measurement struct {
	Af                    int                    `json:"af"`
	CreationTime          int                    `json:"creation_time"`
	Description           string                 `json:"description"`
	DestinationOptionSize interface{}            `json:"destination_option_size"`
	DontFragment          interface{}            `json:"dont_fragment"`
	DuplicateTimeout      interface{}            `json:"duplicate_timeout"`
	FirstHop              int                    `json:"first_hop"`
	Group                 string                 `json:"group"`
	GroupID               int                    `json:"group_id"`
	HopByHopOptionSize    interface{}            `json:"hop_by_hop_option_size"`
	ID                    int                    `json:"id"`
	InWifiGroup           bool                   `json:"in_wifi_group"`
	Interval              int                    `json:"interval"`
	IsAllScheduled        bool                   `json:"is_all_scheduled"`
	IsOneoff              bool                   `json:"is_oneoff"`
	IsPublic              bool                   `json:"is_public"`
	MaxHops               int                    `json:"max_hops"`
	PacketInterval        interface{}            `json:"packet_interval"`
	Packets               int                    `json:"packets"`
	Paris                 int                    `json:"paris"`
	ParticipantCount      int                    `json:"participant_count"`
	ParticipationRequests []ParticipationRequest `json:"participation_requests"`
	Port                  interface{}            `json:"port"`
	ProbesRequested       int                    `json:"probes_requested"`
	ProbesScheduled       int                    `json:"probes_scheduled"`
	Protocol              string                 `json:"protocol"`
	ResolveOnProbe        bool                   `json:"resolve_on_probe"`
	ResolvedIPs           []string               `json:"resolved_ips"`
	ResponseTimeout       int                    `json:"response_timeout"`
	Result                string                 `json:"result"`
	Size                  int                    `json:"size"`
	Spread                interface{}            `json:"spread"`
	StartTime             int                    `json:"start_time"`
	Status                struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	} `json:"status"`
	StopTime  int    `json:"stop_time"`
	Target    string `json:"target"`
	TargetASN int    `json:"target_asn"`
	TargetIP  string `json:"target_ip"`
	Type      string `json:"type"`
}

// ParticipationRequest allow you to add or remove probes from a measurement that
// was already created
type ParticipationRequest struct {
	Action        string `json:"action"`
	CreatedAt     int    `json:"created_at"`
	ID            int    `json:"id"`
	Self          string `json:"self"`
	Measurement   string `json:"measurement"`
	MeasurementID int    `json:"measurement_id"`
	Requested     int    `json:"requested"`
	Type          string `json:"type"`
	Value         string `json:"value"`
	Logs          string `json:"logs"`
}

var (
	// ProbeTypes should be obvious
	ProbeTypes = []string{"area", "country", "prefix", "asn", "probes", "msm"}
	// AreaTypes should also be obvious
	AreaTypes = []string{"WW", "West", "North-Central", "South-Central", "North-East", "South-East"}
)

// MeasurementRequest contains the different measurement to create/view
type MeasurementRequest struct {
	// see below for definition
	Definitions []Definition `json:"definitions"`

	// requested set of probes
	Probes ProbeSet `json:"probes"`
	//
	BillTo       int  `json:"bill_to,omitempty"`
	IsOneoff     bool `json:"is_oneoff,omitempty"`
	SkipDNSCheck bool `json:"skip_dns_check,omitempty"`
	Times        int  `json:"times,omitempty"`
	StartTime    int  `json:"start_time,omitempty"`
	StopTime     int  `json:"stop_time,omitempty"`
}

// ProbeSet is a set of probes obviously
type ProbeSet []struct {
	Requested int               `json:"requested"` // number of probes
	Type      string            `json:"type"`      // area, country, prefix, asn, probes, msm
	Value     string            `json:"value"`     // can be numeric or string
	Tags      map[string]string `json:"tags,omitempty"`
}

// Definition is used to create measurements
type Definition struct {
	// Required fields
	Description string `json:"description"`
	Type        string `json:"type"`
	AF          int    `json:"af"`

	// Required for all but "dns"
	Target string `json:"target,omitempty"`

	GroupID        int    `json:"group_id,omitempty"`
	Group          string `json:"group,omitempty"`
	InWifiGroup    bool   `json:"in_wifi_group,omitempty"`
	Spread         int    `json:"spread,omitempty"`
	Packets        int    `json:"packets,omitempty"`
	PacketInterval int    `json:"packet_interval,omitempty"`

	// Common parameters
	ExtraWait      int  `json:"extra_wait,omitempty"`
	IsOneoff       bool `json:"is_oneoff,omitempty"`
	IsPublic       bool `json:"is_public,omitempty"`
	ResolveOnProbe bool `json:"resolve_on_probe,omitempty"`

	// Default depends on type
	Interval int `json:"interval,omitempty"`

	// dns & traceroute parameters
	Protocol string `json:"protocol"`

	// dns parameters
	QueryClass       string `json:"query_class,omitempty"`
	QueryType        string `json:"query_type,omitempty"`
	QueryArgument    string `json:"query_argument,omitempty"`
	Retry            int    `json:"retry"`
	SetCDBit         bool   `json:"set_cd_bit"`
	SetDOBit         bool   `json:"set_do_bit"`
	SetNSIDBit       bool   `json:"set_nsid_bit"`
	SetRDBit         bool   `json:"set_rd_bit"`
	UDPPayloadSize   int    `json:"udp_payload_size"`
	UseProbeResolver bool   `json:"use_probe_resolver"`

	// ping parameters
	//   none (see target)

	// traceroute parameters
	DestinationOptionSize int  `json:"destination_option_size,omitempty"`
	DontFragment          bool `json:"dont_fragment,omitempty"`
	DuplicateTimeout      int  `json:"duplicate_timeout,omitempty"`
	FirstHop              int  `json:"first_hop,omitempty"`
	HopByHopOptionSize    int  `json:"hop_by_hop_option_size,omitempty"`
	MaxHops               int  `json:"max_hops,omitempty"`
	Paris                 int  `json:"paris,omitempty"`

	// ntp parameters
	//   none (see target)

	// http parameters
	ExtendedTiming     bool   `json:"extended_timing,omitempty"`
	HeaderBytes        int    `json:"header_bytes,omitempty"`
	Method             string `json:"method"`
	MoreExtendedTiming bool   `json:"more_extended_timing,omitempty"`
	Path               string `json:"path,omitempty"`
	QueryOptions       string `json:"query_options,omitempty"`
	UserAgent          string `json:"user_agent,omitempty"`
	Version            string `json:"version,omitempty"`

	// sslcert parameters
	//   none (see target)

	// sslcert & traceroute & http parameters
	Port int `json:"port,omitempty"`

	// ping & traceroute parameters
	Size int `json:"size,omitempty"`

	// wifi parameters
	AnonymousIdentity string `json:"anonymous_identity,omitempty"`
	Cert              string `json:"cert,omitempty"`
	EAP               string `json:"eap,omitempty"`
}
<commit_msg>Make some more fields ",omitempty".<commit_after>// types.go

// This file contains the various types used by the API

package atlas

// APIError is for errors returned by the RIPE API.
type APIError struct {
	Error struct {
		Status int    `json:"status"`
		Code   int    `json:"code"`
		Detail string `json:"detail"`
		Title  string `json:"title"`
	} `json:"error"`
}

// Key is holding the API key parameters
type Key struct {
	UUID      string `json:"uuid"`
	ValidFrom string `json:"valid_from"`
	ValidTo   string `json:"valid_to"`
	Enabled   bool
	IsActive  bool    `json:"is_active"`
	CreatedAt string  `json:"created_at"`
	Label     string  `json:"label"`
	Grants    []Grant `json:"grants"`
	Type      string  `json:"type"`
}

// Grant is the permission(s) associated with a key
type Grant struct {
	Permission string `json:"permission"`
	Target     struct {
		Type string `json:"type"`
		ID   string `json:"id"`
	} `json:"target"`
}

// Probe is holding probe's data
type Probe struct {
	AddressV4      string `json:"address_v4"`
	AddressV6      string `json:"address_v6"`
	AsnV4          int    `json:"asn_v4"`
	AsnV6          int    `json:"asn_v6"`
	CountryCode    string `json:"country_code"`
	Description    string `json:"description"`
	FirstConnected int    `json:"first_connected"`
	Geometry       struct {
		Type        string    `json:"type"`
		Coordinates []float64 `json:"coordinates"`
	} `json:"geometry"`
	ID            int    `json:"id"`
	IsAnchor      bool   `json:"is_anchor"`
	IsPublic      bool   `json:"is_public"`
	LastConnected int    `json:"last_connected"`
	PrefixV4      string `json:"prefix_v4"`
	PrefixV6      string `json:"prefix_v6"`
	Status        struct {
		Since string `json:"since"`
		ID    int    `json:"id"`
		Name  string `json:"name"`
	} `json:"status"`
	StatusSince int `json:"status_since"`
	Tags        []struct {
		Name string `json:"name"`
		Slug string `json:"slug"`
	} `json:"tags"`
	Type string `json:"type"`
}

// Measurement is what we are working with
type Measurement struct {
	Af                    int                    `json:"af"`
	CreationTime          int                    `json:"creation_time"`
	Description           string                 `json:"description"`
	DestinationOptionSize interface{}            `json:"destination_option_size"`
	DontFragment          interface{}            `json:"dont_fragment"`
	DuplicateTimeout      interface{}            `json:"duplicate_timeout"`
	FirstHop              int                    `json:"first_hop"`
	Group                 string                 `json:"group"`
	GroupID               int                    `json:"group_id"`
	HopByHopOptionSize    interface{}            `json:"hop_by_hop_option_size"`
	ID                    int                    `json:"id"`
	InWifiGroup           bool                   `json:"in_wifi_group"`
	Interval              int                    `json:"interval"`
	IsAllScheduled        bool                   `json:"is_all_scheduled"`
	IsOneoff              bool                   `json:"is_oneoff"`
	IsPublic              bool                   `json:"is_public"`
	MaxHops               int                    `json:"max_hops"`
	PacketInterval        interface{}            `json:"packet_interval"`
	Packets               int                    `json:"packets"`
	Paris                 int                    `json:"paris"`
	ParticipantCount      int                    `json:"participant_count"`
	ParticipationRequests []ParticipationRequest `json:"participation_requests"`
	Port                  interface{}            `json:"port"`
	ProbesRequested       int                    `json:"probes_requested"`
	ProbesScheduled       int                    `json:"probes_scheduled"`
	Protocol              string                 `json:"protocol"`
	ResolveOnProbe        bool                   `json:"resolve_on_probe"`
	ResolvedIPs           []string               `json:"resolved_ips"`
	ResponseTimeout       int                    `json:"response_timeout"`
	Result                string                 `json:"result"`
	Size                  int                    `json:"size"`
	Spread                interface{}            `json:"spread"`
	StartTime             int                    `json:"start_time"`
	Status                struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	} `json:"status"`
	StopTime  int    `json:"stop_time"`
	Target    string `json:"target"`
	TargetASN int    `json:"target_asn"`
	TargetIP  string `json:"target_ip"`
	Type      string `json:"type"`
}

// ParticipationRequest allow you to add or remove probes from a measurement that
// was already created
type ParticipationRequest struct {
	Action        string `json:"action"`
	CreatedAt     int    `json:"created_at"`
	ID            int    `json:"id"`
	Self          string `json:"self"`
	Measurement   string `json:"measurement"`
	MeasurementID int    `json:"measurement_id"`
	Requested     int    `json:"requested"`
	Type          string `json:"type"`
	Value         string `json:"value"`
	Logs          string `json:"logs"`
}

var (
	// ProbeTypes should be obvious
	ProbeTypes = []string{"area", "country", "prefix", "asn", "probes", "msm"}
	// AreaTypes should also be obvious
	AreaTypes = []string{"WW", "West", "North-Central", "South-Central", "North-East", "South-East"}
)

// MeasurementRequest contains the different measurement to create/view
type MeasurementRequest struct {
	// see below for definition
	Definitions []Definition `json:"definitions"`

	// requested set of probes
	Probes ProbeSet `json:"probes"`
	//
	BillTo       int  `json:"bill_to,omitempty"`
	IsOneoff     bool `json:"is_oneoff,omitempty"`
	SkipDNSCheck bool `json:"skip_dns_check,omitempty"`
	Times        int  `json:"times,omitempty"`
	StartTime    int  `json:"start_time,omitempty"`
	StopTime     int  `json:"stop_time,omitempty"`
}

// ProbeSet is a set of probes obviously
type ProbeSet []struct {
	Requested int               `json:"requested"` // number of probes
	Type      string            `json:"type"`      // area, country, prefix, asn, probes, msm
	Value     string            `json:"value"`     // can be numeric or string
	Tags      map[string]string `json:"tags,omitempty"`
}

// Definition is used to create measurements
type Definition struct {
	// Required fields
	Description string `json:"description"`
	Type        string `json:"type"`
	AF          int    `json:"af"`

	// Required for all but "dns"
	Target string `json:"target,omitempty"`

	GroupID        int    `json:"group_id,omitempty"`
	Group          string `json:"group,omitempty"`
	InWifiGroup    bool   `json:"in_wifi_group,omitempty"`
	Spread         int    `json:"spread,omitempty"`
	Packets        int    `json:"packets,omitempty"`
	PacketInterval int    `json:"packet_interval,omitempty"`

	// Common parameters
	ExtraWait      int  `json:"extra_wait,omitempty"`
	IsOneoff       bool `json:"is_oneoff,omitempty"`
	IsPublic       bool `json:"is_public,omitempty"`
	ResolveOnProbe bool `json:"resolve_on_probe,omitempty"`

	// Default depends on type
	Interval int `json:"interval,omitempty"`

	// dns & traceroute parameters
	Protocol string `json:"protocol,omitempty"`

	// dns parameters
	QueryClass       string `json:"query_class,omitempty"`
	QueryType        string `json:"query_type,omitempty"`
	QueryArgument    string `json:"query_argument,omitempty"`
	Retry            int    `json:"retry,omitempty"`
	SetCDBit         bool   `json:"set_cd_bit,omitempty"`
	SetDOBit         bool   `json:"set_do_bit,omitempty"`
	SetNSIDBit       bool   `json:"set_nsid_bit,omitempty"`
	SetRDBit         bool   `json:"set_rd_bit,omitempty"`
	UDPPayloadSize   int    `json:"udp_payload_size,omitempty"`
	UseProbeResolver bool   `json:"use_probe_resolver"`

	// ping parameters
	//   none (see target)

	// traceroute parameters
	DestinationOptionSize int  `json:"destination_option_size,omitempty"`
	DontFragment          bool `json:"dont_fragment,omitempty"`
	DuplicateTimeout      int  `json:"duplicate_timeout,omitempty"`
	FirstHop              int  `json:"first_hop,omitempty"`
	HopByHopOptionSize    int  `json:"hop_by_hop_option_size,omitempty"`
	MaxHops               int  `json:"max_hops,omitempty"`
	Paris                 int  `json:"paris,omitempty"`

	// ntp parameters
	//   none (see target)

	// http parameters
	ExtendedTiming     bool   `json:"extended_timing,omitempty"`
	HeaderBytes        int    `json:"header_bytes,omitempty"`
	Method             string `json:"method,omitempty"`
	MoreExtendedTiming bool   `json:"more_extended_timing,omitempty"`
	Path               string `json:"path,omitempty"`
	QueryOptions       string `json:"query_options,omitempty"`
	UserAgent          string `json:"user_agent,omitempty"`
	Version            string `json:"version,omitempty"`

	// sslcert parameters
	//   none (see target)

	// sslcert & traceroute & http parameters
	Port int `json:"port,omitempty"`

	// ping & traceroute parameters
	Size int `json:"size,omitempty"`

	// wifi parameters
	AnonymousIdentity string `json:"anonymous_identity,omitempty"`
	Cert              string `json:"cert,omitempty"`
	EAP               string `json:"eap,omitempty"`
}
<|endoftext|>


<commit_before>// Package log provides a helpful wrapper around the standard log package.
//
// Anticipated basic usage:
// log.Infof("This is an info level message")
// log.Warnf("This is a warn level message")
// log.Errorf("This is an error level message")
// log.V(5, "This is info level, but will only show up if --verbosity >= 5")
// log.Panicf("This message is error level, and also becomes a panic()")
// log.Fatalf("This message is fatal level, and os.Exit(1) follows immediately")
package log

import (
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
)

var (
	Verbosity = flag.Int("verbosity", 0, "Logging verbosity level. Higher means more logs.")

	// Info is where all INFO-level messages get written.
	Info io.Writer = os.Stderr

	// Warn is where all WARN-level messages get written.
	Warn io.Writer = os.Stderr

	// Error is where all ERROR-level messages (including Panic) get written.
	Error io.Writer = os.Stderr

	// Fatal is where all FATAL-level messages get written.
	Fatal io.Writer = os.Stderr
)

// The rewriter type allows us to change the destination of written data without
// rebuilding the actual log.Logger objects used.
type rewriter struct {
	w *io.Writer
}

func (w *rewriter) Write(p []byte) (int, error) {
	return (*w.w).Write(p)
}

var (
	// The loggers used internally.
	i, w, e, f *log.Logger
)

func init() {
	flags := log.Ldate | log.Ltime | log.Lshortfile
	i = log.New(&rewriter{&Info}, "I", flags)
	w = log.New(&rewriter{&Warn}, "W", flags)
	e = log.New(&rewriter{&Error}, "E", flags)
	f = log.New(&rewriter{&Error}, "F", flags)
}

// Formats the message and writes it to the given logger.
// Returns the formatted message.
// If there is an error writing to the given logger, writes a description
// including the given message to the base logger.
func write(l *log.Logger, name, format string, v ...interface{}) string {
	msg := fmt.Sprintf(format, v...)
	if err := l.Output(3, msg); err != nil {
		log.Printf("Failed to write to %s logger: %v.\n  Message: %s", name, err, msg)
	}
	return msg
}

// LoudEnough returns whether the verbosity is high enough to include messages of the given level.
func LoudEnough(level int) bool {
	return level <= *Verbosity
}

// V writes log messages at INFO level, but only if the configured verbosity is equal or greater than the provided level.
func V(level int, format string, v ...interface{}) {
	if LoudEnough(level) {
		write(i, "info", format, v...)
	}
}

// Infof writes log messages at INFO level.
func Infof(format string, v ...interface{}) {
	write(i, "info", format, v...)
}

// Printf is synonymous with Infof.
// It exists for compatibility with the basic log package.
func Printf(format string, v ...interface{}) {
	write(i, "info", format, v...)
}

// Warnf writes log messages at WARN level.
func Warnf(format string, v ...interface{}) {
	write(w, "warn", format, v...)
}

// Errorf writes log messages at ERROR level.
func Errorf(format string, v ...interface{}) {
	write(e, "error", format, v...)
}

// Panicf writes log messages at ERROR level, and then panics.
// The panic parameter is an error with the formatted message.
func Panicf(format string, v ...interface{}) {
	panic(errors.New(write(e, "error", format, v...)))
}

// Fatalf writes log messages at FATAL level, and then calls os.Exit(1).
func Fatalf(format string, v ...interface{}) {
	write(f, "fatal", format, v...)
	os.Exit(1)
}
<commit_msg>The fatal logger was writing to the error log.<commit_after>// Package log provides a helpful wrapper around the standard log package.
//
// Anticipated basic usage:
// log.Infof("This is an info level message")
// log.Warnf("This is a warn level message")
// log.Errorf("This is an error level message")
// log.V(5, "This is info level, but will only show up if --verbosity >= 5")
// log.Panicf("This message is error level, and also becomes a panic()")
// log.Fatalf("This message is fatal level, and os.Exit(1) follows immediately")
package log

import (
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
)

var (
	Verbosity = flag.Int("verbosity", 0, "Logging verbosity level. Higher means more logs.")

	// Info is where all INFO-level messages get written.
	Info io.Writer = os.Stderr

	// Warn is where all WARN-level messages get written.
	Warn io.Writer = os.Stderr

	// Error is where all ERROR-level messages (including Panic) get written.
	Error io.Writer = os.Stderr

	// Fatal is where all FATAL-level messages get written.
	Fatal io.Writer = os.Stderr
)

// The rewriter type allows us to change the destination of written data without
// rebuilding the actual log.Logger objects used.
type rewriter struct {
	w *io.Writer
}

func (w *rewriter) Write(p []byte) (int, error) {
	return (*w.w).Write(p)
}

var (
	// The loggers used internally.
	i, w, e, f *log.Logger
)

func init() {
	flags := log.Ldate | log.Ltime | log.Lshortfile
	i = log.New(&rewriter{&Info}, "I", flags)
	w = log.New(&rewriter{&Warn}, "W", flags)
	e = log.New(&rewriter{&Error}, "E", flags)
	f = log.New(&rewriter{&Fatal}, "F", flags)
}

// Formats the message and writes it to the given logger.
// Returns the formatted message.
// If there is an error writing to the given logger, writes a description
// including the given message to the base logger.
func write(l *log.Logger, name, format string, v ...interface{}) string {
	msg := fmt.Sprintf(format, v...)
	if err := l.Output(3, msg); err != nil {
		log.Printf("Failed to write to %s logger: %v.\n  Message: %s", name, err, msg)
	}
	return msg
}

// LoudEnough returns whether the verbosity is high enough to include messages of the given level.
func LoudEnough(level int) bool {
	return level <= *Verbosity
}

// V writes log messages at INFO level, but only if the configured verbosity is equal or greater than the provided level.
func V(level int, format string, v ...interface{}) {
	if LoudEnough(level) {
		write(i, "info", format, v...)
	}
}

// Infof writes log messages at INFO level.
func Infof(format string, v ...interface{}) {
	write(i, "info", format, v...)
}

// Printf is synonymous with Infof.
// It exists for compatibility with the basic log package.
func Printf(format string, v ...interface{}) {
	write(i, "info", format, v...)
}

// Warnf writes log messages at WARN level.
func Warnf(format string, v ...interface{}) {
	write(w, "warn", format, v...)
}

// Errorf writes log messages at ERROR level.
func Errorf(format string, v ...interface{}) {
	write(e, "error", format, v...)
}

// Panicf writes log messages at ERROR level, and then panics.
// The panic parameter is an error with the formatted message.
func Panicf(format string, v ...interface{}) {
	panic(errors.New(write(e, "error", format, v...)))
}

// Fatalf writes log messages at FATAL level, and then calls os.Exit(1).
func Fatalf(format string, v ...interface{}) {
	write(f, "fatal", format, v...)
	os.Exit(1)
}
<|endoftext|>


<commit_before>package govalidator

import "reflect"

// Validator is a wrapper for validator functions, that returns bool and accepts string.
type Validator func(str string) bool
type tagOptions []string

// UnsupportedTypeError is a wrapper for reflect.Type
type UnsupportedTypeError struct {
	Type reflect.Type
}

// stringValues is a slice of reflect.Value holding *reflect.StringValue.
// It implements the methods to sort by string.
type stringValues []reflect.Value

// TagMap is a map of functions, that can be used as tags for ValidateStruct function.
var TagMap = map[string]Validator{
	"email":           IsEmail,
	"url":             IsURL,
	"alpha":           IsAlpha,
	"unicodeletter":   IsUnicodeLetter,
	"alphanum":        IsAlphanumeric,
	"unicodealphanum": IsUnicodeLetterNumeric,
	"numeric":         IsNumeric,
	"unicodenumeric":  IsUnicodeNumeric,
	"unicodedigit":    IsUnicodeDigit,
	"hexadecimal":     IsHexadecimal,
	"hexcolor":        IsHexcolor,
	"rgbcolor":        IsRGBcolor,
	"lowercase":       IsLowerCase,
	"uppercase":       IsUpperCase,
	"int":             IsInt,
	"float":           IsFloat,
	"null":            IsNull,
	"uuid":            IsUUID,
	"uuidv3":          IsUUIDv3,
	"uuidv4":          IsUUIDv4,
	"uuidv5":          IsUUIDv5,
	"creditcard":      IsCreditCard,
	"isbn10":          IsISBN10,
	"isbn13":          IsISBN13,
	"json":            IsJSON,
	"multibyte":       IsMultibyte,
	"ascii":           IsASCII,
	"fullwidth":       IsFullWidth,
	"halfwidth":       IsHalfWidth,
	"variablewidth":   IsVariableWidth,
	"base64":          IsBase64,
	"datauri":         IsDataURI,
	"ip":              IsIP,
	"ipv4":            IsIPv4,
	"ipv6":            IsIPv6,
	"mac":             IsMAC,
	"latitude":        IsLatitude,
	"longitude":       IsLongitude,
}
<commit_msg>fixed small typo on unicodeletternum<commit_after>package govalidator

import "reflect"

// Validator is a wrapper for validator functions, that returns bool and accepts string.
type Validator func(str string) bool
type tagOptions []string

// UnsupportedTypeError is a wrapper for reflect.Type
type UnsupportedTypeError struct {
	Type reflect.Type
}

// stringValues is a slice of reflect.Value holding *reflect.StringValue.
// It implements the methods to sort by string.
type stringValues []reflect.Value

// TagMap is a map of functions, that can be used as tags for ValidateStruct function.
var TagMap = map[string]Validator{
	"email":            IsEmail,
	"url":              IsURL,
	"alpha":            IsAlpha,
	"unicodeletter":    IsUnicodeLetter,
	"alphanum":         IsAlphanumeric,
	"unicodeletternum": IsUnicodeLetterNumeric,
	"numeric":          IsNumeric,
	"unicodenumeric":   IsUnicodeNumeric,
	"unicodedigit":     IsUnicodeDigit,
	"hexadecimal":      IsHexadecimal,
	"hexcolor":         IsHexcolor,
	"rgbcolor":         IsRGBcolor,
	"lowercase":        IsLowerCase,
	"uppercase":        IsUpperCase,
	"int":              IsInt,
	"float":            IsFloat,
	"null":             IsNull,
	"uuid":             IsUUID,
	"uuidv3":           IsUUIDv3,
	"uuidv4":           IsUUIDv4,
	"uuidv5":           IsUUIDv5,
	"creditcard":       IsCreditCard,
	"isbn10":           IsISBN10,
	"isbn13":           IsISBN13,
	"json":             IsJSON,
	"multibyte":        IsMultibyte,
	"ascii":            IsASCII,
	"fullwidth":        IsFullWidth,
	"halfwidth":        IsHalfWidth,
	"variablewidth":    IsVariableWidth,
	"base64":           IsBase64,
	"datauri":          IsDataURI,
	"ip":               IsIP,
	"ipv4":             IsIPv4,
	"ipv6":             IsIPv6,
	"mac":              IsMAC,
	"latitude":         IsLatitude,
	"longitude":        IsLongitude,
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/btcsuite/btclog"
	"github.com/btcsuite/seelog"
	"github.com/lightningnetwork/lnd/chainntfs"
	"github.com/lightningnetwork/lnd/channeldb"
	"github.com/lightningnetwork/lnd/lnwallet"
)

// Loggers per subsystem.  Note that backendLog is a seelog logger that all of
// the subsystem loggers route their messages to.  When adding new subsystems,
// add a reference here, to the subsystemLoggers map, and the useLogger
// function.
var (
	backendLog = seelog.Disabled
	ltndLog    = btclog.Disabled
	lnwlLog    = btclog.Disabled
	peerLog    = btclog.Disabled
	rpcsLog    = btclog.Disabled
	srvrLog    = btclog.Disabled
	ntfnLog    = btclog.Disabled
	chdbLog    = btclog.Disabled
)

// subsystemLoggers maps each subsystem identifier to its associated logger.
var subsystemLoggers = map[string]btclog.Logger{
	"LTND": ltndLog,
	"LNWL": lnwlLog,
	"PEER": peerLog,
	"RPCS": rpcsLog,
	"SRVR": srvrLog,
	"NTFN": ntfnLog,
	"CHDB": chdbLog,
}

// useLogger updates the logger references for subsystemID to logger.  Invalid
// subsystems are ignored.
func useLogger(subsystemID string, logger btclog.Logger) {
	if _, ok := subsystemLoggers[subsystemID]; !ok {
		return
	}
	subsystemLoggers[subsystemID] = logger

	switch subsystemID {
	case "LTND":
		ltndLog = logger

	case "LNWL":
		lnwlLog = logger
		lnwallet.UseLogger(logger)

	case "PEER":
		peerLog = logger

	case "RPCS":
		rpcsLog = logger

	case "SRVR":
		srvrLog = logger

	case "NTFN":
		ntfnLog = logger
		chainntnfs.UseLogger(logger)

	case "CHDB":
		chdbLog = logger
		channeldb.UseLogger(logger)
	}
}

// initSeelogLogger initializes a new seelog logger that is used as the backend
// for all logging subsystems.
func initSeelogLogger(logFile string) {
	config := `
	<seelog type="adaptive" mininterval="2000000" maxinterval="100000000"
		critmsgcount="500" minlevel="trace">
		<outputs formatid="all">
			<console />
			<rollingfile type="size" filename="%s" maxsize="10485760" maxrolls="3" />
		</outputs>
		<formats>
			<format id="all" format="%%Time %%Date [%%LEV] %%Msg%%n" />
		</formats>
	</seelog>`
	config = fmt.Sprintf(config, logFile)

	logger, err := seelog.LoggerFromConfigAsString(config)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create logger: %v", err)
		os.Exit(1)
	}

	backendLog = logger
}

// setLogLevel sets the logging level for provided subsystem.  Invalid
// subsystems are ignored.  Uninitialized subsystems are dynamically created as
// needed.
func setLogLevel(subsystemID string, logLevel string) {
	// Ignore invalid subsystems.
	logger, ok := subsystemLoggers[subsystemID]
	if !ok {
		return
	}

	// Default to info if the log level is invalid.
	level, ok := btclog.LogLevelFromString(logLevel)
	if !ok {
		level = btclog.InfoLvl
	}

	// Create new logger for the subsystem if needed.
	if logger == btclog.Disabled {
		logger = btclog.NewSubsystemLogger(backendLog, subsystemID+": ")
		useLogger(subsystemID, logger)
	}
	logger.SetLevel(level)
}

// setLogLevels sets the log level for all subsystem loggers to the passed
// level.  It also dynamically creates the subsystem loggers as needed, so it
// can be used to initialize the logging system.
func setLogLevels(logLevel string) {
	// Configure all sub-systems with the new logging level.  Dynamically
	// create loggers as needed.
	for subsystemID := range subsystemLoggers {
		setLogLevel(subsystemID, logLevel)
	}
}
<commit_msg>lnd: create logger for fundingManger add closures<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/btcsuite/btclog"
	"github.com/btcsuite/seelog"
	"github.com/lightningnetwork/lnd/chainntfs"
	"github.com/lightningnetwork/lnd/channeldb"
	"github.com/lightningnetwork/lnd/lnwallet"
)

// Loggers per subsystem.  Note that backendLog is a seelog logger that all of
// the subsystem loggers route their messages to.  When adding new subsystems,
// add a reference here, to the subsystemLoggers map, and the useLogger
// function.
var (
	backendLog = seelog.Disabled
	ltndLog    = btclog.Disabled
	lnwlLog    = btclog.Disabled
	peerLog    = btclog.Disabled
	fndgLog    = btclog.Disabled
	rpcsLog    = btclog.Disabled
	srvrLog    = btclog.Disabled
	ntfnLog    = btclog.Disabled
	chdbLog    = btclog.Disabled
)

// subsystemLoggers maps each subsystem identifier to its associated logger.
var subsystemLoggers = map[string]btclog.Logger{
	"LTND": ltndLog,
	"LNWL": lnwlLog,
	"PEER": peerLog,
	"RPCS": rpcsLog,
	"SRVR": srvrLog,
	"NTFN": ntfnLog,
	"CHDB": chdbLog,
	"FNDG": fndgLog,
}

// useLogger updates the logger references for subsystemID to logger.  Invalid
// subsystems are ignored.
func useLogger(subsystemID string, logger btclog.Logger) {
	if _, ok := subsystemLoggers[subsystemID]; !ok {
		return
	}
	subsystemLoggers[subsystemID] = logger

	switch subsystemID {
	case "LTND":
		ltndLog = logger

	case "LNWL":
		lnwlLog = logger
		lnwallet.UseLogger(logger)

	case "PEER":
		peerLog = logger

	case "RPCS":
		rpcsLog = logger

	case "SRVR":
		srvrLog = logger

	case "NTFN":
		ntfnLog = logger
		chainntnfs.UseLogger(logger)

	case "CHDB":
		chdbLog = logger
		channeldb.UseLogger(logger)

	case "FNDG":
		fndgLog = logger
	}
}

// initSeelogLogger initializes a new seelog logger that is used as the backend
// for all logging subsystems.
func initSeelogLogger(logFile string) {
	config := `
	<seelog type="adaptive" mininterval="2000000" maxinterval="100000000"
		critmsgcount="500" minlevel="trace">
		<outputs formatid="all">
			<console />
			<rollingfile type="size" filename="%s" maxsize="10485760" maxrolls="3" />
		</outputs>
		<formats>
			<format id="all" format="%%Time %%Date [%%LEV] %%Msg%%n" />
		</formats>
	</seelog>`
	config = fmt.Sprintf(config, logFile)

	logger, err := seelog.LoggerFromConfigAsString(config)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create logger: %v", err)
		os.Exit(1)
	}

	backendLog = logger
}

// setLogLevel sets the logging level for provided subsystem.  Invalid
// subsystems are ignored.  Uninitialized subsystems are dynamically created as
// needed.
func setLogLevel(subsystemID string, logLevel string) {
	// Ignore invalid subsystems.
	logger, ok := subsystemLoggers[subsystemID]
	if !ok {
		return
	}

	// Default to info if the log level is invalid.
	level, ok := btclog.LogLevelFromString(logLevel)
	if !ok {
		level = btclog.InfoLvl
	}

	// Create new logger for the subsystem if needed.
	if logger == btclog.Disabled {
		logger = btclog.NewSubsystemLogger(backendLog, subsystemID+": ")
		useLogger(subsystemID, logger)
	}
	logger.SetLevel(level)
}

// setLogLevels sets the log level for all subsystem loggers to the passed
// level. It also dynamically creates the subsystem loggers as needed, so it
// can be used to initialize the logging system.
func setLogLevels(logLevel string) {
	// Configure all sub-systems with the new logging level. Dynamically
	// create loggers as needed.
	for subsystemID := range subsystemLoggers {
		setLogLevel(subsystemID, logLevel)
	}
}

// logClosure is used to provide a closure over expensive logging operations
// so don't have to be performed when the logging level doesn't warrant it.
type logClosure func() string

// String invokes the underlying function and returns the result.
func (c logClosure) String() string {
	return c()
}

// newLogClosure returns a new closure over a function that returns a string
// which itself provides a Stringer interface so that it can be used with the
// logging system.
func newLogClosure(c func() string) logClosure {
	return logClosure(c)
}
<|endoftext|>


<commit_before>package superast

type id struct {
	ID int `json:"id"`
}

type line struct {
	Line int `json:"line"`
}

type block struct {
	id
	Stmts []stmt `json:"statements"`
}

type stmt interface{}

type dataType struct {
	id
	Name string `json:"name"`
}

type varDecl struct {
	id
	line
	Name     string    `json:"name"`
	DataType *dataType `json:"data-type"`
}

type funcDecl struct {
	id
	line
	Type    string    `json:"type"`
	Name    string    `json:"name"`
	Params  []varDecl `json:"parameters,omitempty"`
	RetType *dataType `json:"return-type"`
	Block   *block    `json:"block"`
}

type statement struct {
	id
	line
	Type     string     `json:"type"`
	Name     string     `json:"name,omitempty"`
	Value    string     `json:"value,omitempty"`
	DataType *dataType  `json:"data-type,omitempty"`
	RetType  *dataType  `json:"return-type,omitempty"`
	Params   []varDecl  `json:"parameters,omitempty"`
	Args     []stmt     `json:"arguments,omitempty"`
	Init     *statement `json:"init,omitempty"`
	Left     *statement `json:"left,omitempty"`
	Right    *statement `json:"right,omitempty"`
	Block    *block     `json:"block,omitempty"`
}

type identifier struct {
	id
	line
	Type  string `json:"type"`
	Value string `json:"value"`
}

type funcCall struct {
	id
	line
	Type string `json:"type"`
	Name string `json:"name"`
	Args []stmt `json:"arguments"`
}

type structDecl struct {
	id
	line
	Type  string    `json:"type"`
	Name  string    `json:"name"`
	Attrs []varDecl `json:"attributes"`
}
<commit_msg>Remove now unused types from the old stmt struct<commit_after>package superast

type id struct {
	ID int `json:"id"`
}

type line struct {
	Line int `json:"line"`
}

type block struct {
	id
	Stmts []stmt `json:"statements"`
}

type stmt interface{}

type dataType struct {
	id
	Name string `json:"name"`
}

type varDecl struct {
	id
	line
	Name     string    `json:"name"`
	DataType *dataType `json:"data-type"`
}

type funcDecl struct {
	id
	line
	Type    string    `json:"type"`
	Name    string    `json:"name"`
	Params  []varDecl `json:"parameters,omitempty"`
	RetType *dataType `json:"return-type"`
	Block   *block    `json:"block"`
}

type statement struct {
	id
	line
	Type     string     `json:"type"`
	Name     string     `json:"name,omitempty"`
	Value    string     `json:"value,omitempty"`
	DataType *dataType  `json:"data-type,omitempty"`
	Init     *statement `json:"init,omitempty"`
	Left     *statement `json:"left,omitempty"`
	Right    *statement `json:"right,omitempty"`
}

type identifier struct {
	id
	line
	Type  string `json:"type"`
	Value string `json:"value"`
}

type funcCall struct {
	id
	line
	Type string `json:"type"`
	Name string `json:"name"`
	Args []stmt `json:"arguments"`
}

type structDecl struct {
	id
	line
	Type  string    `json:"type"`
	Name  string    `json:"name"`
	Attrs []varDecl `json:"attributes"`
}
<|endoftext|>


<commit_before>package lru

import (
	"sync"

	"github.com/hashicorp/golang-lru/simplelru"
)

// Cache is a thread-safe fixed size LRU cache.
type Cache struct {
	lru  simplelru.LRUCache
	lock sync.RWMutex
}

// New creates an LRU of the given size.
func New(size int) (*Cache, error) {
	return NewWithEvict(size, nil)
}

// NewWithEvict constructs a fixed size cache with the given eviction
// callback.
func NewWithEvict(size int, onEvicted func(key interface{}, value interface{})) (*Cache, error) {
	lru, err := simplelru.NewLRU(size, simplelru.EvictCallback(onEvicted))
	if err != nil {
		return nil, err
	}
	c := &Cache{
		lru: lru,
	}
	return c, nil
}

// Purge is used to completely clear the cache.
func (c *Cache) Purge() {
	c.lock.Lock()
	c.lru.Purge()
	c.lock.Unlock()
}

// Add adds a value to the cache.  Returns true if an eviction occurred.
func (c *Cache) Add(key, value interface{}) (evicted bool) {
	c.lock.Lock()
	evicted = c.lru.Add(key, value)
	c.lock.Unlock()
	return evicted
}

// Get looks up a key's value from the cache.
func (c *Cache) Get(key interface{}) (value interface{}, ok bool) {
	c.lock.Lock()
	value, ok = c.lru.Get(key)
	c.lock.Unlock()
	return value, ok
}

// Contains checks if a key is in the cache, without updating the
// recent-ness or deleting it for being stale.
func (c *Cache) Contains(key interface{}) bool {
	c.lock.RLock()
	containKey := c.lru.Contains(key)
	c.lock.RUnlock()
	return containKey
}

// Peek returns the key value (or undefined if not found) without updating
// the "recently used"-ness of the key.
func (c *Cache) Peek(key interface{}) (value interface{}, ok bool) {
	c.lock.RLock()
	value, ok = c.lru.Peek(key)
	c.lock.RUnlock()
	return value, ok
}

// ContainsOrAdd checks if a key is in the cache  without updating the
// recent-ness or deleting it for being stale,  and if not, adds the value.
// Returns whether found and whether an eviction occurred.
func (c *Cache) ContainsOrAdd(key, value interface{}) (ok, evicted bool) {
	c.lock.Lock()
	defer c.lock.Unlock()

	if c.lru.Contains(key) {
		return true, false
	}
	evicted = c.lru.Add(key, value)
	return false, evicted
}

// Remove removes the provided key from the cache.
func (c *Cache) Remove(key interface{}) {
	c.lock.Lock()
	c.lru.Remove(key)
	c.lock.Unlock()
}

// RemoveOldest removes the oldest item from the cache.
func (c *Cache) RemoveOldest() {
	c.lock.Lock()
	c.lru.RemoveOldest()
	c.lock.Unlock()
}

// Keys returns a slice of the keys in the cache, from oldest to newest.
func (c *Cache) Keys() []interface{} {
	c.lock.RLock()
	keys := c.lru.Keys()
	c.lock.RUnlock()
	return keys
}

// Len returns the number of items in the cache.
func (c *Cache) Len() int {
	c.lock.RLock()
	length := c.lru.Len()
	c.lock.RUnlock()
	return length
}
<commit_msg>lru: don't kill the return values of Remove and RemoveOldest<commit_after>package lru

import (
	"sync"

	"github.com/hashicorp/golang-lru/simplelru"
)

// Cache is a thread-safe fixed size LRU cache.
type Cache struct {
	lru  simplelru.LRUCache
	lock sync.RWMutex
}

// New creates an LRU of the given size.
func New(size int) (*Cache, error) {
	return NewWithEvict(size, nil)
}

// NewWithEvict constructs a fixed size cache with the given eviction
// callback.
func NewWithEvict(size int, onEvicted func(key interface{}, value interface{})) (*Cache, error) {
	lru, err := simplelru.NewLRU(size, simplelru.EvictCallback(onEvicted))
	if err != nil {
		return nil, err
	}
	c := &Cache{
		lru: lru,
	}
	return c, nil
}

// Purge is used to completely clear the cache.
func (c *Cache) Purge() {
	c.lock.Lock()
	c.lru.Purge()
	c.lock.Unlock()
}

// Add adds a value to the cache.  Returns true if an eviction occurred.
func (c *Cache) Add(key, value interface{}) (evicted bool) {
	c.lock.Lock()
	evicted = c.lru.Add(key, value)
	c.lock.Unlock()
	return evicted
}

// Get looks up a key's value from the cache.
func (c *Cache) Get(key interface{}) (value interface{}, ok bool) {
	c.lock.Lock()
	value, ok = c.lru.Get(key)
	c.lock.Unlock()
	return value, ok
}

// Contains checks if a key is in the cache, without updating the
// recent-ness or deleting it for being stale.
func (c *Cache) Contains(key interface{}) bool {
	c.lock.RLock()
	containKey := c.lru.Contains(key)
	c.lock.RUnlock()
	return containKey
}

// Peek returns the key value (or undefined if not found) without updating
// the "recently used"-ness of the key.
func (c *Cache) Peek(key interface{}) (value interface{}, ok bool) {
	c.lock.RLock()
	value, ok = c.lru.Peek(key)
	c.lock.RUnlock()
	return value, ok
}

// ContainsOrAdd checks if a key is in the cache  without updating the
// recent-ness or deleting it for being stale,  and if not, adds the value.
// Returns whether found and whether an eviction occurred.
func (c *Cache) ContainsOrAdd(key, value interface{}) (ok, evicted bool) {
	c.lock.Lock()
	defer c.lock.Unlock()

	if c.lru.Contains(key) {
		return true, false
	}
	evicted = c.lru.Add(key, value)
	return false, evicted
}

// Remove removes the provided key from the cache.
func (c *Cache) Remove(key interface{}) (present bool) {
	c.lock.Lock()
	present = c.lru.Remove(key)
	c.lock.Unlock()
	return
}

// RemoveOldest removes the oldest item from the cache.
func (c *Cache) RemoveOldest() (key interface{}, value interface{}, ok bool) {
	c.lock.Lock()
	key, value, ok = c.lru.RemoveOldest()
	c.lock.Unlock()
	return
}

// Keys returns a slice of the keys in the cache, from oldest to newest.
func (c *Cache) Keys() []interface{} {
	c.lock.RLock()
	keys := c.lru.Keys()
	c.lock.RUnlock()
	return keys
}

// Len returns the number of items in the cache.
func (c *Cache) Len() int {
	c.lock.RLock()
	length := c.lru.Len()
	c.lock.RUnlock()
	return length
}
<|endoftext|>


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

package reverse

import (
	"bytes"
	"fmt"
	"regexp"
	"regexp/syntax"
)

// Regexp stores a regular expression that can be "reverted" or "built":
// outermost capturing groups become placeholders to be filled by variables.
//
// For example, given a Regexp with the pattern `1(\d+)3`, we can call
// re.Revert([]string{"2"}, nil) to get a resulting string "123".
// This also works for named capturing groups: we can revert `1(?P<two>\d+)3`
// calling re.Revert(nil, map[string]string{"two": "2"}).
//
// There are a few limitations that can't be changed:
//
// 1. Nested capturing groups are ignored; only the outermost groups become
// a placeholder. So in `1(\d+([a-z]+))3` there is only one placeholder
// although there are two capturing groups: re.Revert([]string{"2", "a"}, nil)
// results in "123" and not "12a3".
//
// 2. Literals inside capturing groups are ignored; the whole group becomes
// a placeholder.
type Regexp struct {
	compiled *regexp.Regexp // compiled regular expression
	template string         // reverse template
	groups   []string       // order of positional and named capturing groups;
							// names for named and empty strings for positional
	indices  []int          // indices of the outermost groups
}

// Compile compiles the regular expression pattern and creates a template
// to revert it.
func Compile(pattern string) (*Regexp, error) {
	re, err := syntax.Parse(pattern, syntax.Perl)
	if err != nil {
		return nil, err
	}
	tpl := &template{buffer: new(bytes.Buffer)}
	tpl.write(re)
	return &Regexp{
		compiled: regexp.MustCompile(pattern),
		template: tpl.buffer.String(),
		groups:   tpl.groups,
		indices:  tpl.indices,
	}, nil
}

// Regexp returns the compiled regular expression to be used for matching.
func (r *Regexp) Regexp() *regexp.Regexp {
	return r.compiled
}

// Groups returns an ordered list of the outermost capturing groups found in
// the regexp, and the indices of these groups.
//
// Positional groups are listed as an empty string and named groups use
// the group name.
func (r *Regexp) Groups() ([]string, []int) {
	return r.groups, r.indices
}

// Revert builds a string for this regexp using the given values.
//
// The args parameter is used for positional and named capturing groups,
// and the kwds parameter is optionally used for named groups only;
// if a name is not provided in kwds, the value is taken from args, in order.
func (r *Regexp) Revert(args []string, kwds map[string]string) (string, error) {
	i := 0
	values := make([]interface{}, len(r.groups))
	for k, v := range r.groups {
		if v != "" && kwds != nil {
			// A named group. Check if it was passed in kwds.
			if tmp, ok := kwds[v]; ok {
				values[k] = tmp
				continue
			}
		}
		if i >= len(args) {
			return "", fmt.Errorf(
				"Not enough values to revert the regexp " +
				"(expected %d variables)", len(r.groups))
		}
		values[k] = args[i]
		i++
	}
	return fmt.Sprintf(r.template, values...), nil
}

// ValidRevert is the same as Revert but it also validates the resulting
// string matching it against the compiled regexp.
func (r *Regexp) ValidRevert(args []string, kwds map[string]string) (string, error) {
	reverse, err := r.Revert(args, kwds)
	if err != nil {
		return "", err
	}
	if !r.compiled.MatchString(reverse) {
		return "", fmt.Errorf("Resulting string doesn't match the regexp: %q",
			reverse)
	}
	return reverse, nil
}

// template builds a reverse template for a regexp.
type template struct {
	buffer  *bytes.Buffer
	groups  []string      // outermost capturing groups: empty string for
						  // positional or name for named groups
	indices []int         // indices of outermost capturing groups
	index   int           // current group index
	level   int           // current capturing group nesting level
}

// write writes a reverse template to the buffer.
func (t *template) write(re *syntax.Regexp) {
	switch re.Op {
	case syntax.OpLiteral:
		if t.level == 0 {
			for _, r := range re.Rune {
				t.buffer.WriteRune(r)
				if r == '%' {
					t.buffer.WriteRune('%')
				}
			}
		}
	case syntax.OpCapture:
		t.level++
		t.index++
		if t.level == 1 {
			t.groups = append(t.groups, re.Name)
			t.indices = append(t.indices, t.index)
			t.buffer.WriteString("%s")
		}
		for _, sub := range re.Sub {
			t.write(sub)
		}
		t.level--
	case syntax.OpConcat:
		for _, sub := range re.Sub {
			t.write(sub)
		}
	}
}
<commit_msg>reverse: use regexp.Compile, not MustCompile.<commit_after>// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package reverse

import (
	"bytes"
	"fmt"
	"regexp"
	"regexp/syntax"
)

// Regexp stores a regular expression that can be "reverted" or "built":
// outermost capturing groups become placeholders to be filled by variables.
//
// For example, given a Regexp with the pattern `1(\d+)3`, we can call
// re.Revert([]string{"2"}, nil) to get a resulting string "123".
// This also works for named capturing groups: we can revert `1(?P<two>\d+)3`
// calling re.Revert(nil, map[string]string{"two": "2"}).
//
// There are a few limitations that can't be changed:
//
// 1. Nested capturing groups are ignored; only the outermost groups become
// a placeholder. So in `1(\d+([a-z]+))3` there is only one placeholder
// although there are two capturing groups: re.Revert([]string{"2", "a"}, nil)
// results in "123" and not "12a3".
//
// 2. Literals inside capturing groups are ignored; the whole group becomes
// a placeholder.
type Regexp struct {
	compiled *regexp.Regexp // compiled regular expression
	template string         // reverse template
	groups   []string       // order of positional and named capturing groups;
							// names for named and empty strings for positional
	indices  []int          // indices of the outermost groups
}

// Compile compiles the regular expression pattern and creates a template
// to revert it.
func Compile(pattern string) (*Regexp, error) {
	compiled, err := regexp.Compile(pattern)
	if err != nil {
		return nil, err
	}
	re, err := syntax.Parse(pattern, syntax.Perl)
	if err != nil {
		return nil, err
	}
	tpl := &template{buffer: new(bytes.Buffer)}
	tpl.write(re)
	return &Regexp{
		compiled: compiled,
		template: tpl.buffer.String(),
		groups:   tpl.groups,
		indices:  tpl.indices,
	}, nil
}

// Regexp returns the compiled regular expression to be used for matching.
func (r *Regexp) Regexp() *regexp.Regexp {
	return r.compiled
}

// Groups returns an ordered list of the outermost capturing groups found in
// the regexp, and the indices of these groups.
//
// Positional groups are listed as an empty string and named groups use
// the group name.
func (r *Regexp) Groups() ([]string, []int) {
	return r.groups, r.indices
}

// Revert builds a string for this regexp using the given values.
//
// The args parameter is used for positional and named capturing groups,
// and the kwds parameter is optionally used for named groups only;
// if a name is not provided in kwds, the value is taken from args, in order.
func (r *Regexp) Revert(args []string, kwds map[string]string) (string, error) {
	i := 0
	values := make([]interface{}, len(r.groups))
	for k, v := range r.groups {
		if v != "" && kwds != nil {
			// A named group. Check if it was passed in kwds.
			if tmp, ok := kwds[v]; ok {
				values[k] = tmp
				continue
			}
		}
		if i >= len(args) {
			return "", fmt.Errorf(
				"Not enough values to revert the regexp " +
				"(expected %d variables)", len(r.groups))
		}
		values[k] = args[i]
		i++
	}
	return fmt.Sprintf(r.template, values...), nil
}

// ValidRevert is the same as Revert but it also validates the resulting
// string matching it against the compiled regexp.
func (r *Regexp) ValidRevert(args []string, kwds map[string]string) (string, error) {
	reverse, err := r.Revert(args, kwds)
	if err != nil {
		return "", err
	}
	if !r.compiled.MatchString(reverse) {
		return "", fmt.Errorf("Resulting string doesn't match the regexp: %q",
			reverse)
	}
	return reverse, nil
}

// template builds a reverse template for a regexp.
type template struct {
	buffer  *bytes.Buffer
	groups  []string      // outermost capturing groups: empty string for
						  // positional or name for named groups
	indices []int         // indices of outermost capturing groups
	index   int           // current group index
	level   int           // current capturing group nesting level
}

// write writes a reverse template to the buffer.
func (t *template) write(re *syntax.Regexp) {
	switch re.Op {
	case syntax.OpLiteral:
		if t.level == 0 {
			for _, r := range re.Rune {
				t.buffer.WriteRune(r)
				if r == '%' {
					t.buffer.WriteRune('%')
				}
			}
		}
	case syntax.OpCapture:
		t.level++
		t.index++
		if t.level == 1 {
			t.groups = append(t.groups, re.Name)
			t.indices = append(t.indices, t.index)
			t.buffer.WriteString("%s")
		}
		for _, sub := range re.Sub {
			t.write(sub)
		}
		t.level--
	case syntax.OpConcat:
		for _, sub := range re.Sub {
			t.write(sub)
		}
	}
}
<|endoftext|>


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

// rewrite contains commands for writing the altered import statements.
package rewrite

import (
	"errors"
	"fmt"
	"os"
	"path"
	"path/filepath"
	"sort"
	"strings"
)

type ListStatus byte

func (ls ListStatus) String() string {
	switch ls {
	case StatusUnknown:
		return "?"
	case StatusMissing:
		return "m"
	case StatusStd:
		return "s"
	case StatusLocal:
		return "l"
	case StatusExternal:
		return "e"
	case StatusInternal:
		return "i"
	case StatusUnused:
		return "u"
	}
	return ""
}

const (
	StatusUnknown ListStatus = iota
	StatusMissing
	StatusStd
	StatusLocal
	StatusExternal
	StatusInternal
	StatusUnused
)

type ListItem struct {
	Status ListStatus
	Path   string
}

func (li ListItem) String() string {
	return li.Status.String() + " " + li.Path
}

type ListItemSort []ListItem

func (li ListItemSort) Len() int      { return len(li) }
func (li ListItemSort) Swap(i, j int) { li[i], li[j] = li[j], li[i] }
func (li ListItemSort) Less(i, j int) bool {
	if li[i].Status == li[j].Status {
		return strings.Compare(li[i].Path, li[j].Path) < 0
	}
	return li[i].Status > li[j].Status
}

const (
	vendorFilename = "vendor.json"
	internalFolder = "internal"
	toolName       = "github.com/kardianos/vendor"
)

var (
	internalVendor      = filepath.Join(internalFolder, vendorFilename)
	internalFolderSlash = string(filepath.Separator) + internalFolder + string(filepath.Separator)
)

var (
	ErrVendorFileExists  = errors.New(internalVendor + " file already exists.")
	ErrMissingVendorFile = errors.New("Unable to find internal folder with vendor file.")
	ErrMissingGOROOT     = errors.New("Unable to determine GOROOT.")
	ErrMissingGOPATH     = errors.New("Missing GOPATH.")
	ErrVendorExists      = errors.New("Package already exists as a vendor package.")
	ErrLocalPackage      = errors.New("Cannot vendor a local package.")
	ErrImportExists      = errors.New("Import exists. To update use update command.")
	ErrImportNotExists   = errors.New("Import does not exist.")
	ErrNoLocalPath       = errors.New("Import is present in vendor file, but is missing local path.")
)

type ErrNotInGOPATH struct {
	Missing string
}

func (err ErrNotInGOPATH) Error() string {
	return fmt.Sprintf("Package %q not in GOPATH.", err.Missing)
}

func CmdInit() error {
	/*
		1. Determine if CWD contains "internal/vendor.json".
		2. If exists, return error.
		3. Create directory if it doesn't exist.
		4. Create "internal/vendor.json" file.
	*/
	wd, err := os.Getwd()
	if err != nil {
		return err
	}
	_, err = os.Stat(filepath.Join(wd, internalVendor))
	if os.IsNotExist(err) == false {
		return ErrVendorFileExists
	}
	err = os.MkdirAll(filepath.Join(wd, internalFolder), 0777)
	if err != nil {
		return err
	}
	vf := &VendorFile{
		Tool: toolName,
	}
	return writeVendorFile(wd, vf)
}

func CmdList() ([]ListItem, error) {
	/*
		1. Find vendor root.
		2. Find vendor root import path via GOPATH.
		3. Walk directory, find all directories with go files.
		4. Parse imports for all go files.
		5. Determine the status of all imports.
		  * Std
		  * Local
		  * External Vendor
		  * Internal Vendor
		  * Unused Vendor
		6. Return Vendor import paths.
	*/
	ctx, err := NewContextWD()
	if err != nil {
		return nil, err
	}

	err = ctx.LoadPackage()
	if err != nil {
		return nil, err
	}

	li := make([]ListItem, 0, len(ctx.Package))
	for _, pkg := range ctx.Package {
		li = append(li, ListItem{Status: pkg.Status, Path: pkg.ImportPath})
	}
	// Sort li by Status, then Path.
	sort.Sort(ListItemSort(li))

	return li, nil
}

/*
	Add, Update, and Remove will start with the same steps as List.
	Rather then returning the results, it will find any affected files,
	alter their imports, then write the files back out. Also copy or remove
	files and folders as needed.
*/

func CmdAdd(importPath string) error {
	return addUpdateImportPath(importPath, verifyAdd)
}

func CmdUpdate(importPath string) error {
	return addUpdateImportPath(importPath, verifyUpdate)
}

func verifyAdd(ctx *Context, importPath string) error {
	for _, pkg := range ctx.VendorFile.Package {
		if pkg.Vendor == importPath {
			return ErrImportExists
		}
	}
	return nil
}
func verifyUpdate(ctx *Context, importPath string) error {
	for _, pkg := range ctx.VendorFile.Package {
		if pkg.Vendor == importPath {
			return nil
		}
	}
	return ErrImportNotExists
}

func addUpdateImportPath(importPath string, verify func(ctx *Context, importPath string) error) error {
	importPath = slashToImportPath(importPath)
	ctx, err := NewContextWD()
	if err != nil {
		return err
	}

	err = ctx.LoadPackage(importPath)
	if err != nil {
		return err
	}

	err = verify(ctx, importPath)
	if err != nil {
		return err
	}

	pkg := ctx.Package[importPath]
	if pkg.Status != StatusExternal {
		if pkg.Status == StatusInternal {
			return ErrVendorExists
		}
		if pkg.Status == StatusLocal {
			return ErrLocalPackage
		}
		return ErrNotInGOPATH{importPath}
	}

	// Determine correct local import path (from GOPATH).
	/*
		"crypto/tls" -> "path/to/mypkg/internal/crypto/tls"
		"yours/internal/yourpkg" -> "path/to/mypkg/internal/yourpkg"
		"github.com/kardianos/osext" -> "patn/to/mypkg/internal/github.com/kardianos/osext"
	*/
	// The following method "cheats" and doesn't look at any external vendor file.
	ss := strings.Split(importPath, internalFolderSlash)
	localImportPath := path.Join(ctx.RootImportPath, internalFolder, ss[len(ss)-1])

	// Update vendor file with correct Local field.
	// TODO: find the Version and VersionTime.
	var vp *VendorPackage
	for _, pkg := range ctx.VendorFile.Package {
		if pkg.Vendor == importPath {
			vp = pkg
			break
		}
	}
	if vp == nil {
		vp = &VendorPackage{
			Vendor: importPath,
			Local:  localImportPath,
		}
		ctx.VendorFile.Package = append(ctx.VendorFile.Package, vp)
	}
	err = writeVendorFile(ctx.RootDir, ctx.VendorFile)
	if err != nil {
		return err
	}
	err = CopyPackage(filepath.Join(ctx.RootGopath, slashToFilepath(localImportPath)), pkg.Dir)
	if err != nil {
		return err
	}

	err = ctx.AddImports(importPath)
	if err != nil {
		return err
	}

	// Determine which files to touch.
	files := ctx.fileImports[importPath]

	// TODO: also check for any existing vendor file paths to update.
	return ctx.RewriteFiles(files, []Rule{Rule{From: importPath, To: localImportPath}})
}
func CmdRemove(importPath string) error {
	importPath = slashToImportPath(importPath)
	ctx, err := NewContextWD()
	if err != nil {
		return err
	}

	err = ctx.LoadPackage(importPath)
	if err != nil {
		return err
	}

	localPath := ""
	localFound := false
	vendorFileIndex := 0
	for i, pkg := range ctx.VendorFile.Package {
		if pkg.Vendor == importPath {
			localPath = pkg.Local
			localFound = true
			vendorFileIndex = i
			break
		}
	}
	if !localFound {
		return ErrImportNotExists
	}
	if localPath == "" {
		return ErrNoLocalPath
	}

	files := ctx.fileImports[localPath]

	err = ctx.RewriteFiles(files, []Rule{Rule{From: localPath, To: importPath}})
	if err != nil {
		return err
	}

	err = RemovePackage(filepath.Join(ctx.RootGopath, slashToFilepath(localPath)))
	if err != nil {
		return err
	}
	nextPkg := make([]*VendorPackage, 0, len(ctx.VendorFile.Package)-1)
	for i, pkg := range ctx.VendorFile.Package {
		if i == vendorFileIndex {
			continue
		}
		nextPkg = append(nextPkg, pkg)
	}
	ctx.VendorFile.Package = nextPkg

	return writeVendorFile(ctx.RootDir, ctx.VendorFile)
}
<commit_msg>rewrite: rewrite all needed files and paths. Check for existing files before adding.<commit_after>// Copyright 2015 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.

// rewrite contains commands for writing the altered import statements.
package rewrite

import (
	"errors"
	"fmt"
	"os"
	"path"
	"path/filepath"
	"sort"
	"strings"
)

type ListStatus byte

func (ls ListStatus) String() string {
	switch ls {
	case StatusUnknown:
		return "?"
	case StatusMissing:
		return "m"
	case StatusStd:
		return "s"
	case StatusLocal:
		return "l"
	case StatusExternal:
		return "e"
	case StatusInternal:
		return "i"
	case StatusUnused:
		return "u"
	}
	return ""
}

const (
	StatusUnknown ListStatus = iota
	StatusMissing
	StatusStd
	StatusLocal
	StatusExternal
	StatusInternal
	StatusUnused
)

type ListItem struct {
	Status ListStatus
	Path   string
}

func (li ListItem) String() string {
	return li.Status.String() + " " + li.Path
}

type ListItemSort []ListItem

func (li ListItemSort) Len() int      { return len(li) }
func (li ListItemSort) Swap(i, j int) { li[i], li[j] = li[j], li[i] }
func (li ListItemSort) Less(i, j int) bool {
	if li[i].Status == li[j].Status {
		return strings.Compare(li[i].Path, li[j].Path) < 0
	}
	return li[i].Status > li[j].Status
}

const (
	vendorFilename = "vendor.json"
	internalFolder = "internal"
	toolName       = "github.com/kardianos/vendor"
)

var (
	internalVendor      = filepath.Join(internalFolder, vendorFilename)
	internalFolderSlash = string(filepath.Separator) + internalFolder + string(filepath.Separator)
)

var (
	ErrVendorFileExists  = errors.New(internalVendor + " file already exists.")
	ErrMissingVendorFile = errors.New("Unable to find internal folder with vendor file.")
	ErrMissingGOROOT     = errors.New("Unable to determine GOROOT.")
	ErrMissingGOPATH     = errors.New("Missing GOPATH.")
	ErrVendorExists      = errors.New("Package already exists as a vendor package.")
	ErrLocalPackage      = errors.New("Cannot vendor a local package.")
	ErrImportExists      = errors.New("Import exists. To update use update command.")
	ErrImportNotExists   = errors.New("Import does not exist.")
	ErrNoLocalPath       = errors.New("Import is present in vendor file, but is missing local path.")
	ErrFilesExists       = errors.New("Files exists at destination of internal vendor path.")
)

type ErrNotInGOPATH struct {
	Missing string
}

func (err ErrNotInGOPATH) Error() string {
	return fmt.Sprintf("Package %q not in GOPATH.", err.Missing)
}

func CmdInit() error {
	/*
		1. Determine if CWD contains "internal/vendor.json".
		2. If exists, return error.
		3. Create directory if it doesn't exist.
		4. Create "internal/vendor.json" file.
	*/
	wd, err := os.Getwd()
	if err != nil {
		return err
	}
	_, err = os.Stat(filepath.Join(wd, internalVendor))
	if os.IsNotExist(err) == false {
		return ErrVendorFileExists
	}
	err = os.MkdirAll(filepath.Join(wd, internalFolder), 0777)
	if err != nil {
		return err
	}
	vf := &VendorFile{
		Tool: toolName,
	}
	return writeVendorFile(wd, vf)
}

func CmdList() ([]ListItem, error) {
	/*
		1. Find vendor root.
		2. Find vendor root import path via GOPATH.
		3. Walk directory, find all directories with go files.
		4. Parse imports for all go files.
		5. Determine the status of all imports.
		  * Std
		  * Local
		  * External Vendor
		  * Internal Vendor
		  * Unused Vendor
		6. Return Vendor import paths.
	*/
	ctx, err := NewContextWD()
	if err != nil {
		return nil, err
	}

	err = ctx.LoadPackage()
	if err != nil {
		return nil, err
	}

	li := make([]ListItem, 0, len(ctx.Package))
	for _, pkg := range ctx.Package {
		li = append(li, ListItem{Status: pkg.Status, Path: pkg.ImportPath})
	}
	// Sort li by Status, then Path.
	sort.Sort(ListItemSort(li))

	return li, nil
}

/*
	Add, Update, and Remove will start with the same steps as List.
	Rather then returning the results, it will find any affected files,
	alter their imports, then write the files back out. Also copy or remove
	files and folders as needed.
*/

func CmdAdd(importPath string) error {
	return addUpdateImportPath(importPath, verifyAdd)
}

func CmdUpdate(importPath string) error {
	return addUpdateImportPath(importPath, verifyUpdate)
}

func verifyAdd(ctx *Context, importPath, local string) error {
	for _, pkg := range ctx.VendorFile.Package {
		if pkg.Vendor == importPath {
			return ErrImportExists
		}
	}
	// Check fo existing internal folders present.
	dirPath := filepath.Join(ctx.RootGopath, local)
	dir, err := os.Open(dirPath)
	if err != nil {
		if os.IsNotExist(err) {
			// No folder present, no need to check for files.
			return nil
		}
		return err
	}
	fl, err := dir.Readdir(-1)
	dir.Close()
	if err != nil {
		return err
	}
	for _, fi := range fl {
		if fi.IsDir() == false {
			return ErrFilesExists
		}
	}
	return nil
}
func verifyUpdate(ctx *Context, importPath, local string) error {
	for _, pkg := range ctx.VendorFile.Package {
		if pkg.Vendor == importPath {
			return nil
		}
	}
	return ErrImportNotExists
}

func addUpdateImportPath(importPath string, verify func(ctx *Context, importPath, local string) error) error {
	importPath = slashToImportPath(importPath)
	ctx, err := NewContextWD()
	if err != nil {
		return err
	}

	err = ctx.LoadPackage(importPath)
	if err != nil {
		return err
	}

	// Determine correct local import path (from GOPATH).
	/*
		"crypto/tls" -> "path/to/mypkg/internal/crypto/tls"
		"yours/internal/yourpkg" -> "path/to/mypkg/internal/yourpkg"
		"github.com/kardianos/osext" -> "patn/to/mypkg/internal/github.com/kardianos/osext"
	*/
	// The following method "cheats" and doesn't look at any external vendor file.
	ss := strings.Split(importPath, internalFolderSlash)
	localImportPath := path.Join(ctx.RootImportPath, internalFolder, ss[len(ss)-1])

	err = verify(ctx, importPath, localImportPath)
	if err != nil {
		return err
	}

	pkg := ctx.Package[importPath]
	if pkg.Status != StatusExternal {
		if pkg.Status == StatusInternal {
			return ErrVendorExists
		}
		if pkg.Status == StatusLocal {
			return ErrLocalPackage
		}
		return ErrNotInGOPATH{importPath}
	}

	// Update vendor file with correct Local field.
	// TODO: find the Version and VersionTime.
	var vp *VendorPackage
	for _, pkg := range ctx.VendorFile.Package {
		if pkg.Vendor == importPath {
			vp = pkg
			break
		}
	}
	if vp == nil {
		vp = &VendorPackage{
			Vendor: importPath,
			Local:  localImportPath,
		}
		ctx.VendorFile.Package = append(ctx.VendorFile.Package, vp)
	}
	err = writeVendorFile(ctx.RootDir, ctx.VendorFile)
	if err != nil {
		return err
	}
	err = CopyPackage(filepath.Join(ctx.RootGopath, slashToFilepath(localImportPath)), pkg.Dir)
	if err != nil {
		return err
	}

	err = ctx.AddImports(importPath)
	if err != nil {
		return err
	}

	// Determine which files to touch.
	fileUnique := make(map[string]struct{}, len(ctx.VendorFile.Package)*3)

	// Rules are all lines in the vendor file.
	rules := make([]Rule, 0, len(ctx.VendorFile.Package))
	for _, vp := range ctx.VendorFile.Package {
		for _, f := range ctx.fileImports[vp.Vendor] {
			fileUnique[f] = struct{}{}
		}
		rules = append(rules, Rule{From: vp.Vendor, To: vp.Local})
	}
	files := make([]string, 0, len(fileUnique))
	for f := range fileUnique {
		files = append(files, f)
	}

	return ctx.RewriteFiles(files, rules)
}
func CmdRemove(importPath string) error {
	importPath = slashToImportPath(importPath)
	ctx, err := NewContextWD()
	if err != nil {
		return err
	}

	err = ctx.LoadPackage(importPath)
	if err != nil {
		return err
	}

	localPath := ""
	localFound := false
	vendorFileIndex := 0
	for i, pkg := range ctx.VendorFile.Package {
		if pkg.Vendor == importPath {
			localPath = pkg.Local
			localFound = true
			vendorFileIndex = i
			break
		}
	}
	if !localFound {
		return ErrImportNotExists
	}
	if localPath == "" {
		return ErrNoLocalPath
	}

	files := ctx.fileImports[localPath]

	err = ctx.RewriteFiles(files, []Rule{Rule{From: localPath, To: importPath}})
	if err != nil {
		return err
	}

	err = RemovePackage(filepath.Join(ctx.RootGopath, slashToFilepath(localPath)))
	if err != nil {
		return err
	}
	nextPkg := make([]*VendorPackage, 0, len(ctx.VendorFile.Package)-1)
	for i, pkg := range ctx.VendorFile.Package {
		if i == vendorFileIndex {
			continue
		}
		nextPkg = append(nextPkg, pkg)
	}
	ctx.VendorFile.Package = nextPkg

	return writeVendorFile(ctx.RootDir, ctx.VendorFile)
}
<|endoftext|>


<commit_before>/*
 Handles all of the rewriting tasks
*/
package rewrite

import (
	"gesture/util"
	"regexp"
	"strings"
)

var (
	linkPrefixes    = []string{"t.co", "cl.ly", "www", "bit.ly", "j.mp", "tcrn.ch", "http"}
	expanders       = []expander{expandUrl, expandEmbeddedImages}
	embeddedRePairs = []embeddedRePair{
		makeRePair(`(http://)?(www\.)?cl\.ly[^\s]+`, `a class="embed".*(http://cl\.ly[^"]+)`, 1),
		makeRePair(`(http://)?(www\.)?instagr.?am[^\s]+`, `img class="photo".*(http://[^"]+)`, 1),
		makeRePair(`(http://)?(x\.)?kingsh\.it[^\s]+`, `a class="embed".*(http://x\.kingsh\.it[^"]+)`, 1),
		makeRePair(`(https?://)?(www\.)?twitter\.com.*photo?[^\s]+`, `img src="(https?://[^"]+)".*Embedded image`, 1),
		makeRePair(`(https?://)?(www\.)?twitter\.com.*photo?[^\s]+`, `img.*media-slideshow-image.*src="(https?://[^"]+):.*".*`, 1),
	}
)

func makeRePair(link string, image string, imageSubmatch int) embeddedRePair {
	return embeddedRePair{
		regexp.MustCompile(link),
		regexp.MustCompile(image),
		imageSubmatch,
	}
}

type embeddedRePair struct {
	link          *regexp.Regexp // tests whether or not a token is a link
	image         *regexp.Regexp // what to search for in the fetched html
	imageSubmatch int            // what submatch to pull out of the image regexp
}

// GetRewrittenLinks takes an input line and rewrite any links that are shortened links into their full representation
// the return value is a slice of those rewritten links
func GetRewrittenLinks(input string) (result []string) {
	for _, link := range strings.Split(input, " ") {
		rewritten, err := expandAll(link)
		if err == nil && rewritten != "" {
			result = append(result, rewritten)
		}
	}
	return
}

// Rewrite takes an input string, tokenizes it on whitespace, and then attempte to rewrite
// each token. The final result is joined back together at the end
func Rewrite(input string) string {
	tokens := strings.Split(input, " ")
	for idx, token := range tokens {
		rewritten, err := expandAll(token)
		if err == nil && rewritten != "" {
			tokens[idx] = rewritten
		}
	}
	return strings.Join(tokens, " ")
}

// an expander is something that takes in a string and possibly expands it
type expander func(string) (string, error)

// thoroughly expand the input string by running it through the expander functions
func expandAll(input string) (string, error) {
	known := make(map[string]bool) // to track what we've seen already
	current := input
	known[current] = true
	for {
		rewritten := false
		for _, fn := range expanders {
			if result, err := fn(current); result != "" && err == nil {
				if known[result] {
					break
				}
				current = result
				known[current] = true
				rewritten = true
				break
			}
		}
		if !rewritten {
			break
		}
	}
	if current == input {
		return "", nil
	}
	return current, nil
}

func expandEmbeddedImages(url string) (result string, err error) {
	for _, rePair := range embeddedRePairs {
		if found := rePair.link.FindString(url); found != "" {
			body, err := util.GetUrl(found)
			if err != nil {
				return "", err
			}
			if matches := rePair.image.FindStringSubmatch(string(body)); matches != nil {
				return matches[rePair.imageSubmatch], nil
			}
		}
	}
	return "", nil
}

// expandUrl is an expander that expands shortened links
func expandUrl(url string) (result string, err error) {
	prefixFound := false
	for _, prefix := range linkPrefixes {
		if strings.HasPrefix(url, prefix) {
			prefixFound = true
			break
		}
	}
	if !prefixFound {
		return "", nil
	}
	if !strings.HasPrefix(url, "http") {
		url = "http://" + url
	}
	return util.ResolveRedirects(url)
}
<commit_msg>Don't search for redirects on every link<commit_after>/*
 Handles all of the rewriting tasks
*/
package rewrite

import (
	"gesture/util"
	"regexp"
	"strings"
	"log"
)

var (
	linkPrefixes    = []*regexp.Regexp{
		makeLinkRe("t.co"),
		makeLinkRe("cl.ly"),
		makeLinkRe("bit.ly"),
		makeLinkRe("j.mp"),
		makeLinkRe("tcrn.ch")}
	expanders       = []expander{expandUrl, expandEmbeddedImages}
	embeddedRePairs = []embeddedRePair{
		makeRePair(`(http://)?(www\.)?cl\.ly[^\s]+`, `a class="embed".*(http://cl\.ly[^"]+)`, 1),
		makeRePair(`(http://)?(www\.)?instagr.?am[^\s]+`, `img class="photo".*(http://[^"]+)`, 1),
		makeRePair(`(http://)?(x\.)?kingsh\.it[^\s]+`, `a class="embed".*(http://x\.kingsh\.it[^"]+)`, 1),
		makeRePair(`(https?://)?(www\.)?twitter\.com.*photo?[^\s]+`, `img src="(https?://[^"]+)".*Embedded image`, 1),
		makeRePair(`(https?://)?(www\.)?twitter\.com.*photo?[^\s]+`, `img.*media-slideshow-image.*src="(https?://[^"]+):.*".*`, 1),
	}
)

func makeLinkRe(part string) *regexp.Regexp {
	return regexp.MustCompile("^(http|https)?(://)?(www.)?" + part)
}

func makeRePair(link string, image string, imageSubmatch int) embeddedRePair {
	return embeddedRePair{
		regexp.MustCompile(link),
		regexp.MustCompile(image),
		imageSubmatch,
	}
}

type embeddedRePair struct {
	link          *regexp.Regexp // tests whether or not a token is a link
	image         *regexp.Regexp // what to search for in the fetched html
	imageSubmatch int            // what submatch to pull out of the image regexp
}

// GetRewrittenLinks takes an input line and rewrite any links that are shortened links into their full representation
// the return value is a slice of those rewritten links
func GetRewrittenLinks(input string) (result []string) {
	for _, link := range strings.Split(input, " ") {
		rewritten, err := expandAll(link)
		if err == nil && rewritten != "" {
			result = append(result, rewritten)
		}
	}
	return
}

// Rewrite takes an input string, tokenizes it on whitespace, and then attempte to rewrite
// each token. The final result is joined back together at the end
func Rewrite(input string) string {
	tokens := strings.Split(input, " ")
	for idx, token := range tokens {
		rewritten, err := expandAll(token)
		if err == nil && rewritten != "" {
			tokens[idx] = rewritten
		}
	}
	return strings.Join(tokens, " ")
}

// an expander is something that takes in a string and possibly expands it
type expander func(string) (string, error)

// thoroughly expand the input string by running it through the expander functions
func expandAll(input string) (string, error) {
	known := make(map[string]bool) // to track what we've seen already
	current := input
	known[current] = true
	for {
		rewritten := false
		for _, fn := range expanders {
			if result, err := fn(current); result != "" && err == nil {
				if known[result] {
					break
				}
				current = result
				known[current] = true
				rewritten = true
				break
			}
		}
		if !rewritten {
			break
		}
	}
	if current == input {
		return "", nil
	}
	return current, nil
}

func expandEmbeddedImages(url string) (result string, err error) {
	for _, rePair := range embeddedRePairs {
		if found := rePair.link.FindString(url); found != "" {
			body, err := util.GetUrl(found)
			if err != nil {
				return "", err
			}
			if matches := rePair.image.FindStringSubmatch(string(body)); matches != nil {
				return matches[rePair.imageSubmatch], nil
			}
		}
	}
	return "", nil
}

// expandUrl is an expander that expands shortened links
func expandUrl(url string) (result string, err error) {
	prefixFound := false
	for _, prefixRE := range linkPrefixes {
		if found := prefixRE.FindString(url); found != "" {
			prefixFound = true
			break
		}
	}
	if !prefixFound {
		return "", nil
	}
	if !strings.HasPrefix(url, "http") {
		url = "http://" + url
	}
	log.Println("Resolving url", url)
	return util.ResolveRedirects(url)
}
<|endoftext|>